Skip to content

Commit 376ee57

Browse files
committed
fixes
1 parent 3e15094 commit 376ee57

File tree

7 files changed

+318
-24
lines changed

7 files changed

+318
-24
lines changed

Sources/StructuredQueriesCore/ColumnGroup.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public struct ColumnGroup<Root: Table, Values: Table>: QueryExpression {
5151
}
5252

5353
public subscript<Member>(
54-
dynamicMember keyPath: KeyPath<Values.TableColumns, TableColumn<Values, Member>> & Sendable
54+
dynamicMember keyPath: KeyPath<Values.TableColumns, TableColumn<Values, Member>>
5555
) -> TableColumn<Root, Member> {
5656
let column = Values.columns[keyPath: keyPath]
5757
return TableColumn<Root, Member>(
@@ -60,4 +60,24 @@ public struct ColumnGroup<Root: Table, Values: Table>: QueryExpression {
6060
default: column.defaultValue
6161
)
6262
}
63+
64+
public subscript<Member>(
65+
dynamicMember keyPath: KeyPath<Values.TableColumns, GeneratedColumn<Values, Member>>
66+
) -> GeneratedColumn<Root, Member> {
67+
let column = Values.columns[keyPath: keyPath]
68+
return GeneratedColumn<Root, Member>(
69+
column.name,
70+
keyPath: self.keyPath.appending(path: column.keyPath),
71+
default: column.defaultValue
72+
)
73+
}
74+
75+
public subscript<Member>(
76+
dynamicMember keyPath: KeyPath<Values.TableColumns, ColumnGroup<Values, Member>>
77+
) -> ColumnGroup<Root, Member> {
78+
let column = Values.columns[keyPath: keyPath]
79+
return ColumnGroup<Root, Member>(
80+
keyPath: self.keyPath.appending(path: column.keyPath)
81+
)
82+
}
6383
}

Sources/StructuredQueriesCore/Optional.swift

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,39 @@ extension Optional: Table, PartialSelectStatement, Statement where Wrapped: Tabl
9595
public typealias QueryValue = Optional
9696

9797
public static var allColumns: [any TableColumnExpression] {
98-
Wrapped.TableColumns.allColumns
98+
func open<Root, Value>(
99+
_ column: some TableColumnExpression<Root, Value>
100+
) -> any TableColumnExpression {
101+
guard let column = column as? TableColumn<Wrapped, Value>
102+
else {
103+
let column = column as! GeneratedColumn<Wrapped, Value>
104+
return GeneratedColumn<Optional, Value?>(
105+
column.name,
106+
keyPath: \.[member: \Value.self, column: column.keyPath],
107+
default: column.defaultValue
108+
)
109+
}
110+
return TableColumn<Optional, Value?>(
111+
column.name,
112+
keyPath: \.[member: \Value.self, column: column.keyPath],
113+
default: column.defaultValue
114+
)
115+
}
116+
return Wrapped.TableColumns.allColumns.map { open($0) }
99117
}
100118

101119
public static var writableColumns: [any WritableTableColumnExpression] {
102-
Wrapped.TableColumns.writableColumns
120+
func open<Root, Value>(
121+
_ column: some WritableTableColumnExpression<Root, Value>
122+
) -> any WritableTableColumnExpression {
123+
let column = column as! TableColumn<Wrapped, Value>
124+
return TableColumn<Optional, Value?>(
125+
column.name,
126+
keyPath: \.[member: \Value.self, column: column.keyPath],
127+
default: column.defaultValue
128+
)
129+
}
130+
return Wrapped.TableColumns.writableColumns.map { open($0) }
103131
}
104132

105133
public subscript<Member>(
@@ -108,7 +136,7 @@ extension Optional: Table, PartialSelectStatement, Statement where Wrapped: Tabl
108136
let column = Wrapped.columns[keyPath: keyPath]
109137
return TableColumn<Optional, Member?>(
110138
column.name,
111-
keyPath: \.[member: \Member.self, column: column._keyPath]
139+
keyPath: \.[member: \Member.self, column: column.keyPath]
112140
)
113141
}
114142

