Skip to content

Commit

Permalink
Merge pull request #19 from moneymanagerex/re_protocol
Browse files Browse the repository at this point in the history
refactor ModelProtocol, RepositoryProtocol
  • Loading branch information
guanlisheng authored Sep 22, 2024
2 parents ec5094e + 8ae491c commit aba245a
Show file tree
Hide file tree
Showing 34 changed files with 480 additions and 872 deletions.
12 changes: 10 additions & 2 deletions MMEX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -77,6 +79,8 @@
929EF6622C9FF3ED0051A3E6 /* AssetRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetRepository.swift; sourceTree = "<group>"; };
929EF6642C9FF3FB0051A3E6 /* StockRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StockRepository.swift; sourceTree = "<group>"; };
929EF6662CA023EE0051A3E6 /* EnumCollateNoCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumCollateNoCase.swift; sourceTree = "<group>"; };
929EF6682CA034770051A3E6 /* RepositoryProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryProtocol.swift; sourceTree = "<group>"; };
929EF66A2CA03AF90051A3E6 /* ModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModelProtocol.swift; sourceTree = "<group>"; };
A3363EE22C9323A5004696C7 /* CategoryEditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEditView.swift; sourceTree = "<group>"; };
A3363EE42C9323D2004696C7 /* CategoryDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryDetailView.swift; sourceTree = "<group>"; };
A3363EE62C93249D004696C7 /* CategoryAddView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryAddView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -154,6 +158,8 @@
children = (
A3462F652C94854800F79145 /* ExportableEntity.swift */,
929EF6662CA023EE0051A3E6 /* EnumCollateNoCase.swift */,
929EF66A2CA03AF90051A3E6 /* ModelProtocol.swift */,
929EF6682CA034770051A3E6 /* RepositoryProtocol.swift */,
);
path = Protocols;
sourceTree = "<group>";
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand All @@ -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 */,
Expand Down
8 changes: 8 additions & 0 deletions MMEX/Models/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 8 additions & 0 deletions MMEX/Models/Asset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
9 changes: 8 additions & 1 deletion MMEX/Models/Category.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
) }
Expand All @@ -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",
Expand Down
9 changes: 8 additions & 1 deletion MMEX/Models/Currency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@ 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,
scale: 0, baseConversionRate: 0, symbol: "", type: ""
) }
}

extension Currency: ModelProtocol {
static let modelName = "Currency"

func shortDesc() -> String {
"\(self.name)"
}
}

extension Currency {
/// A `NumberFormatter` configured specifically for the currency.
var formatter: NumberFormatter {
Expand Down
8 changes: 8 additions & 0 deletions MMEX/Models/Infotable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
9 changes: 8 additions & 1 deletion MMEX/Models/Payee.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
8 changes: 8 additions & 0 deletions MMEX/Models/Stock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
12 changes: 10 additions & 2 deletions MMEX/Models/Transaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion MMEX/Protocols/EnumCollateNoCase.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Asset.swift
// EnumCollateNoCase.swift
// MMEX
//
// Created 2024-09-22 by George Ef ([email protected])
Expand Down
15 changes: 15 additions & 0 deletions MMEX/Protocols/ModelProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// ModelProtocal.swift
// MMEX
//
// Created 2024-09-22 by George Ef ([email protected])
//

import Foundation

protocol ModelProtocol {
static var modelName: String { get }

var id: Int64 { get set }
func shortDesc() -> String
}
102 changes: 102 additions & 0 deletions MMEX/Protocols/RepositoryProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// RepositoryProtocaol.swift
// MMEX
//
// Created 2024-09-22 by George Ef ([email protected])
//

import Foundation
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<Int64> { get }
static func itemSetters(_ item: RepositoryItem) -> [SQLite.Setter]
}

extension RepositoryProtocol {
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("Successfull select in \(Self.repositoryName): \(results.count)")
return results
} catch {
print("Failed select in \(Self.repositoryName): \(error)")
return []
}
}

func insert(_ item: inout RepositoryItem) -> Bool {
guard let db else { return false }
do {
let query = Self.repositoryTable
.insert(Self.itemSetters(item))
let rowid = try db.run(query)
item.id = rowid
print("Successfull insert in \(RepositoryItem.modelName): \(item.shortDesc())")
return true
} catch {
print("Failed insert in \(RepositoryItem.modelName): \(error)")
return false
}
}

func update(_ item: RepositoryItem) -> Bool {
guard let db else { return false }
do {
let query = Self.repositoryTable
.filter(Self.col_id == item.id)
.update(Self.itemSetters(item))
try db.run(query)
print("Successfull update in \(RepositoryItem.modelName): \(item.shortDesc())")
return true
} catch {
print("Failed update in \(RepositoryItem.modelName): \(error)")
return false
}
}

func delete(_ item: RepositoryItem) -> Bool {
guard let db else { return false }
do {
let query = Self.repositoryTable
.filter(Self.col_id == item.id)
.delete()
try db.run(query)
print("Successfull delete in \(RepositoryItem.modelName): \(item.shortDesc())")
return true
} catch {
print("Failed delete in \(RepositoryItem.modelName): \(error)")
return false
}
}
}
Loading

0 comments on commit aba245a

Please sign in to comment.