Skip to content

Commit ee06810

Browse files
authored
test(postgrest): increase code coverage (#651)
* test(postgrest): increase code coverage * move deprecated code to Deprecated.swift file
1 parent c2cc6f9 commit ee06810

13 files changed

+2014
-125
lines changed

.swiftpm/xcode/xcshareddata/xcschemes/PostgREST.xcscheme

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
33
LastUpgradeVersion = "1510"
4-
version = "1.7">
4+
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"
77
buildImplicitDependencies = "YES">
@@ -26,8 +26,29 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29-
shouldUseLaunchSchemeArgsEnv = "YES">
29+
shouldUseLaunchSchemeArgsEnv = "YES"
30+
codeCoverageEnabled = "YES"
31+
onlyGenerateCoverageForSpecifiedTargets = "YES">
32+
<CodeCoverageTargets>
33+
<BuildableReference
34+
BuildableIdentifier = "primary"
35+
BlueprintIdentifier = "PostgREST"
36+
BuildableName = "PostgREST"
37+
BlueprintName = "PostgREST"
38+
ReferencedContainer = "container:">
39+
</BuildableReference>
40+
</CodeCoverageTargets>
3041
<Testables>
42+
<TestableReference
43+
skipped = "NO">
44+
<BuildableReference
45+
BuildableIdentifier = "primary"
46+
BlueprintIdentifier = "PostgRESTTests"
47+
BuildableName = "PostgRESTTests"
48+
BlueprintName = "PostgRESTTests"
49+
ReferencedContainer = "container:">
50+
</BuildableReference>
51+
</TestableReference>
3152
</Testables>
3253
</TestAction>
3354
<LaunchAction

Sources/PostgREST/Deprecated.swift

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ extension PostgrestClient.Configuration {
2323
@available(
2424
*,
2525
deprecated,
26-
message: "Replace usages of this initializer with new init(url:schema:headers:logger:fetch:encoder:decoder:)"
26+
message:
27+
"Replace usages of this initializer with new init(url:schema:headers:logger:fetch:encoder:decoder:)"
2728
)
2829
public init(
2930
url: URL,
@@ -57,7 +58,8 @@ extension PostgrestClient {
5758
@available(
5859
*,
5960
deprecated,
60-
message: "Replace usages of this initializer with new init(url:schema:headers:logger:fetch:encoder:decoder:)"
61+
message:
62+
"Replace usages of this initializer with new init(url:schema:headers:logger:fetch:encoder:decoder:)"
6163
)
6264
public convenience init(
6365
url: URL,
@@ -78,3 +80,57 @@ extension PostgrestClient {
7880
)
7981
}
8082
}
83+
84+
extension PostgrestFilterBuilder {
85+
86+
@available(*, deprecated, renamed: "like(_:pattern:)")
87+
public func like(
88+
_ column: String,
89+
value: any URLQueryRepresentable
90+
) -> PostgrestFilterBuilder {
91+
like(column, pattern: value)
92+
}
93+
94+
@available(*, deprecated, renamed: "in(_:values:)")
95+
public func `in`(
96+
_ column: String,
97+
value: [any URLQueryRepresentable]
98+
) -> PostgrestFilterBuilder {
99+
`in`(column, values: value)
100+
}
101+
102+
@available(*, deprecated, message: "Use textSearch(_:query:config:type) with .plain type.")
103+
public func plfts(
104+
_ column: String,
105+
query: any URLQueryRepresentable,
106+
config: String? = nil
107+
) -> PostgrestFilterBuilder {
108+
textSearch(column, query: query, config: config, type: .plain)
109+
}
110+
111+
@available(*, deprecated, message: "Use textSearch(_:query:config:type) with .phrase type.")
112+
public func phfts(
113+
_ column: String,
114+
query: any URLQueryRepresentable,
115+
config: String? = nil
116+
) -> PostgrestFilterBuilder {
117+
textSearch(column, query: query, config: config, type: .phrase)
118+
}
119+
120+
@available(*, deprecated, message: "Use textSearch(_:query:config:type) with .websearch type.")
121+
public func wfts(
122+
_ column: String,
123+
query: any URLQueryRepresentable,
124+
config: String? = nil
125+
) -> PostgrestFilterBuilder {
126+
textSearch(column, query: query, config: config, type: .websearch)
127+
}
128+
129+
@available(*, deprecated, renamed: "ilike(_:pattern:)")
130+
public func ilike(
131+
_ column: String,
132+
value: any URLQueryRepresentable
133+
) -> PostgrestFilterBuilder {
134+
ilike(column, pattern: value)
135+
}
136+
}

Sources/PostgREST/PostgrestBuilder.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,7 @@ public class PostgrestBuilder: @unchecked Sendable {
106106
}
107107

108108
if let count = $0.fetchOptions.count {
109-
if let prefer = $0.request.headers[.prefer] {
110-
$0.request.headers[.prefer] = "\(prefer),count=\(count.rawValue)"
111-
} else {
112-
$0.request.headers[.prefer] = "count=\(count.rawValue)"
113-
}
109+
$0.request.headers.appendOrUpdate(.prefer, value: "count=\(count.rawValue)")
114110
}
115111

116112
if $0.request.headers[.accept] == nil {

Sources/PostgREST/PostgrestFilterBuilder.swift

Lines changed: 16 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Helpers
44
public class PostgrestFilterBuilder: PostgrestTransformBuilder, @unchecked Sendable {
55
public enum Operator: String, CaseIterable, Sendable {
66
case eq, neq, gt, gte, lt, lte, like, ilike, `is`, `in`, cs, cd, sl, sr, nxl, nxr, adj, ov, fts,
7-
plfts, phfts, wfts
7+
plfts, phfts, wfts
88
}
99

1010
// MARK: - Filters
@@ -17,10 +17,11 @@ public class PostgrestFilterBuilder: PostgrestTransformBuilder, @unchecked Senda
1717
let queryValue = value.queryValue
1818

1919
mutableState.withValue {
20-
$0.request.query.append(URLQueryItem(
21-
name: column,
22-
value: "not.\(op.rawValue).\(queryValue)"
23-
))
20+
$0.request.query.append(
21+
URLQueryItem(
22+
name: column,
23+
value: "not.\(op.rawValue).\(queryValue)"
24+
))
2425
}
2526

2627
return self
@@ -152,14 +153,6 @@ public class PostgrestFilterBuilder: PostgrestTransformBuilder, @unchecked Senda
152153
return self
153154
}
154155

155-
@available(*, deprecated, renamed: "like(_:pattern:)")
156-
public func like(
157-
_ column: String,
158-
value: any URLQueryRepresentable
159-
) -> PostgrestFilterBuilder {
160-
like(column, pattern: value)
161-
}
162-
163156
/// Match only rows where `column` matches all of `patterns` case-sensitively.
164157
/// - Parameters:
165158
/// - column: The column to filter on
@@ -206,14 +199,6 @@ public class PostgrestFilterBuilder: PostgrestTransformBuilder, @unchecked Senda
206199
return self
207200
}
208201

209-
@available(*, deprecated, renamed: "ilike(_:pattern:)")
210-
public func ilike(
211-
_ column: String,
212-
value: any URLQueryRepresentable
213-
) -> PostgrestFilterBuilder {
214-
ilike(column, pattern: value)
215-
}
216-
217202
/// Match only rows where `column` matches all of `patterns` case-insensitively.
218203
/// - Parameters:
219204
/// - column: The column to filter on
@@ -284,14 +269,6 @@ public class PostgrestFilterBuilder: PostgrestTransformBuilder, @unchecked Senda
284269
return self
285270
}
286271

287-
@available(*, deprecated, renamed: "in(_:values:)")
288-
public func `in`(
289-
_ column: String,
290-
value: [any URLQueryRepresentable]
291-
) -> PostgrestFilterBuilder {
292-
`in`(column, values: value)
293-
}
294-
295272
/// Match only rows where `column` contains every element appearing in `value`.
296273
///
297274
/// Only relevant for jsonb, array, and range columns.
@@ -472,33 +449,6 @@ public class PostgrestFilterBuilder: PostgrestTransformBuilder, @unchecked Senda
472449
textSearch(column, query: query, config: config, type: nil)
473450
}
474451

475-
@available(*, deprecated, message: "Use textSearch(_:query:config:type) with .plain type.")
476-
public func plfts(
477-
_ column: String,
478-
query: any URLQueryRepresentable,
479-
config: String? = nil
480-
) -> PostgrestFilterBuilder {
481-
textSearch(column, query: query, config: config, type: .plain)
482-
}
483-
484-
@available(*, deprecated, message: "Use textSearch(_:query:config:type) with .phrase type.")
485-
public func phfts(
486-
_ column: String,
487-
query: any URLQueryRepresentable,
488-
config: String? = nil
489-
) -> PostgrestFilterBuilder {
490-
textSearch(column, query: query, config: config, type: .phrase)
491-
}
492-
493-
@available(*, deprecated, message: "Use textSearch(_:query:config:type) with .websearch type.")
494-
public func wfts(
495-
_ column: String,
496-
query: any URLQueryRepresentable,
497-
config: String? = nil
498-
) -> PostgrestFilterBuilder {
499-
textSearch(column, query: query, config: config, type: .websearch)
500-
}
501-
502452
/// Match only rows which satisfy the filter. This is an escape hatch - you should use the specific filter methods wherever possible.
503453
///
504454
/// Unlike most filters, `opearator` and `value` are used as-is and need to follow [PostgREST syntax](https://postgrest.org/en/stable/api.html#operators). You also need to make sure they are properly sanitized.
@@ -513,10 +463,11 @@ public class PostgrestFilterBuilder: PostgrestTransformBuilder, @unchecked Senda
513463
value: String
514464
) -> PostgrestFilterBuilder {
515465
mutableState.withValue {
516-
$0.request.query.append(URLQueryItem(
517-
name: column,
518-
value: "\(`operator`).\(value)"
519-
))
466+
$0.request.query.append(
467+
URLQueryItem(
468+
name: column,
469+
value: "\(`operator`).\(value)"
470+
))
520471
}
521472
return self
522473
}
@@ -530,10 +481,11 @@ public class PostgrestFilterBuilder: PostgrestTransformBuilder, @unchecked Senda
530481
let query = query.mapValues(\.queryValue)
531482
mutableState.withValue { mutableState in
532483
for (key, value) in query {
533-
mutableState.request.query.append(URLQueryItem(
534-
name: key,
535-
value: "eq.\(value.queryValue)"
536-
))
484+
mutableState.request.query.append(
485+
URLQueryItem(
486+
name: key,
487+
value: "eq.\(value.queryValue)"
488+
))
537489
}
538490
}
539491
return self