Sources/StructuredQueriesCore/TableAlias.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public struct TableAlias<
145145
let column = Base.columns[keyPath: keyPath]
146146
return TableColumn<TableAlias, Member>(
147147
column.name,
148-
keyPath: \.[member: \Member.self, column: column._keyPath]
148+
keyPath: \.[member: \Member.self, column: column.keyPath]
149149
)
150150
}
151151

@@ -155,7 +155,7 @@ public struct TableAlias<
155155
let column = Base.columns[keyPath: keyPath]
156156
return GeneratedColumn<TableAlias, Member>(
157157
column.name,
158-
keyPath: \.[member: \Member.self, column: column._keyPath]
158+
keyPath: \.[member: \Member.self, column: column.keyPath]
159159
)
160160
}
161161
}

Sources/StructuredQueriesCore/TableColumn.swift

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// A type representing a table column.
22
///
3-
/// This protocol has a single conformance, ``TableColumn``, and simply provides type erasure over
4-
/// a table's columns. You should not conform to this protocol directly.
3+
/// This protocol has two concrete conformances, ``TableColumn`` and ``GeneratedColumn``, and
4+
/// provides type erasure over a table's columns. You should not conform to this protocol directly.
55
public protocol TableColumnExpression<Root, Value>: QueryExpression where Value == QueryValue {
66
associatedtype Root: Table
77
associatedtype Value: QueryRepresentable & QueryBindable
@@ -48,11 +48,7 @@ public struct TableColumn<Root: Table, Value: QueryRepresentable & QueryBindable
4848

4949
public let defaultValue: Value.QueryOutput?
5050

51-
let _keyPath: KeyPath<Root, Value.QueryOutput>
52-
53-
public var keyPath: KeyPath<Root, Value.QueryOutput> {
54-
_keyPath
55-
}
51+
public let keyPath: KeyPath<Root, Value.QueryOutput>
5652

5753
public init(
5854
_ name: String,
@@ -61,7 +57,7 @@ public struct TableColumn<Root: Table, Value: QueryRepresentable & QueryBindable
6157
) {
6258
self.name = name
6359
self.defaultValue = defaultValue
64-
self._keyPath = keyPath
60+
self.keyPath = keyPath
6561
}
6662

6763
public init(
@@ -71,7 +67,7 @@ public struct TableColumn<Root: Table, Value: QueryRepresentable & QueryBindable
7167
) where Value == Value.QueryOutput {
7268
self.name = name
7369
self.defaultValue = defaultValue
74-
self._keyPath = keyPath
70+
self.keyPath = keyPath
7571
}
7672

7773
public func decode(_ decoder: inout some QueryDecoder) throws -> Value.QueryOutput {
@@ -87,7 +83,7 @@ public struct TableColumn<Root: Table, Value: QueryRepresentable & QueryBindable
8783
) -> any WritableTableColumnExpression<TableAlias<Root, Name>, Value> {
8884
TableColumn<TableAlias<Root, Name>, Value>(
8985
name,
90-
keyPath: \.[member: \Value.self, column: _keyPath]
86+
keyPath: \.[member: \Value.self, column: keyPath]
9187
)
9288
}
9389
}
@@ -117,11 +113,7 @@ public struct GeneratedColumn<Root: Table, Value: QueryRepresentable & QueryBind
117113

118114
public let defaultValue: Value.QueryOutput?
119115

120-
let _keyPath: KeyPath<Root, Value.QueryOutput>
121-
122-
public var keyPath: KeyPath<Root, Value.QueryOutput> {
123-
_keyPath
124-
}
116+
public let keyPath: KeyPath<Root, Value.QueryOutput>
125117

126118
public init(
127119
_ name: String,
@@ -130,7 +122,7 @@ public struct GeneratedColumn<Root: Table, Value: QueryRepresentable & QueryBind
130122
) {
131123
self.name = name
132124
self.defaultValue = defaultValue
133-
self._keyPath = keyPath
125+
self.keyPath = keyPath
134126
}
135127

