// // Logs.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.Database { /** * Database context of logs object */ public class Logs { 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 logs( id integer primary key autoincrement not null, guid text not null, message text not null, type text not 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.Logs", method: "CreateDBIfNotExists") } } } return result } /** * Inserts a log in the database */ public static func Create(log: Core.Database.Log) -> Bool { var result: Bool = false if(log.message != nil && log.type != nil) { if(DatabaseExists()) { let con = CreateConnection() if(con != nil) { var cmd: OpaquePointer? = nil let sql = "insert into logs (guid, message, type, created) values(?, ?, ?, ?)" if(sqlite3_prepare_v2(con, sql, -1, &cmd, nil) == SQLITE_OK) { let guid = (log.guid != nil ? log.guid! : UUID().uuidString) sqlite3_bind_text(cmd, 1, (guid as NSString).utf8String, -1, SQLITE_TRANSIENT) sqlite3_bind_text(cmd, 2, (log.message! as NSString).utf8String, -1, SQLITE_TRANSIENT) sqlite3_bind_text(cmd, 3, (log.type! 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, 4, (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.Logs", method: "Create(Log)") } sqlite3_finalize(cmd) } else { let dbError = String(cString: sqlite3_errmsg(con)) Core.Log.Critical(msg: dbError, namespace: "Core.Database.Logs", method: "Create(Log)") } sqlite3_close(con) result = true } else { let dbError = String(cString: sqlite3_errmsg(con)) Core.Log.Critical(msg: dbError, namespace: "Core.Database.Logs", method: "Create(Log)") } } } return result } /** * Returns logs from the database */ public static func GetLogs() -> Array? { var result: Array? = nil if(DatabaseExists()) { let con = CreateConnection() if(con != nil) { var cmd: OpaquePointer? = nil let sql = "select id, guid, message, type, created from logs order by created desc" if(sqlite3_prepare_v2(con, sql, -1, &cmd, nil) == SQLITE_OK) { result = Array() while(sqlite3_step(cmd) == SQLITE_ROW) { var log = Core.Database.Log() log.id = sqlite3_column_int(cmd, 0) log.guid = String(cString: sqlite3_column_text(cmd, 1)) log.message = String(cString: sqlite3_column_text(cmd, 2)) log.type = String(cString: sqlite3_column_text(cmd, 3)) let created_str = String(cString: sqlite3_column_text(cmd, 4)) let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" log.created = dateFormatter.date(from: created_str) result!.append(log) } sqlite3_finalize(cmd) } else { let dbError = String(cString: sqlite3_errmsg(con)) Core.Log.Critical(msg: dbError, namespace: "Core.Database.Logs", method: "GetLogs") } sqlite3_close(con) } else { let dbError = String(cString: sqlite3_errmsg(con)) Core.Log.Critical(msg: dbError, namespace: "Core.Database.Logs", method: "GetLogs") } } return result } /** * Returns logs by type from the database */ public static func GetLogs(type: String) -> Array? { var result: Array? = nil if(DatabaseExists()) { let con = CreateConnection() if(con != nil) { var cmd: OpaquePointer? = nil let sql = "select id, guid, message, type, created from logs where type = ? order by created desc" if(sqlite3_prepare_v2(con, sql, -1, &cmd, nil) == SQLITE_OK) { sqlite3_bind_text(cmd, 1, (type as NSString).utf8String, -1, nil) result = Array() while(sqlite3_step(cmd) == SQLITE_ROW) { var log = Core.Database.Log() log.id = sqlite3_column_int(cmd, 0) log.guid = String(cString: sqlite3_column_text(cmd, 1)) log.message = String(cString: sqlite3_column_text(cmd, 2)) log.type = String(cString: sqlite3_column_text(cmd, 3)) let created_str = String(cString: sqlite3_column_text(cmd, 4)) let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" log.created = dateFormatter.date(from: created_str) result!.append(log) } sqlite3_finalize(cmd) } else { let dbError = String(cString: sqlite3_errmsg(con)) Core.Log.Critical(msg: dbError, namespace: "Core.Database.Logs", method: "GetLogs(String)") } sqlite3_close(con) } else { let dbError = String(cString: sqlite3_errmsg(con)) Core.Log.Critical(msg: dbError, namespace: "Core.Database.Logs", method: "GetLogs(String)") } } return result } /** * Deletes the database of logs */ public static func DeleteLogs() -> Bool { var result = false let dbPath = Core.System.LogsDatabasePath() if(dbPath != nil) { result = Core.System.DeleteFile(atPath: dbPath!) } return result } /** * Check if database exists */ private static func DatabaseExists() -> Bool { let dbPath = Core.System.LogsDatabasePath() 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.LogsDatabasePath() if(dbPath != nil && sqlite3_open(dbPath!, &result) == SQLITE_OK) { return result } return result } } /** * Database log object */ public struct Log { public var id: Int32 = 0 public var guid: String? = nil public var message: String? = nil public var type: String? = nil public var created: Date? = nil } }