Sources/PostgREST/PostgrestTransformBuilder.swift

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,7 @@ public class PostgrestTransformBuilder: PostgrestBuilder, @unchecked Sendable {
2323
.joined(separator: "")
2424
mutableState.withValue {
2525
$0.request.query.appendOrUpdate(URLQueryItem(name: "select", value: cleanedColumns))
26-
27-
if let prefer = $0.request.headers[.prefer] {
28-
var components = prefer.components(separatedBy: ",")
29-
30-
if let index = components.firstIndex(where: { $0.hasPrefix("return=") }) {
31-
components[index] = "return=representation"
32-
} else {
33-
components.append("return=representation")
34-
}
35-
36-
$0.request.headers[.prefer] = components.joined(separator: ",")
37-
} else {
38-
$0.request.headers[.prefer] = "return=representation"
39-
}
26+
$0.request.headers.appendOrUpdate(.prefer, value: "return=representation")
4027
}
4128
return self
4229
}
@@ -64,7 +51,7 @@ public class PostgrestTransformBuilder: PostgrestBuilder, @unchecked Sendable {
6451
"\(column).\(ascending ? "asc" : "desc").\(nullsFirst ? "nullsfirst" : "nullslast")"
6552

6653
if let existingOrderIndex,
67-
let currentValue = $0.request.query[existingOrderIndex].value
54+
let currentValue = $0.request.query[existingOrderIndex].value
6855
{
6956
$0.request.query[existingOrderIndex] = URLQueryItem(
7057
name: key,
@@ -85,11 +72,7 @@ public class PostgrestTransformBuilder: PostgrestBuilder, @unchecked Sendable {
8572
public func limit(_ count: Int, referencedTable: String? = nil) -> PostgrestTransformBuilder {
8673
mutableState.withValue {
8774
let key = referencedTable.map { "\($0).limit" } ?? "limit"
88-
if let index = $0.request.query.firstIndex(where: { $0.name == key }) {
89-
$0.request.query[index] = URLQueryItem(name: key, value: "\(count)")
90-
} else {
91-
$0.request.query.append(URLQueryItem(name: key, value: "\(count)"))
92-
}
75+
$0.request.query.appendOrUpdate(URLQueryItem(name: key, value: "\(count)"))
9376
}
9477
return self
9578
}
@@ -113,24 +96,10 @@ public class PostgrestTransformBuilder: PostgrestBuilder, @unchecked Sendable {
11396
let keyLimit = referencedTable.map { "\($0).limit" } ?? "limit"
11497

11598
mutableState.withValue {
116-
if let index = $0.request.query.firstIndex(where: { $0.name == keyOffset }) {
117-
$0.request.query[index] = URLQueryItem(name: keyOffset, value: "\(from)")
118-
} else {
119-
$0.request.query.append(URLQueryItem(name: keyOffset, value: "\(from)"))
120-
}
99+
$0.request.query.appendOrUpdate(URLQueryItem(name: keyOffset, value: "\(from)"))
121100

122101
// Range is inclusive, so add 1
123-
if let index = $0.request.query.firstIndex(where: { $0.name == keyLimit }) {
124-
$0.request.query[index] = URLQueryItem(
125-
name: keyLimit,
126-
value: "\(to - from + 1)"
127-
)
128-
} else {
129-
$0.request.query.append(URLQueryItem(
130-
name: keyLimit,
131-
value: "\(to - from + 1)"
132-
))
133-
}
102+
$0.request.query.appendOrUpdate(URLQueryItem(name: keyLimit, value: "\(to - from + 1)"))
134103
}
135104

136105
return self
@@ -195,7 +164,8 @@ public class PostgrestTransformBuilder: PostgrestBuilder, @unchecked Sendable {
195164
.compactMap { $0 }
196165
.joined(separator: "|")
197166
let forMediaType = $0.request.headers[.accept] ?? "application/json"
198-
$0.request.headers[.accept] = "application/vnd.pgrst.plan+\"\(format)\"; for=\(forMediaType); options=\(options);"
167+
$0.request.headers[.accept] =
168+
"application/vnd.pgrst.plan+\"\(format)\"; for=\(forMediaType); options=\(options);"
199169
}
200170

201171
return self

Sources/PostgREST/URLQueryRepresentable.swift

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,15 @@ extension Optional: URLQueryRepresentable where Wrapped: URLQueryRepresentable {
6868
extension JSONObject: URLQueryRepresentable {
6969
public var queryValue: String {
7070
let value = mapValues(\.value)
71-
return JSONSerialization.stringfy(value)
71+
return JSONSerialization.stringfy(value)!
7272
}
7373
}
7474

7575
extension JSONSerialization {
76-
static func stringfy(_ object: Any) -> String {
77-
guard
78-
let data = try? data(
79-
withJSONObject: object, options: [.withoutEscapingSlashes, .sortedKeys]
80-
),
81-
let string = String(data: data, encoding: .utf8)
82-
else {
83-
return "{}"
84-
}
85-
return string
76+
static func stringfy(_ object: Any) -> String? {
77+
let data = try? data(
78+
withJSONObject: object, options: [.withoutEscapingSlashes, .sortedKeys]
79+
)
80+
return data.flatMap { String(data: $0, encoding: .utf8) }
8681
}
8782
}

0 commit comments

Comments
 (0)