Skip to content

Commit 55f4565

Browse files
authored
Merge pull request #1137 from atultw/master
add decoding for UUID
2 parents 578be41 + be3a5ce commit 55f4565

File tree

4 files changed

+59
-44
lines changed

4 files changed

+59
-44
lines changed

Sources/SQLite/Typed/Coding.swift

+24-18
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,14 @@ private class SQLiteEncoder: Encoder {
203203
}
204204

205205
func encode<T>(_ value: T, forKey key: Key) throws where T: Swift.Encodable {
206-
if let data = value as? Data {
206+
switch value {
207+
case let data as Data:
207208
encoder.setters.append(Expression(key.stringValue) <- data)
208-
} else if let date = value as? Date {
209+
case let date as Date:
209210
encoder.setters.append(Expression(key.stringValue) <- date.datatypeValue)
210-
} else if let uuid = value as? UUID {
211+
case let uuid as UUID:
211212
encoder.setters.append(Expression(key.stringValue) <- uuid.datatypeValue)
212-
} else {
213+
default:
213214
let encoded = try JSONEncoder().encode(value)
214215
let string = String(data: encoded, encoding: .utf8)
215216
encoder.setters.append(Expression(key.stringValue) <- string)
@@ -261,7 +262,7 @@ private class SQLiteEncoder: Encoder {
261262
}
262263

263264
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key)
264-
-> KeyedEncodingContainer<NestedKey> where NestedKey: CodingKey {
265+
-> KeyedEncodingContainer<NestedKey> where NestedKey: CodingKey {
265266
fatalError("encoding a nested container is not supported")
266267
}
267268

@@ -381,27 +382,32 @@ private class SQLiteDecoder: Decoder {
381382

382383
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Swift.Decodable {
383384
// swiftlint:disable force_cast
384-
if type == Data.self {
385+
switch type {
386+
case is Data.Type:
385387
let data = try row.get(Expression<Data>(key.stringValue))
386388
return data as! T
387-
} else if type == Date.self {
389+
case is Date.Type:
388390
let date = try row.get(Expression<Date>(key.stringValue))
389391
return date as! T
392+
case is UUID.Type:
393+
let uuid = try row.get(Expression<UUID>(key.stringValue))
394+
return uuid as! T
395+
default:
396+
// swiftlint:enable force_cast
397+
guard let JSONString = try row.get(Expression<String?>(key.stringValue)) else {
398+
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: codingPath,
399+
debugDescription: "an unsupported type was found"))
400+
}
401+
guard let data = JSONString.data(using: .utf8) else {
402+
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath,
403+
debugDescription: "invalid utf8 data found"))
404+
}
405+
return try JSONDecoder().decode(type, from: data)
390406
}
391-
// swiftlint:enable force_cast
392-
guard let JSONString = try row.get(Expression<String?>(key.stringValue)) else {
393-
throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: codingPath,
394-
debugDescription: "an unsupported type was found"))
395-
}
396-
guard let data = JSONString.data(using: .utf8) else {
397-
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath,
398-
debugDescription: "invalid utf8 data found"))
399-
}
400-
return try JSONDecoder().decode(type, from: data)
401407
}
402408

403409
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws
404-
-> KeyedDecodingContainer<NestedKey> where NestedKey: CodingKey {
410+
-> KeyedDecodingContainer<NestedKey> where NestedKey: CodingKey {
405411
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath,
406412
debugDescription: "decoding nested containers is not supported"))
407413
}

Tests/SQLiteTests/QueryIntegrationTests.swift

+4-3
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@ class QueryIntegrationTests: SQLiteTestCase {
7575
builder.column(Expression<Double>("float"))
7676
builder.column(Expression<Double>("double"))
7777
builder.column(Expression<Date>("date"))
78+
builder.column(Expression<UUID>("uuid"))
7879
builder.column(Expression<String?>("optional"))
7980
builder.column(Expression<Data>("sub"))
8081
})
8182

8283
let value1 = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4,
83-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: nil)
84+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: nil)
8485
let value = TestCodable(int: 5, string: "6", bool: true, float: 7, double: 8,
85-
date: Date(timeIntervalSince1970: 5000), optional: "optional", sub: value1)
86-
86+
date: Date(timeIntervalSince1970: 5000), uuid: testUUIDValue, optional: "optional", sub: value1)
8787
try db.run(table.insert(value))
8888

