From 15ca2ba0ef5275e97690182979a8155f70b1878b Mon Sep 17 00:00:00 2001 From: Enrique Lacal Date: Wed, 25 Apr 2018 10:56:40 +0100 Subject: [PATCH] fix: Refactoring the Model --- Sources/SwiftKueryORM/Model.swift | 928 +++++++++--------------------- 1 file changed, 276 insertions(+), 652 deletions(-) diff --git a/Sources/SwiftKueryORM/Model.swift b/Sources/SwiftKueryORM/Model.swift index 05249cd..9b4aa1f 100644 --- a/Sources/SwiftKueryORM/Model.swift +++ b/Sources/SwiftKueryORM/Model.swift @@ -142,15 +142,9 @@ public extension Model { static func createTable(using db: Database? = nil, _ onCompletion: @escaping (Bool?, RequestError?) -> Void) { var connection: Connection - do { - connection = try Self.getConnection(using: db) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - var table: Table do { + connection = try Self.getConnection(using: db) table = try Self.getTable() } catch let error { onCompletion(nil, Self.convertError(error)) @@ -201,16 +195,10 @@ public extension Model { static func dropTable(using db : Database? = nil, _ onCompletion: @escaping (Bool?, RequestError?) -> Void) { var connection: Connection - do { - connection = try Self.getConnection(using: db) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - var table: Table do { table = try Self.getTable() + connection = try Self.getConnection(using: db) } catch let error { onCompletion(nil, Self.convertError(error)) return @@ -237,14 +225,6 @@ public extension Model { } func save(using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void) { - var connection: Connection - do { - connection = try Self.getConnection(using: db) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - var table: Table var values: [String : Any] do { @@ -258,36 +238,10 @@ public extension Model { let columns = table.columns.filter({$0.autoIncrement != true}) let valueTuples = columns.filter({values[$0.name] != nil}).map({($0, values[$0.name]!)}) let query = Insert(into: table, valueTuples: valueTuples) - - connection.connect { error in - if let error = error { - onCompletion(nil, Self.convertError(error)) - return - } else { - connection.execute(query: query) { result in - guard result.success else { - guard let error = result.asError else { - onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) - return - } - onCompletion(nil, Self.convertError(error)) - return - } - onCompletion(self, nil) - } - } - } + self.executeQuery(query: query, using: db, onCompletion) } func save(using db: Database? = nil, _ onCompletion: @escaping (I?, Self?, RequestError?) -> Void) { - var connection: Connection - do { - connection = try Self.getConnection(using: db) - } catch let error { - onCompletion(nil, nil, Self.convertError(error)) - return - } - var table: Table var values: [String : Any] do { @@ -301,61 +255,13 @@ public extension Model { let columns = table.columns.filter({$0.autoIncrement != true}) let valueTuples = columns.filter({values[$0.name] != nil}).map({($0, values[$0.name]!)}) let query = Insert(into: table, valueTuples: valueTuples, returnID: true) - - connection.connect { error in - if let error = error { - onCompletion(nil, nil, Self.convertError(error)) - return - } else { - connection.execute(query: query) { result in - guard result.success else { - guard let error = result.asError else { - onCompletion(nil, nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) - return - } - onCompletion(nil, nil, Self.convertError(error)) - return - } - - guard let rows = result.asRows, rows.count > 0 else { - onCompletion(nil, nil, RequestError(.ormNotFound, reason: "Could not retrieve id value for: \(String(describing: self))")) - return - } - - let dict = rows[0] - guard let value = dict[Self.idColumnName] else { - onCompletion(nil, nil, RequestError(.ormNotFound, reason: "Could not find return id")) - return - } - - guard let unwrappedValue: Any = value else { - onCompletion(nil, nil, RequestError(.ormNotFound, reason: "Return id is nil")) - return - } - - do { - let identifier = try I(value: String(describing: unwrappedValue)) - onCompletion(identifier, self, nil) - } catch { - onCompletion(nil, nil, RequestError(.ormIdentifierError, reason: "Could not construct Identifier")) - } - } - } - } + self.executeQuery(query: query, using: db, onCompletion) } /// Find a model with an id /// - Parameter using: Optional Database to use /// - Returns: A tuple (Model, RequestError) static func find(id: I, using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void) { - var connection: Connection - do { - connection = try Self.getConnection(using: db) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - var table: Table do { table = try Self.getTable() @@ -370,54 +276,27 @@ public extension Model { } let query = Select(from: table).where(idColumn == id.value) - var dictionaryTitleToValue = [String: Any?]() - - connection.connect { error in - if let error = error { - onCompletion(nil, Self.convertError(error)) - return - } else { - connection.execute(query: query) { result in - guard result.success else { - guard let error = result.asError else { - onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) - return - } - onCompletion(nil, Self.convertError(error)) - return - } - - guard let rows = result.asRows, rows.count > 0 else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve value for id: " + String(describing: id))) - return - } - - dictionaryTitleToValue = rows[0] - - var decodedModel: Self - do { - decodedModel = try DatabaseDecoder().decode(Self.self, dictionaryTitleToValue) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - - onCompletion(decodedModel, nil) - } - } - } + Self.executeQuery(query: query, using: db, onCompletion) } /// static func findAll(using db: Database? = nil, _ onCompletion: @escaping ([Self]?, RequestError?) -> Void) { - var connection: Connection + var table: Table do { - connection = try Self.getConnection(using: db) + table = try Self.getTable() } catch let error { onCompletion(nil, Self.convertError(error)) return } + let query = Select(from: table) + Self.executeQuery(query: query, using: db, onCompletion) + } + + /// Find all the models + /// - Parameter using: Optional Database to use + /// - Returns: An array of tuples (id, model) + static func findAll(using db: Database? = nil, _ onCompletion: @escaping ([(I, Self)]?, RequestError?) -> Void) { var table: Table do { table = try Self.getTable() @@ -427,499 +306,185 @@ public extension Model { } let query = Select(from: table) - var dictionariesTitleToValue = [[String: Any?]]() + Self.executeQuery(query: query, using: db, onCompletion) + } - connection.connect { error in + /// :nodoc: + static func findAll(using db: Database? = nil, _ onCompletion: @escaping ([I: Self]?, RequestError?) -> Void) { + var table: Table + do { + table = try Self.getTable() + } catch let error { + onCompletion(nil, Self.convertError(error)) + return + } + + let query = Select(from: table) + Self.executeQuery(query: query, using: db) { (tuples: [(I, Self)]?, error: RequestError?) in if let error = error { - onCompletion(nil, Self.convertError(error)) + onCompletion(nil, error) return - } else { - connection.execute(query: query) { result in - guard result.success else { - guard let error = result.asError else { - onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) - return - } - onCompletion(nil, Self.convertError(error)) - return - } - - if case QueryResult.successNoData = result { - onCompletion([], nil) - return - } - - guard let rows = result.asRows else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve values from table: \(String(describing: Self.tableName))")) - return - } - - for row in rows { - dictionariesTitleToValue.append(row) - } - - var result = [Self]() - for dictionary in dictionariesTitleToValue { - var decodedModel: Self - do { - decodedModel = try DatabaseDecoder().decode(Self.self, dictionary) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - result.append(decodedModel) - } - onCompletion(result, nil) + } else if let tuples = tuples { + var result = [I: Self]() + for (id, model) in tuples { + result[id] = model } + onCompletion(result, nil) + return + } else { + onCompletion(nil, .ormInternalError) } } } - /// Find all the models + /// - Parameter matching: Optional QueryParams to use + /// - Returns: An array of model + static func findAll(using db: Database? = nil, matching queryParams: Q, _ onCompletion: @escaping ([Self]?, RequestError?) -> Void) { + var table: Table + var filter: Filter + do { + table = try Self.getTable() + filter = try Self.getFilter(queryParams: queryParams, table: table) + } catch let error { + onCompletion(nil, Self.convertError(error)) + return + } + + let query = Select(from: table).where(filter) + Self.executeQuery(query: query, using: db, onCompletion) + } + + /// Find all the models matching the QueryParams /// - Parameter using: Optional Database to use /// - Returns: An array of tuples (id, model) - static func findAll(using db: Database? = nil, _ onCompletion: @escaping ([(I, Self)]?, RequestError?) -> Void) { - var connection: Connection + static func findAll(using db: Database? = nil, matching queryParams: Q, _ onCompletion: @escaping ([(I, Self)]?, RequestError?) -> Void) { + var table: Table + var filter: Filter do { - connection = try Self.getConnection(using: db) + table = try Self.getTable() + filter = try Self.getFilter(queryParams: queryParams, table: table) } catch let error { onCompletion(nil, Self.convertError(error)) return } + let query = Select(from: table).where(filter) + Self.executeQuery(query: query, using: db, onCompletion) + } + + /// Find all the models matching the QueryParams + /// - Parameter using: Optional Database to use + /// - Returns: A dictionary [id: model] + static func findAll(using db: Database? = nil, matching queryParams: Q, _ onCompletion: @escaping ([I: Self]?, RequestError?) -> Void) { var table: Table + var filter: Filter do { table = try Self.getTable() + filter = try Self.getFilter(queryParams: queryParams, table: table) } catch let error { onCompletion(nil, Self.convertError(error)) return } - let query = Select(from: table) - var dictionariesTitleToValue = [[String: Any?]]() - - connection.connect { error in + let query = Select(from: table).where(filter) + Self.executeQuery(query: query, using: db) { (tuples: [(I, Self)]?, error: RequestError?) in if let error = error { - onCompletion(nil, Self.convertError(error)) + onCompletion(nil, error) + return + } else if let tuples = tuples { + var result = [I: Self]() + for (id, model) in tuples { + result[id] = model + } + onCompletion(result, nil) return } else { - connection.execute(query: query) { result in - guard result.success else { - guard let error = result.asError else { - onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) - return - } - onCompletion(nil, Self.convertError(error)) - return - } - - if case QueryResult.successNoData = result { - onCompletion([], nil) - return - } - - guard let rows = result.asRows else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve values from table: \(String(describing: Self.tableName))")) - return - } - - for row in rows { - dictionariesTitleToValue.append(row) - } - - var result = [(I,Self)]() - for dictionary in dictionariesTitleToValue { - var decodedModel: Self - do { - decodedModel = try DatabaseDecoder().decode(Self.self, dictionary) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - - guard let value = dictionary[idColumnName] else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not find return id")) - return - } - - guard let unwrappedValue: Any = value else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Return id is nil")) - return - } - - do { - let identifier = try I(value: String(describing: unwrappedValue)) - result.append((identifier, decodedModel)) - } catch { - onCompletion(nil, RequestError(.ormIdentifierError, reason: "Could not construct Identifier")) - } - - } - onCompletion(result, nil) - } - } - } - } - - /// :nodoc: - static func findAll(using db: Database? = nil, _ onCompletion: @escaping ([I: Self]?, RequestError?) -> Void) { - var connection: Connection - do { - connection = try Self.getConnection(using: db) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } + onCompletion(nil, .ormInternalError) + } + } + } + func update(id: I, using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void) { var table: Table + var values: [String: Any] do { table = try Self.getTable() + values = try DatabaseEncoder().encode(self) } catch let error { onCompletion(nil, Self.convertError(error)) return } - let query = Select(from: table) - var dictionariesTitleToValue = [[String: Any?]]() - - connection.connect { error in - if let error = error { - onCompletion(nil, Self.convertError(error)) - return - } else { - connection.execute(query: query) { result in - guard result.success else { - guard let error = result.asError else { - onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) - return - } - onCompletion(nil, Self.convertError(error)) - return - } - - if case QueryResult.successNoData = result { - onCompletion([:], nil) - return - } - - guard let rows = result.asRows else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve values from table: \(String(describing: Self.tableName))")) - return - } - - for row in rows { - dictionariesTitleToValue.append(row) - } - - var result = [I: Self]() - for dictionary in dictionariesTitleToValue { - var decodedModel: Self - do { - decodedModel = try DatabaseDecoder().decode(Self.self, dictionary) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - - guard let value = dictionary[idColumnName] else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not find return id")) - return - } - - guard let unwrappedValue: Any = value else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Return id is nil")) - return - } - - do { - let identifier = try I(value: String(describing: unwrappedValue)) - result[identifier] = decodedModel - } catch { - onCompletion(nil, RequestError(.ormIdentifierError, reason: "Could not construct Identifier")) - } - } - onCompletion(result, nil) - } - } - } - } - - /// Find all the models matching the QueryParams - /// - Parameter using: Optional Database to use - /// - Parameter matching: Optional QueryParams to use - /// - Returns: An array of model - static func findAll(using db: Database? = nil, matching queryParams: Q, _ onCompletion: @escaping ([Self]?, RequestError?) -> Void) { - var connection: Connection - do { - connection = try Self.getConnection(using: db) - } catch let error { - onCompletion(nil, Self.convertError(error)) + let columns = table.columns.filter({$0.autoIncrement != true}) + let valueTuples = columns.filter({values[$0.name] != nil}).map({($0, values[$0.name]!)}) + guard let idColumn = table.columns.first(where: {$0.name == Self.idColumnName}) else { + onCompletion(nil, RequestError(rawValue: 708, reason: "Could not find id column")) return } + let query = Update(table, set: valueTuples).where(idColumn == id.value) + executeQuery(query: query, using: db, onCompletion) + } + + static func delete(id: Identifier, using db: Database? = nil, _ onCompletion: @escaping (RequestError?) -> Void) { var table: Table - var filter: Filter do { table = try Self.getTable() - filter = try Self.getFilter(queryParams: queryParams, table: table) } catch let error { - onCompletion(nil, Self.convertError(error)) + onCompletion(Self.convertError(error)) return } - let query = Select(from: table).where(filter) - var dictionariesTitleToValue = [[String: Any?]]() - - connection.connect { error in - if let error = error { - onCompletion(nil, Self.convertError(error)) - return - } else { - connection.execute(query: query) { result in - guard result.success else { - guard let error = result.asError else { - onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) - return - } - onCompletion(nil, Self.convertError(error)) - return - } - - if case QueryResult.successNoData = result { - onCompletion([], nil) - return - } - - guard let rows = result.asRows else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve values from table: \(String(describing: Self.tableName))")) - return - } - - for row in rows { - dictionariesTitleToValue.append(row) - } - - var result = [Self]() - for dictionary in dictionariesTitleToValue { - var decodedModel: Self - do { - decodedModel = try DatabaseDecoder().decode(Self.self, dictionary) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - result.append(decodedModel) - } - onCompletion(result, nil) - } - } - } - } - - /// Find all the models matching the QueryParams - /// - Parameter using: Optional Database to use - /// - Returns: An array of tuples (id, model) - static func findAll(using db: Database? = nil, matching queryParams: Q, _ onCompletion: @escaping ([(I, Self)]?, RequestError?) -> Void) { - var connection: Connection - do { - connection = try Self.getConnection(using: db) - } catch let error { - onCompletion(nil, Self.convertError(error)) + guard let idColumn = table.columns.first(where: {$0.name == idColumnName}) else { + onCompletion(RequestError(.ormNotFound, reason: "Could not find id column")) return } + let query = Delete(from: table).where(idColumn == id.value) + Self.executeQuery(query: query, using: db, onCompletion) + } + + static func deleteAll(using db: Database? = nil, _ onCompletion: @escaping (RequestError?) -> Void) { var table: Table - var filter: Filter do { table = try Self.getTable() - filter = try Self.getFilter(queryParams: queryParams, table: table) } catch let error { - onCompletion(nil, Self.convertError(error)) + onCompletion(Self.convertError(error)) return } - let query = Select(from: table).where(filter) - var dictionariesTitleToValue = [[String: Any?]]() - - connection.connect { error in - if let error = error { - onCompletion(nil, Self.convertError(error)) - return - } else { - connection.execute(query: query) { result in - guard result.success else { - guard let error = result.asError else { - onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) - return - } - onCompletion(nil, Self.convertError(error)) - return - } - - if case QueryResult.successNoData = result { - onCompletion([], nil) - return - } - - guard let rows = result.asRows else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve values from table: \(String(describing: Self.tableName))")) - return - } - - for row in rows { - dictionariesTitleToValue.append(row) - } - - var result = [(I,Self)]() - for dictionary in dictionariesTitleToValue { - var decodedModel: Self - do { - decodedModel = try DatabaseDecoder().decode(Self.self, dictionary) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - - guard let value = dictionary[idColumnName] else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not find return id")) - return - } - - guard let unwrappedValue: Any = value else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Return id is nil")) - return - } - - do { - let identifier = try I(value: String(describing: unwrappedValue)) - result.append((identifier, decodedModel)) - } catch { - onCompletion(nil, RequestError(.ormIdentifierError, reason: "Could not construct Identifier")) - } - - } - onCompletion(result, nil) - } - } - } + let query = Delete(from: table) + self.executeQuery(query: query, using: db, onCompletion) } - /// Find all the models matching the QueryParams + /// Delete all the models matching the QueryParams /// - Parameter using: Optional Database to use - /// - Returns: A dictionary [id: model] - static func findAll(using db: Database? = nil, matching queryParams: Q, _ onCompletion: @escaping ([I: Self]?, RequestError?) -> Void) { - var connection: Connection - do { - connection = try Self.getConnection(using: db) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - + /// - Returns: An optional RequestError + static func deleteAll(using db: Database? = nil, matching queryParams: Q, _ onCompletion: @escaping (RequestError?) -> Void) { var table: Table var filter: Filter do { - table = try Self.getTable() - filter = try Self.getFilter(queryParams: queryParams, table: table) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - - let query = Select(from: table).where(filter) - var dictionariesTitleToValue = [[String: Any?]]() - - connection.connect { error in - if let error = error { - onCompletion(nil, Self.convertError(error)) - return - } else { - connection.execute(query: query) { result in - guard result.success else { - guard let error = result.asError else { - onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) - return - } - onCompletion(nil, Self.convertError(error)) - return - } - - if case QueryResult.successNoData = result { - onCompletion([:], nil) - return - } - - guard let rows = result.asRows else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve values from table: \(String(describing: Self.tableName))")) - return - } - - for row in rows { - dictionariesTitleToValue.append(row) - } - - var result = [I: Self]() - for dictionary in dictionariesTitleToValue { - var decodedModel: Self - do { - decodedModel = try DatabaseDecoder().decode(Self.self, dictionary) - } catch let error { - onCompletion(nil, Self.convertError(error)) - return - } - - guard let value = dictionary[idColumnName] else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not find return id")) - return - } - - guard let unwrappedValue: Any = value else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Return id is nil")) - return - } - - do { - let identifier = try I(value: String(describing: unwrappedValue)) - result[identifier] = decodedModel - } catch { - onCompletion(nil, RequestError(.ormIdentifierError, reason: "Could not construct Identifier")) - } - } - onCompletion(result, nil) - } - } - } - } - - func update(id: I, using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void) { - var connection: Connection - do { - connection = try Self.getConnection(using: db) + table = try Self.getTable() + filter = try Self.getFilter(queryParams: queryParams, table: table) } catch let error { - onCompletion(nil, Self.convertError(error)) + onCompletion(Self.convertError(error)) return } - var table: Table - var values: [String: Any] + let query = Delete(from: table).where(filter) + Self.executeQuery(query: query, using: db, onCompletion) + } + + internal func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void ) { + var connection: Connection do { - table = try Self.getTable() - values = try DatabaseEncoder().encode(self) + connection = try Self.getConnection(using: db) } catch let error { onCompletion(nil, Self.convertError(error)) return } - let columns = table.columns.filter({$0.autoIncrement != true}) - let valueTuples = columns.filter({values[$0.name] != nil}).map({($0, values[$0.name]!)}) - guard let idColumn = table.columns.first(where: {$0.name == Self.idColumnName}) else { - onCompletion(nil, RequestError(rawValue: 708, reason: "Could not find id column")) - return - } - - let query = Update(table, set: valueTuples).where(idColumn == id.value) - - connection.connect {error in + connection.connect { error in if let error = error { onCompletion(nil, Self.convertError(error)) return @@ -933,149 +498,186 @@ public extension Model { onCompletion(nil, Self.convertError(error)) return } - onCompletion(self,nil) + + onCompletion(self, nil) } } } } - static func delete(id: Identifier, using db: Database? = nil, _ onCompletion: @escaping (RequestError?) -> Void) { + internal func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping (I?, Self?, RequestError?) -> Void ) { + var connection: Connection do { connection = try Self.getConnection(using: db) } catch let error { - onCompletion(Self.convertError(error)) - return - } - - var table: Table - do { - table = try Self.getTable() - } catch let error { - onCompletion(Self.convertError(error)) - return - } - - guard let idColumn = table.columns.first(where: {$0.name == idColumnName}) else { - onCompletion(RequestError(.ormNotFound, reason: "Could not find id column")) + onCompletion(nil, nil, Self.convertError(error)) return } - let query = Delete(from: table).where(idColumn == id.value) + var dictionaryTitleToValue = [String: Any?]() - connection.connect {error in + connection.connect { error in if let error = error { - onCompletion(Self.convertError(error)) + onCompletion(nil, nil, Self.convertError(error)) return } else { connection.execute(query: query) { result in guard result.success else { guard let error = result.asError else { - onCompletion(Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) + onCompletion(nil, nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) return } - onCompletion(Self.convertError(error)) + onCompletion(nil, nil, Self.convertError(error)) return } - onCompletion(nil) + + guard let rows = result.asRows, rows.count > 0 else { + onCompletion(nil, nil, RequestError(.ormNotFound, reason: "Could not retrieve value for Query: \(String(describing: query))")) + return + } + + dictionaryTitleToValue = rows[0] + + guard let value = dictionaryTitleToValue[Self.idColumnName] else { + onCompletion(nil, nil, RequestError(.ormNotFound, reason: "Could not find return id")) + return + } + + guard let unwrappedValue: Any = value else { + onCompletion(nil, nil, RequestError(.ormNotFound, reason: "Return id is nil")) + return + } + + var identifier: I + do { + identifier = try I(value: String(describing: unwrappedValue)) + } catch { + onCompletion(nil, nil, RequestError(.ormIdentifierError, reason: "Could not construct Identifier")) + return + } + + onCompletion(identifier, self, nil) } } } } - static func deleteAll(using db: Database? = nil, _ onCompletion: @escaping (RequestError?) -> Void) { + internal static func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void ) { var connection: Connection do { connection = try Self.getConnection(using: db) } catch let error { - onCompletion(Self.convertError(error)) - return - } - - var table: Table - do { - table = try Self.getTable() - } catch let error { - onCompletion(Self.convertError(error)) + onCompletion(nil, Self.convertError(error)) return } - let query = Delete(from: table) + var dictionaryTitleToValue = [String: Any?]() - connection.connect {error in + connection.connect { error in if let error = error { - onCompletion(Self.convertError(error)) + onCompletion(nil, Self.convertError(error)) return } else { connection.execute(query: query) { result in guard result.success else { guard let error = result.asError else { - onCompletion(Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) + onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) return } - onCompletion(Self.convertError(error)) + onCompletion(nil, Self.convertError(error)) return } - onCompletion(nil) + + guard let rows = result.asRows, rows.count > 0 else { + onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve value for Query: \(String(describing: query))")) + return + } + + dictionaryTitleToValue = rows[0] + + var decodedModel: Self + do { + decodedModel = try DatabaseDecoder().decode(Self.self, dictionaryTitleToValue) + } catch { + onCompletion(nil, Self.convertError(error)) + return + } + + onCompletion(decodedModel, nil) } } } } - /// Delete all the models matching the QueryParams - /// - Parameter using: Optional Database to use - /// - Returns: An optional RequestError - static func deleteAll(using db: Database? = nil, matching queryParams: Q, _ onCompletion: @escaping (RequestError?) -> Void) { + internal static func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping (I?, Self?, RequestError?) -> Void ) { var connection: Connection do { connection = try Self.getConnection(using: db) } catch let error { - onCompletion(Self.convertError(error)) - return - } - - var table: Table - do { - table = try Self.getTable() - } catch let error { - onCompletion(Self.convertError(error)) - return - } - - var filter: Filter - do { - filter = try Self.getFilter(queryParams: queryParams, table: table) - } catch let error { - onCompletion(Self.convertError(error)) + onCompletion(nil, nil, Self.convertError(error)) return } - let query = Delete(from: table).where(filter) + var dictionaryTitleToValue = [String: Any?]() - connection.connect {error in + connection.connect { error in if let error = error { - onCompletion(Self.convertError(error)) + onCompletion(nil, nil, Self.convertError(error)) return } else { connection.execute(query: query) { result in guard result.success else { guard let error = result.asError else { - onCompletion(Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) + onCompletion(nil, nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil"))) return } - onCompletion(Self.convertError(error)) + onCompletion(nil, nil, Self.convertError(error)) return } - onCompletion(nil) + + guard let rows = result.asRows, rows.count > 0 else { + onCompletion(nil, nil, RequestError(.ormNotFound, reason: "Could not retrieve value for Query: \(String(describing: query))")) + return + } + + dictionaryTitleToValue = rows[0] + + guard let value = dictionaryTitleToValue[Self.idColumnName] else { + onCompletion(nil, nil, RequestError(.ormNotFound, reason: "Could not find return id")) + return + } + + guard let unwrappedValue: Any = value else { + onCompletion(nil, nil, RequestError(.ormNotFound, reason: "Return id is nil")) + return + } + + var identifier: I + do { + identifier = try I(value: String(describing: unwrappedValue)) + } catch { + onCompletion(nil, nil, RequestError(.ormIdentifierError, reason: "Could not construct Identifier")) + return + } + + var decodedModel: Self + do { + decodedModel = try DatabaseDecoder().decode(Self.self, dictionaryTitleToValue) + } catch { + onCompletion(nil, nil, Self.convertError(error)) + return + } + + onCompletion(identifier, decodedModel, nil) } } } } - static func getTable() throws -> Table { - return try Database.tableInfo.getTable((Self.idColumnName, Self.idColumnType), Self.tableName, for: Self.self) - } - internal static func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void ) { + /// - Parameter using: Optional Database to use + /// - Returns: A tuple ([Model], RequestError) + internal static func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping ([Self]?, RequestError?)-> Void ) { var connection: Connection do { connection = try Self.getConnection(using: db) @@ -1084,7 +686,7 @@ public extension Model { return } - var dictionaryTitleToValue = [String: Any?]() + var dictionariesTitleToValue = [[String: Any?]]() connection.connect { error in if let error = error { @@ -1101,22 +703,34 @@ public extension Model { return } - guard let rows = result.asRows, rows.count > 0 else { - onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve value for Query: \(String(describing: query))")) + if case QueryResult.successNoData = result { + onCompletion([], nil) return } - dictionaryTitleToValue = rows[0] - - var decodedModel: Self - do { - decodedModel = try DatabaseDecoder().decode(Self.self, dictionaryTitleToValue) - } catch let error { - onCompletion(nil, Self.convertError(error)) + guard let rows = result.asRows else { + onCompletion(nil, RequestError(.ormNotFound, reason: "Could not retrieve values from table: \(String(describing: Self.tableName)))")) return } - onCompletion(decodedModel, nil) + for row in rows { + dictionariesTitleToValue.append(row) + } + + var list = [Self]() + for dictionary in dictionariesTitleToValue { + var decodedModel: Self + do { + decodedModel = try DatabaseDecoder().decode(Self.self, dictionary) + } catch { + onCompletion(nil, Self.convertError(error)) + return + } + + list.append(decodedModel) + } + + onCompletion(list, nil) } } } @@ -1124,7 +738,7 @@ public extension Model { /// - Parameter using: Optional Database to use /// - Returns: A tuple ([Model], RequestError) - internal static func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping ([Self]?, RequestError?)-> Void ) { + internal static func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping ([(I, Self)]?, RequestError?) -> Void ) { var connection: Connection do { connection = try Self.getConnection(using: db) @@ -1164,7 +778,7 @@ public extension Model { dictionariesTitleToValue.append(row) } - var list = [Self]() + var result = [(I, Self)]() for dictionary in dictionariesTitleToValue { var decodedModel: Self do { @@ -1174,10 +788,25 @@ public extension Model { return } - list.append(decodedModel) + guard let value = dictionary[idColumnName] else { + onCompletion(nil, RequestError(.ormNotFound, reason: "Could not find return id")) + return + } + + guard let unwrappedValue: Any = value else { + onCompletion(nil, RequestError(.ormNotFound, reason: "Return id is nil")) + return + } + + do { + let identifier = try I(value: String(describing: unwrappedValue)) + result.append((identifier, decodedModel)) + } catch { + onCompletion(nil, RequestError(.ormIdentifierError, reason: "Could not construct Identifier")) + } } - onCompletion(list, nil) + onCompletion(result, nil) } } } @@ -1185,7 +814,8 @@ public extension Model { /// - Parameter using: Optional Database to use /// - Returns: An optional RequestError - internal static func executeQuery(using db: Database? = nil, _ onCompletion: @escaping (RequestError?) -> Void ) { + + internal static func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping (RequestError?) -> Void ) { var connection: Connection do { connection = try Self.getConnection(using: db) @@ -1194,16 +824,6 @@ public extension Model { return } - var table: Table - do { - table = try Self.getTable() - } catch let error { - onCompletion(Self.convertError(error)) - return - } - - let query = Delete(from: table) - connection.connect {error in if let error = error { onCompletion(Self.convertError(error)) @@ -1224,6 +844,10 @@ public extension Model { } } + static func getTable() throws -> Table { + return try Database.tableInfo.getTable((Self.idColumnName, Self.idColumnType), Self.tableName, for: Self.self) + } + /// This function converts the Query Parameter into a Filter used in SwiftKuery /// Parameters: /// - A generic QueryParams instance