forked from groue/GRDB.swift
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJSONColumn.swift
More file actions
93 lines (91 loc) · 2.92 KB
/
JSONColumn.swift
File metadata and controls
93 lines (91 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/// A JSON column in a database table.
///
/// ## Overview
///
/// `JSONColumn` has benefits over ``Column`` for database columns that
/// contain JSON strings.
///
/// It behaves like a regular `Column`, with all extra conveniences and
/// behaviors of ``SQLJSONExpressible``.
///
/// For example, the sample code below directly accesses the "countryCode"
/// key of the "address" JSON column:
///
/// ```swift
/// struct Player: Codable {
/// var id: Int64
/// var name: String
/// var address: Address
/// }
///
/// struct Address: Codable {
/// var street: String
/// var city: String
/// var countryCode: String
/// }
///
/// extension Player: FetchableRecord, PersistableRecord {
/// enum Columns {
/// static let id = Column(CodingKeys.id)
/// static let name = Column(CodingKeys.name)
/// static let address = JSONColumn(CodingKeys.address) // JSONColumn
/// }
/// }
///
/// try dbQueue.write { db in
/// // In a real app, table creation should happen in a migration.
/// try db.create(table: "player") { t in
/// t.autoIncrementedPrimaryKey("id")
/// t.column("name", .text).notNull()
/// t.column("address", .jsonText).notNull()
/// }
///
/// // Fetch all country codes
/// // SELECT DISTINCT address ->> 'countryCode' FROM player
/// let countryCodes: [String] = try Player
/// .select({ $0.address["countryCode"] }, as: String.self)
/// .distinct()
/// .fetchAll(db)
/// }
/// ```
///
/// > Tip: When you can not create a `JSONColumn`, you'll get the same
/// > convenient access to JSON subcomponents
/// > with ``SQLSpecificExpressible/asJSON``.
/// >
/// > For example, the above sample can be adapted as below:
/// >
/// > ```swift
/// > extension Player: FetchableRecord, PersistableRecord {
/// > // That's another valid way to define columns.
/// > // But we don't have any JSONColumn this time.
/// > enum Columns {
/// > static let id = Column("id")
/// > static let name = Column("name")
/// > static let address = Column("address")
/// > }
/// > }
/// >
/// > try dbQueue.write { db in
/// > // Fetch all country codes
/// > // SELECT DISTINCT address ->> 'countryCode' FROM player
/// > let countryCodes: [String] = try Player
/// > .select({ $0.address.asJSON["countryCode"] }, as: String.self)
/// > .distinct()
/// > .fetchAll(db)
/// > }
/// > ```
public struct JSONColumn: ColumnExpression, SQLJSONExpressible, Sendable {
public var name: String
/// Creates a `JSONColumn` given its name.
///
/// The name should be unqualified, such as `"score"`. Qualified name such
/// as `"player.score"` are unsupported.
public init(_ name: String) {
self.name = name
}
/// Creates a `JSONColumn` given a `CodingKey`.
public init(_ codingKey: some CodingKey) {
self.name = codingKey.stringValue
}
}