Skip to content

Commit 5382411

Browse files
authored
fix: add columns query param to insert and upsert methods (#205)
* feat: add NullEncodable property wrapper * fix: add columns query param to insert and upsert methods * fix tests by using a custom JSONEncoder for sorting keys
1 parent d8489a7 commit 5382411

File tree

4 files changed

+78
-16
lines changed

4 files changed

+78
-16
lines changed

Sources/PostgREST/PostgrestQueryBuilder.swift

+11-9
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,11 @@ public final class PostgrestQueryBuilder: PostgrestBuilder {
6969
if !prefersHeaders.isEmpty {
7070
$0.request.headers["Prefer"] = prefersHeaders.joined(separator: ",")
7171
}
72-
73-
// TODO: How to do this in Swift?
74-
// if (Array.isArray(values)) {
75-
// const columns = values.reduce((acc, x) => acc.concat(Object.keys(x)), [] as string[])
76-
// if (columns.length > 0) {
77-
// const uniqueColumns = [...new Set(columns)].map((column) => `"${column}"`)
78-
// this.url.searchParams.set('columns', uniqueColumns.join(','))
79-
// }
80-
// }
72+
if let body = $0.request.body, let jsonObject = try JSONSerialization.jsonObject(with: body) as? [[String: Any]] {
73+
let allKeys = jsonObject.flatMap(\.keys)
74+
let uniqueKeys = Set(allKeys).sorted()
75+
$0.request.query.append(URLQueryItem(name: "columns", value: uniqueKeys.joined(separator: ",")))
76+
}
8177
}
8278

8379
return PostgrestFilterBuilder(self)
@@ -118,6 +114,12 @@ public final class PostgrestQueryBuilder: PostgrestBuilder {
118114
if !prefersHeaders.isEmpty {
119115
$0.request.headers["Prefer"] = prefersHeaders.joined(separator: ",")
120116
}
117+
118+
if let body = $0.request.body, let jsonObject = try JSONSerialization.jsonObject(with: body) as? [[String: Any]] {
119+
let allKeys = jsonObject.flatMap(\.keys)
120+
let uniqueKeys = Set(allKeys).sorted()
121+
$0.request.query.append(URLQueryItem(name: "columns", value: uniqueKeys.joined(separator: ",")))
122+
}
121123
}
122124
return PostgrestFilterBuilder(self)
123125
}

Tests/PostgRESTTests/BuildURLRequestTests.swift

+52-7
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,43 @@ import XCTest
1010
import FoundationNetworking
1111
#endif
1212

13+
struct User: Encodable {
14+
var email: String
15+
var username: String?
16+
}
17+
1318
@MainActor
1419
final class BuildURLRequestTests: XCTestCase {
1520
let url = URL(string: "https://example.supabase.co")!
1621

1722
struct TestCase: Sendable {
1823
let name: String
19-
var record = false
24+
let record: Bool
25+
let file: StaticString
26+
let line: UInt
2027
let build: @Sendable (PostgrestClient) async throws -> PostgrestBuilder
28+
29+
init(
30+
name: String,
31+
record: Bool = false,
32+
file: StaticString = #file,
33+
line: UInt = #line,
34+
build: @escaping @Sendable (PostgrestClient) async throws -> PostgrestBuilder
35+
) {
36+
self.name = name
37+
self.record = record
38+
self.file = file
39+
self.line = line
40+
self.build = build
41+
}
2142
}
2243

2344
func testBuildRequest() async throws {
2445
let runningTestCase = ActorIsolated(TestCase?.none)
2546

47+
let encoder = PostgrestClient.Configuration.jsonEncoder
48+
encoder.outputFormatting = .sortedKeys
49+
2650
let client = PostgrestClient(
2751
url: url,
2852
schema: nil,
@@ -39,12 +63,15 @@ final class BuildURLRequestTests: XCTestCase {
3963
as: .curl,
4064
named: runningTestCase.name,
4165
record: runningTestCase.record,
42-
testName: "testBuildRequest()"
66+
file: runningTestCase.file,
67+
testName: "testBuildRequest()",
68+
line: runningTestCase.line
4369
)
4470
}
4571

4672
return (Data(), URLResponse())
47-
}
73+
},
74+
encoder: encoder
4875
)
4976

5077
let testCases: [TestCase] = [
@@ -55,7 +82,16 @@ final class BuildURLRequestTests: XCTestCase {
5582
},
5683
TestCase(name: "insert new user") { client in
5784
try await client.from("users")
58-
.insert(["email": "[email protected]"])
85+
.insert(User(email: "[email protected]"))
86+
},
87+
TestCase(name: "bulk insert users") { client in
88+
try await client.from("users")
89+
.insert(
90+
[
91+
User(email: "[email protected]"),
92+
User(email: "[email protected]", username: "johndoe2"),
93+
]
94+
)
5995
},
6096
TestCase(name: "call rpc") { client in
6197
try await client.rpc("test_fcn", params: ["KEY": "VALUE"])
@@ -89,11 +125,20 @@ final class BuildURLRequestTests: XCTestCase {
89125
},
90126
TestCase(name: "test upsert not ignoring duplicates") { client in
91127
try await client.from("users")
92-
.upsert(["email": "[email protected]"])
128+
.upsert(User(email: "[email protected]"))
129+
},
130+
TestCase(name: "bulk upsert") { client in
131+
try await client.from("users")
132+
.upsert(
133+
[
134+
User(email: "[email protected]"),
135+
User(email: "[email protected]", username: "johndoe2"),
136+
]
137+
)
93138
},
94139
TestCase(name: "test upsert ignoring duplicates") { client in
95140
try await client.from("users")
96-
.upsert(["email": "[email protected]"], ignoreDuplicates: true)
141+
.upsert(User(email: "[email protected]"), ignoreDuplicates: true)
97142
},
98143
TestCase(name: "query with + character") { client in
99144
await client.from("users")
@@ -110,7 +155,7 @@ final class BuildURLRequestTests: XCTestCase {
110155
await client.schema("storage")
111156
.from("objects")
112157
.select()
113-
}
158+
},
114159
]
115160

116161
for testCase in testCases {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
curl \
2+
--request POST \
3+
--header "Accept: application/json" \
4+
--header "Content-Type: application/json" \
5+
--header "X-Client-Info: postgrest-swift/x.y.z" \
6+
--data "[{\"email\":\"[email protected]\"},{\"email\":\"[email protected]\",\"username\":\"johndoe2\"}]" \
7+
"https://example.supabase.co/users?columns=email,username"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
curl \
2+
--request POST \
3+
--header "Accept: application/json" \
4+
--header "Content-Type: application/json" \
5+
--header "Prefer: resolution=merge-duplicates,return=representation" \
6+
--header "X-Client-Info: postgrest-swift/x.y.z" \
7+
--data "[{\"email\":\"[email protected]\"},{\"email\":\"[email protected]\",\"username\":\"johndoe2\"}]" \
8+
"https://example.supabase.co/users?columns=email,username"

0 commit comments

Comments
 (0)