@@ -4,7 +4,7 @@ import Otter
44struct Interest: Hashable, Sendable, Identifiable, RowDecodable {
55 let id: Int
66 let value: String
7- let userId: String ?
7+ let userId: Int ?
88
99 static let nonOptionalIndices: [Int32] = [0, 1]
1010
@@ -20,7 +20,7 @@ struct Interest: Hashable, Sendable, Identifiable, RowDecodable {
2020 init(
2121 id: Int,
2222 value: String,
23- userId: String ?
23+ userId: Int ?
2424 ) {
2525 self.id = id
2626 self.value = value
@@ -35,10 +35,10 @@ struct User: Hashable, Sendable, Identifiable, RowDecodable {
3535 let preference: Bool?
3636 let favoriteNumber: Int?
3737 let randomValue: SQLAny?
38- let bornOn: Date
38+ let bornOn: Date?
3939 let fullName: String
4040
41- static let nonOptionalIndices: [Int32] = [0, 1, 2, 6, 7]
41+ static let nonOptionalIndices: [Int32] = [0, 1, 2, 7]
4242
4343 init(
4444 row: borrowing Otter.Row,
@@ -47,10 +47,10 @@ struct User: Hashable, Sendable, Identifiable, RowDecodable {
4747 self.id = try row.value(at: start + 0)
4848 self.firstName = try row.value(at: start + 1)
4949 self.lastName = try row.value(at: start + 2)
50- self.preference = try row.optionalValue(at: start + 3, using: BoolDatabaseValueAdapter.self)
50+ self.preference = try row.optionalValue(at: start + 3, using: BoolDatabaseValueAdapter.self, storage: Int.self )
5151 self.favoriteNumber = try row.value(at: start + 4)
5252 self.randomValue = try row.value(at: start + 5)
53- self.bornOn = try row.value (at: start + 6, using: CustomDateDatabaseValueAdapter.self)
53+ self.bornOn = try row.optionalValue (at: start + 6, using: CustomDateDatabaseValueAdapter.self, storage: String .self)
5454 self.fullName = try row.value(at: start + 7)
5555 }
5656
@@ -61,7 +61,7 @@ struct User: Hashable, Sendable, Identifiable, RowDecodable {
6161 preference: Bool?,
6262 favoriteNumber: Int?,
6363 randomValue: SQLAny?,
64- bornOn: Date,
64+ bornOn: Date? ,
6565 fullName: String
6666 ) {
6767 self.id = id
@@ -75,6 +75,16 @@ struct User: Hashable, Sendable, Identifiable, RowDecodable {
7575 }
7676}
7777
78+ struct InsertUserInput: Hashable, Sendable, Identifiable {
79+ let id: Int
80+ let firstName: String
81+ let lastName: String
82+ let preference: Bool?
83+ let favoriteNumber: Int?
84+ let randomValue: SQLAny?
85+ let bornOn: Date?
86+ }
87+
7888struct SelectUserWithManyInputsInput: Hashable, Sendable, Identifiable {
7989 let id: Int
8090 let firstName: String
@@ -173,6 +183,8 @@ struct SelectWithOptionalInterestOutput: Hashable, Sendable, RowDecodable {
173183}
174184
175185protocol QueriesQueries {
186+ associatedtype InsertUser: InsertUserQuery
187+ var insertUser: InsertUser { get }
176188 associatedtype SelectUsers: SelectUsersQuery
177189 var selectUsers: SelectUsers { get }
178190 associatedtype SelectUserById: SelectUserByIdQuery
@@ -190,6 +202,7 @@ protocol QueriesQueries {
190202}
191203
192204struct QueriesQueriesNoop: QueriesQueries {
205+ let insertUser: AnyQuery<InsertUserInput, ()>
193206 let selectUsers: AnyQuery<(), [User]>
194207 let selectUserById: AnyQuery<Int, User?>
195208 let selectUserByIds: AnyQuery<[Int], [User]>
@@ -199,6 +212,7 @@ struct QueriesQueriesNoop: QueriesQueries {
199212 let selectWithOptionalInterest: AnyQuery<(), [SelectWithOptionalInterestOutput]>
200213
201214 init(
215+ insertUser: any InsertUserQuery = Queries.Just(),
202216 selectUsers: any SelectUsersQuery = Queries.Just(),
203217 selectUserById: any SelectUserByIdQuery = Queries.Just(),
204218 selectUserByIds: any SelectUserByIdsQuery = Queries.Just(),
@@ -207,6 +221,7 @@ struct QueriesQueriesNoop: QueriesQueries {
207221 selectWithInterest: any SelectWithInterestQuery = Queries.Just(),
208222 selectWithOptionalInterest: any SelectWithOptionalInterestQuery = Queries.Just()
209223 ) {
224+ self.insertUser = insertUser.eraseToAnyQuery()
210225 self.selectUsers = selectUsers.eraseToAnyQuery()
211226 self.selectUserById = selectUserById.eraseToAnyQuery()
212227 self.selectUserByIds = selectUserByIds.eraseToAnyQuery()
@@ -220,6 +235,29 @@ struct QueriesQueriesNoop: QueriesQueries {
220235struct QueriesQueriesImpl: QueriesQueries {
221236 let connection: any Connection
222237
238+ var insertUser: AnyDatabaseQuery<InsertUserInput, ()> {
239+ AnyDatabaseQuery<InsertUserInput, ()>(
240+ .write,
241+ in: connection,
242+ watchingTables: ["user"]
243+ ) { input, tx in
244+ var statement = try Otter.Statement(
245+ """
246+ INSERT INTO user VALUES (?, ?, ?, ?, ?, ?, ?)
247+ """,
248+ transaction: tx
249+ )
250+ try statement.bind(value: input.id, to: 1)
251+ try statement.bind(value: input.firstName, to: 2)
252+ try statement.bind(value: input.lastName, to: 3)
253+ try statement.bind(value: input.preference, to: 4, using: BoolDatabaseValueAdapter.self, as: Int.self)
254+ try statement.bind(value: input.favoriteNumber, to: 5)
255+ try statement.bind(value: input.randomValue, to: 6)
256+ try statement.bind(value: input.bornOn, to: 7, using: CustomDateDatabaseValueAdapter.self, as: String.self)
257+ _ = try statement.step()
258+ }
259+ }
260+
223261 var selectUsers: AnyDatabaseQuery<(), [User]> {
224262 AnyDatabaseQuery<(), [User]>(
225263 .read,
@@ -301,8 +339,8 @@ struct QueriesQueriesImpl: QueriesQueries {
301339 """,
302340 transaction: tx
303341 )
304- try statement.bind(value: id. input, to: 1)
305- try statement.bind(value: firstName. input, to: 2)
342+ try statement.bind(value: input.id , to: 1)
343+ try statement.bind(value: input.firstName , to: 2)
306344 return try statement.fetchOne()
307345 }
308346 }
@@ -353,15 +391,15 @@ struct DB: Database{
353391 preference INTEGER ,
354392 favoriteNumber INTEGER,
355393 randomValue ANY,
356- bornOn STRING USING CustomDate NOT NULL ,
394+ bornOn TEXT ,
357395 fullName TEXT NOT NULL GENERATED ALWAYS AS (firstName || ' ' || lastName)
358396 );
359397 """,
360398 """
361399 CREATE TABLE interest (
362400 id INTEGER PRIMARY KEY AUTOINCREMENT,
363401 value TEXT NOT NULL,
364- userId TEXT REFERENCES user(id)
402+ userId INTEGER REFERENCES user(id)
365403 );;
366404 """
367405 ]
@@ -371,6 +409,17 @@ struct DB: Database{
371409 }
372410}
373411
412+ typealias InsertUserQuery = Query<InsertUserInput, ()>
413+ extension Query where Input == InsertUserInput {
414+ func execute(id: Int, firstName: String, lastName: String, preference: Bool?, favoriteNumber: Int?, randomValue: SQLAny?, bornOn: Date?) async throws -> Output {
415+ try await execute(with: InsertUserInput(id: id, firstName: firstName, lastName: lastName, preference: preference, favoriteNumber: favoriteNumber, randomValue: randomValue, bornOn: bornOn))
416+ }
417+
418+ func observe(id: Int, firstName: String, lastName: String, preference: Bool?, favoriteNumber: Int?, randomValue: SQLAny?, bornOn: Date?) -> any QueryObservation<Output> {
419+ observe(with: InsertUserInput(id: id, firstName: firstName, lastName: lastName, preference: preference, favoriteNumber: favoriteNumber, randomValue: randomValue, bornOn: bornOn))
420+ }
421+ }
422+
374423typealias SelectUsersQuery = Query<(), [User]>
375424typealias SelectUserByIdQuery = Query<Int, User?>
376425typealias SelectUserByIdsQuery = Query<[Int], [User]>
0 commit comments