patbef-iOS/Befund/Core/Database/Database.swift

628 lines
28 KiB
Swift
Raw Normal View History

2024-01-29 16:20:42 +01:00
//
// Database.swift
// Befund
// Created by Irakli Abetschkhrischwili on 21.05.22.
// Copyright © 2022 MVZ Dr. Stein und Kollegen. All rights reserved.
import Foundation
import SQLite3
extension Core
{
public class Database
{
/**
* Database context of results object
*/
public class Results
{
static let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
static let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
/**
* Creates a database if it still not exist
*/
public static func CreateDBIfNotExists() -> Bool
{
var result: Bool = false
if(!DatabaseExists())
{
let con = CreateConnection()
if(con != nil)
{
let sql = """
create table if not exists results(
pgs text primary key not null,
pat_hash text null,
available integer not null default 0,
available_ts datetime null,
picked_up bit(1) not null default 0,
picked_up_ts datetime null,
file_checksum text null,
status text not null,
modified datetime null,
created datetime not null
)
"""
if(sqlite3_exec(con, sql, nil, nil, nil) == SQLITE_OK)
{
sqlite3_close(con)
result = true
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "CreateDBIfNotExists")
}
}
}
return result
}
/**
* Inserts a results in the database
*/
public static func Create(results: Core.Models.Database.Results) -> Bool
{
var result: Bool = false
if(results.pgs != nil)
{
if(DatabaseExists())
{
let con = CreateConnection()
if(con != nil)
{
var cmd: OpaquePointer? = nil
let sql = "insert into results (pgs, pat_hash, available, available_ts, picked_up, picked_up_ts, file_checksum, status, created) values(?, ?, ?, ?, ?, ?, ?, ?, ?)"
if(sqlite3_prepare_v2(con, sql, -1, &cmd, nil) == SQLITE_OK)
{
sqlite3_bind_text(cmd, 1, (results.pgs! as NSString).utf8String, -1, SQLITE_TRANSIENT)
if(results.pat_hash != nil)
{
sqlite3_bind_text(cmd, 2, (results.pat_hash! as NSString).utf8String, -1, SQLITE_TRANSIENT)
}
else
{
sqlite3_bind_null(cmd, 2)
}
sqlite3_bind_int(cmd, 3, (results.available ? 1 : 0))
if(results.available_ts != nil)
{
sqlite3_bind_text(cmd, 4, (results.available_ts! as NSString).utf8String, -1, SQLITE_TRANSIENT)
}
else
{
sqlite3_bind_null(cmd, 4)
}
sqlite3_bind_int(cmd, 5, (results.picked_up ? 1 : 0))
if(results.picked_up_ts != nil)
{
sqlite3_bind_text(cmd, 6, (results.picked_up_ts! as NSString).utf8String, -1, SQLITE_TRANSIENT)
}
else
{
sqlite3_bind_null(cmd, 6)
}
if(results.file_checksum != nil)
{
sqlite3_bind_text(cmd, 7, (results.file_checksum! as NSString).utf8String, -1, SQLITE_TRANSIENT)
}
else
{
sqlite3_bind_null(cmd, 7)
}
sqlite3_bind_text(cmd, 8, (results.status! as NSString).utf8String, -1, SQLITE_TRANSIENT)
let now = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let created = dateFormatter.string(from: now)
sqlite3_bind_text(cmd, 9, (created as NSString).utf8String, -1, SQLITE_TRANSIENT)
if(sqlite3_step(cmd) != SQLITE_DONE)
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "Create(Results)")
}
sqlite3_finalize(cmd)
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "Create(Results)")
}
sqlite3_close(con)
result = true
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "Create(Results)")
}
}
}
return result
}
/**
* Updates a results in the database
*/
public static func Update(results: Core.Models.Database.Results) -> Bool
{
var result: Bool = false
if(results.pgs != nil)
{
if(DatabaseExists())
{
let con = CreateConnection()
if(con != nil)
{
var cmd: OpaquePointer? = nil
let sql = """
update results set
pat_hash = ?,
available = ?,
available_ts = ?,
picked_up = ?,
picked_up_ts = ?,
file_checksum = ?,
status = ?,
modified = ?
where
pgs = ?
"""
if(sqlite3_prepare_v2(con, sql, -1, &cmd, nil) == SQLITE_OK)
{
if(results.pat_hash != nil)
{
sqlite3_bind_text(cmd, 1, (results.pat_hash! as NSString).utf8String, -1, SQLITE_TRANSIENT)
}
else
{
sqlite3_bind_null(cmd, 1)
}
sqlite3_bind_int(cmd, 2, (results.available ? 1 : 0))
if(results.available_ts != nil)
{
sqlite3_bind_text(cmd, 3, (results.available_ts! as NSString).utf8String, -1, SQLITE_TRANSIENT)
}
else
{
sqlite3_bind_null(cmd, 3)
}
sqlite3_bind_int(cmd, 4, (results.picked_up ? 1 : 0))
if(results.picked_up_ts != nil)
{
sqlite3_bind_text(cmd, 5, (results.picked_up_ts! as NSString).utf8String, -1, SQLITE_TRANSIENT)
}
else
{
sqlite3_bind_null(cmd, 5)
}
if(results.file_checksum != nil)
{
sqlite3_bind_text(cmd, 6, (results.file_checksum! as NSString).utf8String, -1, SQLITE_TRANSIENT)
}
else
{
sqlite3_bind_null(cmd, 6)
}
sqlite3_bind_text(cmd, 7, (results.status! as NSString).utf8String, -1, SQLITE_TRANSIENT)
let now = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let modified = dateFormatter.string(from: now)
sqlite3_bind_text(cmd, 8, (modified as NSString).utf8String, -1, SQLITE_TRANSIENT)
sqlite3_bind_text(cmd, 9, (results.pgs! as NSString).utf8String, -1, SQLITE_TRANSIENT)
if(sqlite3_step(cmd) != SQLITE_DONE)
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "Update(Results)")
}
sqlite3_finalize(cmd)
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "Update(Results)")
}
sqlite3_close(con)
result = true
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "Update(Results)")
}
}
}
return result
}
/**
* Deletes a results from the databse
*/
public static func Delete(results: Core.Models.Database.Results) -> Bool
{
var result: Bool = false
if(results.pgs != nil)
{
if(DatabaseExists())
{
let con = CreateConnection()
if(con != nil)
{
var cmd: OpaquePointer? = nil
let sql = "delete from results where pgs = ?"
if(sqlite3_prepare_v2(con, sql, -1, &cmd, nil) == SQLITE_OK)
{
sqlite3_bind_text(cmd, 1, (results.pgs! as NSString).utf8String, -1, SQLITE_TRANSIENT)
if(sqlite3_step(cmd) != SQLITE_DONE)
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "Delete(Results)")
}
else
{
let filePath = Core.System.GetURLForStorageEncryptedFile(filename: results.pgs!)
if(filePath != nil && Core.System.FileExists(atPath: filePath!.path))
{
result = Core.System.DeleteFile(atPath: filePath!.path)
}
}
sqlite3_finalize(cmd)
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "Delete(Results)")
}
sqlite3_close(con)
result = true
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "Delete(Results)")
}
}
}
return result
}
/**
* Creates or update results in the database
*/
public static func CreateOrUpdate(results: Core.Models.Database.Results) -> Bool
{
let dbResults = GetResults(pgs: results.pgs!)
if(dbResults != nil)
{
return Update(results: results)
}
else
{
return Create(results: results)
}
}
/**
* Returns results by pgs
*/
public static func GetResults(pgs: String) -> Core.Models.Database.Results?
{
var result: Core.Models.Database.Results? = nil
if(DatabaseExists())
{
let con = CreateConnection()
if(con != nil)
{
var cmd: OpaquePointer? = nil
let sql = """
select
pgs,
pat_hash,
available,
available_ts,
picked_up,
picked_up_ts,
file_checksum,
status,
modified,
created
from
results
where
pgs = ?
"""
if(sqlite3_prepare_v2(con, sql, -1, &cmd, nil) == SQLITE_OK)
{
sqlite3_bind_text(cmd, 1, (pgs as NSString).utf8String, -1, nil)
if(sqlite3_step(cmd) == SQLITE_ROW)
{
result = Core.Models.Database.Results()
result!.pgs = String(cString: sqlite3_column_text(cmd, 0))
let pat_hash = sqlite3_column_text(cmd, 1)
if(pat_hash != nil)
{
result!.pat_hash = String(cString: pat_hash!)
}
result!.available = (sqlite3_column_int(cmd, 2) == 1)
let available_ts = sqlite3_column_text(cmd, 3)
if(available_ts != nil)
{
result!.available_ts = String(cString: available_ts!)
}
result!.picked_up = (sqlite3_column_int(cmd, 4) == 1)
let picked_up_ts = sqlite3_column_text(cmd, 5)
if(picked_up_ts != nil)
{
result!.picked_up_ts = String(cString: picked_up_ts!)
}
let file_checksum = sqlite3_column_text(cmd, 6)
if(file_checksum != nil)
{
result!.file_checksum = String(cString: file_checksum!)
}
let status = sqlite3_column_text(cmd, 7)
if(status != nil)
{
result!.status = String(cString: status!)
}
let modified_str = sqlite3_column_text(cmd, 8)
if(modified_str != nil)
{
result!.modified = String(cString: modified_str!)
}
let created_str = sqlite3_column_text(cmd, 9)
if(created_str != nil)
{
result!.created = String(cString: created_str!)
}
}
sqlite3_finalize(cmd)
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "GetResults(String)")
}
sqlite3_close(con)
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "GetResults(String)")
}
}
return result
}
/**
* Returns all results from the database
*/
public static func GetResults(activeOnly: Bool = true) -> Array<Core.Models.Database.Results>?
{
var result: Array<Core.Models.Database.Results>? = nil
if(DatabaseExists())
{
let con = CreateConnection()
if(con != nil)
{
var cmd: OpaquePointer? = nil
let sql = """
select
pgs,
pat_hash,
available,
available_ts,
picked_up,
picked_up_ts,
file_checksum,
status,
modified,
created
from
results
order by
created desc
"""
if(sqlite3_prepare_v2(con, sql, -1, &cmd, nil) == SQLITE_OK)
{
result = Array<Core.Models.Database.Results>()
while(sqlite3_step(cmd) == SQLITE_ROW)
{
var results = Core.Models.Database.Results()
results.pgs = String(cString: sqlite3_column_text(cmd, 0))
let pat_hash = sqlite3_column_text(cmd, 1)
if(pat_hash != nil)
{
results.pat_hash = String(cString: pat_hash!)
}
results.available = (sqlite3_column_int(cmd, 2) == 1)
let available_ts = sqlite3_column_text(cmd, 3)
if(available_ts != nil)
{
results.available_ts = String(cString: available_ts!)
}
results.picked_up = (sqlite3_column_int(cmd, 4) == 1)
let picked_up_ts = sqlite3_column_text(cmd, 5)
if(picked_up_ts != nil)
{
results.picked_up_ts = String(cString: picked_up_ts!)
}
let file_checksum = sqlite3_column_text(cmd, 6)
if(file_checksum != nil)
{
results.file_checksum = String(cString: file_checksum!)
}
let status = sqlite3_column_text(cmd, 7)
if(status != nil)
{
results.status = String(cString: status!)
}
let modified_str = sqlite3_column_text(cmd, 8)
if(modified_str != nil)
{
results.modified = String(cString: modified_str!)
}
let created_str = sqlite3_column_text(cmd, 9)
if(created_str != nil)
{
results.created = String(cString: created_str!)
}
// Show only ready results
if(activeOnly)
{
let statusCode = results.GetStatus()
if((statusCode == .COMPLETED || statusCode == .EXPIRED) && (results.picked_up || results.available))
{
result!.append(results)
}
}
else
{
result!.append(results)
}
}
sqlite3_finalize(cmd)
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "GetResults")
}
sqlite3_close(con)
}
else
{
let dbError = String(cString: sqlite3_errmsg(con))
Core.Log.Critical(msg: dbError, namespace: "Core.Database.Results", method: "GetResults")
}
}
return result
}
/**
* Check if database exists
*/
private static func DatabaseExists() -> Bool
{
let dbPath = Core.System.ResultsDatabasePath()
return (dbPath != nil && Core.System.FileExists(atPath: dbPath!))
}
/**
* Returns database connection pointer
*/
private static func CreateConnection() -> OpaquePointer?
{
var result: OpaquePointer? = nil
let dbPath = Core.System.ResultsDatabasePath()
if(dbPath != nil && sqlite3_open(dbPath!, &result) == SQLITE_OK)
{
return result
}
return result
}
}
}
}