628 lines
28 KiB
Swift
628 lines
28 KiB
Swift
//
|
|
// 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
|
|
}
|
|
}
|
|
}
|
|
}
|