136128
public init(
@@ -140,7 +132,7 @@ public struct GeneratedColumn<Root: Table, Value: QueryRepresentable & QueryBind
140132
) where Value == Value.QueryOutput {
141133
self.name = name
142134
self.defaultValue = defaultValue
143-
self._keyPath = keyPath
135+
self.keyPath = keyPath
144136
}
145137

146138
public func decode(_ decoder: inout some QueryDecoder) throws -> Value.QueryOutput {
@@ -156,7 +148,7 @@ public struct GeneratedColumn<Root: Table, Value: QueryRepresentable & QueryBind
156148
) -> any TableColumnExpression<TableAlias<Root, Name>, Value> {
157149
TableColumn<TableAlias<Root, Name>, Value>(
158150
name,
159-
keyPath: \.[member: \Value.self, column: _keyPath]
151+
keyPath: \.[member: \Value.self, column: keyPath]
160152
)
161153
}
162154
}

Sources/StructuredQueriesMacros/TableMacro.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ extension TableMacro: ExtensionMacro {
284284
)
285285
"""
286286
)
287+
allColumns.append(identifier)
287288
} else if isGenerated {
288289
columnsProperties.append(
289290
"""
@@ -300,6 +301,7 @@ extension TableMacro: ExtensionMacro {
300301
}
301302
"""
302303
)
304+
allColumns.append(identifier)
303305
} else {
304306
columnsProperties.append(
305307
"""
@@ -934,6 +936,7 @@ extension TableMacro: MemberMacro {
934936
draftProperties.append(
935937
DeclSyntax(
936938
property.trimmed
939+
.with(\.attributes.trailingTrivia, .space)
937940
.with(\.bindingSpecifier.leadingTrivia, "")
938941
.removingAccessors()
939942
.rewritten(selfRewriter)

Tests/StructuredQueriesMacrosTests/TableMacroTests.swift

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2728,5 +2728,140 @@ extension SnapshotTests {
27282728
"""#
27292729
}
27302730
}
2731+
2732+
@Test func nested() {
2733+
assertMacro {
2734+
"""
2735+
@Table
2736+
private struct Row {
2737+
let id: UUID
2738+
@Columns
2739+
var timestamps: Timestamps
2740+
}
2741+
"""
2742+
} expansion: {
2743+
#"""
2744+
private struct Row {
2745+
let id: UUID
2746+
@Columns
2747+
var timestamps: Timestamps
2748+
2749+
public nonisolated struct TableColumns: StructuredQueriesCore.TableDefinition, StructuredQueriesCore.PrimaryKeyedTableDefinition {
2750+
public typealias QueryValue = Row
2751+
public let id = StructuredQueriesCore.TableColumn<QueryValue, UUID>("id", keyPath: \QueryValue.id)
2752+
public let timestamps = StructuredQueriesCore.ColumnGroup<QueryValue, Timestamps>(keyPath: \QueryValue.timestamps)
2753+
public var primaryKey: StructuredQueriesCore.TableColumn<QueryValue, UUID> {
2754+
self.id
2755+
}
2756+
public static var allColumns: [any StructuredQueriesCore.TableColumnExpression] {
2757+
[[QueryValue.columns.id], StructuredQueriesCore.ColumnGroup.allColumns(keyPath: \QueryValue.timestamps)].flatMap(\.self)
2758+
}
2759+
public static var writableColumns: [any StructuredQueriesCore.WritableTableColumnExpression] {
2760+
[[QueryValue.columns.id], StructuredQueriesCore.ColumnGroup.writableColumns(keyPath: \QueryValue.timestamps)].flatMap(\.self)
2761+
}
2762+
public var queryFragment: QueryFragment {
2763+
"\(self.id), \(self.timestamps)"
2764+
}
2765+
}
2766+
2767+
public struct Selection: StructuredQueriesCore.TableExpression {
2768+
public typealias QueryValue = Row
2769+
public let allColumns: [any StructuredQueriesCore.QueryExpression]
2770+
public init(
2771+
id: some StructuredQueriesCore.QueryExpression<UUID>,
2772+
timestamps: some StructuredQueriesCore.QueryExpression<Timestamps>
2773+
) {
2774+
self.allColumns = [id, timestamps]
2775+
}
2776+
}
2777+
2778+
public struct Draft: StructuredQueriesCore.TableDraft {
2779+
public typealias PrimaryTable = Row
2780+
let id: UUID?
2781+
@Columns var timestamps: Timestamps
2782+
public nonisolated struct TableColumns: StructuredQueriesCore.TableDefinition {
2783+
public typealias QueryValue = Draft
2784+
public let id = StructuredQueriesCore.TableColumn<QueryValue, UUID?>("id", keyPath: \QueryValue.id)
2785+
public let timestamps = StructuredQueriesCore.ColumnGroup<QueryValue, Timestamps>(keyPath: \QueryValue.timestamps)
2786+
public static var allColumns: [any StructuredQueriesCore.TableColumnExpression] {
2787+
[[QueryValue.columns.id], StructuredQueriesCore.ColumnGroup.allColumns(keyPath: \QueryValue.timestamps)].flatMap(\.self)
2788+
}
2789+
public static var writableColumns: [any StructuredQueriesCore.WritableTableColumnExpression] {
2790+
[[QueryValue.columns.id], StructuredQueriesCore.ColumnGroup.writableColumns(keyPath: \QueryValue.timestamps)].flatMap(\.self)
2791+
}
2792+
public var queryFragment: QueryFragment {
2793+
"\(self.id), \(self.timestamps)"
2794+
}
2795+
}
2796+
public struct Selection: StructuredQueriesCore.TableExpression {
2797+
public typealias QueryValue = Draft
2798+
public let allColumns: [any StructuredQueriesCore.QueryExpression]
2799+
public init(
2800+
id: some StructuredQueriesCore.QueryExpression<UUID?>,
2801+
timestamps: some StructuredQueriesCore.QueryExpression<Timestamps>
2802+
) {
2803+
self.allColumns = [id, timestamps]
2804+
}
2805+
}
2806+
public typealias QueryValue = Self
2807+
2808+
public typealias From = Swift.Never
2809+
2810+
public nonisolated static var columns: TableColumns {
2811+
TableColumns()
2812+
}
2813+
2814+
public nonisolated static var tableName: String {
2815+
Row.tableName
2816+
}
2817+
2818+
public nonisolated init(decoder: inout some StructuredQueriesCore.QueryDecoder) throws {
2819+
self.id = try decoder.decode(UUID.self)
2820+
let timestamps = try decoder.decode(Timestamps.self)
2821+
guard let timestamps else {
2822+
throw QueryDecodingError.missingRequiredColumn
2823+
}
2824+
self.timestamps = timestamps
2825+
}
2826+
2827+
public nonisolated init(_ other: Row) {
2828+
self.id = other.id
2829+
self.timestamps = other.timestamps
2830+
}
2831+
public init(
2832+
id: UUID? = nil,
2833+
timestamps: Timestamps
2834+
) {
2835+
self.id = id
2836+
self.timestamps = timestamps
2837+
}
2838+
}
2839+
}
2840+
2841+
nonisolated extension Row: StructuredQueriesCore.Table, StructuredQueriesCore.PrimaryKeyedTable, StructuredQueriesCore.PartialSelectStatement {
2842+
public typealias QueryValue = Self
2843+
public typealias From = Swift.Never
2844+
public nonisolated static var columns: TableColumns {
2845+
TableColumns()
2846+
}
2847+
public nonisolated static var tableName: String {
2848+
"rows"
2849+
}
2850+
public nonisolated init(decoder: inout some StructuredQueriesCore.QueryDecoder) throws {
2851+
let id = try decoder.decode(UUID.self)
2852+
let timestamps = try decoder.decode(Timestamps.self)
2853+
guard let id else {
2854+
throw QueryDecodingError.missingRequiredColumn
2855+
}
2856+
guard let timestamps else {
2857+
throw QueryDecodingError.missingRequiredColumn
2858+
}
2859+
self.id = id
2860+
self.timestamps = timestamps
2861+
}
2862+
}
2863+
"""#
2864+
}
2865+
}
27312866
}
27322867
}

0 commit comments

Comments
 (0)