diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index d618fd0f..220898f8 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -4,14 +4,14 @@ on: pull_request: paths: - "Sources/Auth/**" - - "Tests/Auth/**" + - "Tests/AuthTests/**" - ".github/workflows/auth.yml" push: branches: - main paths: - "Sources/Auth/**" - - "Tests/Auth/**" + - "Tests/AuthTests/**" - ".github/workflows/auth.yml" concurrency: diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index fc9fca16..b001d808 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -4,14 +4,14 @@ on: pull_request: paths: - "Sources/Functions/**" - - "Tests/Functions/**" + - "Tests/FunctionsTests/**" - ".github/workflows/functions.yml" push: branches: - main paths: - "Sources/Functions/**" - - "Tests/Functions/**" + - "Tests/FunctionsTests/**" - ".github/workflows/functions.yml" concurrency: diff --git a/.github/workflows/postgrest.yml b/.github/workflows/postgrest.yml index fea0171d..23f640c0 100644 --- a/.github/workflows/postgrest.yml +++ b/.github/workflows/postgrest.yml @@ -4,14 +4,14 @@ on: pull_request: paths: - "Sources/PostgREST/**" - - "Tests/PostgREST/**" + - "Tests/PostgRESTTests/**" - ".github/workflows/postgrest.yml" push: branches: - main paths: - "Sources/PostgREST/**" - - "Tests/PostgREST/**" + - "Tests/PostgRESTTests/**" - ".github/workflows/postgrest.yml" concurrency: diff --git a/.github/workflows/realtime.yml b/.github/workflows/realtime.yml index 5d8d88c3..3f5b58b7 100644 --- a/.github/workflows/realtime.yml +++ b/.github/workflows/realtime.yml @@ -4,14 +4,14 @@ on: pull_request: paths: - "Sources/Realtime/**" - - "Tests/Realtime/**" + - "Tests/RealtimeTests/**" - ".github/workflows/realtime.yml" push: branches: - main paths: - "Sources/Realtime/**" - - "Tests/Realtime/**" + - "Tests/RealtimeTests/**" - ".github/workflows/realtime.yml" concurrency: diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 8d2e3644..c0a1b6b0 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -4,14 +4,14 @@ on: pull_request: paths: - "Sources/Storage/**" - - "Tests/Storage/**" + - "Tests/StorageTests/**" - ".github/workflows/storage.yml" push: branches: - main paths: - "Sources/Storage/**" - - "Tests/Storage/**" + - "Tests/StorageTests/**" - ".github/workflows/storage.yml" concurrency: diff --git a/.github/workflows/supabase.yml b/.github/workflows/supabase.yml index 0d50ce84..28f0be53 100644 --- a/.github/workflows/supabase.yml +++ b/.github/workflows/supabase.yml @@ -4,14 +4,14 @@ on: pull_request: paths: - "Sources/Supabase/**" - - "Tests/Supabase/**" + - "Tests/SupabaseTests/**" - ".github/workflows/supabase.yml" push: branches: - main paths: - "Sources/Supabase/**" - - "Tests/Supabase/**" + - "Tests/SupabaseTests/**" - ".github/workflows/supabase.yml" concurrency: diff --git a/Sources/_Helpers/FoundationExtensions.swift b/Sources/_Helpers/FoundationExtensions.swift index fa8ae126..00b1ba83 100644 --- a/Sources/_Helpers/FoundationExtensions.swift +++ b/Sources/_Helpers/FoundationExtensions.swift @@ -42,8 +42,14 @@ extension URL { return } - let currentQueryItems = components.queryItems ?? [] - components.queryItems = currentQueryItems + queryItems + let currentQueryItems = components.percentEncodedQueryItems ?? [] + + components.percentEncodedQueryItems = currentQueryItems + queryItems.map { + URLQueryItem( + name: escape($0.name), + value: $0.value.map(escape) + ) + } if let newURL = components.url { self = newURL @@ -56,3 +62,27 @@ extension URL { return url } } + +func escape(_ string: String) -> String { + string.addingPercentEncoding(withAllowedCharacters: .sbURLQueryAllowed) ?? string +} + +extension CharacterSet { + /// Creates a CharacterSet from RFC 3986 allowed characters. + /// + /// RFC 3986 states that the following characters are "reserved" characters. + /// + /// - General Delimiters: ":", "#", "[", "]", "@", "?", "/" + /// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=" + /// + /// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow + /// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/" + /// should be percent-escaped in the query string. + static let sbURLQueryAllowed: CharacterSet = { + let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 + let subDelimitersToEncode = "!$&'()*+,;=" + let encodableDelimiters = CharacterSet(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)") + + return CharacterSet.urlQueryAllowed.subtracting(encodableDelimiters) + }() +} diff --git a/Tests/PostgRESTTests/BuildURLRequestTests.swift b/Tests/PostgRESTTests/BuildURLRequestTests.swift index 7d4203b7..352610b9 100644 --- a/Tests/PostgRESTTests/BuildURLRequestTests.swift +++ b/Tests/PostgRESTTests/BuildURLRequestTests.swift @@ -206,6 +206,11 @@ final class BuildURLRequestTests: XCTestCase { .select() .containedBy("userMetadata", value: ["age": 18]) }, + TestCase(name: "filter starting with non-alphanumeric") { client in + client.from("users") + .select() + .eq("to", value: "+16505555555") + }, ] for testCase in testCases { diff --git a/Tests/PostgRESTTests/__Snapshots__/BuildURLRequestTests/testBuildRequest.filter-starting-with-non-alphanumeric.txt b/Tests/PostgRESTTests/__Snapshots__/BuildURLRequestTests/testBuildRequest.filter-starting-with-non-alphanumeric.txt new file mode 100644 index 00000000..ecff5260 --- /dev/null +++ b/Tests/PostgRESTTests/__Snapshots__/BuildURLRequestTests/testBuildRequest.filter-starting-with-non-alphanumeric.txt @@ -0,0 +1,5 @@ +curl \ + --header "Accept: application/json" \ + --header "Content-Type: application/json" \ + --header "X-Client-Info: postgrest-swift/x.y.z" \ + "https://example.supabase.co/users?select=*&to=eq.+16505555555" \ No newline at end of file