|
8 | 8 | import Foundation
|
9 | 9 | import PerfectCRUD
|
10 | 10 |
|
| 11 | +// Promises that instances.count == returnValue.count on exit |
| 12 | +// otherwise it will throw |
| 13 | +private func _insert<OverAllForm: Codable, FromTableType: TableProtocol>(fromTable ft: FromTableType, |
| 14 | + instances: [OverAllForm], |
| 15 | + includeKeys: [PartialKeyPath<OverAllForm>], |
| 16 | + excludeKeys: [PartialKeyPath<OverAllForm>]) throws -> [OverAllForm] { |
| 17 | + typealias OAF = OverAllForm |
| 18 | + let delegate = ft.databaseConfiguration.sqlGenDelegate |
| 19 | + var state = SQLGenState(delegate: delegate) |
| 20 | + state.command = .insert |
| 21 | + try ft.setState(state: &state) |
| 22 | + let td = state.tableData[0] |
| 23 | + let kpDecoder = td.keyPathDecoder |
| 24 | + guard let kpInstance = td.modelInstance else { |
| 25 | + throw CRUDSQLGenError("Could not get model instance for key path decoder \(OAF.self)") |
| 26 | + } |
| 27 | + guard let databaseConfiguration = ft.databaseConfiguration as? PostgresDatabaseConfiguration else { |
| 28 | + throw CRUDSQLGenError("This is for Postgres only.") |
| 29 | + } |
| 30 | + let includeNames: [String] |
| 31 | + if includeKeys.isEmpty { |
| 32 | + let columnDecoder = CRUDColumnNameDecoder() |
| 33 | + _ = try OverAllForm.init(from: columnDecoder) |
| 34 | + includeNames = columnDecoder.collectedKeys.map { $0.name } |
| 35 | + } else { |
| 36 | + includeNames = try includeKeys.map { |
| 37 | + guard let n = try kpDecoder.getKeyPathName(kpInstance, keyPath: $0) else { |
| 38 | + throw CRUDSQLGenError("Could not get key path name for \(OAF.self) \($0)") |
| 39 | + } |
| 40 | + return n |
| 41 | + } |
| 42 | + } |
| 43 | + let excludeNames: [String] = try excludeKeys.map { |
| 44 | + guard let n = try kpDecoder.getKeyPathName(kpInstance, keyPath: $0) else { |
| 45 | + throw CRUDSQLGenError("Could not get key path name for \(OAF.self) \($0)") |
| 46 | + } |
| 47 | + return n |
| 48 | + } |
| 49 | + |
| 50 | + let encoder = try CRUDBindingsEncoder(delegate: delegate) |
| 51 | + try instances[0].encode(to: encoder) |
| 52 | + |
| 53 | + let bindings = try encoder.completedBindings(allKeys: includeNames, ignoreKeys: Set(excludeNames)) |
| 54 | + let columnNames = try bindings.map { try delegate.quote(identifier: $0.column) } |
| 55 | + let bindIdentifiers = bindings.map { $0.identifier } |
| 56 | + |
| 57 | + let nameQ = try delegate.quote(identifier: "\(OAF.CRUDTableName)") |
| 58 | + let sqlStr = """ |
| 59 | + INSERT INTO \(nameQ) (\(columnNames.joined(separator: ", "))) |
| 60 | + VALUES (\(bindIdentifiers.joined(separator: ", "))) |
| 61 | + RETURNING * |
| 62 | + """ |
| 63 | + CRUDLogging.log(.query, sqlStr) |
| 64 | + let exeDelegate = PostgresExeDelegate(connection: databaseConfiguration.connection, sql: sqlStr) |
| 65 | + try exeDelegate.bind(delegate.bindings) |
| 66 | + guard try exeDelegate.hasNext() else { |
| 67 | + throw CRUDSQLGenError("Did not get return value from statement \(sqlStr).") |
| 68 | + } |
| 69 | + var ret: [OverAllForm] = [] |
| 70 | + ret.append(try OverAllForm(from: CRUDRowDecoder<ColumnKey>(delegate: exeDelegate))) |
| 71 | + for instance in instances[1...] { |
| 72 | + exeDelegate.resetResults() |
| 73 | + let delegate = databaseConfiguration.sqlGenDelegate |
| 74 | + let encoder = try CRUDBindingsEncoder(delegate: delegate) |
| 75 | + try instance.encode(to: encoder) |
| 76 | + _ = try encoder.completedBindings(allKeys: includeNames, ignoreKeys: Set(excludeNames)) |
| 77 | + try exeDelegate.bind(delegate.bindings) |
| 78 | + guard try exeDelegate.hasNext() else { |
| 79 | + throw CRUDSQLGenError("Did not get return value from statement \(sqlStr).") |
| 80 | + } |
| 81 | + ret.append(try OverAllForm(from: CRUDRowDecoder<ColumnKey>(delegate: exeDelegate))) |
| 82 | + } |
| 83 | + return ret |
| 84 | +} |
| 85 | + |
11 | 86 | // Promises that instances.count == returnValue.count on exit
|
12 | 87 | // otherwise it will throw
|
13 | 88 | private func _insert<OverAllForm: Codable, FromTableType: TableProtocol, R: Decodable>(fromTable ft: FromTableType,
|
@@ -90,27 +165,69 @@ private func _insert<OverAllForm: Codable, FromTableType: TableProtocol, R: Deco
|
90 | 165 | }
|
91 | 166 |
|
92 | 167 | public extension Table where C.Configuration == PostgresDatabaseConfiguration {
|
93 |
| - func insert<R: Decodable>(_ instance: Form, returning: KeyPath<OverAllForm, R>) throws -> R { |
| 168 | + /// Insert the instance and return the new column value. |
| 169 | + func returning<R: Decodable>(_ returning: KeyPath<OverAllForm, R>, insert instance: Form) throws -> R { |
94 | 170 | return try _insert(fromTable: self, instances: [instance], returning: returning, includeKeys: [], excludeKeys: []).first!
|
95 | 171 | }
|
96 |
| - func insert<R: Decodable>(_ instance: Form, returning: KeyPath<OverAllForm, R>, |
97 |
| - setKeys: PartialKeyPath<OverAllForm>, _ rest: PartialKeyPath<OverAllForm>...) throws -> R { |
| 172 | + /// Insert the instance and return the new column value. |
| 173 | + func returning<R: Decodable, Z: Decodable>(_ returning: KeyPath<OverAllForm, R>, insert instance: Form, |
| 174 | + setKeys: KeyPath<OverAllForm, Z>, _ rest: PartialKeyPath<OverAllForm>...) throws -> R { |
98 | 175 | return try _insert(fromTable: self, instances: [instance], returning: returning, includeKeys: [setKeys] + rest, excludeKeys: []).first!
|
99 | 176 | }
|
100 |
| - func insert<R: Decodable>(_ instance: Form, returning: KeyPath<OverAllForm, R>, |
101 |
| - ignoreKeys: PartialKeyPath<OverAllForm>, _ rest: PartialKeyPath<OverAllForm>...) throws -> R { |
| 177 | + /// Insert the instance and return the new column value. |
| 178 | + func returning<R: Decodable, Z: Decodable>(_ returning: KeyPath<OverAllForm, R>, insert instance: Form, |
| 179 | + ignoreKeys: KeyPath<OverAllForm, Z>, _ rest: PartialKeyPath<OverAllForm>...) throws -> R { |
102 | 180 | return try _insert(fromTable: self, instances: [instance], returning: returning, includeKeys: [], excludeKeys: [ignoreKeys] + rest).first!
|
103 | 181 | }
|
104 |
| - |
105 |
| - func insert<R: Decodable>(_ instances: [Form], returning: KeyPath<OverAllForm, R>) throws -> [R] { |
| 182 | + /// Insert the instances and return the new column values. |
| 183 | + /// Guarantees that insert.count == returnValue.count. |
| 184 | + func returning<R: Decodable>(_ returning: KeyPath<OverAllForm, R>, insert instances: [Form]) throws -> [R] { |
106 | 185 | return try _insert(fromTable: self, instances: instances, returning: returning, includeKeys: [], excludeKeys: [])
|
107 | 186 | }
|
108 |
| - func insert<R: Decodable>(_ instances: [Form], returning: KeyPath<OverAllForm, R>, |
109 |
| - setKeys: PartialKeyPath<OverAllForm>, _ rest: PartialKeyPath<OverAllForm>...) throws -> [R] { |
| 187 | + /// Insert the instances and return the new column values. |
| 188 | + /// Guarantees that insert.count == returnValue.count. |
| 189 | + func returning<R: Decodable, Z: Decodable>(_ returning: KeyPath<OverAllForm, R>, insert instances: [Form], |
| 190 | + setKeys: KeyPath<OverAllForm, Z>, _ rest: PartialKeyPath<OverAllForm>...) throws -> [R] { |
110 | 191 | return try _insert(fromTable: self, instances: instances, returning: returning, includeKeys: [setKeys] + rest, excludeKeys: [])
|
111 | 192 | }
|
112 |
| - func insert<R: Decodable>(_ instances: [Form], returning: KeyPath<OverAllForm, R>, |
113 |
| - ignoreKeys: PartialKeyPath<OverAllForm>, _ rest: PartialKeyPath<OverAllForm>...) throws -> [R] { |
| 193 | + /// Insert the instances and return the new column values. |
| 194 | + /// Guarantees that insert.count == returnValue.count. |
| 195 | + func returning<R: Decodable, Z: Decodable>(_ returning: KeyPath<OverAllForm, R>, insert instances: [Form], |
| 196 | + ignoreKeys: KeyPath<OverAllForm, Z>, _ rest: PartialKeyPath<OverAllForm>...) throws -> [R] { |
114 | 197 | return try _insert(fromTable: self, instances: instances, returning: returning, includeKeys: [], excludeKeys: [ignoreKeys] + rest)
|
115 | 198 | }
|
116 | 199 | }
|
| 200 | + |
| 201 | +public extension Table where C.Configuration == PostgresDatabaseConfiguration { |
| 202 | + /// Insert the instance and return the new object value. |
| 203 | + func returning(insert instance: Form) throws -> OverAllForm { |
| 204 | + return try _insert(fromTable: self, instances: [instance], includeKeys: [], excludeKeys: []).first! |
| 205 | + } |
| 206 | + /// Insert the instance and return the new object value. |
| 207 | + func returning<Z: Decodable>(insert instance: Form, |
| 208 | + setKeys: KeyPath<OverAllForm, Z>, _ rest: PartialKeyPath<OverAllForm>...) throws -> OverAllForm { |
| 209 | + return try _insert(fromTable: self, instances: [instance], includeKeys: [setKeys] + rest, excludeKeys: []).first! |
| 210 | + } |
| 211 | + /// Insert the instance and return the new object value. |
| 212 | + func returning<Z: Decodable>(insert instance: Form, |
| 213 | + ignoreKeys: KeyPath<OverAllForm, Z>, _ rest: PartialKeyPath<OverAllForm>...) throws -> OverAllForm { |
| 214 | + return try _insert(fromTable: self, instances: [instance], includeKeys: [], excludeKeys: [ignoreKeys] + rest).first! |
| 215 | + } |
| 216 | + /// Insert the instances and return the new object values. |
| 217 | + /// Guarantees that insert.count == returnValue.count. |
| 218 | + func returning(insert instances: [Form]) throws -> [OverAllForm] { |
| 219 | + return try _insert(fromTable: self, instances: instances, includeKeys: [], excludeKeys: []) |
| 220 | + } |
| 221 | + /// Insert the instances and return the new object values. |
| 222 | + /// Guarantees that insert.count == returnValue.count. |
| 223 | + func returning<Z: Decodable>(insert instances: [Form], |
| 224 | + setKeys: KeyPath<OverAllForm, Z>, _ rest: PartialKeyPath<OverAllForm>...) throws -> [OverAllForm] { |
| 225 | + return try _insert(fromTable: self, instances: instances, includeKeys: [setKeys] + rest, excludeKeys: []) |
| 226 | + } |
| 227 | + /// Insert the instances and return the new object values. |
| 228 | + /// Guarantees that insert.count == returnValue.count. |
| 229 | + func returning<Z: Decodable>(insert instances: [Form], |
| 230 | + ignoreKeys: KeyPath<OverAllForm, Z>, _ rest: PartialKeyPath<OverAllForm>...) throws -> [OverAllForm] { |
| 231 | + return try _insert(fromTable: self, instances: instances, includeKeys: [], excludeKeys: [ignoreKeys] + rest) |
| 232 | + } |
| 233 | +} |
0 commit comments