8989
let rows = try db.prepare(table)
@@ -95,6 +95,7 @@ class QueryIntegrationTests: SQLiteTestCase {
9595
XCTAssertEqual(values[0].float, 7)
9696
XCTAssertEqual(values[0].double, 8)
9797
XCTAssertEqual(values[0].date, Date(timeIntervalSince1970: 5000))
98+
XCTAssertEqual(values[0].uuid, testUUIDValue)
9899
XCTAssertEqual(values[0].optional, "optional")
99100
XCTAssertEqual(values[0].sub?.int, 1)
100101
XCTAssertEqual(values[0].sub?.string, "2")

Tests/SQLiteTests/QueryTests.swift

+25-22
Original file line numberDiff line numberDiff line change
@@ -279,12 +279,12 @@ class QueryTests: XCTestCase {
279279
func test_insert_encodable() throws {
280280
let emails = Table("emails")
281281
let value = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4,
282-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: nil)
282+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: nil)
283283
let insert = try emails.insert(value)
284284
assertSQL(
285285
"""
286-
INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\", \"date\")
287-
VALUES (1, '2', 1, 3.0, 4.0, '1970-01-01T00:00:00.000')
286+
INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\", \"date\", \"uuid\")
287+
VALUES (1, '2', 1, 3.0, 4.0, '1970-01-01T00:00:00.000', 'E621E1F8-C36C-495A-93FC-0C247A3E6E5F')
288288
""".replacingOccurrences(of: "\n", with: ""),
289289
insert
290290
)
@@ -294,16 +294,17 @@ class QueryTests: XCTestCase {
294294
func test_insert_encodable_with_nested_encodable() throws {
295295
let emails = Table("emails")
296296
let value1 = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4,
297-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: nil)
297+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: nil)
298298
let value = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4,
299-
date: Date(timeIntervalSince1970: 0), optional: "optional", sub: value1)
299+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: "optional", sub: value1)
300300
let insert = try emails.insert(value)
301301
let encodedJSON = try JSONEncoder().encode(value1)
302302
let encodedJSONString = String(data: encodedJSON, encoding: .utf8)!
303303
assertSQL(
304304
"""
305-
INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\", \"date\", \"optional\",
306-
\"sub\") VALUES (1, '2', 1, 3.0, 4.0, '1970-01-01T00:00:00.000', 'optional', '\(encodedJSONString)')
305+
INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\", \"date\", \"uuid\", \"optional\",
306+
\"sub\") VALUES (1, '2', 1, 3.0, 4.0, '1970-01-01T00:00:00.000', 'E621E1F8-C36C-495A-93FC-0C247A3E6E5F',
307+
'optional', '\(encodedJSONString)')
307308
""".replacingOccurrences(of: "\n", with: ""),
308309
insert
309310
)
@@ -350,14 +351,15 @@ class QueryTests: XCTestCase {
350351
let emails = Table("emails")
351352
let string = Expression<String>("string")
352353
let value = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4,
353-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: nil)
354+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: nil)
354355
let insert = try emails.upsert(value, onConflictOf: string)
355356
assertSQL(
356357
"""
357-
INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\", \"date\")
358-
VALUES (1, '2', 1, 3.0, 4.0, '1970-01-01T00:00:00.000') ON CONFLICT (\"string\")
358+
INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\", \"date\", \"uuid\")
359+
VALUES (1, '2', 1, 3.0, 4.0, '1970-01-01T00:00:00.000', 'E621E1F8-C36C-495A-93FC-0C247A3E6E5F') ON CONFLICT (\"string\")
359360
DO UPDATE SET \"int\" = \"excluded\".\"int\", \"bool\" = \"excluded\".\"bool\",
360-
\"float\" = \"excluded\".\"float\", \"double\" = \"excluded\".\"double\", \"date\" = \"excluded\".\"date\"
361+
\"float\" = \"excluded\".\"float\", \"double\" = \"excluded\".\"double\", \"date\" = \"excluded\".\"date\",
362+
\"uuid\" = \"excluded\".\"uuid\"
361363
""".replacingOccurrences(of: "\n", with: ""),
362364
insert
363365
)
@@ -366,17 +368,18 @@ class QueryTests: XCTestCase {
366368
func test_insert_many_encodable() throws {
367369
let emails = Table("emails")
368370
let value1 = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4,
369-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: nil)
371+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: nil)
370372
let value2 = TestCodable(int: 2, string: "3", bool: true, float: 3, double: 5,
371-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: nil)
373+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: nil)
372374
let value3 = TestCodable(int: 3, string: "4", bool: true, float: 3, double: 6,
373-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: nil)
375+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: nil)
374376
let insert = try emails.insertMany([value1, value2, value3])
375377
assertSQL(
376378
"""
377-
INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\", \"date\")
378-
VALUES (1, '2', 1, 3.0, 4.0, '1970-01-01T00:00:00.000'), (2, '3', 1, 3.0, 5.0, '1970-01-01T00:00:00.000'),
379-
(3, '4', 1, 3.0, 6.0, '1970-01-01T00:00:00.000')
379+
INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\", \"date\", \"uuid\")
380+
VALUES (1, '2', 1, 3.0, 4.0, '1970-01-01T00:00:00.000', 'E621E1F8-C36C-495A-93FC-0C247A3E6E5F'),
381+
(2, '3', 1, 3.0, 5.0, '1970-01-01T00:00:00.000', 'E621E1F8-C36C-495A-93FC-0C247A3E6E5F'),
382+
(3, '4', 1, 3.0, 6.0, '1970-01-01T00:00:00.000', 'E621E1F8-C36C-495A-93FC-0C247A3E6E5F')
380383
""".replacingOccurrences(of: "\n", with: ""),
381384
insert
382385
)
@@ -399,12 +402,12 @@ class QueryTests: XCTestCase {
399402
func test_update_encodable() throws {
400403
let emails = Table("emails")
401404
let value = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4,
402-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: nil)
405+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: nil)
403406
let update = try emails.update(value)
404407
assertSQL(
405408
"""
406409
UPDATE \"emails\" SET \"int\" = 1, \"string\" = '2', \"bool\" = 1, \"float\" = 3.0, \"double\" = 4.0,
407-
\"date\" = '1970-01-01T00:00:00.000'
410+
\"date\" = '1970-01-01T00:00:00.000', \"uuid\" = 'E621E1F8-C36C-495A-93FC-0C247A3E6E5F'
408411
""".replacingOccurrences(of: "\n", with: ""),
409412
update
410413
)
@@ -413,9 +416,9 @@ class QueryTests: XCTestCase {
413416
func test_update_encodable_with_nested_encodable() throws {
414417
let emails = Table("emails")
415418
let value1 = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4,
416-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: nil)
419+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: nil)
417420
let value = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4,
418-
date: Date(timeIntervalSince1970: 0), optional: nil, sub: value1)
421+
date: Date(timeIntervalSince1970: 0), uuid: testUUIDValue, optional: nil, sub: value1)
419422
let update = try emails.update(value)
420423

