Skip to content

Commit 0723ede

Browse files
committed
wip
1 parent fa8b00d commit 0723ede

File tree

14 files changed

+237
-46
lines changed

14 files changed

+237
-46
lines changed

Sources/StructuredQueries/Macros.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public macro Column(
5252
@attached(peer)
5353
public macro Columns(
5454
// as representableType: (any QueryRepresentable.Type)? = nil,
55-
// primaryKey: Bool = false
55+
primaryKey: Bool = false
5656
) =
5757
#externalMacro(
5858
module: "StructuredQueriesMacros",

Sources/StructuredQueriesCore/ColumnGroup.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
@dynamicMemberLookup
2-
public struct ColumnGroup<Root: Table, Values: Table>: QueryExpression {
2+
public struct ColumnGroup<Root: Table, Values: Table>: _TableColumnExpression
3+
where Values.QueryOutput == Values {
4+
public typealias Value = Values
5+
6+
public var name: String { Values.tableName }
7+
38
public typealias QueryValue = Values
49

510
public static func allColumns(keyPath: KeyPath<Root, Values>) -> [any TableColumnExpression] {
@@ -40,7 +45,7 @@ public struct ColumnGroup<Root: Table, Values: Table>: QueryExpression {
4045
}
4146
}
4247

43-
let keyPath: KeyPath<Root, Values>
48+
public let keyPath: KeyPath<Root, Values>
4449

4550
public init(keyPath: KeyPath<Root, Values>) {
4651
self.keyPath = keyPath

Sources/StructuredQueriesCore/Internal/Deprecations.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,10 @@ extension PrimaryKeyedTable {
110110
) -> InsertOf<Self> {
111111
insert(values: { rows }, onConflictDoUpdate: updates)
112112
}
113+
}
113114

115+
// TODO: Support composite keys.
116+
extension PrimaryKeyedTable where TableColumns.PrimaryKeyColumn == TableColumn<Self, PrimaryKey> {
114117
@available(
115118
*, deprecated, message: "Use a trailing closure, instead: 'Table.upsert { draft }'"
116119
)

Sources/StructuredQueriesCore/Optional.swift

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,35 @@ extension Optional: Table, PartialSelectStatement, Statement where Wrapped: Tabl
157157
public typealias Selection = Wrapped.Selection?
158158
}
159159

160-
extension Optional: PrimaryKeyedTable where Wrapped: PrimaryKeyedTable {
160+
// TODO: Support composite keys.
161+
extension Optional: PrimaryKeyedTable
162+
where
163+
Wrapped: PrimaryKeyedTable,
164+
Wrapped.TableColumns.PrimaryKeyColumn == TableColumn<Wrapped, Wrapped.PrimaryKey>
165+
{
161166
public typealias Draft = Wrapped.Draft?
162167
}
163168

164-
extension Optional: TableDraft where Wrapped: TableDraft {
169+
// TODO: Support composite keys.
170+
extension Optional: TableDraft
171+
where
172+
Wrapped: TableDraft,
173+
Wrapped.PrimaryTable.TableColumns.PrimaryKeyColumn == TableColumn<
174+
Wrapped.PrimaryTable, Wrapped.PrimaryTable.PrimaryKey
175+
>
176+
{
165177
public typealias PrimaryTable = Wrapped.PrimaryTable?
166178
public init(_ primaryTable: Wrapped.PrimaryTable?) {
167179
self = primaryTable.map(Wrapped.init)
168180
}
169181
}
170182

183+
// TODO: Support composite keys.
171184
extension Optional.TableColumns: PrimaryKeyedTableDefinition
172-
where Wrapped.TableColumns: PrimaryKeyedTableDefinition {
185+
where
186+
Wrapped.TableColumns: PrimaryKeyedTableDefinition,
187+
Wrapped.TableColumns.PrimaryKeyColumn == TableColumn<Wrapped, Wrapped.PrimaryKey>
188+
{
173189
public typealias PrimaryKey = Wrapped.TableColumns.PrimaryKey?
174190

175191
public var primaryKey: TableColumn<Optional, Wrapped.TableColumns.PrimaryKey.QueryValue?> {

Sources/StructuredQueriesCore/PrimaryKeyed.swift

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ where TableColumns: PrimaryKeyedTableDefinition<PrimaryKey> {
44
/// A type representing this table's primary key.
55
///
66
/// For auto-incrementing tables, this is typically `Int`.
7-
associatedtype PrimaryKey: QueryBindable where PrimaryKey.QueryValue == PrimaryKey
7+
associatedtype PrimaryKey: QueryRepresentable & QueryExpression
8+
where PrimaryKey.QueryValue == PrimaryKey
89

910
/// A type that represents this type, but with an optional primary key.
1011
///
@@ -48,10 +49,13 @@ where QueryValue: PrimaryKeyedTable {
4849
/// A type representing this table's primary key.
4950
///
5051
/// For auto-incrementing tables, this is typically `Int`.
51-
associatedtype PrimaryKey: QueryBindable where PrimaryKey.QueryValue == PrimaryKey
52+
associatedtype PrimaryKey: QueryRepresentable & QueryExpression
53+
where PrimaryKey.QueryValue == PrimaryKey
54+
55+
associatedtype PrimaryKeyColumn: _TableColumnExpression<QueryValue, PrimaryKey>
5256

5357
/// The column representing this table's primary key.
54-
var primaryKey: TableColumn<QueryValue, PrimaryKey> { get }
58+
var primaryKey: PrimaryKeyColumn { get }
5559
}
5660

5761
extension TableDefinition where QueryValue: TableDraft {
@@ -62,7 +66,7 @@ extension TableDefinition where QueryValue: TableDraft {
6266
}
6367
}
6468

65-
extension PrimaryKeyedTableDefinition {
69+
extension PrimaryKeyedTableDefinition where PrimaryKeyColumn: TableColumnExpression {
6670
/// A query expression representing the number of rows in this table.
6771
///
6872
/// - Parameters:
@@ -78,15 +82,16 @@ extension PrimaryKeyedTableDefinition {
7882
}
7983
}
8084

81-
extension PrimaryKeyedTable {
85+
// TODO: Support composite keys.
86+
extension PrimaryKeyedTable where PrimaryKey: QueryBindable {
8287
/// A where clause filtered by a primary key.
8388
///
8489
/// - Parameter primaryKey: A primary key identifying a table row.
8590
/// - Returns: A `WHERE` clause.
8691
public static func find(
8792
_ primaryKey: some QueryExpression<TableColumns.PrimaryKey>
8893
) -> Where<Self> {
89-
Self.find([primaryKey])
94+
find([primaryKey])
9095
}
9196

9297
/// A where clause filtered by primary keys.
@@ -104,7 +109,8 @@ extension PrimaryKeyedTable {
104109
}
105110
}
106111

107-
extension TableDraft {
112+
// TODO: Support composite keys.
113+
extension TableDraft where PrimaryTable.PrimaryKey: QueryBindable {
108114
/// A where clause filtered by a primary key.
109115
///
110116
/// - Parameter primaryKey: A primary key identifying a table row.
@@ -126,7 +132,8 @@ extension TableDraft {
126132
}
127133
}
128134

129-
extension Where where From: PrimaryKeyedTable {
135+
// TODO: Support composite keys.
136+
extension Where where From: PrimaryKeyedTable, From.PrimaryKey: QueryBindable {
130137
/// Adds a primary key condition to a where clause.
131138
///
132139
/// - Parameter primaryKey: A primary key.
@@ -146,7 +153,8 @@ extension Where where From: PrimaryKeyedTable {
146153
}
147154
}
148155

149-
extension Where where From: TableDraft {
156+
// TODO: Support composite keys.
157+
extension Where where From: TableDraft, From.PrimaryTable.PrimaryKey: QueryBindable {
150158
/// Adds a primary key condition to a where clause.
151159
///
152160
/// - Parameter primaryKey: A primary key.
@@ -168,7 +176,8 @@ extension Where where From: TableDraft {
168176
}
169177
}
170178

171-
extension Select where From: PrimaryKeyedTable {
179+
// TODO: Support composite keys.
180+
extension Select where From: PrimaryKeyedTable, From.PrimaryKey: QueryBindable {
172181
/// A select statement filtered by a primary key.
173182
///
174183
/// - Parameter primaryKey: A primary key identifying a table row.
@@ -188,7 +197,8 @@ extension Select where From: PrimaryKeyedTable {
188197
}
189198
}
190199

191-
extension Select where From: TableDraft {
200+
// TODO: Support composite keys.
201+
extension Select where From: TableDraft, From.PrimaryTable.PrimaryKey: QueryBindable {
192202
/// A select statement filtered by a primary key.
193203
///
194204
/// - Parameter primaryKey: A primary key identifying a table row.
@@ -210,7 +220,8 @@ extension Select where From: TableDraft {
210220
}
211221
}
212222

213-
extension Update where From: PrimaryKeyedTable {
223+
// TODO: Support composite keys.
224+
extension Update where From: PrimaryKeyedTable, From.PrimaryKey: QueryBindable {
214225
/// An update statement filtered by a primary key.
215226
///
216227
/// - Parameter primaryKey: A primary key identifying a table row.
@@ -230,7 +241,8 @@ extension Update where From: PrimaryKeyedTable {
230241
}
231242
}
232243

233-
extension Update where From: TableDraft {
244+
// TODO: Support composite keys.
245+
extension Update where From: TableDraft, From.PrimaryTable.PrimaryKey: QueryBindable {
234246
/// An update statement filtered by a primary key.
235247
///
236248
/// - Parameter primaryKey: A primary key identifying a table row.
@@ -252,7 +264,8 @@ extension Update where From: TableDraft {
252264
}
253265
}
254266

255-
extension Delete where From: PrimaryKeyedTable {
267+
// TODO: Support composite keys.
268+
extension Delete where From: PrimaryKeyedTable, From.PrimaryKey: QueryBindable {
256269
/// A delete statement filtered by a primary key.
257270
///
258271
/// - Parameter primaryKey: A primary key identifying a table row.
@@ -272,7 +285,8 @@ extension Delete where From: PrimaryKeyedTable {
272285
}
273286
}
274287

275-
extension Delete where From: TableDraft {
288+
// TODO: Support composite keys.
289+
extension Delete where From: TableDraft, From.PrimaryTable.PrimaryKey: QueryBindable {
276290
/// A delete statement filtered by a primary key.
277291
///
278292
/// - Parameter primaryKey: A primary key identifying a table row.

Sources/StructuredQueriesCore/Statements/Insert.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,8 @@ extension Table {
616616
}
617617
}
618618

619-
extension PrimaryKeyedTable {
619+
// TODO: Support composite keys.
620+
extension PrimaryKeyedTable where TableColumns.PrimaryKeyColumn == TableColumn<Self, PrimaryKey> {
620621
/// An upsert statement for given drafts.
621622
///
622623
/// Generates an insert statement with an upsert clause. Useful for building forms that can both

Sources/StructuredQueriesCore/TableAlias.swift

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,19 +175,35 @@ public struct TableAlias<
175175
}
176176
}
177177

178-
extension TableAlias: PrimaryKeyedTable where Base: PrimaryKeyedTable {
178+
// TODO: Support composite keys.
179+
extension TableAlias: PrimaryKeyedTable
180+
where
181+
Base: PrimaryKeyedTable,
182+
Base.TableColumns.PrimaryKeyColumn == TableColumn<Base, Base.PrimaryKey>
183+
{
179184
public typealias Draft = TableAlias<Base.Draft, Name>
180185
}
181186

182-
extension TableAlias: TableDraft where Base: TableDraft {
187+
// TODO: Support composite keys.
188+
extension TableAlias: TableDraft
189+
where
190+
Base: TableDraft,
191+
Base.PrimaryTable.TableColumns.PrimaryKeyColumn == TableColumn<
192+
Base.PrimaryTable, Base.PrimaryTable.PrimaryKey
193+
>
194+
{
183195
public typealias PrimaryTable = TableAlias<Base.PrimaryTable, Name>
184196
public init(_ primaryTable: TableAlias<Base.PrimaryTable, Name>) {
185197
self.init(base: Base(primaryTable.base))
186198
}
187199
}
188200

201+
// TODO: Support composite keys.
189202
extension TableAlias.TableColumns: PrimaryKeyedTableDefinition
190-
where Base.TableColumns: PrimaryKeyedTableDefinition {
203+
where
204+
Base.TableColumns: PrimaryKeyedTableDefinition,
205+
Base.TableColumns.PrimaryKeyColumn == TableColumn<Base, Base.PrimaryKey>
206+
{
191207
public typealias PrimaryKey = Base.TableColumns.PrimaryKey
192208

193209
public var primaryKey: TableColumn<TableAlias, Base.TableColumns.PrimaryKey.QueryValue> {
@@ -261,7 +277,8 @@ extension TableAlias: Encodable where Base: Encodable {
261277

262278
extension QueryFragment {
263279
fileprivate func replacingOccurrences<T: Table, A: AliasName>(
264-
of _: T.Type, with _: A.Type
280+
of _: T.Type,
281+
with _: A.Type
265282
) -> QueryFragment {
266283
var query = self
267284
for index in query.segments.indices {

Sources/StructuredQueriesCore/TableColumn.swift

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
1+
public protocol _TableColumnExpression<Root, Value>: QueryExpression where Value == QueryValue {
2+
associatedtype Root: Table
3+
associatedtype Value: QueryRepresentable
4+
5+
/// The name of the table column.
6+
var name: String { get }
7+
8+
/// The table model key path associated with this table column.
9+
var keyPath: KeyPath<Root, Value.QueryOutput> { get }
10+
}
11+
112
/// A type representing a table column.
213
///
314
/// This protocol has two concrete conformances, ``TableColumn`` and ``GeneratedColumn``, and
415
/// provides type erasure over a table's columns. You should not conform to this protocol directly.
5-
public protocol TableColumnExpression<Root, Value>: QueryExpression where Value == QueryValue {
6-
associatedtype Root: Table
7-
associatedtype Value: QueryRepresentable & QueryBindable
8-
16+
public protocol TableColumnExpression<Root, Value>: _TableColumnExpression
17+
where Value: QueryBindable {
918
/// The name of the table column.
1019
var name: String { get }
1120

1221
/// The default value of the table column.
1322
var defaultValue: Value.QueryOutput? { get }
1423

15-
/// The table model key path associated with this table column.
16-
var keyPath: KeyPath<Root, Value.QueryOutput> { get }
17-
1824
func _aliased<Name: AliasName>(
1925
_ alias: Name.Type
2026
) -> any TableColumnExpression<TableAlias<Root, Name>, Value>

Sources/StructuredQueriesCore/Updates.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,33 @@ public struct Updates<Base: Table> {
5353
)
5454
}
5555
}
56+
57+
public subscript<Value: QueryExpression>(
58+
dynamicMember keyPath: KeyPath<Base.TableColumns, ColumnGroup<Base, Value>>
59+
) -> Updates<Value> {
60+
get { Updates<Value> { _ in } }
61+
set { updates.append(contentsOf: newValue.updates) }
62+
}
63+
64+
@_disfavoredOverload
65+
public subscript<Value: QueryExpression>(
66+
dynamicMember keyPath: KeyPath<Base.TableColumns, ColumnGroup<Base, Value>>
67+
) -> Value.QueryOutput {
68+
@available(*, unavailable)
69+
get { fatalError() }
70+
set {
71+
func open<Root, V>(
72+
_ column: some WritableTableColumnExpression<Root, V>
73+
) -> QueryFragment {
74+
Value(queryOutput: newValue)[keyPath: column.keyPath as! KeyPath<Value, V>].queryFragment
75+
}
76+
updates.append(
77+
contentsOf: Value.TableColumns.writableColumns.map { column in
78+
(column.name, open(column))
79+
}
80+
)
81+
}
82+
}
5683
}
5784

5885
extension Updates: QueryExpression {

0 commit comments

Comments
 (0)