Skip to content

Commit d3e277f

Browse files
committed
wip
1 parent 416dc7a commit d3e277f

File tree

2 files changed

+161
-18
lines changed

2 files changed

+161
-18
lines changed

Sources/StructuredQueriesCore/Statements/Select.swift

Lines changed: 147 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,16 +1143,17 @@ extension Select {
11431143
/// Creates a new select statement from this one by appending a predicate to its `WHERE` clause.
11441144
///
11451145
/// - Parameter predicate: A closure that produces a Boolean query expression from this select's
1146-
/// tables with a single join.
1146+
/// tables.
11471147
/// - Returns: A new select statement that appends the given predicate to its `WHERE` clause.
1148-
public func `where`(
1149-
_ predicate: (From.TableColumns, Joins.TableColumns) -> some QueryExpression<
1148+
@_disfavoredOverload
1149+
public func `where`<each J: Table>(
1150+
_ predicate: (From.TableColumns, repeat (each J).TableColumns) -> some QueryExpression<
11501151
some _OptionalPromotable<Bool?>
11511152
>
11521153
) -> Self
1153-
where Joins: Table {
1154+
where Joins == (repeat each J) {
11541155
var select = self
1155-
select.where.append(predicate(From.columns, Joins.columns).queryFragment)
1156+
select.where.append(predicate(From.columns, repeat (each J).columns).queryFragment)
11561157
return select
11571158
}
11581159

@@ -1161,13 +1162,13 @@ extension Select {
11611162
/// - Parameter predicate: A result builder closure that returns a Boolean expression to filter
11621163
/// by.
11631164
/// - Returns: A new select statement that appends the given predicate to its `WHERE` clause.
1164-
public func `where`(
1165+
public func `where`<each J: Table>(
11651166
@QueryFragmentBuilder<Bool>
1166-
_ predicate: (From.TableColumns, Joins.TableColumns) -> [QueryFragment]
1167+
_ predicate: (From.TableColumns, repeat (each J).TableColumns) -> [QueryFragment]
11671168
) -> Self
1168-
where Joins: Table {
1169+
where Joins == (repeat each J) {
11691170
var select = self
1170-
select.where.append(contentsOf: predicate(From.columns, Joins.columns))
1171+
select.where.append(contentsOf: predicate(From.columns, repeat (each J).columns))
11711172
return select
11721173
}
11731174

@@ -1177,14 +1178,14 @@ extension Select {
11771178
/// tables.
11781179
/// - Returns: A new select statement that appends the given predicate to its `WHERE` clause.
11791180
@_disfavoredOverload
1180-
public func `where`<each J: Table>(
1181-
_ predicate: (From.TableColumns, repeat (each J).TableColumns) -> some QueryExpression<
1181+
public func `where`(
1182+
_ predicate: (From.TableColumns, Joins.TableColumns) -> some QueryExpression<
11821183
some _OptionalPromotable<Bool?>
11831184
>
11841185
) -> Self
1185-
where Joins == (repeat each J) {
1186+
where Joins: Table {
11861187
var select = self
1187-
select.where.append(predicate(From.columns, repeat (each J).columns).queryFragment)
1188+
select.where.append(predicate(From.columns, Joins.columns).queryFragment)
11881189
return select
11891190
}
11901191

@@ -1193,13 +1194,13 @@ extension Select {
11931194
/// - Parameter predicate: A result builder closure that returns a Boolean expression to filter
11941195
/// by.
11951196
/// - Returns: A new select statement that appends the given predicate to its `WHERE` clause.
1196-
public func `where`<each J: Table>(
1197+
public func `where`(
11971198
@QueryFragmentBuilder<Bool>
1198-
_ predicate: (From.TableColumns, repeat (each J).TableColumns) -> [QueryFragment]
1199+
_ predicate: (From.TableColumns, Joins.TableColumns) -> [QueryFragment]
11991200
) -> Self
1200-
where Joins == (repeat each J) {
1201+
where Joins: Table {
12011202
var select = self
1202-
select.where.append(contentsOf: predicate(From.columns, repeat (each J).columns))
1203+
select.where.append(contentsOf: predicate(From.columns, Joins.columns))
12031204
return select
12041205
}
12051206

@@ -1252,6 +1253,32 @@ extension Select {
12521253
_group(by: grouping)
12531254
}
12541255

1256+
/// Creates a new select statement from this one by appending the given column to its `GROUP BY`
1257+
/// clause.
1258+
///
1259+
/// - Parameter grouping: A closure that returns a column to group by from this select's tables.
1260+
/// - Returns: A new select statement that groups by the given column.
1261+
public func group<C: QueryExpression>(
1262+
by grouping: (From.TableColumns, Joins.TableColumns) -> C
1263+
) -> Self where Joins: Table {
1264+
_group(by: grouping)
1265+
}
1266+
1267+
/// Creates a new select statement from this one by appending the given columns to its `GROUP BY`
1268+
/// clause.
1269+
///
1270+
/// - Parameter grouping: A closure that returns a column to group by from this select's tables.
1271+
/// - Returns: A new select statement that groups by the given column.
1272+
public func group<
1273+
C1: QueryExpression,
1274+
C2: QueryExpression,
1275+
each C3: QueryExpression
1276+
>(
1277+
by grouping: (From.TableColumns, Joins.TableColumns) -> (C1, C2, repeat each C3)
1278+
) -> Self where Joins: Table {
1279+
_group(by: grouping)
1280+
}
1281+
12551282
private func _group<
12561283
each C: QueryExpression,
12571284
each J: Table
@@ -1266,6 +1293,17 @@ extension Select {
12661293
return select
12671294
}
12681295

1296+
private func _group<each C: QueryExpression>(
1297+
by grouping: (From.TableColumns, Joins.TableColumns) -> (repeat each C)
1298+
) -> Self where Joins: Table {
1299+
var select = self
1300+
select.group
1301+
.append(
1302+
contentsOf: Array(repeat each grouping(From.columns, Joins.columns))
1303+
)
1304+
return select
1305+
}
1306+
12691307
/// Creates a new select statement from this one by appending a predicate to its `HAVING` clause.
12701308
///
12711309
/// - Parameter predicate: A closure that produces a Boolean query expression from this select's
@@ -1298,6 +1336,38 @@ extension Select {
12981336
return select
12991337
}
13001338

1339+
/// Creates a new select statement from this one by appending a predicate to its `HAVING` clause.
1340+
///
1341+
/// - Parameter predicate: A closure that produces a Boolean query expression from this select's
1342+
/// tables.
1343+
/// - Returns: A new select statement that appends the given predicate to its `HAVING` clause.
1344+
@_disfavoredOverload
1345+
public func having(
1346+
_ predicate: (From.TableColumns, Joins.TableColumns) -> some QueryExpression<
1347+
some _OptionalPromotable<Bool?>
1348+
>
1349+
) -> Self
1350+
where Joins: Table {
1351+
var select = self
1352+
select.having.append(predicate(From.columns, Joins.columns).queryFragment)
1353+
return select
1354+
}
1355+
1356+
/// Creates a new select statement from this one by appending a predicate to its `HAVING` clause.
1357+
///
1358+
/// - Parameter predicate: A result builder closure that returns a Boolean expression to filter
1359+
/// by.
1360+
/// - Returns: A new select statement that appends the given predicate to its `HAVING` clause.
1361+
public func having(
1362+
@QueryFragmentBuilder<Bool>
1363+
_ predicate: (From.TableColumns, Joins.TableColumns) -> [QueryFragment]
1364+
) -> Self
1365+
where Joins: Table {
1366+
var select = self
1367+
select.having.append(contentsOf: predicate(From.columns, Joins.columns))
1368+
return select
1369+
}
1370+
13011371
/// Creates a new select statement from this one by appending a column to its `ORDER BY` clause.
13021372
///
13031373
/// - Parameter ordering: A key path to a column to order by.
@@ -1322,6 +1392,20 @@ extension Select {
13221392
return select
13231393
}
13241394

1395+
/// Creates a new select statement from this one by appending columns to its `ORDER BY` clause.
1396+
///
1397+
/// - Parameter ordering: A result builder closure that returns columns to order by.
1398+
/// - Returns: A new select statement that appends the returned columns to its `ORDER BY` clause.
1399+
public func order(
1400+
@QueryFragmentBuilder<()>
1401+
by ordering: (From.TableColumns, Joins.TableColumns) -> [QueryFragment]
1402+
) -> Self
1403+
where Joins: Table {
1404+
var select = self
1405+
select.order.append(contentsOf: ordering(From.columns, Joins.columns))
1406+
return select
1407+
}
1408+
13251409
/// Creates a new select statement from this one by overriding its `LIMIT` and `OFFSET` clauses.
13261410
///
13271411
/// - Parameters:
@@ -1330,7 +1414,7 @@ extension Select {
13301414
/// - Returns: A new select statement that overrides this one's `LIMIT` and `OFFSET` clauses.
13311415
public func limit<each J: Table>(
13321416
_ maxLength: (From.TableColumns, repeat (each J).TableColumns) -> some QueryExpression<Int>,
1333-
offset: ((From.TableColumns, repeat (each J).TableColumns) -> some QueryExpression<Int>)? = nil
1417+
offset: ((From.TableColumns, repeat (each J).TableColumns) -> any QueryExpression<Int>)? = nil
13341418
) -> Self
13351419
where Joins == (repeat each J) {
13361420
var select = self
@@ -1341,6 +1425,25 @@ extension Select {
13411425
return select
13421426
}
13431427

1428+
/// Creates a new select statement from this one by overriding its `LIMIT` and `OFFSET` clauses.
1429+
///
1430+
/// - Parameters:
1431+
/// - maxLength: A closure that produces a `LIMIT` expression from this select's tables.
1432+
/// - offset: A closure that produces an `OFFSET` expression from this select's tables.
1433+
/// - Returns: A new select statement that overrides this one's `LIMIT` and `OFFSET` clauses.
1434+
public func limit(
1435+
_ maxLength: (From.TableColumns, Joins.TableColumns) -> some QueryExpression<Int>,
1436+
offset: ((From.TableColumns, Joins.TableColumns) -> any QueryExpression<Int>)? = nil
1437+
) -> Self
1438+
where Joins: Table {
1439+
var select = self
1440+
select.limit = _LimitClause(
1441+
maxLength: maxLength(From.columns, Joins.columns).queryFragment,
1442+
offset: offset?(From.columns, Joins.columns).queryFragment ?? select.limit?.offset
1443+
)
1444+
return select
1445+
}
1446+
13441447
/// Creates a new select statement from this one by overriding its `LIMIT` and `OFFSET` clauses.
13451448
///
13461449
/// - Parameters:
@@ -1383,6 +1486,32 @@ extension Select {
13831486
return select { _ in .count(filter: filter) }
13841487
}
13851488

1489+
/// Creates a new select statement from this one by appending `count(*)` to its selection.
1490+
///
1491+
/// - Parameter filter: A `FILTER` clause to apply to the aggregation.
1492+
/// - Returns: A new select statement that selects `count(*)`.
1493+
public func count(
1494+
filter: ((From.TableColumns, Joins.TableColumns) -> any QueryExpression<Bool>)? = nil
1495+
) -> Select<Int, From, Joins>
1496+
where Columns == (), Joins: Table {
1497+
let filter = filter?(From.columns, Joins.columns)
1498+
return select { _, _ in .count(filter: filter) }
1499+
}
1500+
1501+
/// Creates a new select statement from this one by appending `count(*)` to its selection.
1502+
///
1503+
/// - Parameter filter: A `FILTER` clause to apply to the aggregation.
1504+
/// - Returns: A new select statement that selects `count(*)`.
1505+
public func count<each C: QueryRepresentable>(
1506+
filter: ((From.TableColumns, Joins.TableColumns) -> any QueryExpression<Bool>)? = nil
1507+
) -> Select<
1508+
(repeat each C, Int), From, Joins
1509+
>
1510+
where Columns == (repeat each C), Joins: Table {
1511+
let filter = filter?(From.columns, Joins.columns)
1512+
return select { _, _ in .count(filter: filter) }
1513+
}
1514+
13861515
/// Creates a new select statement from this one by transforming its selected columns to a new
13871516
/// selection.
13881517
///

Tests/StructuredQueriesTests/SelectTests.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,20 @@ extension SnapshotTests {
14021402
}
14031403
}
14041404
}
1405+
1406+
@Test func singleJoinChaining() {
1407+
let base = Reminder.group(by: \.id).join(ReminderTag.all) { $0.id.eq($1.reminderID) }
1408+
_ = base.select { r, _ in r.isCompleted }
1409+
_ = base.where { r, _ in r.isCompleted }
1410+
_ = base.group { r, _ in r.isCompleted }
1411+
_ = base.having { r, _ in r.isCompleted }
1412+
_ = base.order { r, _ in r.isCompleted }
1413+
_ = base.limit { r, _ in r.title.length() }
1414+
_ = base.limit(1)
1415+
_ = base.count()
1416+
_ = base.count { r, _ in r.isCompleted }
1417+
_ = base.map {}
1418+
}
14051419
}
14061420
}
14071421

0 commit comments

Comments
 (0)