421424
// NOTE: As Linux JSON decoding doesn't order keys the same way, we need to check prefix, suffix,
@@ -424,7 +427,7 @@ class QueryTests: XCTestCase {
424427
let expectedPrefix =
425428
"""
426429
UPDATE \"emails\" SET \"int\" = 1, \"string\" = '2', \"bool\" = 1, \"float\" = 3.0, \"double\" = 4.0,
427-
\"date\" = '1970-01-01T00:00:00.000', \"sub\" = '
430+
\"date\" = '1970-01-01T00:00:00.000', \"uuid\" = 'E621E1F8-C36C-495A-93FC-0C247A3E6E5F', \"sub\" = '
428431
""".replacingOccurrences(of: "\n", with: "")
429432
let expectedSuffix = "'"
430433

Tests/SQLiteTests/TestHelpers.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ let stringOptional = Expression<String?>("stringOptional")
9898
let uuid = Expression<UUID>("uuid")
9999
let uuidOptional = Expression<UUID?>("uuidOptional")
100100

101+
let testUUIDValue = UUID(uuidString: "E621E1F8-C36C-495A-93FC-0C247A3E6E5F")!
102+
101103
func assertSQL(_ expression1: @autoclosure () -> String, _ expression2: @autoclosure () -> Expressible,
102104
file: StaticString = #file, line: UInt = #line) {
103105
XCTAssertEqual(expression1(), expression2().asSQL(), file: file, line: line)
@@ -115,16 +117,18 @@ class TestCodable: Codable, Equatable {
115117
let float: Float
116118
let double: Double
117119
let date: Date
120+
let uuid: UUID
118121
let optional: String?
119122
let sub: TestCodable?
120123

121-
init(int: Int, string: String, bool: Bool, float: Float, double: Double, date: Date, optional: String?, sub: TestCodable?) {
124+
init(int: Int, string: String, bool: Bool, float: Float, double: Double, date: Date, uuid: UUID, optional: String?, sub: TestCodable?) {
122125
self.int = int
123126
self.string = string
124127
self.bool = bool
125128
self.float = float
126129
self.double = double
127130
self.date = date
131+
self.uuid = uuid
128132
self.optional = optional
129133
self.sub = sub
130134
}
@@ -136,6 +140,7 @@ class TestCodable: Codable, Equatable {
136140
lhs.float == rhs.float &&
137141
lhs.double == rhs.double &&
138142
lhs.date == rhs.date &&
143+
lhs.uuid == lhs.uuid &&
139144
lhs.optional == rhs.optional &&
140145
lhs.sub == rhs.sub
141146
}

0 commit comments

Comments
 (0)