Skip to content

Commit 388c255

Browse files
Handle single Join & Where on query helpers (#121)
* Handle single Join & Where on query helpers * wip --------- Co-authored-by: Stephen Celis <[email protected]>
1 parent a2a7c06 commit 388c255

File tree

2 files changed

+175
-1
lines changed

2 files changed

+175
-1
lines changed

Sources/StructuredQueriesCore/Statements/Select.swift

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,38 @@ extension Select {
11721172
return select
11731173
}
11741174

1175+
/// Creates a new select statement from this one by appending a predicate to its `WHERE` clause.
1176+
///
1177+
/// - Parameter predicate: A closure that produces a Boolean query expression from this select's
1178+
/// tables.
1179+
/// - Returns: A new select statement that appends the given predicate to its `WHERE` clause.
1180+
@_disfavoredOverload
1181+
public func `where`(
1182+
_ predicate: (From.TableColumns, Joins.TableColumns) -> some QueryExpression<
1183+
some _OptionalPromotable<Bool?>
1184+
>
1185+
) -> Self
1186+
where Joins: Table {
1187+
var select = self
1188+
select.where.append(predicate(From.columns, Joins.columns).queryFragment)
1189+
return select
1190+
}
1191+
1192+
/// Creates a new select statement from this one by appending a predicate to its `WHERE` clause.
1193+
///
1194+
/// - Parameter predicate: A result builder closure that returns a Boolean expression to filter
1195+
/// by.
1196+
/// - Returns: A new select statement that appends the given predicate to its `WHERE` clause.
1197+
public func `where`(
1198+
@QueryFragmentBuilder<Bool>
1199+
_ predicate: (From.TableColumns, Joins.TableColumns) -> [QueryFragment]
1200+
) -> Self
1201+
where Joins: Table {
1202+
var select = self
1203+
select.where.append(contentsOf: predicate(From.columns, Joins.columns))
1204+
return select
1205+
}
1206+
11751207
public func and(_ other: Where<From>) -> Self {
11761208
var select = self
11771209
select.where = (select.where + other.predicates).removingDuplicates()
@@ -1221,6 +1253,32 @@ extension Select {
12211253
_group(by: grouping)
12221254
}
12231255

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+
12241282
private func _group<
12251283
each C: QueryExpression,
12261284
each J: Table
@@ -1235,6 +1293,17 @@ extension Select {
12351293
return select
12361294
}
12371295

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+
12381307
/// Creates a new select statement from this one by appending a predicate to its `HAVING` clause.
12391308
///
12401309
/// - Parameter predicate: A closure that produces a Boolean query expression from this select's
@@ -1267,6 +1336,38 @@ extension Select {
12671336
return select
12681337
}
12691338

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+
12701371
/// Creates a new select statement from this one by appending a column to its `ORDER BY` clause.
12711372
///
12721373
/// - Parameter ordering: A key path to a column to order by.
@@ -1291,6 +1392,20 @@ extension Select {
12911392
return select
12921393
}
12931394

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+
12941409
/// Creates a new select statement from this one by overriding its `LIMIT` and `OFFSET` clauses.
12951410
///
12961411
/// - Parameters:
@@ -1299,7 +1414,7 @@ extension Select {
12991414
/// - Returns: A new select statement that overrides this one's `LIMIT` and `OFFSET` clauses.
13001415
public func limit<each J: Table>(
13011416
_ maxLength: (From.TableColumns, repeat (each J).TableColumns) -> some QueryExpression<Int>,
1302-
offset: ((From.TableColumns, repeat (each J).TableColumns) -> some QueryExpression<Int>)? = nil
1417+
offset: ((From.TableColumns, repeat (each J).TableColumns) -> any QueryExpression<Int>)? = nil
13031418
) -> Self
13041419
where Joins == (repeat each J) {
13051420
var select = self
@@ -1310,6 +1425,25 @@ extension Select {
13101425
return select
13111426
}
13121427

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+
13131447
/// Creates a new select statement from this one by overriding its `LIMIT` and `OFFSET` clauses.
13141448
///
13151449
/// - Parameters:
@@ -1352,6 +1486,32 @@ extension Select {
13521486
return select { _ in .count(filter: filter) }
13531487
}
13541488

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+
13551515
/// Creates a new select statement from this one by transforming its selected columns to a new
13561516
/// selection.
13571517
///

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)