From 7732cf79b2d7ceb6a90a432a5752924433016a8b Mon Sep 17 00:00:00 2001 From: George Ef Date: Sun, 22 Sep 2024 16:19:54 +0200 Subject: [PATCH 1/8] refactor ModelProtocol, RepositoryProtocol --- MMEX.xcodeproj/project.pbxproj | 12 ++- MMEX/Models/Account.swift | 8 ++ MMEX/Models/Asset.swift | 8 ++ MMEX/Models/Category.swift | 9 +- MMEX/Models/Currency.swift | 9 +- MMEX/Models/Infotable.swift | 8 ++ MMEX/Models/Payee.swift | 9 +- MMEX/Models/Stock.swift | 8 ++ MMEX/Models/Transaction.swift | 8 ++ MMEX/Protocols/EnumCollateNoCase.swift | 2 +- MMEX/Protocols/ModelProtocol.swift | 15 +++ MMEX/Protocols/RepositoryProtocol.swift | 79 ++++++++++++++ MMEX/Repositories/AccountRepository.swift | 93 +++------------- MMEX/Repositories/AssetRepository.swift | 93 +++------------- MMEX/Repositories/CategoryRepository.swift | 90 ++-------------- MMEX/Repositories/CurrencyRepository.swift | 102 +++--------------- MMEX/Repositories/InfotableRepository.swift | 88 +++------------ MMEX/Repositories/PayeeRepository.swift | 95 +++------------- MMEX/Repositories/StockRepository.swift | 87 ++------------- MMEX/Repositories/TransactionRepository.swift | 2 +- MMEX/Views/Accounts/AccountDetailView.swift | 4 +- MMEX/Views/Accounts/AccountListView.swift | 6 +- .../Views/Categories/CategoryDetailView.swift | 4 +- MMEX/Views/Categories/CategoryListView.swift | 4 +- .../Views/Currencies/CurrencyDetailView.swift | 4 +- MMEX/Views/Currencies/CurrencyListView.swift | 6 +- MMEX/Views/ManagementView.swift | 4 +- MMEX/Views/Payees/PayeeDetailView.swift | 4 +- MMEX/Views/Payees/PayeeListView.swift | 6 +- .../Transactions/TransactionAddView2.swift | 6 +- .../Transactions/TransactionListView.swift | 6 +- .../Transactions/TransactionListView2.swift | 6 +- 32 files changed, 287 insertions(+), 598 deletions(-) create mode 100644 MMEX/Protocols/ModelProtocol.swift create mode 100644 MMEX/Protocols/RepositoryProtocol.swift diff --git a/MMEX.xcodeproj/project.pbxproj b/MMEX.xcodeproj/project.pbxproj index ba11ff2b..da52c24f 100644 --- a/MMEX.xcodeproj/project.pbxproj +++ b/MMEX.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ 929EF6632C9FF3ED0051A3E6 /* AssetRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 929EF6622C9FF3ED0051A3E6 /* AssetRepository.swift */; }; 929EF6652C9FF3FB0051A3E6 /* StockRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 929EF6642C9FF3FB0051A3E6 /* StockRepository.swift */; }; 929EF6672CA023EE0051A3E6 /* EnumCollateNoCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 929EF6662CA023EE0051A3E6 /* EnumCollateNoCase.swift */; }; + 929EF6692CA034770051A3E6 /* RepositoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 929EF6682CA034770051A3E6 /* RepositoryProtocol.swift */; }; + 929EF66B2CA03AF90051A3E6 /* ModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 929EF66A2CA03AF90051A3E6 /* ModelProtocol.swift */; }; A3363EE32C9323A5004696C7 /* CategoryEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3363EE22C9323A5004696C7 /* CategoryEditView.swift */; }; A3363EE52C9323D2004696C7 /* CategoryDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3363EE42C9323D2004696C7 /* CategoryDetailView.swift */; }; A3363EE72C93249D004696C7 /* CategoryAddView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3363EE62C93249D004696C7 /* CategoryAddView.swift */; }; @@ -77,6 +79,8 @@ 929EF6622C9FF3ED0051A3E6 /* AssetRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetRepository.swift; sourceTree = ""; }; 929EF6642C9FF3FB0051A3E6 /* StockRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StockRepository.swift; sourceTree = ""; }; 929EF6662CA023EE0051A3E6 /* EnumCollateNoCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumCollateNoCase.swift; sourceTree = ""; }; + 929EF6682CA034770051A3E6 /* RepositoryProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryProtocol.swift; sourceTree = ""; }; + 929EF66A2CA03AF90051A3E6 /* ModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModelProtocol.swift; sourceTree = ""; }; A3363EE22C9323A5004696C7 /* CategoryEditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEditView.swift; sourceTree = ""; }; A3363EE42C9323D2004696C7 /* CategoryDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryDetailView.swift; sourceTree = ""; }; A3363EE62C93249D004696C7 /* CategoryAddView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryAddView.swift; sourceTree = ""; }; @@ -154,6 +158,8 @@ children = ( A3462F652C94854800F79145 /* ExportableEntity.swift */, 929EF6662CA023EE0051A3E6 /* EnumCollateNoCase.swift */, + 929EF66A2CA03AF90051A3E6 /* ModelProtocol.swift */, + 929EF6682CA034770051A3E6 /* RepositoryProtocol.swift */, ); path = Protocols; sourceTree = ""; @@ -316,10 +322,10 @@ children = ( A39B1B3E2C9A6714003E5562 /* Settings */, A39B1B3D2C9A66F7003E5562 /* Currencies */, + A39B1B392C9A668F003E5562 /* Accounts */, A39B1B3C2C9A66E6003E5562 /* Categories */, - A39B1B3B2C9A66CB003E5562 /* Transactions */, A39B1B3A2C9A66B8003E5562 /* Payees */, - A39B1B392C9A668F003E5562 /* Accounts */, + A39B1B3B2C9A66CB003E5562 /* Transactions */, A3C142A72C906E0A00D3CEC0 /* CustomNumberPadView.swift */, A3462F632C9426F500F79145 /* InsightsViewModel.swift */, A3C142AD2C9134DD00D3CEC0 /* InsightsView.swift */, @@ -435,6 +441,7 @@ A3C1429A2C8FF77D00D3CEC0 /* TransactionDetailView.swift in Sources */, A3C142942C8FE13E00D3CEC0 /* PayeeRepository.swift in Sources */, A3C1429E2C8FFCF100D3CEC0 /* TransactionAddView.swift in Sources */, + 929EF66B2CA03AF90051A3E6 /* ModelProtocol.swift in Sources */, A3C142922C8FE11700D3CEC0 /* AccountRepository.swift in Sources */, A3C1422B2C89751500D3CEC0 /* MMEXApp.swift in Sources */, A39B1B362C99A0C2003E5562 /* CurrencyEditView.swift in Sources */, @@ -456,6 +463,7 @@ A3363EE32C9323A5004696C7 /* CategoryEditView.swift in Sources */, A3C142652C8ED8EA00D3CEC0 /* AccountEditView.swift in Sources */, A3C142632C8ED8C000D3CEC0 /* AccountAddView.swift in Sources */, + 929EF6692CA034770051A3E6 /* RepositoryProtocol.swift in Sources */, A3C142A22C90267F00D3CEC0 /* CategoryRepository.swift in Sources */, A37E7D862C9AC2D000B4ECFC /* AboutView.swift in Sources */, A3363EE92C9326A1004696C7 /* CategoryListView.swift in Sources */, diff --git a/MMEX/Models/Account.swift b/MMEX/Models/Account.swift index d28d7ec1..9acd3361 100644 --- a/MMEX/Models/Account.swift +++ b/MMEX/Models/Account.swift @@ -91,6 +91,14 @@ extension Account { ) } } +extension Account: ModelProtocol { + static let modelName = "Account" + + func shortDesc() -> String { + "\(self.name)" + } +} + extension Account { static let accountTypeToSFSymbol: [String: String] = [ "Cash" : "dollarsign.circle.fill", diff --git a/MMEX/Models/Asset.swift b/MMEX/Models/Asset.swift index a7424ea5..c12af451 100644 --- a/MMEX/Models/Asset.swift +++ b/MMEX/Models/Asset.swift @@ -74,6 +74,14 @@ struct Asset: ExportableEntity { } } +extension Asset: ModelProtocol { + static let modelName = "Asset" + + func shortDesc() -> String { + "\(self.name), \(self.id)" + } +} + extension Asset { static let sampleData: [Asset] = [ Asset( diff --git a/MMEX/Models/Category.swift b/MMEX/Models/Category.swift index d9bb6599..b2a120e3 100644 --- a/MMEX/Models/Category.swift +++ b/MMEX/Models/Category.swift @@ -16,7 +16,6 @@ struct Category: ExportableEntity { } extension Category { - // empty category static var empty : Category { Category( id: 1, name: "cateogry name", active: true, parentId: nil ) } @@ -26,6 +25,14 @@ extension Category { } } +extension Category: ModelProtocol { + static let modelName = "Category" + + func shortDesc() -> String { + "\(self.name), \(self.id)" + } +} + extension Category { static let categoryToSFSymbol: [String: String] = [ "Unknown": "camera.metering.unknown", diff --git a/MMEX/Models/Currency.swift b/MMEX/Models/Currency.swift index 5549d7b2..3f883d42 100644 --- a/MMEX/Models/Currency.swift +++ b/MMEX/Models/Currency.swift @@ -24,7 +24,6 @@ struct Currency: ExportableEntity { } extension Currency { - // empty currency static var empty: Currency { Currency( id: 0, name: "", prefixSymbol: nil, suffixSymbol: nil, decimalPoint: nil, groupSeparator: nil, unitName: nil, centName: nil, @@ -32,6 +31,14 @@ extension Currency { ) } } +extension Currency: ModelProtocol { + static let modelName = "Currency" + + func shortDesc() -> String { + "\(self.name)" + } +} + extension Currency { /// A `NumberFormatter` configured specifically for the currency. var formatter: NumberFormatter { diff --git a/MMEX/Models/Infotable.swift b/MMEX/Models/Infotable.swift index 0a7596c4..7eb80191 100644 --- a/MMEX/Models/Infotable.swift +++ b/MMEX/Models/Infotable.swift @@ -52,6 +52,14 @@ extension Infotable { ) } } +extension Infotable: ModelProtocol { + static let modelName = "Infotable" + + func shortDesc() -> String { + "\(self.name)" + } +} + extension Infotable { static let sampleData: [Infotable] = [ Infotable(id: 1, name: "DATAVERSION", value: "3"), diff --git a/MMEX/Models/Payee.swift b/MMEX/Models/Payee.swift index 55f821d2..bf15633a 100644 --- a/MMEX/Models/Payee.swift +++ b/MMEX/Models/Payee.swift @@ -34,10 +34,17 @@ struct Payee: ExportableEntity { } extension Payee { - // empty payee static var empty: Payee { Payee(id: 0, name: "", categoryId: 0) } } +extension Payee: ModelProtocol { + static let modelName = "Payee" + + func shortDesc() -> String { + "\(self.name)" + } +} + extension Payee { static let sampleData: [Payee] = [ Payee( diff --git a/MMEX/Models/Stock.swift b/MMEX/Models/Stock.swift index cc50ba99..390c68cb 100644 --- a/MMEX/Models/Stock.swift +++ b/MMEX/Models/Stock.swift @@ -48,6 +48,14 @@ struct Stock: ExportableEntity { } } +extension Stock: ModelProtocol { + static let modelName = "Stock" + + func shortDesc() -> String { + "\(self.name), \(self.id)" + } +} + extension Stock { static let sampleData: [Stock] = [ Stock( diff --git a/MMEX/Models/Transaction.swift b/MMEX/Models/Transaction.swift index 31c92320..1bf86b78 100644 --- a/MMEX/Models/Transaction.swift +++ b/MMEX/Models/Transaction.swift @@ -89,6 +89,14 @@ extension Transaction { ) } } +extension Transaction: ModelProtocol { + static let modelName = "Transaction" + + func shortDesc() -> String { + "\(self.id)" + } +} + extension Transaction { var day: String { // Extract the date portion (ignoring the time) from ISO-8601 string diff --git a/MMEX/Protocols/EnumCollateNoCase.swift b/MMEX/Protocols/EnumCollateNoCase.swift index 5958058e..2cf24c31 100644 --- a/MMEX/Protocols/EnumCollateNoCase.swift +++ b/MMEX/Protocols/EnumCollateNoCase.swift @@ -1,5 +1,5 @@ // -// Asset.swift +// EnumCollateNoCase.swift // MMEX // // Created 2024-09-22 by George Ef (george.a.ef@gmail.com) diff --git a/MMEX/Protocols/ModelProtocol.swift b/MMEX/Protocols/ModelProtocol.swift new file mode 100644 index 00000000..b1450451 --- /dev/null +++ b/MMEX/Protocols/ModelProtocol.swift @@ -0,0 +1,15 @@ +// +// ModelProtocal.swift +// MMEX +// +// Created 2024-09-22 by George Ef (george.a.ef@gmail.com) +// + +import Foundation + +protocol ModelProtocol { + static var modelName: String { get } + + var id: Int64 { get set } + func shortDesc() -> String +} diff --git a/MMEX/Protocols/RepositoryProtocol.swift b/MMEX/Protocols/RepositoryProtocol.swift new file mode 100644 index 00000000..3d7eb16e --- /dev/null +++ b/MMEX/Protocols/RepositoryProtocol.swift @@ -0,0 +1,79 @@ +// +// RepositoryProtocaol.swift +// MMEX +// +// Created 2024-09-22 by George Ef (george.a.ef@gmail.com) +// + +import Foundation +import SQLite + +protocol RepositoryProtocol { + associatedtype RepositoryItem: ModelProtocol + + static var repositoryName: String { get } + static var table: SQLite.Table { get } + static var selectQuery: SQLite.Table { get } + static func selectResult(_ row: SQLite.Row) -> RepositoryItem + static var col_id: SQLite.Expression { get } + static func itemSetters(_ item: RepositoryItem) -> [SQLite.Setter] + + var db: Connection? { get } +} + +extension RepositoryProtocol { + func select(query: SQLite.Table = Self.selectQuery) -> [RepositoryItem] { + guard let db else { return [] } + do { + var results: [RepositoryItem] = [] + for row in try db.prepare(query) { + results.append(Self.selectResult(row)) + } + print("Successfully loaded from \(Self.repositoryName): \(results.count)") + return results + } catch { + print("Error loading from \(Self.repositoryName): \(error)") + return [] + } + } + + func insert(_ item: inout RepositoryItem) -> Bool { + guard let db else { return false } + do { + let query = Self.table.insert(Self.itemSetters(item)) + let rowid = try db.run(query) + item.id = rowid + print("Successfully added \(RepositoryItem.modelName): \(item.shortDesc())") + return true + } catch { + print("Failed to add \(RepositoryItem.modelName): \(error)") + return false + } + } + + func update(_ item: RepositoryItem) -> Bool { + guard let db else { return false } + do { + let query = Self.table.filter(Self.col_id == item.id).update(Self.itemSetters(item)) + try db.run(query) + print("Successfully updated \(RepositoryItem.modelName): \(item.shortDesc())") + return true + } catch { + print("Failed to update \(RepositoryItem.modelName): \(error)") + return false + } + } + + func delete(_ item: RepositoryItem) -> Bool { + guard let db else { return false } + do { + let query = Self.table.filter(Self.col_id == item.id).delete() + try db.run(query) + print("Successfully deleted \(RepositoryItem.modelName): \(item.shortDesc())") + return true + } catch { + print("Failed to delete \(RepositoryItem.modelName): \(error)") + return false + } + } +} diff --git a/MMEX/Repositories/AccountRepository.swift b/MMEX/Repositories/AccountRepository.swift index e1396aca..aca9ab0e 100644 --- a/MMEX/Repositories/AccountRepository.swift +++ b/MMEX/Repositories/AccountRepository.swift @@ -16,9 +16,11 @@ class AccountRepository { } } -extension AccountRepository { - // table query - static let table = SQLite.Table("ACCOUNTLIST_V1") +extension AccountRepository: RepositoryProtocol { + typealias RepositoryItem = Account + + static let repositoryName = "ACCOUNTLIST_V1" + static let table = SQLite.Table(repositoryName) // column | type | other // ----------------+---------+------ @@ -73,10 +75,7 @@ extension AccountRepository { static let cast_creditLimit = cast(col_creditLimit) as SQLite.Expression static let cast_interestRate = cast(col_interestRate) as SQLite.Expression static let cast_minimumPayment = cast(col_minimumPayment) as SQLite.Expression -} -extension AccountRepository { - // select query static let selectQuery = table.select( col_id, col_name, @@ -101,8 +100,7 @@ extension AccountRepository { cast_minimumPayment ) - // select result - static func selectResult(_ row: Row) -> Account { + static func selectResult(_ row: SQLite.Row) -> Account { return Account( id : row[col_id], name : row[col_name], @@ -129,7 +127,7 @@ extension AccountRepository { ) } - static func insertSetters(_ account: Account) -> [Setter] { + static func itemSetters(_ account: Account) -> [SQLite.Setter] { return [ col_name <- account.name, col_type <- account.type.id, @@ -153,47 +151,21 @@ extension AccountRepository { col_minimumPayment <- account.minimumPayment ] } - - // insert query - static func insertQuery(_ account: Account) -> SQLite.Insert { - return table.insert(insertSetters(account)) - } - - // update query - static func updateQuery(_ account: Account) -> SQLite.Update { - return table.filter(col_id == account.id).update(insertSetters(account)) - } - - // delete query - static func deleteQuery(_ account: Account) -> SQLite.Delete { - return table.filter(col_id == account.id).delete() - } } extension AccountRepository { - func loadAccounts() -> [Account] { - guard let db else { return [] } - do { - var accounts: [Account] = [] - for row in try db.prepare(AccountRepository.selectQuery - .order(AccountRepository.col_name) - ) { - accounts.append(AccountRepository.selectResult(row)) - } - print("Successfully loaded accountss: \(accounts.count)") - return accounts - } catch { - print("Error loading accounts: \(error)") - return [] - } + func load() -> [Account] { + return select(query: Self.selectQuery + .order(Self.col_name) + ) } - func loadAccountsWithCurrency() -> [Account] { + func loadWithCurrency() -> [Account] { // TODO guard let db else {return []} - var accounts = loadAccounts(); - let currencies = CurrencyRepository(db: db).loadCurrencies(); + var accounts = load(); + let currencies = CurrencyRepository(db: db).load(); // Create a lookup dictionary for currencies by currencyId let currencyDictionary = Dictionary(uniqueKeysWithValues: currencies.map { ($0.id, $0) }) @@ -206,41 +178,4 @@ extension AccountRepository { return accounts } - - func addAccount(account: inout Account) -> Bool { - guard let db else { return false } - do { - let rowid = try db.run(AccountRepository.insertQuery(account)) - account.id = rowid - print("Successfully added account: \(account.name), \(account.id)") - return true - } catch { - print("Failed to add account: \(error)") - return false - } - } - - func updateAccount(account: Account) -> Bool { - guard let db else { return false } - do { - try db.run(AccountRepository.updateQuery(account)) - print("Successfully updated account: \(account.name)") - return true - } catch { - print("Failed to update account: \(error)") - return false - } - } - - func deleteAccount(account: Account) -> Bool { - guard let db else { return false } - do { - try db.run(AccountRepository.deleteQuery(account)) - print("Successfully deleted account: \(account.name)") - return true - } catch { - print("Failed to delete account: \(error)") - return false - } - } } diff --git a/MMEX/Repositories/AssetRepository.swift b/MMEX/Repositories/AssetRepository.swift index e794d327..6030396c 100644 --- a/MMEX/Repositories/AssetRepository.swift +++ b/MMEX/Repositories/AssetRepository.swift @@ -16,9 +16,11 @@ class AssetRepository { } } -extension AssetRepository { - // table query - static let table = SQLite.Table("ASSETS_V1") +extension AssetRepository: RepositoryProtocol { + typealias RepositoryItem = Asset + + static let repositoryName = "ASSETS_V1" + static let table = SQLite.Table(repositoryName) // column | type | other // ----------------+---------+------ @@ -33,8 +35,8 @@ extension AssetRepository { // VALUECHANGEMODE | TEXT | (Percentage, Linear) // VALUECHANGERATE | NUMERIC | // NOTES | TEXT | - - // table columns + + // columns static let col_id = SQLite.Expression("ASSETID") static let col_type = SQLite.Expression("ASSETTYPE") static let col_status = SQLite.Expression("ASSETSTATUS") @@ -46,14 +48,11 @@ extension AssetRepository { static let col_changeMode = SQLite.Expression("VALUECHANGEMODE") static let col_changeRate = SQLite.Expression("VALUECHANGERATE") static let col_notes = SQLite.Expression("NOTES") - + // cast NUMERIC to REAL static let cast_value = cast(col_value) as SQLite.Expression static let cast_changeRate = cast(col_changeRate) as SQLite.Expression -} -extension AssetRepository { - // select query static let selectQuery = table.select( col_id, col_type, @@ -68,8 +67,7 @@ extension AssetRepository { col_notes ) - // select result - static func selectResult(_ row: Row) -> Asset { + static func selectResult(_ row: SQLite.Row) -> Asset { return Asset( id : row[col_id], type : AssetType(collateNoCase: row[col_type]), @@ -85,7 +83,7 @@ extension AssetRepository { ) } - static func insertSetters(_ asset: Asset) -> [Setter] { + static func itemSetters(_ asset: Asset) -> [SQLite.Setter] { return [ col_id <- asset.id, col_type <- asset.type.map { $0.name }, @@ -100,75 +98,10 @@ extension AssetRepository { col_notes <- asset.notes ] } - - // insert query - static func insertQuery(_ asset: Asset) -> SQLite.Insert { - return table.insert(insertSetters(asset)) - } - - // update query - static func updateQuery(_ asset: Asset) -> SQLite.Update { - return table.filter(col_id == asset.id).update(insertSetters(asset)) - } - - // delete query - static func deleteQuery(_ asset: Asset) -> SQLite.Delete { - return table.filter(col_id == asset.id).delete() - } } extension AssetRepository { - func loadAssets() -> [Asset] { - guard let db else { return [] } - do { - var assets: [Asset] = [] - for row in try db.prepare(AssetRepository.selectQuery - .order(AssetRepository.col_type, AssetRepository.col_status.desc, AssetRepository.col_name) - ) { - assets.append(AssetRepository.selectResult(row)) - } - print("Successfully loaded assets: \(assets.count)") - return assets - } catch { - print("Error loading assets: \(error)") - return [] - } - } - - func addAsset(asset: inout Asset) -> Bool { - guard let db else { return false } - do { - let rowid = try db.run(AssetRepository.insertQuery(asset)) - asset.id = rowid - print("Successfully added asset: \(asset.name), \(asset.id)") - return true - } catch { - print("Failed to add asset: \(error)") - return false - } - } - - func updateAsset(asset: Asset) -> Bool { - guard let db else { return false } - do { - try db.run(AssetRepository.updateQuery(asset)) - print("Successfully updated asset: \(asset.name), \(asset.id)") - return true - } catch { - print("Failed to update asset: \(error)") - return false - } - } - - func deleteAsset(asset: Asset) -> Bool { - guard let db else { return false } - do { - try db.run(AssetRepository.deleteQuery(asset)) - print("Successfully deleted asset: \(asset.name), \(asset.id)") - return true - } catch { - print("Failed to delete asset: \(error)") - return false - } - } + func load() -> [Asset] { select(query: AssetRepository.selectQuery + .order(Self.col_type, Self.col_status.desc, Self.col_name) + ) } } diff --git a/MMEX/Repositories/CategoryRepository.swift b/MMEX/Repositories/CategoryRepository.swift index 7e85279d..9c0324ed 100644 --- a/MMEX/Repositories/CategoryRepository.swift +++ b/MMEX/Repositories/CategoryRepository.swift @@ -15,9 +15,11 @@ class CategoryRepository { } } -extension CategoryRepository { - // table query - static let table = SQLite.Table("CATEGORY_V1") +extension CategoryRepository: RepositoryProtocol { + typealias RepositoryItem = Category + + static let repositoryName = "CATEGORY_V1" + static let table = SQLite.Table(repositoryName) // column | type | other // ----------+---------+------ @@ -32,10 +34,7 @@ extension CategoryRepository { static let col_name = SQLite.Expression("CATEGNAME") static let col_active = SQLite.Expression("ACTIVE") static let col_parentId = SQLite.Expression("PARENTID") -} -extension CategoryRepository { - // select query static let selectQuery = table.select( col_id, col_name, @@ -43,8 +42,7 @@ extension CategoryRepository { col_parentId ) - // select result - static func selectResult(_ row: Row) -> Category { + static func selectResult(_ row: SQLite.Row) -> Category { return Category( id : row[col_id], name : row[col_name], @@ -53,84 +51,18 @@ extension CategoryRepository { ) } - // insert query - static func insertQuery(_ category: Category) -> SQLite.Insert { - return table.insert( + static func itemSetters(_ category: Category) -> [SQLite.Setter] { + return [ col_name <- category.name, col_active <- category.active ?? false ? 1 : 0, col_parentId <- category.parentId - ) - } - - // update query - static func updateQuery(_ category: Category) -> SQLite.Update { - return table.filter(col_id == category.id).update( - col_name <- category.name, - col_active <- category.active ?? false ? 1 : 0, - col_parentId <- category.parentId - ) - } - - // delete query - static func deleteQuery(_ category: Category) -> SQLite.Delete { - return table.filter(col_id == category.id).delete() + ] } } extension CategoryRepository { // load all categories - func loadCategories() -> [Category] { - guard let db = db else { return [] } - do { - var categories: [Category] = [] - for row in try db.prepare(CategoryRepository.selectQuery) { - categories.append(CategoryRepository.selectResult(row)) - } - print("Successfully loaded categories: \(categories.count)") - return categories - } catch { - print("Error loading categories: \(error)") - return [] - } - } - - // add a new category - func addCategory(category: inout Category) -> Bool { - guard let db else { return false } - do { - let rowid = try db.run(CategoryRepository.insertQuery(category)) - category.id = rowid // Update the category ID with the inserted row ID - print("Successfully added category: \(category.name), \(category.id)") - return true - } catch { - print("Failed to add category: \(error)") - return false - } - } - - // update an existing category - func updateCategory(category: Category) -> Bool { - guard let db else { return false } - do { - try db.run(CategoryRepository.updateQuery(category)) - print("Successfully updated category: \(category.name), \(category.id)") - return true - } catch { - print("Failed to update category: \(error)") - return false - } - } - - // delete a category - func deleteCategory(category: Category) -> Bool { - guard let db else { return false } - do { - try db.run(CategoryRepository.deleteQuery(category)) - print("Successfully deleted category: \(category.name), \(category.id)") - return true - } catch { - print("Failed to delete category: \(error)") - return false - } + func load() -> [Category] { + return select(query: Self.selectQuery) } } diff --git a/MMEX/Repositories/CurrencyRepository.swift b/MMEX/Repositories/CurrencyRepository.swift index 34e07427..21a1d17d 100644 --- a/MMEX/Repositories/CurrencyRepository.swift +++ b/MMEX/Repositories/CurrencyRepository.swift @@ -16,9 +16,11 @@ class CurrencyRepository { } } -extension CurrencyRepository { - // table query - static let table = SQLite.Table("CURRENCYFORMATS_V1") +extension CurrencyRepository: RepositoryProtocol { + typealias RepositoryItem = Currency + + static let repositoryName = "CURRENCYFORMATS_V1" + static let table = SQLite.Table(repositoryName) // column | type | other // ----------------+---------+------ @@ -51,10 +53,7 @@ extension CurrencyRepository { // cast NUMERIC to REAL static let cast_baseConversionRate = cast(col_baseConversionRate) as SQLite.Expression -} -extension CurrencyRepository { - // select query static let selectQuery = table.select( col_id, col_name, @@ -70,8 +69,7 @@ extension CurrencyRepository { col_type ) - // select result - static func selectResult(_ row: Row) -> Currency { + static func selectResult(_ row: SQLite.Row) -> Currency { return Currency( id : row[col_id], name : row[col_name], @@ -88,26 +86,8 @@ extension CurrencyRepository { ) } - // insert query - static func insertQuery(_ currency: Currency) -> SQLite.Insert { - return table.insert( - col_name <- currency.name, - col_prefixSymbol <- currency.prefixSymbol, - col_suffixSymbol <- currency.suffixSymbol, - col_decimalPoint <- currency.decimalPoint, - col_groupSeparator <- currency.groupSeparator, - col_unitName <- currency.unitName, - col_centName <- currency.centName, - col_scale <- currency.scale, - col_baseConversionRate <- currency.baseConversionRate, - col_symbol <- currency.symbol, - col_type <- currency.type - ) - } - - // update query - static func updateQuery(_ currency: Currency) -> SQLite.Update { - return table.filter(col_id == currency.id).update( + static func itemSetters(_ currency: Currency) -> [SQLite.Setter] { + return [ col_name <- currency.name, col_prefixSymbol <- currency.prefixSymbol, col_suffixSymbol <- currency.suffixSymbol, @@ -119,71 +99,15 @@ extension CurrencyRepository { col_baseConversionRate <- currency.baseConversionRate, col_symbol <- currency.symbol, col_type <- currency.type - ) - } - - // delete query - static func deleteQuery(_ currency: Currency) -> SQLite.Delete { - return table.filter(col_id == currency.id).delete() + ] } } extension CurrencyRepository { // load all currencies - func loadCurrencies() -> [Currency] { - guard let db else { return [] } - do { - var currencies: [Currency] = [] - for row in try db.prepare(CurrencyRepository.selectQuery - .order(CurrencyRepository.col_name) - ) { - currencies.append(CurrencyRepository.selectResult(row)) - } - print("Successfully loaded currencies: \(currencies.count)") - return currencies - } catch { - print("Error loading currencies: \(error)") - return [] - } - } - - // add a new currency - func addCurrency(currency: inout Currency) -> Bool { - guard let db else { return false } - do { - let rowid = try db.run(CurrencyRepository.insertQuery(currency)) - currency.id = rowid - print("Successfully added currency: \(currency.name), \(currency.id)") - return true - } catch { - print("Failed to add currency: \(error)") - return false - } - } - - // update an existing currency - func updateCurrency(currency: Currency) -> Bool { - guard let db else { return false } - do { - try db.run(CurrencyRepository.updateQuery(currency)) - print("Successfully updated currency: \(currency.name)") - return true - } catch { - print("Failed to update currency: \(error)") - return false - } - } - - // delete a currency - func deleteCurrency(currency: Currency) -> Bool { - guard let db else { return false } - do { - try db.run(CurrencyRepository.deleteQuery(currency)) - print("Successfully deleted currency: \(currency.name)") - return true - } catch { - print("Failed to delete currency: \(error)") - return false - } + func load() -> [Currency] { + return select(query: Self.selectQuery + .order(Self.col_name) + ) } } diff --git a/MMEX/Repositories/InfotableRepository.swift b/MMEX/Repositories/InfotableRepository.swift index 37fafa65..80c580d6 100644 --- a/MMEX/Repositories/InfotableRepository.swift +++ b/MMEX/Repositories/InfotableRepository.swift @@ -16,9 +16,11 @@ class InfotableRepository { } } -extension InfotableRepository { - // table query - static let table = SQLite.Table("INFOTABLE_V1") +extension InfotableRepository: RepositoryProtocol { + typealias RepositoryItem = Infotable + + static let repositoryName = "INFOTABLE_V1" + static let table = SQLite.Table(repositoryName) // column | type | other // ----------+---------+------ @@ -30,18 +32,14 @@ extension InfotableRepository { static let col_id = SQLite.Expression("INFOID") static let col_name = SQLite.Expression("INFONAME") static let col_value = SQLite.Expression("INFOVALUE") -} -extension InfotableRepository { - // select query static let selectQuery = table.select( col_id, col_name, col_value ) - // select result - static func selectResult(_ row: Row) -> Infotable { + static func selectResult(_ row: SQLite.Row) -> Infotable { return Infotable( id : row[col_id], name : row[col_name], @@ -49,47 +47,22 @@ extension InfotableRepository { ) } - // insert query - static func insertQuery(_ info: Infotable) -> SQLite.Insert { - return table.insert( - col_name <- info.name, - col_value <- info.value - ) - } - - // update query - static func updateQuery(_ info: Infotable) -> SQLite.Update { - return table.filter(col_id == info.id).update( + static func itemSetters(_ info: Infotable) -> [SQLite.Setter] { + return [ col_name <- info.name, col_value <- info.value - ) - } - - // delete query - static func deleteQuery(_ info: Infotable) -> SQLite.Delete { - return table.filter(col_id == info.id).delete() + ] } } extension InfotableRepository { // load all keys - func loadInfo() -> [Infotable] { - guard let db else { return [] } - do { - var results: [Infotable] = [] - for row in try db.prepare(InfotableRepository.selectQuery) { - results.append(InfotableRepository.selectResult(row)) - } - print("Successfully loaded infotable: \(results.count)") - return results - } catch { - print("Error loading infotable: \(error)") - return [] - } + func load() -> [Infotable] { + return select() } // load specific keys into a dictionary - func loadInfo(for keys: [InfoKey]) -> [InfoKey: Infotable] { + func load(for keys: [InfoKey]) -> [InfoKey: Infotable] { guard let db else { return [:] } do { var results: [InfoKey: Infotable] = [:] @@ -111,43 +84,6 @@ extension InfotableRepository { } } - func addInfo(info: inout Infotable) -> Bool { - guard let db else { return false } - do { - let rowid = try db.run(InfotableRepository.insertQuery(info)) - info.id = rowid - print("Successfully added infokey: \(info.name), \(info.id)") - return true - } catch { - print("Failed to add infotable: \(error)") - return false - } - } - - func updateInfo(info: Infotable) -> Bool { - guard let db else { return false } - do { - try db.run(InfotableRepository.updateQuery(info)) - print("Successfully updated infokey: \(info.name)") - return true - } catch { - print("Failed to update info: \(error)") - return false - } - } - - func deleteInfo(info: Infotable) -> Bool { - guard let db else { return false } - do { - try db.run(InfotableRepository.deleteQuery(info)) - print("Successfully deleted infokey: \(info.name)") - return true - } catch { - print("Failed to delete infokey: \(error)") - return false - } - } - // New Methods for Key-Value Pairs // Fetch value for a specific key, allowing for String or Int64 func getValue(for key: String, as type: T.Type) -> T? { diff --git a/MMEX/Repositories/PayeeRepository.swift b/MMEX/Repositories/PayeeRepository.swift index e4f38859..e48a9157 100644 --- a/MMEX/Repositories/PayeeRepository.swift +++ b/MMEX/Repositories/PayeeRepository.swift @@ -16,9 +16,11 @@ class PayeeRepository { } } -extension PayeeRepository { - // table query - static let table = SQLite.Table("PAYEE_V1") +extension PayeeRepository: RepositoryProtocol { + typealias RepositoryItem = Payee + + static let repositoryName = "PAYEE_V1" + static let table = SQLite.Table(repositoryName) // column | type | other // ----------+---------+------ @@ -40,10 +42,7 @@ extension PayeeRepository { static let col_notes = SQLite.Expression("NOTES") static let col_active = SQLite.Expression("ACTIVE") static let col_pattern = SQLite.Expression("PATTERN") -} -extension PayeeRepository { - // select query static let selectQuery = table.select( col_id, col_name, @@ -55,8 +54,7 @@ extension PayeeRepository { col_pattern ) - // select result - static func selectResult(_ row: Row) -> Payee { + static func selectResult(_ row: SQLite.Row) -> Payee { return Payee( id : row[col_id], name : row[col_name], @@ -69,22 +67,8 @@ extension PayeeRepository { ) } - // insert query - static func insertQuery(_ payee: Payee) -> SQLite.Insert { - return table.insert( - col_name <- payee.name, - col_categoryId <- payee.categoryId, - col_number <- payee.number, - col_website <- payee.website, - col_notes <- payee.notes, - col_active <- payee.active, - col_pattern <- payee.pattern - ) - } - - // update query - static func updateQuery(_ payee: Payee) -> SQLite.Update { - return table.filter(col_id == payee.id).update( + static func itemSetters(_ payee: Payee) -> [SQLite.Setter] { + return [ col_name <- payee.name, col_categoryId <- payee.categoryId, col_number <- payee.number, @@ -92,67 +76,14 @@ extension PayeeRepository { col_notes <- payee.notes, col_active <- payee.active, col_pattern <- payee.pattern - ) - } - - // delete query - static func deleteQuery(_ payee: Payee) -> SQLite.Delete { - return table.filter(col_id == payee.id).delete() + ] } } extension PayeeRepository { - func loadPayees() -> [Payee] { - guard let db else { return [] } - do { - var payees: [Payee] = [] - for row in try db.prepare(PayeeRepository.selectQuery - .order(PayeeRepository.col_active.desc, PayeeRepository.col_name) - ) { - payees.append(PayeeRepository.selectResult(row)) - } - print("Successfully loaded payees: \(payees.count)") - return payees - } catch { - print("Error loading payees: \(error)") - return [] - } - } - - func addPayee(payee: inout Payee) -> Bool { - guard let db else { return false } - do { - let rowid = try db.run(PayeeRepository.insertQuery(payee)) - payee.id = rowid - print("Successfully added payee: \(payee.name), \(payee.id)") - return true - } catch { - print("Failed to add payee: \(error)") - return false - } - } - - func updatePayee(payee: Payee) -> Bool { - guard let db else { return false } - do { - try db.run(PayeeRepository.updateQuery(payee)) - print("Successfully updated payee: \(payee.name)") - return true - } catch { - print("Failed to update payee: \(error)") - return false - } - } - - func deletePayee(payee: Payee) -> Bool { - guard let db else { return false } - do { - try db.run(PayeeRepository.deleteQuery(payee)) - print("Successfully deleted payee: \(payee.name)") - return true - } catch { - print("Failed to delete payee: \(error)") - return false - } + func load() -> [Payee] { + return select(query: Self.selectQuery + .order(Self.col_active.desc, Self.col_name) + ) } } diff --git a/MMEX/Repositories/StockRepository.swift b/MMEX/Repositories/StockRepository.swift index f2007c78..3d9108ec 100644 --- a/MMEX/Repositories/StockRepository.swift +++ b/MMEX/Repositories/StockRepository.swift @@ -16,9 +16,11 @@ class StockRepository { } } -extension StockRepository { - // table query - static let table = SQLite.Table("STOCK_V1") +extension StockRepository: RepositoryProtocol { + typealias RepositoryItem = Stock + + static let repositoryName = "STOCK_V1" + static let table = SQLite.Table(repositoryName) // column | type | other // --------------+---------+------ @@ -53,10 +55,7 @@ extension StockRepository { static let cast_currentPrice = cast(col_currentPrice) as SQLite.Expression static let cast_value = cast(col_value) as SQLite.Expression static let cast_commisison = cast(col_commisison) as SQLite.Expression -} -extension StockRepository { - // select query static let selectQuery = table.select( col_id, col_accountId, @@ -71,8 +70,7 @@ extension StockRepository { col_notes ) - // select result - static func selectResult(_ row: Row) -> Stock { + static func selectResult(_ row: SQLite.Row) -> Stock { return Stock( id : row[col_id], accountId : row[col_accountId], @@ -88,7 +86,7 @@ extension StockRepository { ) } - static func insertSetters(_ stock: Stock) -> [Setter] { + static func itemSetters(_ stock: Stock) -> [Setter] { return [ col_id <- stock.id, col_accountId <- stock.accountId, @@ -103,75 +101,12 @@ extension StockRepository { col_notes <- stock.notes ] } - - // insert query - static func insertQuery(_ stock: Stock) -> SQLite.Insert { - return table.insert(insertSetters(stock)) - } - - // update query - static func updateQuery(_ stock: Stock) -> SQLite.Update { - return table.filter(col_id == stock.id).update(insertSetters(stock)) - } - - // delete query - static func deleteQuery(_ stock: Stock) -> SQLite.Delete { - return table.filter(col_id == stock.id).delete() - } } extension StockRepository { - func loadStocks() -> [Stock] { - guard let db else { return [] } - do { - var stocks: [Stock] = [] - for row in try db.prepare(StockRepository.selectQuery - .order(StockRepository.col_name) - ) { - stocks.append(StockRepository.selectResult(row)) - } - print("Successfully loaded stocks: \(stocks.count)") - return stocks - } catch { - print("Error loading stocks: \(error)") - return [] - } - } - - func addStock(stock: inout Stock) -> Bool { - guard let db else { return false } - do { - let rowid = try db.run(StockRepository.insertQuery(stock)) - stock.id = rowid - print("Successfully added stock: \(stock.name), \(stock.id)") - return true - } catch { - print("Failed to add stock: \(error)") - return false - } - } - - func updateStock(stock: Stock) -> Bool { - guard let db else { return false } - do { - try db.run(StockRepository.updateQuery(stock)) - print("Successfully updated stock: \(stock.name), \(stock.id)") - return true - } catch { - print("Failed to update stock: \(error)") - return false - } - } - - func deleteStock(stock: Stock) -> Bool { - guard let db else { return false } - do { - try db.run(StockRepository.deleteQuery(stock)) - print("Successfully deleted stock: \(stock.name), \(stock.id)") - return true - } catch { - print("Failed to delete stock: \(error)") - return false - } + func load() -> [Stock] { + return select(query: Self.selectQuery + .order(Self.col_name) + ) } } diff --git a/MMEX/Repositories/TransactionRepository.swift b/MMEX/Repositories/TransactionRepository.swift index 9191a4fe..50155769 100644 --- a/MMEX/Repositories/TransactionRepository.swift +++ b/MMEX/Repositories/TransactionRepository.swift @@ -86,7 +86,7 @@ extension TransactionRepository { } // select result - static func selectResult(_ row: Row) -> Transaction { + static func selectResult(_ row: SQLite.Row) -> Transaction { return Transaction( id : row[col_id], accountId : row[col_accountId], diff --git a/MMEX/Views/Accounts/AccountDetailView.swift b/MMEX/Views/Accounts/AccountDetailView.swift index b08b199e..5c1f76d9 100644 --- a/MMEX/Views/Accounts/AccountDetailView.swift +++ b/MMEX/Views/Accounts/AccountDetailView.swift @@ -112,7 +112,7 @@ struct AccountDetailView: View { func saveChanges() { let repository = DataManager(databaseURL: databaseURL).getAccountRepository() - if repository.updateAccount(account: account) { + if repository.update(account) { // Successfully updated } else { // Handle failure @@ -121,7 +121,7 @@ struct AccountDetailView: View { func deleteAccount() { let repository = DataManager(databaseURL: databaseURL).getAccountRepository() - if repository.deleteAccount(account: account) { + if repository.delete(account) { presentationMode.wrappedValue.dismiss() } else { // Handle deletion failure diff --git a/MMEX/Views/Accounts/AccountListView.swift b/MMEX/Views/Accounts/AccountListView.swift index dce4ac8d..456c63e0 100644 --- a/MMEX/Views/Accounts/AccountListView.swift +++ b/MMEX/Views/Accounts/AccountListView.swift @@ -106,7 +106,7 @@ struct AccountListView: View { print("Loading payees in AccountListView...") DispatchQueue.global(qos: .background).async { - let loadedAccounts = repository.loadAccountsWithCurrency() + let loadedAccounts = repository.loadWithCurrency() DispatchQueue.main.async { self.accounts_by_type = Dictionary(grouping: loadedAccounts) { account in account.type.name @@ -120,7 +120,7 @@ struct AccountListView: View { let repo = DataManager(databaseURL: self.databaseURL).getCurrencyRepository() DispatchQueue.global(qos: .background).async { - let loadedCurrencies = repo.loadCurrencies() + let loadedCurrencies = repo.load() DispatchQueue.main.async { self.currencies = loadedCurrencies // other post op @@ -129,7 +129,7 @@ struct AccountListView: View { } func addAccount(account: inout Account) { - if repository.addAccount(account: &account) { + if repository.insert(&account) { // self.accounts.append(account) self.loadAccounts() } diff --git a/MMEX/Views/Categories/CategoryDetailView.swift b/MMEX/Views/Categories/CategoryDetailView.swift index faabf0ed..c585e9cc 100644 --- a/MMEX/Views/Categories/CategoryDetailView.swift +++ b/MMEX/Views/Categories/CategoryDetailView.swift @@ -91,7 +91,7 @@ struct CategoryDetailView: View { func saveChanges() { let repository = DataManager(databaseURL: databaseURL).getCategoryRepository() - if repository.updateCategory(category: category) { + if repository.update(category) { // Handle success } else { // Handle failure @@ -100,7 +100,7 @@ struct CategoryDetailView: View { func deleteCategory() { let repository = DataManager(databaseURL: databaseURL).getCategoryRepository() - if repository.deleteCategory(category: category) { + if repository.delete(category) { // Dismiss the view and go back presentationMode.wrappedValue.dismiss() } else { diff --git a/MMEX/Views/Categories/CategoryListView.swift b/MMEX/Views/Categories/CategoryListView.swift index 2bfb8a00..96fcb7b5 100644 --- a/MMEX/Views/Categories/CategoryListView.swift +++ b/MMEX/Views/Categories/CategoryListView.swift @@ -57,11 +57,11 @@ struct CategoryListView: View { func loadCategories() { let repository = DataManager(databaseURL: databaseURL).getCategoryRepository() - categories = repository.loadCategories() + categories = repository.load() } func addCategory(category: inout Category) { - if repository.addCategory(category: &category) { + if repository.insert(&category) { self.categories.append(category) } } diff --git a/MMEX/Views/Currencies/CurrencyDetailView.swift b/MMEX/Views/Currencies/CurrencyDetailView.swift index 21bd9896..34319c4a 100644 --- a/MMEX/Views/Currencies/CurrencyDetailView.swift +++ b/MMEX/Views/Currencies/CurrencyDetailView.swift @@ -70,7 +70,7 @@ struct CurrencyDetailView: View { func saveChanges() { let repository = DataManager(databaseURL: databaseURL).getCurrencyRepository() - if repository.updateCurrency(currency: currency) { + if repository.update(currency) { // Handle success } else { // Handle failure @@ -79,7 +79,7 @@ struct CurrencyDetailView: View { func deleteCurrency() { let repository = DataManager(databaseURL: databaseURL).getCurrencyRepository() - if repository.deleteCurrency(currency: currency) { + if repository.delete(currency) { presentationMode.wrappedValue.dismiss() } else { // Handle deletion failure diff --git a/MMEX/Views/Currencies/CurrencyListView.swift b/MMEX/Views/Currencies/CurrencyListView.swift index 7bd210a3..d71ec546 100644 --- a/MMEX/Views/Currencies/CurrencyListView.swift +++ b/MMEX/Views/Currencies/CurrencyListView.swift @@ -103,8 +103,8 @@ struct CurrencyListView: View { func loadCurrencies() { // Fetch accounts using repository and update the view DispatchQueue.global(qos: .background).async { - let loadedCurrencies = repository.loadCurrencies() - let loadedAccounts = DataManager(databaseURL: databaseURL).getAccountRepository().loadAccounts() + let loadedCurrencies = repository.load() + let loadedAccounts = DataManager(databaseURL: databaseURL).getAccountRepository().load() // Get a set of all currency IDs used by accounts let usedCurrencyIds = Set(loadedAccounts.map { $0.currencyId }) @@ -120,7 +120,7 @@ struct CurrencyListView: View { } func addCurrency(_ currency: inout Currency) { - if repository.addCurrency(currency: ¤cy) { + if repository.insert(¤cy) { self.loadCurrencies() } else { // TODO diff --git a/MMEX/Views/ManagementView.swift b/MMEX/Views/ManagementView.swift index 21dddf83..de18fcc6 100644 --- a/MMEX/Views/ManagementView.swift +++ b/MMEX/Views/ManagementView.swift @@ -112,7 +112,7 @@ struct ManagementView: View { let repo = DataManager(databaseURL: self.databaseURL).getAccountRepository() DispatchQueue.global(qos: .background).async { - let loadedAccounts = repo.loadAccountsWithCurrency() + let loadedAccounts = repo.loadWithCurrency() DispatchQueue.main.async { self.accounts = loadedAccounts @@ -127,7 +127,7 @@ struct ManagementView: View { let repo = DataManager(databaseURL: self.databaseURL).getCurrencyRepository() DispatchQueue.global(qos: .background).async { - let loadedCurrencies = repo.loadCurrencies() + let loadedCurrencies = repo.load() DispatchQueue.main.async { self.currencies = loadedCurrencies diff --git a/MMEX/Views/Payees/PayeeDetailView.swift b/MMEX/Views/Payees/PayeeDetailView.swift index ff74fba2..d2cbbd4a 100644 --- a/MMEX/Views/Payees/PayeeDetailView.swift +++ b/MMEX/Views/Payees/PayeeDetailView.swift @@ -122,7 +122,7 @@ struct PayeeDetailView: View { func saveChanges() { let repository = DataManager(databaseURL: databaseURL).getPayeeRepository() // pass URL here - if repository.updatePayee(payee: payee) { + if repository.update(payee) { // TODO } else { // TODO update failure @@ -131,7 +131,7 @@ struct PayeeDetailView: View { func deletePayee(){ let repository = DataManager(databaseURL: databaseURL).getPayeeRepository() // pass URL here - if repository.deletePayee(payee: payee) { + if repository.delete(payee) { // Dismiss the PayeeDetailView and go back to the previous view presentationMode.wrappedValue.dismiss() } else { diff --git a/MMEX/Views/Payees/PayeeListView.swift b/MMEX/Views/Payees/PayeeListView.swift index 1a161450..4621ccc6 100644 --- a/MMEX/Views/Payees/PayeeListView.swift +++ b/MMEX/Views/Payees/PayeeListView.swift @@ -66,7 +66,7 @@ struct PayeeListView: View { // Fetch accounts using repository and update the view DispatchQueue.global(qos: .background).async { - let loadedPayees = repository.loadPayees() + let loadedPayees = repository.load() // Update UI on the main thread DispatchQueue.main.async { @@ -80,7 +80,7 @@ struct PayeeListView: View { let repository = DataManager(databaseURL: self.databaseURL).getCategoryRepository() DispatchQueue.global(qos: .background).async { - let loadedCategories = repository.loadCategories() + let loadedCategories = repository.load() DispatchQueue.main.async { self.categories = loadedCategories @@ -90,7 +90,7 @@ struct PayeeListView: View { func addPayee(payee: inout Payee) { // TODO - if self.repository.addPayee(payee: &payee) { + if self.repository.insert(&payee) { self.payees.append(payee) // id is ready after repo call // loadPayees() } else { diff --git a/MMEX/Views/Transactions/TransactionAddView2.swift b/MMEX/Views/Transactions/TransactionAddView2.swift index 6a5a2130..212b819b 100644 --- a/MMEX/Views/Transactions/TransactionAddView2.swift +++ b/MMEX/Views/Transactions/TransactionAddView2.swift @@ -71,7 +71,7 @@ struct TransactionAddView2: View { // Fetch accounts using repository and update the view DispatchQueue.global(qos: .background).async { - let loadedPayees = repository.loadPayees() + let loadedPayees = repository.load() // Update UI on the main thread DispatchQueue.main.async { @@ -84,7 +84,7 @@ struct TransactionAddView2: View { let repository = DataManager(databaseURL: self.databaseURL).getCategoryRepository() DispatchQueue.global(qos: .background).async { - let loadedCategories = repository.loadCategories() + let loadedCategories = repository.load() DispatchQueue.main.async { self.categories = loadedCategories @@ -96,7 +96,7 @@ struct TransactionAddView2: View { let repository = DataManager(databaseURL: self.databaseURL).getAccountRepository() DispatchQueue.global(qos: .background).async { - let loadedAccounts = repository.loadAccountsWithCurrency() + let loadedAccounts = repository.loadWithCurrency() DispatchQueue.main.async { self.accounts = loadedAccounts diff --git a/MMEX/Views/Transactions/TransactionListView.swift b/MMEX/Views/Transactions/TransactionListView.swift index 63a5f532..cd75608e 100644 --- a/MMEX/Views/Transactions/TransactionListView.swift +++ b/MMEX/Views/Transactions/TransactionListView.swift @@ -108,7 +108,7 @@ struct TransactionListView: View { // Fetch accounts using repository and update the view DispatchQueue.global(qos: .background).async { - let loadedPayees = repository.loadPayees() + let loadedPayees = repository.load() // Update UI on the main thread DispatchQueue.main.async { @@ -121,7 +121,7 @@ struct TransactionListView: View { let repository = DataManager(databaseURL: self.databaseURL).getCategoryRepository() DispatchQueue.global(qos: .background).async { - let loadedCategories = repository.loadCategories() + let loadedCategories = repository.load() DispatchQueue.main.async { self.categories = loadedCategories @@ -133,7 +133,7 @@ struct TransactionListView: View { let repository = DataManager(databaseURL: self.databaseURL).getAccountRepository() DispatchQueue.global(qos: .background).async { - let loadedAccounts = repository.loadAccountsWithCurrency() + let loadedAccounts = repository.loadWithCurrency() DispatchQueue.main.async { self.accounts = loadedAccounts diff --git a/MMEX/Views/Transactions/TransactionListView2.swift b/MMEX/Views/Transactions/TransactionListView2.swift index 11f00d98..edd101ad 100644 --- a/MMEX/Views/Transactions/TransactionListView2.swift +++ b/MMEX/Views/Transactions/TransactionListView2.swift @@ -121,7 +121,7 @@ struct TransactionListView2: View { let repository = DataManager(databaseURL: self.databaseURL).getPayeeRepository() DispatchQueue.global(qos: .background).async { - let loadedPayees = repository.loadPayees() + let loadedPayees = repository.load() DispatchQueue.main.async { self.payees = loadedPayees @@ -134,7 +134,7 @@ struct TransactionListView2: View { let repository = DataManager(databaseURL: self.databaseURL).getCategoryRepository() DispatchQueue.global(qos: .background).async { - let loadedCategories = repository.loadCategories() + let loadedCategories = repository.load() DispatchQueue.main.async { self.categories = loadedCategories @@ -147,7 +147,7 @@ struct TransactionListView2: View { let repository = DataManager(databaseURL: self.databaseURL).getAccountRepository() DispatchQueue.global(qos: .background).async { - let loadedAccounts = repository.loadAccountsWithCurrency() + let loadedAccounts = repository.loadWithCurrency() DispatchQueue.main.async { self.accounts = loadedAccounts From 6abf09995b3ae23c225043f49fd43aa81b5d02f7 Mon Sep 17 00:00:00 2001 From: George Ef Date: Sun, 22 Sep 2024 16:28:48 +0200 Subject: [PATCH 2/8] fix typo --- MMEX/Repositories/InfotableRepository.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MMEX/Repositories/InfotableRepository.swift b/MMEX/Repositories/InfotableRepository.swift index 80c580d6..17e45854 100644 --- a/MMEX/Repositories/InfotableRepository.swift +++ b/MMEX/Repositories/InfotableRepository.swift @@ -26,7 +26,7 @@ extension InfotableRepository: RepositoryProtocol { // ----------+---------+------ // INFOID | INTEGER | NOT NULL PRIMARY KEY // INFONAME | TEXT | NOT NULL UNIQUE COLLATE NOCASE - // INFOVALUE | TEXT | NOT NUL + // INFOVALUE | TEXT | NOT NULL // table columns static let col_id = SQLite.Expression("INFOID") From 601783786162858402f3360bd6249c112205daa5 Mon Sep 17 00:00:00 2001 From: George Ef Date: Sun, 22 Sep 2024 17:00:13 +0200 Subject: [PATCH 3/8] refactor TransactionRepository --- MMEX/Protocols/RepositoryProtocol.swift | 6 +- MMEX/Repositories/AccountRepository.swift | 51 ++++---- MMEX/Repositories/AssetRepository.swift | 30 ++--- MMEX/Repositories/CategoryRepository.swift | 16 +-- MMEX/Repositories/CurrencyRepository.swift | 33 ++--- MMEX/Repositories/InfotableRepository.swift | 38 +++--- MMEX/Repositories/PayeeRepository.swift | 24 ++-- MMEX/Repositories/StockRepository.swift | 32 ++--- MMEX/Repositories/TransactionRepository.swift | 114 +++--------------- MMEX/Views/InsightsViewModel.swift | 2 +- .../Transactions/TransactionAddView2.swift | 2 +- .../Transactions/TransactionDetailView.swift | 4 +- .../Transactions/TransactionListView.swift | 4 +- .../Transactions/TransactionListView2.swift | 2 +- 14 files changed, 147 insertions(+), 211 deletions(-) diff --git a/MMEX/Protocols/RepositoryProtocol.swift b/MMEX/Protocols/RepositoryProtocol.swift index 3d7eb16e..eb3ecf56 100644 --- a/MMEX/Protocols/RepositoryProtocol.swift +++ b/MMEX/Protocols/RepositoryProtocol.swift @@ -13,7 +13,7 @@ protocol RepositoryProtocol { static var repositoryName: String { get } static var table: SQLite.Table { get } - static var selectQuery: SQLite.Table { get } + static func selectQuery(from table: SQLite.Table) -> SQLite.Table static func selectResult(_ row: SQLite.Row) -> RepositoryItem static var col_id: SQLite.Expression { get } static func itemSetters(_ item: RepositoryItem) -> [SQLite.Setter] @@ -22,11 +22,11 @@ protocol RepositoryProtocol { } extension RepositoryProtocol { - func select(query: SQLite.Table = Self.selectQuery) -> [RepositoryItem] { + func select(table: SQLite.Table = Self.table) -> [RepositoryItem] { guard let db else { return [] } do { var results: [RepositoryItem] = [] - for row in try db.prepare(query) { + for row in try db.prepare(Self.selectQuery(from: table)) { results.append(Self.selectResult(row)) } print("Successfully loaded from \(Self.repositoryName): \(results.count)") diff --git a/MMEX/Repositories/AccountRepository.swift b/MMEX/Repositories/AccountRepository.swift index aca9ab0e..49afb8c8 100644 --- a/MMEX/Repositories/AccountRepository.swift +++ b/MMEX/Repositories/AccountRepository.swift @@ -76,29 +76,32 @@ extension AccountRepository: RepositoryProtocol { static let cast_interestRate = cast(col_interestRate) as SQLite.Expression static let cast_minimumPayment = cast(col_minimumPayment) as SQLite.Expression - static let selectQuery = table.select( - col_id, - col_name, - col_type, - col_num, - col_status, - col_notes, - col_heldAt, - col_website, - col_contactInfo, - col_accessInfo, - col_initialDate, - cast_initialBal, - col_favoriteAcct, - col_currencyId, - col_statementLocked, - col_statementDate, - cast_minimumBalance, - cast_creditLimit, - cast_interestRate, - col_paymentDueDate, - cast_minimumPayment - ) + + static func selectQuery(from table: SQLite.Table) -> SQLite.Table { + return table.select( + col_id, + col_name, + col_type, + col_num, + col_status, + col_notes, + col_heldAt, + col_website, + col_contactInfo, + col_accessInfo, + col_initialDate, + cast_initialBal, + col_favoriteAcct, + col_currencyId, + col_statementLocked, + col_statementDate, + cast_minimumBalance, + cast_creditLimit, + cast_interestRate, + col_paymentDueDate, + cast_minimumPayment + ) + } static func selectResult(_ row: SQLite.Row) -> Account { return Account( @@ -155,7 +158,7 @@ extension AccountRepository: RepositoryProtocol { extension AccountRepository { func load() -> [Account] { - return select(query: Self.selectQuery + return select(table: Self.table .order(Self.col_name) ) } diff --git a/MMEX/Repositories/AssetRepository.swift b/MMEX/Repositories/AssetRepository.swift index 6030396c..4304c745 100644 --- a/MMEX/Repositories/AssetRepository.swift +++ b/MMEX/Repositories/AssetRepository.swift @@ -53,19 +53,21 @@ extension AssetRepository: RepositoryProtocol { static let cast_value = cast(col_value) as SQLite.Expression static let cast_changeRate = cast(col_changeRate) as SQLite.Expression - static let selectQuery = table.select( - col_id, - col_type, - col_status, - col_name, - col_startDate, - col_currencyId, - cast_value, - col_change, - col_changeMode, - cast_changeRate, - col_notes - ) + static func selectQuery(from table: SQLite.Table) -> SQLite.Table { + return table.select( + col_id, + col_type, + col_status, + col_name, + col_startDate, + col_currencyId, + cast_value, + col_change, + col_changeMode, + cast_changeRate, + col_notes + ) + } static func selectResult(_ row: SQLite.Row) -> Asset { return Asset( @@ -101,7 +103,7 @@ extension AssetRepository: RepositoryProtocol { } extension AssetRepository { - func load() -> [Asset] { select(query: AssetRepository.selectQuery + func load() -> [Asset] { select(table: Self.table .order(Self.col_type, Self.col_status.desc, Self.col_name) ) } } diff --git a/MMEX/Repositories/CategoryRepository.swift b/MMEX/Repositories/CategoryRepository.swift index 9c0324ed..8bee5230 100644 --- a/MMEX/Repositories/CategoryRepository.swift +++ b/MMEX/Repositories/CategoryRepository.swift @@ -35,12 +35,14 @@ extension CategoryRepository: RepositoryProtocol { static let col_active = SQLite.Expression("ACTIVE") static let col_parentId = SQLite.Expression("PARENTID") - static let selectQuery = table.select( - col_id, - col_name, - col_active, - col_parentId - ) + static func selectQuery(from table: SQLite.Table) -> SQLite.Table { + return table.select( + col_id, + col_name, + col_active, + col_parentId + ) + } static func selectResult(_ row: SQLite.Row) -> Category { return Category( @@ -63,6 +65,6 @@ extension CategoryRepository: RepositoryProtocol { extension CategoryRepository { // load all categories func load() -> [Category] { - return select(query: Self.selectQuery) + return select(table: Self.table) } } diff --git a/MMEX/Repositories/CurrencyRepository.swift b/MMEX/Repositories/CurrencyRepository.swift index 21a1d17d..926b677e 100644 --- a/MMEX/Repositories/CurrencyRepository.swift +++ b/MMEX/Repositories/CurrencyRepository.swift @@ -54,20 +54,23 @@ extension CurrencyRepository: RepositoryProtocol { // cast NUMERIC to REAL static let cast_baseConversionRate = cast(col_baseConversionRate) as SQLite.Expression - static let selectQuery = table.select( - col_id, - col_name, - col_prefixSymbol, - col_suffixSymbol, - col_decimalPoint, - col_groupSeparator, - col_unitName, - col_centName, - col_scale, - cast_baseConversionRate, - col_symbol, - col_type - ) + + static func selectQuery(from table: SQLite.Table) -> SQLite.Table { + return table.select( + col_id, + col_name, + col_prefixSymbol, + col_suffixSymbol, + col_decimalPoint, + col_groupSeparator, + col_unitName, + col_centName, + col_scale, + cast_baseConversionRate, + col_symbol, + col_type + ) + } static func selectResult(_ row: SQLite.Row) -> Currency { return Currency( @@ -106,7 +109,7 @@ extension CurrencyRepository: RepositoryProtocol { extension CurrencyRepository { // load all currencies func load() -> [Currency] { - return select(query: Self.selectQuery + return select(table: Self.table .order(Self.col_name) ) } diff --git a/MMEX/Repositories/InfotableRepository.swift b/MMEX/Repositories/InfotableRepository.swift index 17e45854..e164a447 100644 --- a/MMEX/Repositories/InfotableRepository.swift +++ b/MMEX/Repositories/InfotableRepository.swift @@ -33,11 +33,13 @@ extension InfotableRepository: RepositoryProtocol { static let col_name = SQLite.Expression("INFONAME") static let col_value = SQLite.Expression("INFOVALUE") - static let selectQuery = table.select( - col_id, - col_name, - col_value - ) + static func selectQuery(from table: SQLite.Table) -> SQLite.Table { + return table.select( + col_id, + col_name, + col_value + ) + } static func selectResult(_ row: SQLite.Row) -> Infotable { return Infotable( @@ -67,10 +69,10 @@ extension InfotableRepository { do { var results: [InfoKey: Infotable] = [:] for key in keys { - if let row = try db.pluck(InfotableRepository.selectQuery - .filter(InfotableRepository.col_name == key.rawValue) - ) { - results[key] = InfotableRepository.selectResult(row) + if let row = try db.pluck(Self.selectQuery(from: Self.table + .filter(Self.col_name == key.rawValue) + ) ) { + results[key] = Self.selectResult(row) print("Successfully loaded infokey: \(key.rawValue)") } else { @@ -89,10 +91,10 @@ extension InfotableRepository { func getValue(for key: String, as type: T.Type) -> T? { guard let db else { return nil } do { - if let row = try db.pluck(InfotableRepository.selectQuery - .filter(InfotableRepository.col_name == key) - ) { - let value = row[InfotableRepository.col_value] + if let row = try db.pluck(Self.selectQuery(from: Self.table + .filter(Self.col_name == key) + ) ) { + let value = row[Self.col_value] if type == String.self { return value as? T } else if type == Int64.self { @@ -119,18 +121,18 @@ extension InfotableRepository { return } - let query = InfotableRepository.table.filter(InfotableRepository.col_name == key) + let query = InfotableRepository.table.filter(Self.col_name == key) do { if let _ = try db.pluck(query) { // Update existing setting try db.run(query.update( - InfotableRepository.col_value <- stringValue + Self.col_value <- stringValue ) ) } else { // Insert new setting - try db.run(InfotableRepository.table.insert( - InfotableRepository.col_name <- key, - InfotableRepository.col_value <- stringValue + try db.run(Self.table.insert( + Self.col_name <- key, + Self.col_value <- stringValue ) ) } } catch { diff --git a/MMEX/Repositories/PayeeRepository.swift b/MMEX/Repositories/PayeeRepository.swift index e48a9157..de31512f 100644 --- a/MMEX/Repositories/PayeeRepository.swift +++ b/MMEX/Repositories/PayeeRepository.swift @@ -43,16 +43,18 @@ extension PayeeRepository: RepositoryProtocol { static let col_active = SQLite.Expression("ACTIVE") static let col_pattern = SQLite.Expression("PATTERN") - static let selectQuery = table.select( - col_id, - col_name, - col_categoryId, - col_number, - col_website, - col_notes, - col_active, - col_pattern - ) + static func selectQuery(from table: SQLite.Table) -> SQLite.Table { + return table.select( + col_id, + col_name, + col_categoryId, + col_number, + col_website, + col_notes, + col_active, + col_pattern + ) + } static func selectResult(_ row: SQLite.Row) -> Payee { return Payee( @@ -82,7 +84,7 @@ extension PayeeRepository: RepositoryProtocol { extension PayeeRepository { func load() -> [Payee] { - return select(query: Self.selectQuery + return select(table: Self.table .order(Self.col_active.desc, Self.col_name) ) } diff --git a/MMEX/Repositories/StockRepository.swift b/MMEX/Repositories/StockRepository.swift index 3d9108ec..ef2cdeda 100644 --- a/MMEX/Repositories/StockRepository.swift +++ b/MMEX/Repositories/StockRepository.swift @@ -56,19 +56,21 @@ extension StockRepository: RepositoryProtocol { static let cast_value = cast(col_value) as SQLite.Expression static let cast_commisison = cast(col_commisison) as SQLite.Expression - static let selectQuery = table.select( - col_id, - col_accountId, - col_name, - col_symbol, - cast_numShares, - col_purchaseDate, - cast_purchasePrice, - cast_currentPrice, - cast_value, - cast_commisison, - col_notes - ) + static func selectQuery(from table: SQLite.Table) -> SQLite.Table { + return table.select( + col_id, + col_accountId, + col_name, + col_symbol, + cast_numShares, + col_purchaseDate, + cast_purchasePrice, + cast_currentPrice, + cast_value, + cast_commisison, + col_notes + ) + } static func selectResult(_ row: SQLite.Row) -> Stock { return Stock( @@ -86,7 +88,7 @@ extension StockRepository: RepositoryProtocol { ) } - static func itemSetters(_ stock: Stock) -> [Setter] { + static func itemSetters(_ stock: Stock) -> [SQLite.Setter] { return [ col_id <- stock.id, col_accountId <- stock.accountId, @@ -105,7 +107,7 @@ extension StockRepository: RepositoryProtocol { extension StockRepository { func load() -> [Stock] { - return select(query: Self.selectQuery + return select(table: Self.table .order(Self.col_name) ) } diff --git a/MMEX/Repositories/TransactionRepository.swift b/MMEX/Repositories/TransactionRepository.swift index 50155769..c958dbc2 100644 --- a/MMEX/Repositories/TransactionRepository.swift +++ b/MMEX/Repositories/TransactionRepository.swift @@ -16,9 +16,11 @@ class TransactionRepository { } } -extension TransactionRepository { - // table query - static let table = SQLite.Table("CHECKINGACCOUNT_V1") +extension TransactionRepository: RepositoryProtocol { + typealias RepositoryItem = Transaction + + static let repositoryName = "CHECKINGACCOUNT_V1" + static let table = SQLite.Table(repositoryName) // column | type | other // ------------------+---------+------ @@ -60,12 +62,9 @@ extension TransactionRepository { // cast NUMERIC to REAL static let cast_transAmount = cast(col_transAmount) as SQLite.Expression static let cast_toTransAmount = cast(col_toTransAmount) as SQLite.Expression -} - -extension TransactionRepository { - // select query - static func selectQuery(from: SQLite.Table) -> SQLite.Table { - return from.select( + + static func selectQuery(from table: SQLite.Table) -> SQLite.Table { + return table.select( col_id, col_accountId, col_toAccountId, @@ -85,7 +84,6 @@ extension TransactionRepository { ) } - // select result static func selectResult(_ row: SQLite.Row) -> Transaction { return Transaction( id : row[col_id], @@ -107,7 +105,7 @@ extension TransactionRepository { ) } - static func insertSetters(_ txn: Transaction) -> [Setter] { + static func itemSetters(_ txn: Transaction) -> [SQLite.Setter] { return [ col_accountId <- txn.accountId, col_toAccountId <- txn.toAccountId, @@ -126,102 +124,24 @@ extension TransactionRepository { col_color <- txn.color, ] } - - // insert query - static func insertQuery(_ txn: Transaction) -> SQLite.Insert { - return table.insert(insertSetters(txn)) - } - - // update query - static func updateQuery(_ txn: Transaction) -> SQLite.Update { - return table.filter(col_id == txn.id).update(insertSetters(txn)) - } - - // delete query - static func deleteQuery(_ txn: Transaction) -> SQLite.Delete { - return table.filter(col_id == txn.id).delete() - } } extension TransactionRepository { // load all transactions - func loadTransactions() -> [Transaction] { - guard let db else { return [] } - do { - var results: [Transaction] = [] - let query = TransactionRepository.selectQuery(from: TransactionRepository.table) - for row in try db.prepare(query) { - results.append(TransactionRepository.selectResult(row)) - } - print("Successfully loaded transactions: \(results.count)") - return results - } catch { - print("Failed to fetch transactions: \(error)") - return [] - } + func load() -> [Transaction] { + return select(table: Self.table) } // load recent transactions - func loadRecentTransactions( + func loadRecent( startDate: Date? = Calendar.current.date(byAdding: .month, value: -3, to: Date()), endDate: Date? = Date() ) -> [Transaction] { - guard let db else { return [] } - do { - var results: [Transaction] = [] - var from = TransactionRepository.table - // If startDate is set, add filtering by date range - if let startDate { - from = from.filter(TransactionRepository.col_transDate >= startDate.ISO8601Format()) - } - let query = TransactionRepository.selectQuery(from: from) - for row in try db.prepare(query) { - results.append(TransactionRepository.selectResult(row)) - } - print("Successfully loaded transactions: \(results.count)") - return results - } catch { - print("Failed to fetch transactions: \(error)") - return [] - } - } - - // add a new transaction - func addTransaction(txn: inout Transaction) -> Bool { - guard let db else { return false } - do { - let rowid = try db.run(TransactionRepository.insertQuery(txn)) - txn.id = rowid - print("Successfully added transaction with ID: \(txn.id), \(txn)") - return true - } catch { - print("Failed to add transaction: \(error)") - return false - } - } - - // update an existing transaction - func updateTransaction(txn: Transaction) -> Bool { - guard let db else { return false } - do { - try db.run(TransactionRepository.updateQuery(txn)) - print("Successfully updated transaction: \(txn.id)") - return true - } catch { - print("Failed to update transaction: \(error)") - return false - } - } - - func deleteTransaction(txn: Transaction) -> Bool { - guard let db else { return false } - do { - try db.run(TransactionRepository.deleteQuery(txn)) - print("Successfully deleted transaction: \(txn.id)") - return true - } catch { - print("Failed to delete transaction: \(error)") - return false + let table = if let startDate { + Self.table.filter(Self.col_transDate >= startDate.ISO8601Format()) + } else { + Self.table } + return select(table: table) } } diff --git a/MMEX/Views/InsightsViewModel.swift b/MMEX/Views/InsightsViewModel.swift index 906584b6..308be215 100644 --- a/MMEX/Views/InsightsViewModel.swift +++ b/MMEX/Views/InsightsViewModel.swift @@ -41,7 +41,7 @@ class InsightsViewModel: ObservableObject { // Fetch transactions asynchronously DispatchQueue.global(qos: .background).async { - let transactions = repository.loadRecentTransactions(startDate: self.startDate, endDate: self.endDate) + let transactions = repository.loadRecent(startDate: self.startDate, endDate: self.endDate) // Update the published stats on the main thread DispatchQueue.main.async { diff --git a/MMEX/Views/Transactions/TransactionAddView2.swift b/MMEX/Views/Transactions/TransactionAddView2.swift index 212b819b..8da84e62 100644 --- a/MMEX/Views/Transactions/TransactionAddView2.swift +++ b/MMEX/Views/Transactions/TransactionAddView2.swift @@ -59,7 +59,7 @@ struct TransactionAddView2: View { func addTransaction(txn: inout Transaction) { let repository = DataManager(databaseURL: self.databaseURL).getTransactionRepository() - if repository.addTransaction(txn:&txn) { + if repository.insert(&txn) { // id is ready after repo call } else { // TODO diff --git a/MMEX/Views/Transactions/TransactionDetailView.swift b/MMEX/Views/Transactions/TransactionDetailView.swift index 1b799c0d..07ee704a 100644 --- a/MMEX/Views/Transactions/TransactionDetailView.swift +++ b/MMEX/Views/Transactions/TransactionDetailView.swift @@ -127,7 +127,7 @@ struct TransactionDetailView: View { } func saveChanges() { let repository = DataManager(databaseURL: databaseURL).getTransactionRepository() // pass URL here - if repository.updateTransaction(txn: txn) { + if repository.update(txn) { // TODO } else { // TODO update failure @@ -136,7 +136,7 @@ struct TransactionDetailView: View { func deleteTxn(){ let repository = DataManager(databaseURL: databaseURL).getTransactionRepository() // pass URL here - if repository.deleteTransaction(txn: txn) { + if repository.delete(txn) { // Dismiss the TransactionDetailView and go back to the previous view presentationMode.wrappedValue.dismiss() } else { diff --git a/MMEX/Views/Transactions/TransactionListView.swift b/MMEX/Views/Transactions/TransactionListView.swift index cd75608e..b3ef131f 100644 --- a/MMEX/Views/Transactions/TransactionListView.swift +++ b/MMEX/Views/Transactions/TransactionListView.swift @@ -94,7 +94,7 @@ struct TransactionListView: View { // Fetch accounts using repository and update the view DispatchQueue.global(qos: .background).async { - let loadTransactions = repository.loadTransactions() + let loadTransactions = repository.load() // Update UI on the main thread DispatchQueue.main.async { @@ -153,7 +153,7 @@ struct TransactionListView: View { func addTransaction(txn: inout Transaction) { // TODO - if self.repository.addTransaction(txn:&txn) { + if self.repository.insert(&txn) { self.txns.append(txn) // id is ready after repo call } else { // TODO diff --git a/MMEX/Views/Transactions/TransactionListView2.swift b/MMEX/Views/Transactions/TransactionListView2.swift index edd101ad..0b3df42d 100644 --- a/MMEX/Views/Transactions/TransactionListView2.swift +++ b/MMEX/Views/Transactions/TransactionListView2.swift @@ -98,7 +98,7 @@ struct TransactionListView2: View { func loadTransactions() { DispatchQueue.global(qos: .background).async { - let loadTransactions = repository.loadRecentTransactions() + let loadTransactions = repository.loadRecent() DispatchQueue.main.async { self.txns = loadTransactions From 1dc5cbb6a68d2a35ad4d6507dc9ab073f800a4ec Mon Sep 17 00:00:00 2001 From: George Ef Date: Sun, 22 Sep 2024 17:08:48 +0200 Subject: [PATCH 4/8] rename table repositoryTable --- MMEX/Protocols/RepositoryProtocol.swift | 15 ++++++++++----- MMEX/Repositories/AccountRepository.swift | 4 ++-- MMEX/Repositories/AssetRepository.swift | 4 ++-- MMEX/Repositories/CategoryRepository.swift | 4 ++-- MMEX/Repositories/CurrencyRepository.swift | 4 ++-- MMEX/Repositories/InfotableRepository.swift | 10 +++++----- MMEX/Repositories/PayeeRepository.swift | 4 ++-- MMEX/Repositories/StockRepository.swift | 4 ++-- MMEX/Repositories/TransactionRepository.swift | 9 +++++---- 9 files changed, 32 insertions(+), 26 deletions(-) diff --git a/MMEX/Protocols/RepositoryProtocol.swift b/MMEX/Protocols/RepositoryProtocol.swift index eb3ecf56..82d2201d 100644 --- a/MMEX/Protocols/RepositoryProtocol.swift +++ b/MMEX/Protocols/RepositoryProtocol.swift @@ -12,7 +12,7 @@ protocol RepositoryProtocol { associatedtype RepositoryItem: ModelProtocol static var repositoryName: String { get } - static var table: SQLite.Table { get } + static var repositoryTable: SQLite.Table { get } static func selectQuery(from table: SQLite.Table) -> SQLite.Table static func selectResult(_ row: SQLite.Row) -> RepositoryItem static var col_id: SQLite.Expression { get } @@ -22,7 +22,7 @@ protocol RepositoryProtocol { } extension RepositoryProtocol { - func select(table: SQLite.Table = Self.table) -> [RepositoryItem] { + func select(table: SQLite.Table = Self.repositoryTable) -> [RepositoryItem] { guard let db else { return [] } do { var results: [RepositoryItem] = [] @@ -40,7 +40,8 @@ extension RepositoryProtocol { func insert(_ item: inout RepositoryItem) -> Bool { guard let db else { return false } do { - let query = Self.table.insert(Self.itemSetters(item)) + let query = Self.repositoryTable + .insert(Self.itemSetters(item)) let rowid = try db.run(query) item.id = rowid print("Successfully added \(RepositoryItem.modelName): \(item.shortDesc())") @@ -54,7 +55,9 @@ extension RepositoryProtocol { func update(_ item: RepositoryItem) -> Bool { guard let db else { return false } do { - let query = Self.table.filter(Self.col_id == item.id).update(Self.itemSetters(item)) + let query = Self.repositoryTable + .filter(Self.col_id == item.id) + .update(Self.itemSetters(item)) try db.run(query) print("Successfully updated \(RepositoryItem.modelName): \(item.shortDesc())") return true @@ -67,7 +70,9 @@ extension RepositoryProtocol { func delete(_ item: RepositoryItem) -> Bool { guard let db else { return false } do { - let query = Self.table.filter(Self.col_id == item.id).delete() + let query = Self.repositoryTable + .filter(Self.col_id == item.id) + .delete() try db.run(query) print("Successfully deleted \(RepositoryItem.modelName): \(item.shortDesc())") return true diff --git a/MMEX/Repositories/AccountRepository.swift b/MMEX/Repositories/AccountRepository.swift index 49afb8c8..c58145c2 100644 --- a/MMEX/Repositories/AccountRepository.swift +++ b/MMEX/Repositories/AccountRepository.swift @@ -20,7 +20,7 @@ extension AccountRepository: RepositoryProtocol { typealias RepositoryItem = Account static let repositoryName = "ACCOUNTLIST_V1" - static let table = SQLite.Table(repositoryName) + static let repositoryTable = SQLite.Table(repositoryName) // column | type | other // ----------------+---------+------ @@ -158,7 +158,7 @@ extension AccountRepository: RepositoryProtocol { extension AccountRepository { func load() -> [Account] { - return select(table: Self.table + return select(table: Self.repositoryTable .order(Self.col_name) ) } diff --git a/MMEX/Repositories/AssetRepository.swift b/MMEX/Repositories/AssetRepository.swift index 4304c745..83b63850 100644 --- a/MMEX/Repositories/AssetRepository.swift +++ b/MMEX/Repositories/AssetRepository.swift @@ -20,7 +20,7 @@ extension AssetRepository: RepositoryProtocol { typealias RepositoryItem = Asset static let repositoryName = "ASSETS_V1" - static let table = SQLite.Table(repositoryName) + static let repositoryTable = SQLite.Table(repositoryName) // column | type | other // ----------------+---------+------ @@ -103,7 +103,7 @@ extension AssetRepository: RepositoryProtocol { } extension AssetRepository { - func load() -> [Asset] { select(table: Self.table + func load() -> [Asset] { select(table: Self.repositoryTable .order(Self.col_type, Self.col_status.desc, Self.col_name) ) } } diff --git a/MMEX/Repositories/CategoryRepository.swift b/MMEX/Repositories/CategoryRepository.swift index 8bee5230..3c8b6fb0 100644 --- a/MMEX/Repositories/CategoryRepository.swift +++ b/MMEX/Repositories/CategoryRepository.swift @@ -19,7 +19,7 @@ extension CategoryRepository: RepositoryProtocol { typealias RepositoryItem = Category static let repositoryName = "CATEGORY_V1" - static let table = SQLite.Table(repositoryName) + static let repositoryTable = SQLite.Table(repositoryName) // column | type | other // ----------+---------+------ @@ -65,6 +65,6 @@ extension CategoryRepository: RepositoryProtocol { extension CategoryRepository { // load all categories func load() -> [Category] { - return select(table: Self.table) + return select(table: Self.repositoryTable) } } diff --git a/MMEX/Repositories/CurrencyRepository.swift b/MMEX/Repositories/CurrencyRepository.swift index 926b677e..5d491a19 100644 --- a/MMEX/Repositories/CurrencyRepository.swift +++ b/MMEX/Repositories/CurrencyRepository.swift @@ -20,7 +20,7 @@ extension CurrencyRepository: RepositoryProtocol { typealias RepositoryItem = Currency static let repositoryName = "CURRENCYFORMATS_V1" - static let table = SQLite.Table(repositoryName) + static let repositoryTable = SQLite.Table(repositoryName) // column | type | other // ----------------+---------+------ @@ -109,7 +109,7 @@ extension CurrencyRepository: RepositoryProtocol { extension CurrencyRepository { // load all currencies func load() -> [Currency] { - return select(table: Self.table + return select(table: Self.repositoryTable .order(Self.col_name) ) } diff --git a/MMEX/Repositories/InfotableRepository.swift b/MMEX/Repositories/InfotableRepository.swift index e164a447..bf75d25a 100644 --- a/MMEX/Repositories/InfotableRepository.swift +++ b/MMEX/Repositories/InfotableRepository.swift @@ -20,7 +20,7 @@ extension InfotableRepository: RepositoryProtocol { typealias RepositoryItem = Infotable static let repositoryName = "INFOTABLE_V1" - static let table = SQLite.Table(repositoryName) + static let repositoryTable = SQLite.Table(repositoryName) // column | type | other // ----------+---------+------ @@ -69,7 +69,7 @@ extension InfotableRepository { do { var results: [InfoKey: Infotable] = [:] for key in keys { - if let row = try db.pluck(Self.selectQuery(from: Self.table + if let row = try db.pluck(Self.selectQuery(from: Self.repositoryTable .filter(Self.col_name == key.rawValue) ) ) { results[key] = Self.selectResult(row) @@ -91,7 +91,7 @@ extension InfotableRepository { func getValue(for key: String, as type: T.Type) -> T? { guard let db else { return nil } do { - if let row = try db.pluck(Self.selectQuery(from: Self.table + if let row = try db.pluck(Self.selectQuery(from: Self.repositoryTable .filter(Self.col_name == key) ) ) { let value = row[Self.col_value] @@ -121,7 +121,7 @@ extension InfotableRepository { return } - let query = InfotableRepository.table.filter(Self.col_name == key) + let query = Self.repositoryTable.filter(Self.col_name == key) do { if let _ = try db.pluck(query) { // Update existing setting @@ -130,7 +130,7 @@ extension InfotableRepository { ) ) } else { // Insert new setting - try db.run(Self.table.insert( + try db.run(Self.repositoryTable.insert( Self.col_name <- key, Self.col_value <- stringValue ) ) diff --git a/MMEX/Repositories/PayeeRepository.swift b/MMEX/Repositories/PayeeRepository.swift index de31512f..f99433dc 100644 --- a/MMEX/Repositories/PayeeRepository.swift +++ b/MMEX/Repositories/PayeeRepository.swift @@ -20,7 +20,7 @@ extension PayeeRepository: RepositoryProtocol { typealias RepositoryItem = Payee static let repositoryName = "PAYEE_V1" - static let table = SQLite.Table(repositoryName) + static let repositoryTable = SQLite.Table(repositoryName) // column | type | other // ----------+---------+------ @@ -84,7 +84,7 @@ extension PayeeRepository: RepositoryProtocol { extension PayeeRepository { func load() -> [Payee] { - return select(table: Self.table + return select(table: Self.repositoryTable .order(Self.col_active.desc, Self.col_name) ) } diff --git a/MMEX/Repositories/StockRepository.swift b/MMEX/Repositories/StockRepository.swift index ef2cdeda..01879813 100644 --- a/MMEX/Repositories/StockRepository.swift +++ b/MMEX/Repositories/StockRepository.swift @@ -20,7 +20,7 @@ extension StockRepository: RepositoryProtocol { typealias RepositoryItem = Stock static let repositoryName = "STOCK_V1" - static let table = SQLite.Table(repositoryName) + static let repositoryTable = SQLite.Table(repositoryName) // column | type | other // --------------+---------+------ @@ -107,7 +107,7 @@ extension StockRepository: RepositoryProtocol { extension StockRepository { func load() -> [Stock] { - return select(table: Self.table + return select(table: Self.repositoryTable .order(Self.col_name) ) } diff --git a/MMEX/Repositories/TransactionRepository.swift b/MMEX/Repositories/TransactionRepository.swift index c958dbc2..4dc2681b 100644 --- a/MMEX/Repositories/TransactionRepository.swift +++ b/MMEX/Repositories/TransactionRepository.swift @@ -20,7 +20,7 @@ extension TransactionRepository: RepositoryProtocol { typealias RepositoryItem = Transaction static let repositoryName = "CHECKINGACCOUNT_V1" - static let table = SQLite.Table(repositoryName) + static let repositoryTable = SQLite.Table(repositoryName) // column | type | other // ------------------+---------+------ @@ -129,7 +129,7 @@ extension TransactionRepository: RepositoryProtocol { extension TransactionRepository { // load all transactions func load() -> [Transaction] { - return select(table: Self.table) + return select(table: Self.repositoryTable) } // load recent transactions @@ -138,9 +138,10 @@ extension TransactionRepository { endDate: Date? = Date() ) -> [Transaction] { let table = if let startDate { - Self.table.filter(Self.col_transDate >= startDate.ISO8601Format()) + Self.repositoryTable + .filter(Self.col_transDate >= startDate.ISO8601Format()) } else { - Self.table + Self.repositoryTable } return select(table: table) } From d6a71e15064d6822c695b1c2bd56e2ec3981c775 Mon Sep 17 00:00:00 2001 From: George Ef Date: Sun, 22 Sep 2024 17:30:12 +0200 Subject: [PATCH 5/8] minor change --- MMEX/Protocols/RepositoryProtocol.swift | 4 ++-- MMEX/Repositories/AccountRepository.swift | 9 +++------ MMEX/Repositories/AssetRepository.swift | 9 +++------ MMEX/Repositories/CategoryRepository.swift | 9 +++------ MMEX/Repositories/CurrencyRepository.swift | 9 +++------ MMEX/Repositories/InfotableRepository.swift | 11 ++++------- MMEX/Repositories/PayeeRepository.swift | 9 +++------ MMEX/Repositories/StockRepository.swift | 10 +++------- MMEX/Repositories/TransactionRepository.swift | 9 +++------ 9 files changed, 27 insertions(+), 52 deletions(-) diff --git a/MMEX/Protocols/RepositoryProtocol.swift b/MMEX/Protocols/RepositoryProtocol.swift index 82d2201d..6a5e6884 100644 --- a/MMEX/Protocols/RepositoryProtocol.swift +++ b/MMEX/Protocols/RepositoryProtocol.swift @@ -11,14 +11,14 @@ import SQLite protocol RepositoryProtocol { associatedtype RepositoryItem: ModelProtocol + var db: Connection? { get } + static var repositoryName: String { get } static var repositoryTable: SQLite.Table { get } static func selectQuery(from table: SQLite.Table) -> SQLite.Table static func selectResult(_ row: SQLite.Row) -> RepositoryItem static var col_id: SQLite.Expression { get } static func itemSetters(_ item: RepositoryItem) -> [SQLite.Setter] - - var db: Connection? { get } } extension RepositoryProtocol { diff --git a/MMEX/Repositories/AccountRepository.swift b/MMEX/Repositories/AccountRepository.swift index c58145c2..27fc498a 100644 --- a/MMEX/Repositories/AccountRepository.swift +++ b/MMEX/Repositories/AccountRepository.swift @@ -8,16 +8,13 @@ import Foundation import SQLite -class AccountRepository { - let db: Connection? +class AccountRepository: RepositoryProtocol { + typealias RepositoryItem = Account + let db: Connection? init(db: Connection?) { self.db = db } -} - -extension AccountRepository: RepositoryProtocol { - typealias RepositoryItem = Account static let repositoryName = "ACCOUNTLIST_V1" static let repositoryTable = SQLite.Table(repositoryName) diff --git a/MMEX/Repositories/AssetRepository.swift b/MMEX/Repositories/AssetRepository.swift index 83b63850..09a6b6aa 100644 --- a/MMEX/Repositories/AssetRepository.swift +++ b/MMEX/Repositories/AssetRepository.swift @@ -8,16 +8,13 @@ import Foundation import SQLite -class AssetRepository { - let db: Connection? +class AssetRepository: RepositoryProtocol { + typealias RepositoryItem = Asset + let db: Connection? init(db: Connection?) { self.db = db } -} - -extension AssetRepository: RepositoryProtocol { - typealias RepositoryItem = Asset static let repositoryName = "ASSETS_V1" static let repositoryTable = SQLite.Table(repositoryName) diff --git a/MMEX/Repositories/CategoryRepository.swift b/MMEX/Repositories/CategoryRepository.swift index 3c8b6fb0..8d22ac11 100644 --- a/MMEX/Repositories/CategoryRepository.swift +++ b/MMEX/Repositories/CategoryRepository.swift @@ -7,16 +7,13 @@ import SQLite -class CategoryRepository { - let db: Connection? +class CategoryRepository: RepositoryProtocol { + typealias RepositoryItem = Category + let db: Connection? init(db: Connection?) { self.db = db } -} - -extension CategoryRepository: RepositoryProtocol { - typealias RepositoryItem = Category static let repositoryName = "CATEGORY_V1" static let repositoryTable = SQLite.Table(repositoryName) diff --git a/MMEX/Repositories/CurrencyRepository.swift b/MMEX/Repositories/CurrencyRepository.swift index 5d491a19..82b5ff11 100644 --- a/MMEX/Repositories/CurrencyRepository.swift +++ b/MMEX/Repositories/CurrencyRepository.swift @@ -8,16 +8,13 @@ import Foundation import SQLite -class CurrencyRepository { - let db: Connection? +class CurrencyRepository: RepositoryProtocol { + typealias RepositoryItem = Currency + let db: Connection? init(db: Connection?) { self.db = db } -} - -extension CurrencyRepository: RepositoryProtocol { - typealias RepositoryItem = Currency static let repositoryName = "CURRENCYFORMATS_V1" static let repositoryTable = SQLite.Table(repositoryName) diff --git a/MMEX/Repositories/InfotableRepository.swift b/MMEX/Repositories/InfotableRepository.swift index bf75d25a..1b8cbbc8 100644 --- a/MMEX/Repositories/InfotableRepository.swift +++ b/MMEX/Repositories/InfotableRepository.swift @@ -8,16 +8,13 @@ import Foundation import SQLite -class InfotableRepository { - let db: Connection? +class InfotableRepository: RepositoryProtocol { + typealias RepositoryItem = Infotable + let db: Connection? init(db: Connection?) { self.db = db } -} - -extension InfotableRepository: RepositoryProtocol { - typealias RepositoryItem = Infotable static let repositoryName = "INFOTABLE_V1" static let repositoryTable = SQLite.Table(repositoryName) @@ -28,7 +25,7 @@ extension InfotableRepository: RepositoryProtocol { // INFONAME | TEXT | NOT NULL UNIQUE COLLATE NOCASE // INFOVALUE | TEXT | NOT NULL - // table columns + // columns static let col_id = SQLite.Expression("INFOID") static let col_name = SQLite.Expression("INFONAME") static let col_value = SQLite.Expression("INFOVALUE") diff --git a/MMEX/Repositories/PayeeRepository.swift b/MMEX/Repositories/PayeeRepository.swift index f99433dc..5bf94d28 100644 --- a/MMEX/Repositories/PayeeRepository.swift +++ b/MMEX/Repositories/PayeeRepository.swift @@ -8,16 +8,13 @@ import Foundation import SQLite -class PayeeRepository { - let db: Connection? +class PayeeRepository: RepositoryProtocol { + typealias RepositoryItem = Payee + let db: Connection? init(db: Connection?) { self.db = db } -} - -extension PayeeRepository: RepositoryProtocol { - typealias RepositoryItem = Payee static let repositoryName = "PAYEE_V1" static let repositoryTable = SQLite.Table(repositoryName) diff --git a/MMEX/Repositories/StockRepository.swift b/MMEX/Repositories/StockRepository.swift index 01879813..3dc26951 100644 --- a/MMEX/Repositories/StockRepository.swift +++ b/MMEX/Repositories/StockRepository.swift @@ -8,17 +8,13 @@ import Foundation import SQLite -class StockRepository { - let db: Connection? +class StockRepository: RepositoryProtocol { + typealias RepositoryItem = Stock + let db: Connection? init(db: Connection?) { self.db = db } -} - -extension StockRepository: RepositoryProtocol { - typealias RepositoryItem = Stock - static let repositoryName = "STOCK_V1" static let repositoryTable = SQLite.Table(repositoryName) diff --git a/MMEX/Repositories/TransactionRepository.swift b/MMEX/Repositories/TransactionRepository.swift index 4dc2681b..da3d8b32 100644 --- a/MMEX/Repositories/TransactionRepository.swift +++ b/MMEX/Repositories/TransactionRepository.swift @@ -8,16 +8,13 @@ import Foundation import SQLite -class TransactionRepository { +class TransactionRepository: RepositoryProtocol { + typealias RepositoryItem = Transaction + let db: Connection? - init(db: Connection?) { self.db = db } -} - -extension TransactionRepository: RepositoryProtocol { - typealias RepositoryItem = Transaction static let repositoryName = "CHECKINGACCOUNT_V1" static let repositoryTable = SQLite.Table(repositoryName) From d8c531690e1bb0ed804bee2fb12da5ee67bf314a Mon Sep 17 00:00:00 2001 From: George Ef Date: Sun, 22 Sep 2024 17:37:34 +0200 Subject: [PATCH 6/8] minor change in commets --- MMEX/Repositories/AccountRepository.swift | 3 +-- MMEX/Repositories/CategoryRepository.swift | 2 +- MMEX/Repositories/CurrencyRepository.swift | 2 +- MMEX/Repositories/PayeeRepository.swift | 2 +- MMEX/Repositories/StockRepository.swift | 2 +- MMEX/Repositories/TransactionRepository.swift | 2 +- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/MMEX/Repositories/AccountRepository.swift b/MMEX/Repositories/AccountRepository.swift index 27fc498a..7e019298 100644 --- a/MMEX/Repositories/AccountRepository.swift +++ b/MMEX/Repositories/AccountRepository.swift @@ -43,7 +43,7 @@ class AccountRepository: RepositoryProtocol { // PAYMENTDUEDATE | TEXT | // MINIMUMPAYMENT | NUMERIC | - // table columns + // columns static let col_id = SQLite.Expression("ACCOUNTID") static let col_name = SQLite.Expression("ACCOUNTNAME") static let col_type = SQLite.Expression("ACCOUNTTYPE") @@ -73,7 +73,6 @@ class AccountRepository: RepositoryProtocol { static let cast_interestRate = cast(col_interestRate) as SQLite.Expression static let cast_minimumPayment = cast(col_minimumPayment) as SQLite.Expression - static func selectQuery(from table: SQLite.Table) -> SQLite.Table { return table.select( col_id, diff --git a/MMEX/Repositories/CategoryRepository.swift b/MMEX/Repositories/CategoryRepository.swift index 8d22ac11..07484dd7 100644 --- a/MMEX/Repositories/CategoryRepository.swift +++ b/MMEX/Repositories/CategoryRepository.swift @@ -26,7 +26,7 @@ class CategoryRepository: RepositoryProtocol { // ACTIVE | INTEGER | // PARENTID | INTEGER | - // table columns + // columns static let col_id = SQLite.Expression("CATEGID") static let col_name = SQLite.Expression("CATEGNAME") static let col_active = SQLite.Expression("ACTIVE") diff --git a/MMEX/Repositories/CurrencyRepository.swift b/MMEX/Repositories/CurrencyRepository.swift index 82b5ff11..e7c1d583 100644 --- a/MMEX/Repositories/CurrencyRepository.swift +++ b/MMEX/Repositories/CurrencyRepository.swift @@ -34,7 +34,7 @@ class CurrencyRepository: RepositoryProtocol { // CURRENCY_SYMBOL | TEXT | NOT NULL COLLATE NOCASE UNIQUE // CURRENCY_TYPE | TEXT | NOT NULL (Fiat, Crypto) - // table columns + // columns static let col_id = SQLite.Expression("CURRENCYID") static let col_name = SQLite.Expression("CURRENCYNAME") static let col_prefixSymbol = SQLite.Expression("PFX_SYMBOL") diff --git a/MMEX/Repositories/PayeeRepository.swift b/MMEX/Repositories/PayeeRepository.swift index 5bf94d28..6ade4b0c 100644 --- a/MMEX/Repositories/PayeeRepository.swift +++ b/MMEX/Repositories/PayeeRepository.swift @@ -30,7 +30,7 @@ class PayeeRepository: RepositoryProtocol { // ACTIVE | INTEGER | // PATTERN | TEXT | DEFAULT '' - // table columns + // columns static let col_id = SQLite.Expression("PAYEEID") static let col_name = SQLite.Expression("PAYEENAME") static let col_categoryId = SQLite.Expression("CATEGID") diff --git a/MMEX/Repositories/StockRepository.swift b/MMEX/Repositories/StockRepository.swift index 3dc26951..3a6193a6 100644 --- a/MMEX/Repositories/StockRepository.swift +++ b/MMEX/Repositories/StockRepository.swift @@ -32,7 +32,7 @@ class StockRepository: RepositoryProtocol { // COMMISSION | NUMERIC | // NOTES | TEXT | - // table columns + // columns static let col_id = SQLite.Expression("STOCKID") static let col_accountId = SQLite.Expression("HELDAT") static let col_name = SQLite.Expression("STOCKNAME") diff --git a/MMEX/Repositories/TransactionRepository.swift b/MMEX/Repositories/TransactionRepository.swift index da3d8b32..2566ceb6 100644 --- a/MMEX/Repositories/TransactionRepository.swift +++ b/MMEX/Repositories/TransactionRepository.swift @@ -38,7 +38,7 @@ class TransactionRepository: RepositoryProtocol { // TOTRANSAMOUNT | NUMERIC | // COLOR | INTEGER | DEFAULT -1 - // table columns + // columns static let col_id = SQLite.Expression("TRANSID") static let col_accountId = SQLite.Expression("ACCOUNTID") static let col_toAccountId = SQLite.Expression("TOACCOUNTID") From 1a21982848ee450a76f1d4b50cd0519af67c39e6 Mon Sep 17 00:00:00 2001 From: George Ef Date: Sun, 22 Sep 2024 18:29:20 +0200 Subject: [PATCH 7/8] refactor pluck in RepositoryProtocol --- MMEX/Protocols/RepositoryProtocol.swift | 36 +++++++--- MMEX/Repositories/InfotableRepository.swift | 79 +++++++++------------ 2 files changed, 59 insertions(+), 56 deletions(-) diff --git a/MMEX/Protocols/RepositoryProtocol.swift b/MMEX/Protocols/RepositoryProtocol.swift index 6a5e6884..febe8a2c 100644 --- a/MMEX/Protocols/RepositoryProtocol.swift +++ b/MMEX/Protocols/RepositoryProtocol.swift @@ -22,17 +22,35 @@ protocol RepositoryProtocol { } extension RepositoryProtocol { - func select(table: SQLite.Table = Self.repositoryTable) -> [RepositoryItem] { + func pluck(table: SQLite.Table, key: String) -> RepositoryItem? { + guard let db else { return nil } + do { + if let row = try db.pluck(Self.selectQuery(from: table)) { + let item = Self.selectResult(row) + print("Successfull search for \(key) in \(Self.repositoryName): \(item.shortDesc())") + return item + } + else { + print("Unsuccefull search for \(key) in \(Self.repositoryName)") + return nil + } + } catch { + print("Failed search for \(key) in \(Self.repositoryName): \(error)") + return nil + } + } + + func select(table: SQLite.Table) -> [RepositoryItem] { guard let db else { return [] } do { var results: [RepositoryItem] = [] for row in try db.prepare(Self.selectQuery(from: table)) { results.append(Self.selectResult(row)) } - print("Successfully loaded from \(Self.repositoryName): \(results.count)") + print("Successfull select in \(Self.repositoryName): \(results.count)") return results } catch { - print("Error loading from \(Self.repositoryName): \(error)") + print("Failed select in \(Self.repositoryName): \(error)") return [] } } @@ -44,10 +62,10 @@ extension RepositoryProtocol { .insert(Self.itemSetters(item)) let rowid = try db.run(query) item.id = rowid - print("Successfully added \(RepositoryItem.modelName): \(item.shortDesc())") + print("Successfull insert in \(RepositoryItem.modelName): \(item.shortDesc())") return true } catch { - print("Failed to add \(RepositoryItem.modelName): \(error)") + print("Failed insert in \(RepositoryItem.modelName): \(error)") return false } } @@ -59,10 +77,10 @@ extension RepositoryProtocol { .filter(Self.col_id == item.id) .update(Self.itemSetters(item)) try db.run(query) - print("Successfully updated \(RepositoryItem.modelName): \(item.shortDesc())") + print("Successfull update in \(RepositoryItem.modelName): \(item.shortDesc())") return true } catch { - print("Failed to update \(RepositoryItem.modelName): \(error)") + print("Failed update in \(RepositoryItem.modelName): \(error)") return false } } @@ -74,10 +92,10 @@ extension RepositoryProtocol { .filter(Self.col_id == item.id) .delete() try db.run(query) - print("Successfully deleted \(RepositoryItem.modelName): \(item.shortDesc())") + print("Successfull delete in \(RepositoryItem.modelName): \(item.shortDesc())") return true } catch { - print("Failed to delete \(RepositoryItem.modelName): \(error)") + print("Failed delete in \(RepositoryItem.modelName): \(error)") return false } } diff --git a/MMEX/Repositories/InfotableRepository.swift b/MMEX/Repositories/InfotableRepository.swift index 1b8cbbc8..d41347d9 100644 --- a/MMEX/Repositories/InfotableRepository.swift +++ b/MMEX/Repositories/InfotableRepository.swift @@ -57,56 +57,46 @@ class InfotableRepository: RepositoryProtocol { extension InfotableRepository { // load all keys func load() -> [Infotable] { - return select() + return select(table: Self.repositoryTable) } // load specific keys into a dictionary func load(for keys: [InfoKey]) -> [InfoKey: Infotable] { guard let db else { return [:] } - do { - var results: [InfoKey: Infotable] = [:] - for key in keys { - if let row = try db.pluck(Self.selectQuery(from: Self.repositoryTable - .filter(Self.col_name == key.rawValue) - ) ) { - results[key] = Self.selectResult(row) - print("Successfully loaded infokey: \(key.rawValue)") - } - else { - print("Unknown infokey: \(key.rawValue)") - } + var results: [InfoKey: Infotable] = [:] + for key in keys { + if let info = pluck( + table: Self.repositoryTable + .filter(Self.col_name == key.rawValue), + key: key.rawValue + ) { + results[key] = info } - return results - } catch { - print("Error loading info: \(error)") - return [:] } + return results } // New Methods for Key-Value Pairs // Fetch value for a specific key, allowing for String or Int64 func getValue(for key: String, as type: T.Type) -> T? { - guard let db else { return nil } - do { - if let row = try db.pluck(Self.selectQuery(from: Self.repositoryTable - .filter(Self.col_name == key) - ) ) { - let value = row[Self.col_value] - if type == String.self { - return value as? T - } else if type == Int64.self { - return Int64(value) as? T - } + if db == nil { return nil } + if let info = pluck( + table: Self.repositoryTable + .filter(Self.col_name == key), + key: key + ) { + if type == String.self { + return info.value as? T + } else if type == Int64.self { + return Int64(info.value) as? T } - } catch { - print("Error fetching value for key \(key): \(error)") } return nil } // Update or insert a setting with support for String or Int64 values func setValue(_ value: T, for key: String) { - guard let db else { return } + if db == nil { return } var stringValue: String if let stringVal = value as? String { @@ -118,22 +108,17 @@ extension InfotableRepository { return } - let query = Self.repositoryTable.filter(Self.col_name == key) - do { - if let _ = try db.pluck(query) { - // Update existing setting - try db.run(query.update( - Self.col_value <- stringValue - ) ) - } else { - // Insert new setting - try db.run(Self.repositoryTable.insert( - Self.col_name <- key, - Self.col_value <- stringValue - ) ) - } - } catch { - print("Error setting value for key \(key): \(error)") + if var info = pluck( + table: Self.repositoryTable.filter(Self.col_name == key), + key: key + ) { + // Update existing setting + info.value = stringValue + _ = update(info) + } else { + // Insert new setting + var info = Infotable(id: 0, name: key, value: stringValue) + _ = insert(&info) } } } From 8ae491cb7da21f020d43d46ed210b39f859a98a2 Mon Sep 17 00:00:00 2001 From: George Ef Date: Sun, 22 Sep 2024 18:45:39 +0200 Subject: [PATCH 8/8] fix fields with default value (can be NULL) --- MMEX/Models/Transaction.swift | 4 ++-- MMEX/Repositories/InfotableRepository.swift | 2 +- MMEX/Repositories/PayeeRepository.swift | 4 ++-- MMEX/Repositories/TransactionRepository.swift | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MMEX/Models/Transaction.swift b/MMEX/Models/Transaction.swift index 1bf86b78..b07375f0 100644 --- a/MMEX/Models/Transaction.swift +++ b/MMEX/Models/Transaction.swift @@ -53,14 +53,14 @@ struct Transaction: ExportableEntity { var deletedTime: String? var followUpId: Int64? var toTransAmount: Double? - var color: Int64 + var color: Int64? init( id: Int64, accountId: Int64, toAccountId: Int64? = nil, payeeId: Int64, transCode: Transcode, transAmount: Double, status: TransactionStatus, transactionNumber: String? = nil, notes: String? = nil, categId: Int64? = nil, transDate: String?, lastUpdatedTime: String? = nil, deletedTime: String? = nil, - followUpId: Int64? = nil, toTransAmount: Double? = nil, color: Int64 = -1 + followUpId: Int64? = nil, toTransAmount: Double? = nil, color: Int64? = nil ) { self.id = id self.accountId = accountId diff --git a/MMEX/Repositories/InfotableRepository.swift b/MMEX/Repositories/InfotableRepository.swift index d41347d9..a6fe4cc3 100644 --- a/MMEX/Repositories/InfotableRepository.swift +++ b/MMEX/Repositories/InfotableRepository.swift @@ -62,7 +62,7 @@ extension InfotableRepository { // load specific keys into a dictionary func load(for keys: [InfoKey]) -> [InfoKey: Infotable] { - guard let db else { return [:] } + if db == nil { return [:] } var results: [InfoKey: Infotable] = [:] for key in keys { if let info = pluck( diff --git a/MMEX/Repositories/PayeeRepository.swift b/MMEX/Repositories/PayeeRepository.swift index 6ade4b0c..62ca7df4 100644 --- a/MMEX/Repositories/PayeeRepository.swift +++ b/MMEX/Repositories/PayeeRepository.swift @@ -38,7 +38,7 @@ class PayeeRepository: RepositoryProtocol { static let col_website = SQLite.Expression("WEBSITE") static let col_notes = SQLite.Expression("NOTES") static let col_active = SQLite.Expression("ACTIVE") - static let col_pattern = SQLite.Expression("PATTERN") + static let col_pattern = SQLite.Expression("PATTERN") static func selectQuery(from table: SQLite.Table) -> SQLite.Table { return table.select( @@ -62,7 +62,7 @@ class PayeeRepository: RepositoryProtocol { website : row[col_website], notes : row[col_notes], active : row[col_active] ?? 1, - pattern : row[col_pattern] + pattern : row[col_pattern] ?? "" ) } diff --git a/MMEX/Repositories/TransactionRepository.swift b/MMEX/Repositories/TransactionRepository.swift index 2566ceb6..f90ba00b 100644 --- a/MMEX/Repositories/TransactionRepository.swift +++ b/MMEX/Repositories/TransactionRepository.swift @@ -54,7 +54,7 @@ class TransactionRepository: RepositoryProtocol { static let col_deletedTime = SQLite.Expression("DELETEDTIME") static let col_followUpId = SQLite.Expression("FOLLOWUPID") static let col_toTransAmount = SQLite.Expression("TOTRANSAMOUNT") - static let col_color = SQLite.Expression("COLOR") + static let col_color = SQLite.Expression("COLOR") // cast NUMERIC to REAL static let cast_transAmount = cast(col_transAmount) as SQLite.Expression