Skip to content

Commit 46d1a64

Browse files
authored
Allow generic upsert conflict resolutions (#197)
* Clean up all the docs warnings, update CI * Enable specifying an INSERT's conflict resolution strategy as a generic SQLExpression * Make SQLConflictUpdateBuilder's initializer public so it can be reused.
1 parent c0ea243 commit 46d1a64

File tree

14 files changed

+217
-103
lines changed

14 files changed

+217
-103
lines changed

.github/.codecov.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,3 @@ ignore:
3434
- ^Tests/.*
3535
- ^.build/.*
3636
slack_app: false
37-

.github/dependabot.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@ updates:
88
dependencies:
99
patterns:
1010
- "*"
11+
- package-ecosystem: "swift"
12+
directory: "/"
13+
schedule:
14+
interval: "daily"
15+
groups:
16+
dependencies:
17+
patterns:
18+
- "*"

.github/workflows/test.yml

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@ concurrency:
55
on:
66
pull_request: { types: [opened, reopened, synchronize, ready_for_review] }
77
push: { branches: [ main ] }
8-
env:
9-
LOG_LEVEL: info
10-
permissions:
11-
contents: read
128

139
jobs:
1410
unit-tests:
11+
permissions:
12+
contents: read
1513
uses: vapor/ci/.github/workflows/run-unit-tests.yml@main
1614
secrets: inherit
1715
with:
@@ -20,6 +18,8 @@ jobs:
2018

2119
pure-fluent-integration-test:
2220
if: ${{ !(github.event.pull_request.draft || false) }}
21+
permissions:
22+
contents: read
2323
runs-on: ubuntu-latest
2424
container: swift:6.2-noble
2525
steps:
@@ -36,19 +36,21 @@ jobs:
3636
3737
integration-tests:
3838
if: ${{ !(github.event.pull_request.draft || false) }}
39+
permissions:
40+
contents: read
3941
services:
4042
mysql-a:
4143
image: mysql:latest
42-
env: { MYSQL_USER: test_username, MYSQL_PASSWORD: test_password, MYSQL_DATABASE: test_database, MYSQL_ALLOW_EMPTY_PASSWORD: true }
44+
env: &common_mysql_env { MYSQL_USER: test_username, MYSQL_PASSWORD: test_password, MYSQL_DATABASE: test_database, MYSQL_ALLOW_EMPTY_PASSWORD: true }
4345
mysql-b:
4446
image: mysql:latest
45-
env: { MYSQL_USER: test_username, MYSQL_PASSWORD: test_password, MYSQL_DATABASE: test_database, MYSQL_ALLOW_EMPTY_PASSWORD: true }
47+
env: *common_mysql_env
4648
psql-a:
4749
image: postgres:latest
48-
env: { POSTGRES_USER: test_username, POSTGRES_PASSWORD: test_password, POSTGRES_DB: test_database }
50+
env: &common_psql_env { POSTGRES_USER: test_username, POSTGRES_PASSWORD: test_password, POSTGRES_DB: test_database }
4951
psql-b:
5052
image: postgres:latest
51-
env: { POSTGRES_USER: test_username, POSTGRES_PASSWORD: test_password, POSTGRES_DB: test_database }
53+
env: *common_psql_env
5254
strategy:
5355
fail-fast: false
5456
matrix:
@@ -90,3 +92,10 @@ jobs:
9092
run: |
9193
swift package --package-path "${FLUENT_DRIVER}" edit --path sql-kit sql-kit
9294
swift test --package-path "${FLUENT_DRIVER}" --sanitize=thread
95+
96+
submit-dependencies:
97+
permissions:
98+
contents: write
99+
if: ${{ github.event_name == 'push' }}
100+
uses: vapor/ci/.github/workflows/submit-deps.yml@main
101+
secrets: inherit

Sources/SQLKit/Builders/Implementations/SQLConflictUpdateBuilder.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ public final class SQLConflictUpdateBuilder: SQLColumnUpdateBuilder, SQLPredicat
88
public var predicate: (any SQLExpression)? = nil
99

1010
/// Create a conflict update builder.
11-
@usableFromInline
12-
init() {}
11+
@inlinable
12+
public init() {}
1313

1414
/// Add an assignment of the column with the given name, using the value the column was
1515
/// given in the `INSERT` query's `VALUES` list.

Sources/SQLKit/Builders/Prototypes/SQLCommonTableExpressionBuilder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ extension SQLCommonTableExpressionBuilder {
284284
/// This is the common "funnel" method invoked by all other methods provided by
285285
/// ``SQLCommonTableExpressionBuilder``. Most users will not need to call this method directly.
286286
///
287-
/// See ``with(_:columns:as:)-28k4r`` and ``with(recursive:columns:as:)-6yef`` for usage examples.
287+
/// See ``SQLCommonTableExpressionBuilder/with(_:columns:as:)-28k4r`` and ``SQLCommonTableExpressionBuilder/with(recursive:columns:as:)-6yef`` for usage examples.
288288
///
289289
/// > Warning: As with ``SQLCommonTableExpression``, ``SQLCommonTableExpressionBuilder`` does _NOT_ validate
290290
/// > that a recursive CTE's query takes the proper form, nor that a non-recursive CTE's query is not

Sources/SQLKit/Builders/Prototypes/SQLCommonUnionBuilder.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,55 +77,55 @@ extension SQLCommonUnionBuilder {
7777
return self
7878
}
7979

80-
/// Call ``union(distinct:)-15xs8`` with a query generated by a builder.
80+
/// Call ``SQLCommonUnionBuilder/union(distinct:)-15xs8`` with a query generated by a builder.
8181
@inlinable
8282
public func union(distinct predicate: (any SQLSubqueryClauseBuilder) throws -> any SQLSubqueryClauseBuilder) rethrows -> Self {
8383
try self.union(distinct: predicate(SQLSubqueryBuilder()).select)
8484
}
8585

86-
/// Call ``union(all:)-56f28`` with a query generated by a builder.
86+
/// Call ``SQLCommonUnionBuilder/union(all:)-56f28`` with a query generated by a builder.
8787
@inlinable
8888
public func union(all predicate: (any SQLSubqueryClauseBuilder) throws -> any SQLSubqueryClauseBuilder) rethrows -> Self {
8989
try self.union(all: predicate(SQLSubqueryBuilder()).select)
9090
}
9191

92-
/// Alias ``union(distinct:)-921p6`` so it acts as the "default".
92+
/// Alias ``SQLCommonUnionBuilder/union(distinct:)-921p6`` so it acts as the "default".
9393
@inlinable
9494
public func union(_ predicate: (any SQLSubqueryClauseBuilder) throws -> any SQLSubqueryClauseBuilder) rethrows -> Self {
9595
try self.union(distinct: predicate)
9696
}
9797

98-
/// Call ``intersect(distinct:)-161s9`` with a query generated by a builder.
98+
/// Call ``SQLCommonUnionBuilder/intersect(distinct:)-161s9`` with a query generated by a builder.
9999
@inlinable
100100
public func intersect(distinct predicate: (any SQLSubqueryClauseBuilder) throws -> any SQLSubqueryClauseBuilder) rethrows -> Self {
101101
try self.intersect(distinct: predicate(SQLSubqueryBuilder()).select)
102102
}
103103

104-
/// Call ``intersect(all:)-1wiow`` with a query generated by a builder.
104+
/// Call ``SQLCommonUnionBuilder/intersect(all:)-1wiow`` with a query generated by a builder.
105105
@inlinable
106106
public func intersect(all predicate: (any SQLSubqueryClauseBuilder) throws -> any SQLSubqueryClauseBuilder) rethrows -> Self {
107107
try self.intersect(all: predicate(SQLSubqueryBuilder()).select)
108108
}
109109

110-
/// Alias ``intersect(distinct:)-8f71m`` so it acts as the "default".
110+
/// Alias ``SQLCommonUnionBuilder/intersect(distinct:)-8f71m`` so it acts as the "default".
111111
@inlinable
112112
public func intersect(_ predicate: (any SQLSubqueryClauseBuilder) throws -> any SQLSubqueryClauseBuilder) rethrows -> Self {
113113
try self.intersect(distinct: predicate)
114114
}
115115

116-
/// Call ``except(distinct:)-2ygq0`` with a query generated by a builder.
116+
/// Call ``SQLCommonUnionBuilder/except(distinct:)-2ygq0`` with a query generated by a builder.
117117
@inlinable
118118
public func except(distinct predicate: (any SQLSubqueryClauseBuilder) throws -> any SQLSubqueryClauseBuilder) rethrows -> Self {
119119
try self.except(distinct: predicate(SQLSubqueryBuilder()).select)
120120
}
121121

122-
/// Call ``except(all:)-5exbl`` with a query generated by a builder.
122+
/// Call ``SQLCommonUnionBuilder/except(all:)-5exbl`` with a query generated by a builder.
123123
@inlinable
124124
public func except(all predicate: (any SQLSubqueryClauseBuilder) throws -> any SQLSubqueryClauseBuilder) rethrows -> Self {
125125
try self.except(all: predicate(SQLSubqueryBuilder()).select)
126126
}
127127

128-
/// Alias ``except(distinct:)-62w7q`` so it acts as the "default".
128+
/// Alias ``SQLCommonUnionBuilder/except(distinct:)-62w7q`` so it acts as the "default".
129129
@inlinable
130130
public func except(_ predicate: (any SQLSubqueryClauseBuilder) throws -> any SQLSubqueryClauseBuilder) rethrows -> Self {
131131
try self.except(distinct: predicate)

Sources/SQLKit/Docs.docc/BasicUsage.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ WHERE "name" <> NULL AND ("name" = ?1 OR "name" = ?2) -- bindings: ["Milky Way",
206206

207207
### Insert
208208

209-
The ``SQLDatabase/insert(into:)-67oqt`` and ``SQLDatabase/insert(into:)-5n3gh`` methods create an `INSERT` query builder:
209+
The ``SQLDatabase/insert(into:)-(String)`` and ``SQLDatabase/insert(into:)-(SQLExpression)`` methods create an `INSERT` query builder:
210210

211211
```swift
212212
try await db.insert(into: "galaxies")
@@ -236,7 +236,7 @@ This code generates the same SQL as would `builder.columns("name").values("Milky
236236

237237
### Update
238238

239-
The ``SQLDatabase/update(_:)-2tf1c`` and ``SQLDatabase/update(_:)-80964`` methods create an `UPDATE` query builder:
239+
The ``SQLDatabase/update(_:)-(String)`` and ``SQLDatabase/update(_:)-(SQLExpression)`` methods create an `UPDATE` query builder:
240240

241241
```swift
242242
try await db.update("planets")
@@ -255,7 +255,7 @@ The update builder supports the same `where()` and `orWhere()` methods as the se
255255

256256
### Delete
257257

258-
The ``SQLDatabase/delete(from:)-3tx4f`` and ``SQLDatabase/delete(from:)-4bqlu`` methods create a `DELETE` query builder:
258+
The ``SQLDatabase/delete(from:)-(String)`` and ``SQLDatabase/delete(from:)-(SQLExpression)`` methods create a `DELETE` query builder:
259259

260260
```swift
261261
try await db.delete(from: "planets")

Sources/SQLKit/Docs.docc/Resources/vapor-sqlkit-logo.svg

Lines changed: 39 additions & 14 deletions
Loading

Sources/SQLKit/Docs.docc/SQLDatabase+ExtensionDocs.md

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,41 @@
1717

1818
### DML queries
1919

20-
- ``SQLDatabase/delete(from:)-3tx4f``
21-
- ``SQLDatabase/delete(from:)-4bqlu``
22-
- ``SQLDatabase/insert(into:)-67oqt``
23-
- ``SQLDatabase/insert(into:)-5n3gh``
20+
- ``SQLDatabase/delete(from:)-(String)``
21+
- ``SQLDatabase/delete(from:)-(SQLExpression)``
22+
- ``SQLDatabase/insert(into:)-(String)``
23+
- ``SQLDatabase/insert(into:)-(SQLExpression)``
2424
- ``SQLDatabase/select()``
2525
- ``SQLDatabase/union(_:)``
26-
- ``SQLDatabase/update(_:)-2tf1c``
27-
- ``SQLDatabase/update(_:)-80964``
26+
- ``SQLDatabase/update(_:)-(String)``
27+
- ``SQLDatabase/update(_:)-(SQLExpression)``
2828

2929
### DDL queries
3030

31-
- ``SQLDatabase/alter(table:)-42uao``
32-
- ``SQLDatabase/alter(table:)-68pbr``
33-
- ``SQLDatabase/create(table:)-czz4``
34-
- ``SQLDatabase/create(table:)-2wdmn``
35-
- ``SQLDatabase/drop(table:)-938qt``
36-
- ``SQLDatabase/drop(table:)-7k2ai``
37-
38-
- ``SQLDatabase/alter(enum:)-66oin``
39-
- ``SQLDatabase/alter(enum:)-7nb5b``
40-
- ``SQLDatabase/create(enum:)-81hl4``
41-
- ``SQLDatabase/create(enum:)-70oeh``
42-
- ``SQLDatabase/drop(enum:)-5leu1``
43-
- ``SQLDatabase/drop(enum:)-3jgv``
44-
45-
- ``SQLDatabase/create(index:)-7yh28``
46-
- ``SQLDatabase/create(index:)-1iuey``
47-
- ``SQLDatabase/drop(index:)-62i2j``
48-
- ``SQLDatabase/drop(index:)-19tfk``
49-
50-
- ``SQLDatabase/create(trigger:table:when:event:)-6ntdo``
51-
- ``SQLDatabase/create(trigger:table:when:event:)-9upcb``
52-
- ``SQLDatabase/drop(trigger:)-53mq6``
53-
- ``SQLDatabase/drop(trigger:)-5sfa8``
31+
- ``SQLDatabase/alter(table:)-(String)``
32+
- ``SQLDatabase/alter(table:)-(SQLIdentifier)``
33+
- ``SQLDatabase/alter(table:)-(SQLExpression)``
34+
- ``SQLDatabase/create(table:)-(String)``
35+
- ``SQLDatabase/create(table:)-(SQLExpression)``
36+
- ``SQLDatabase/drop(table:)-(String)``
37+
- ``SQLDatabase/drop(table:)-(SQLExpression)``
38+
39+
- ``SQLDatabase/alter(enum:)-(String)``
40+
- ``SQLDatabase/alter(enum:)-(SQLExpression)``
41+
- ``SQLDatabase/create(enum:)-(String)``
42+
- ``SQLDatabase/create(enum:)-(SQLExpression)``
43+
- ``SQLDatabase/drop(enum:)-(String)``
44+
- ``SQLDatabase/drop(enum:)-(SQLExpression)``
45+
46+
- ``SQLDatabase/create(index:)-(String)``
47+
- ``SQLDatabase/create(index:)-(SQLExpression)``
48+
- ``SQLDatabase/drop(index:)-(String)``
49+
- ``SQLDatabase/drop(index:)-(SQLExpression)``
50+
51+
- ``SQLDatabase/create(trigger:table:when:event:)-(String,_,_,_)``
52+
- ``SQLDatabase/create(trigger:table:when:event:)-(SQLExpression,_,_,_)``
53+
- ``SQLDatabase/drop(trigger:)-(String)``
54+
- ``SQLDatabase/drop(trigger:)-(SQLExpression)``
5455

5556
### Raw queries
5657

@@ -63,4 +64,4 @@
6364

6465
### Legacy query interface
6566

66-
- ``SQLDatabase/execute(sql:_:)-90wi9``
67+
- ``SQLDatabase/execute(sql:_:)->_``

Sources/SQLKit/Docs.docc/SQLQueryFetcher+ExtensionDocs.md

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,40 @@
44

55
### Getting Rows
66

7-
- ``SQLQueryFetcher/run(_:)-40swz``
8-
- ``SQLQueryFetcher/run(decoding:_:)-476q1``
9-
- ``SQLQueryFetcher/run(decoding:prefix:keyDecodingStrategy:userInfo:_:)-583ot``
10-
- ``SQLQueryFetcher/run(decoding:with:_:)-8y7ux``
7+
- ``SQLQueryFetcher/run(_:)->()``
8+
- ``SQLQueryFetcher/run(decoding:_:)->()``
9+
- ``SQLQueryFetcher/run(decoding:prefix:keyDecodingStrategy:userInfo:_:)->()``
10+
- ``SQLQueryFetcher/run(decoding:with:_:)->()``
1111

1212
### Getting All Rows
1313

14-
- ``SQLQueryFetcher/all()-8yci1``
15-
- ``SQLQueryFetcher/all(decoding:)-5dt2x``
16-
- ``SQLQueryFetcher/all(decoding:prefix:keyDecodingStrategy:userInfo:)-5u1nz``
17-
- ``SQLQueryFetcher/all(decoding:with:)-6n5ox``
18-
- ``SQLQueryFetcher/all(decodingColumn:as:)-7x9bs``
14+
- ``SQLQueryFetcher/all(decoding:with:)->[D]``
15+
- ``SQLQueryFetcher/all(decoding:)->[D]``
16+
- ``SQLQueryFetcher/all(decoding:prefix:keyDecodingStrategy:userInfo:)->[D]``
17+
- ``SQLQueryFetcher/all(decoding:with:)->[D]``
18+
- ``SQLQueryFetcher/all(decodingColumn:as:)->[D]``
1919

2020
### Getting One Row
2121

22-
- ``SQLQueryFetcher/first()-99pqx``
23-
- ``SQLQueryFetcher/first(decoding:)-63noi``
24-
- ``SQLQueryFetcher/first(decoding:prefix:keyDecodingStrategy:userInfo:)-2str1``
25-
- ``SQLQueryFetcher/first(decoding:with:)-58l9p``
26-
- ``SQLQueryFetcher/first(decodingColumn:as:)-1bcz6``
22+
- ``SQLQueryFetcher/first()->EventLoopFuture<(SQLRow)?>``
23+
- ``SQLQueryFetcher/first(decoding:)->D?``
24+
- ``SQLQueryFetcher/first(decoding:prefix:keyDecodingStrategy:userInfo:)->D?``
25+
- ``SQLQueryFetcher/first(decoding:with:)->D?``
26+
- ``SQLQueryFetcher/first(decodingColumn:as:)->D?``
2727

2828
### Legacy `EventLoopFuture` Interfaces
2929

30-
- ``SQLQueryFetcher/run(_:)-542bs``
31-
- ``SQLQueryFetcher/run(decoding:_:)-6z89k``
32-
- ``SQLQueryFetcher/run(decoding:prefix:keyDecodingStrategy:userInfo:_:)-2cp56``
33-
- ``SQLQueryFetcher/run(decoding:with:_:)-4tte7``
34-
- ``SQLQueryFetcher/all()-5j67e``
35-
- ``SQLQueryFetcher/all(decoding:)-6q02f``
36-
- ``SQLQueryFetcher/all(decoding:prefix:keyDecodingStrategy:userInfo:)-91za9``
37-
- ``SQLQueryFetcher/all(decoding:with:)-5fc4b``
38-
- ``SQLQueryFetcher/all(decodingColumn:as:)-197ym``
39-
- ``SQLQueryFetcher/first()-7o93q``
40-
- ``SQLQueryFetcher/first(decoding:)-6gqh3``
41-
- ``SQLQueryFetcher/first(decoding:prefix:keyDecodingStrategy:userInfo:)-4hfrz``
42-
- ``SQLQueryFetcher/first(decoding:with:)-1n97m``
43-
- ``SQLQueryFetcher/first(decodingColumn:as:)-4965m``
30+
- ``SQLQueryFetcher/run(_:)->_``
31+
- ``SQLQueryFetcher/run(decoding:_:)->_``
32+
- ``SQLQueryFetcher/run(decoding:prefix:keyDecodingStrategy:userInfo:_:)->_``
33+
- ``SQLQueryFetcher/run(decoding:with:_:)->_``
34+
- ``SQLQueryFetcher/all()->EventLoopFuture<[SQLRow]>``
35+
- ``SQLQueryFetcher/all(decoding:)->EventLoopFuture<[D]>``
36+
- ``SQLQueryFetcher/all(decoding:prefix:keyDecodingStrategy:userInfo:)->EventLoopFuture<[D]>``
37+
- ``SQLQueryFetcher/all(decoding:with:)->EventLoopFuture<[D]>``
38+
- ``SQLQueryFetcher/all(decodingColumn:as:)->EventLoopFuture<[D]>``
39+
- ``SQLQueryFetcher/first()->EventLoopFuture<(SQLRow)?>``
40+
- ``SQLQueryFetcher/first(decoding:)->EventLoopFuture<D?>``
41+
- ``SQLQueryFetcher/first(decoding:prefix:keyDecodingStrategy:userInfo:)->EventLoopFuture<D?>``
42+
- ``SQLQueryFetcher/first(decoding:with:)->EventLoopFuture<D?>``
43+
- ``SQLQueryFetcher/first(decodingColumn:as:)->EventLoopFuture<D?>``

0 commit comments

Comments
 (0)