From 72c01a0c8e1a8e61895e42b29049a0f7a86902d6 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 12 Feb 2024 11:49:34 +0000 Subject: [PATCH 01/20] fix: base.php --- tests/Base.php | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/tests/Base.php b/tests/Base.php index ef071dbb7..83e0b4b21 100644 --- a/tests/Base.php +++ b/tests/Base.php @@ -204,25 +204,19 @@ public function testHTTPSuccess(): void echo \implode("\n", $output); - # Some languages deserialize JSON with sorted keys, other not. - # We use this custom assertion to normalise the lines with JSON before comparison. - $this->assertEqualsWithJsonLines($this->expectedOutput, $output); + $this->assertEquals([], \array_diff( + $this->normalizeConsoleLines($output), + $this->normalizeConsoleLines($this->expectedOutput) + )); } - private function assertEqualsWithJsonLines($expectedLines, $actualLines) - { - for ($i = 0; $i < \count($expectedLines); $i++) { - $this->assertArrayHasKey($i, $actualLines, "Missing line {$i}: {$expectedLines[$i]}"); - - $expectedLine = $expectedLines[$i]; - $actualLine = $actualLines[$i]; - - if (\str_starts_with($expectedLine, '{')) { - $this->assertEquals(\json_decode($expectedLine), \json_decode($actualLine)); - } else { - $this->assertEquals($expectedLine, $actualLine); + private function normalizeConsoleLines($lines) { + return \array_map(function (string $line) { + if (\str_starts_with($line, '{')) { + return \json_decode($line); } - } + return $line; + }, $lines); } private function rmdirRecursive($dir): void From 6e344b9924fde89aa6c702565bbe35ce453f28d1 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 12 Feb 2024 11:50:49 +0000 Subject: [PATCH 02/20] chore: fmt --- tests/Base.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Base.php b/tests/Base.php index 83e0b4b21..df286e9e8 100644 --- a/tests/Base.php +++ b/tests/Base.php @@ -205,12 +205,13 @@ public function testHTTPSuccess(): void echo \implode("\n", $output); $this->assertEquals([], \array_diff( - $this->normalizeConsoleLines($output), + $this->normalizeConsoleLines($output), $this->normalizeConsoleLines($this->expectedOutput) )); } - private function normalizeConsoleLines($lines) { + private function normalizeConsoleLines($lines) + { return \array_map(function (string $line) { if (\str_starts_with($line, '{')) { return \json_decode($line); From f19d699b331e79a130e1dc6ad9117bfda0dd3829 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:05:39 +0000 Subject: [PATCH 03/20] chore: revert --- tests/Base.php | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/Base.php b/tests/Base.php index df286e9e8..a24f3246a 100644 --- a/tests/Base.php +++ b/tests/Base.php @@ -204,20 +204,7 @@ public function testHTTPSuccess(): void echo \implode("\n", $output); - $this->assertEquals([], \array_diff( - $this->normalizeConsoleLines($output), - $this->normalizeConsoleLines($this->expectedOutput) - )); - } - - private function normalizeConsoleLines($lines) - { - return \array_map(function (string $line) { - if (\str_starts_with($line, '{')) { - return \json_decode($line); - } - return $line; - }, $lines); + $this->assertEquals([], \array_diff($this->expectedOutput, $output)); } private function rmdirRecursive($dir): void From 2118ada6eb090fa9c2c1e796477da7e7f8d1afec Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:09:24 +0000 Subject: [PATCH 04/20] fix: dart test --- templates/dart/lib/query.dart.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/dart/lib/query.dart.twig b/templates/dart/lib/query.dart.twig index 01a0c3bdf..4fe939e8c 100644 --- a/templates/dart/lib/query.dart.twig +++ b/templates/dart/lib/query.dart.twig @@ -84,7 +84,7 @@ class Query { Query._('contains', attribute, value).toString(); static String or(List queries) => - Query._('and', null, queries.map((query) => jsonDecode(query)).toList()).toString(); + Query._('or', null, queries.map((query) => jsonDecode(query)).toList()).toString(); static String and(List queries) => Query._('and', null, queries.map((query) => jsonDecode(query)).toList()).toString(); From 6c3fb00c66fc27f76b6092ad9f620070876cf73d Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:17:01 +0000 Subject: [PATCH 05/20] fix: php --- templates/php/src/Query.php.twig | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/templates/php/src/Query.php.twig b/templates/php/src/Query.php.twig index aa161e1ab..cff70af56 100644 --- a/templates/php/src/Query.php.twig +++ b/templates/php/src/Query.php.twig @@ -44,7 +44,7 @@ class Query implements \JsonSerializable */ public static function equal(string $attribute, $value): string { - return new Query('equal', $attribute, $value).__toString(); + return (new Query('equal', $attribute, $value))->__toString(); } /** @@ -56,7 +56,7 @@ class Query implements \JsonSerializable */ public static function notEqual(string $attribute, $value): string { - return new Query('notEqual', $attribute, $value).__toString(); + return (new Query('notEqual', $attribute, $value))->__toString(); } /** @@ -68,7 +68,7 @@ class Query implements \JsonSerializable */ public static function lessThan(string $attribute, $value): string { - return new Query('lessThan', $attribute, $value).__toString(); + return (new Query('lessThan', $attribute, $value))->__toString(); } /** @@ -80,7 +80,7 @@ class Query implements \JsonSerializable */ public static function lessThanEqual(string $attribute, $value): string { - return new Query('lessThanEqual', $attribute, $value).__toString(); + return (new Query('lessThanEqual', $attribute, $value))->__toString(); } /** @@ -92,7 +92,7 @@ class Query implements \JsonSerializable */ public static function greaterThan(string $attribute, $value): string { - return new Query('greaterThan', $attribute, $value).__toString(); + return (new Query('greaterThan', $attribute, $value))->__toString(); } /** @@ -104,7 +104,7 @@ class Query implements \JsonSerializable */ public static function greaterThanEqual(string $attribute, $value): string { - return new Query('greaterThanEqual', $attribute, $value).__toString(); + return (new Query('greaterThanEqual', $attribute, $value))->__toString(); } /** @@ -116,7 +116,7 @@ class Query implements \JsonSerializable */ public static function search(string $attribute, string $value): string { - return new Query('search', $attribute, $value).__toString(); + return (new Query('search', $attribute, $value))->__toString(); } /** @@ -127,7 +127,7 @@ class Query implements \JsonSerializable */ public static function isNull(string $attribute): string { - return new Query('isNull', $attribute, null).__toString(); + return (new Query('isNull', $attribute, null))->__toString(); } /** @@ -138,7 +138,7 @@ class Query implements \JsonSerializable */ public static function isNotNull(string $attribute): string { - return new Query('isNotNull', $attribute, null).__toString(); + return (new Query('isNotNull', $attribute, null))->__toString(); } /** @@ -151,7 +151,7 @@ class Query implements \JsonSerializable */ public static function between(string $attribute, $start, $end): string { - return new Query('between', $attribute, [$start, $end]).__toString(); + return (new Query('between', $attribute, [$start, $end]))->__toString(); } /** @@ -163,7 +163,7 @@ class Query implements \JsonSerializable */ public static function startsWith(string $attribute, string $value): string { - return new Query('startsWith', $attribute, $value).__toString(); + return (new Query('startsWith', $attribute, $value))->__toString(); } /** @@ -175,7 +175,7 @@ class Query implements \JsonSerializable */ public static function endsWith(string $attribute, string $value): string { - return new Query('endsWith', $attribute, $value).__toString(); + return (new Query('endsWith', $attribute, $value))->__toString(); } /** @@ -186,7 +186,7 @@ class Query implements \JsonSerializable */ public static function select(array $attributes): string { - return new Query('select', null, $attributes).__toString(); + return (new Query('select', null, $attributes))->__toString(); } /** @@ -197,7 +197,7 @@ class Query implements \JsonSerializable */ public static function cursorAfter(string $documentId): string { - return new Query('cursorAfter', null, $documentId).__toString(); + return (new Query('cursorAfter', null, $documentId))->__toString(); } /** @@ -208,7 +208,7 @@ class Query implements \JsonSerializable */ public static function cursorBefore(string $documentId): string { - return new Query('cursorBefore', null, $documentId).__toString(); + return (new Query('cursorBefore', null, $documentId))->__toString(); } /** @@ -219,7 +219,7 @@ class Query implements \JsonSerializable */ public static function orderAsc(string $attribute): string { - return new Query('orderAsc', $attribute, null).__toString(); + return (new Query('orderAsc', $attribute, null))->__toString(); } /** @@ -230,7 +230,7 @@ class Query implements \JsonSerializable */ public static function orderDesc(string $attribute): string { - return new Query('orderDesc', $attribute, null).__toString(); + return (new Query('orderDesc', $attribute, null))->__toString(); } /** @@ -241,7 +241,7 @@ class Query implements \JsonSerializable */ public static function limit(int $limit): string { - return new Query('limit', null, $limit).__toString(); + return (new Query('limit', null, $limit))->__toString(); } /** @@ -252,7 +252,7 @@ class Query implements \JsonSerializable */ public static function offset(int $offset): string { - return new Query('offset', null, $offset).__toString(); + return (new Query('offset', null, $offset))->__toString(); } /** @@ -264,7 +264,7 @@ class Query implements \JsonSerializable */ public static function contains(string $attribute, string $value): string { - return new Query('contains', $attribute, $value).__toString(); + return (new Query('contains', $attribute, $value))->__toString(); } /** @@ -278,7 +278,7 @@ class Query implements \JsonSerializable foreach ($queries as &$query) { $query = \json_decode($query, true); } - return new Query('or', null, $queries).__toString(); + return (new Query('or', null, $queries))->__toString(); } /** @@ -292,6 +292,6 @@ class Query implements \JsonSerializable foreach ($queries as &$query) { $query = \json_decode($query, true); } - return new Query('and', null, $queries).__toString(); + return (new Query('and', null, $queries))->__toString(); } } From d80a1ba32d77639f687537c59dfb0e137ed0c625 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:42:31 +0000 Subject: [PATCH 06/20] fix: dotnet --- .../io/appwrite/extensions/JsonExtensions.kt.twig | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig index 48e536b3a..74e98a4ab 100644 --- a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig +++ b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig @@ -1,9 +1,14 @@ package {{ sdk.namespace | caseDot }}.extensions import com.google.gson.Gson - -val gson = Gson() - +import com.google.gson.GsonBuilder +import com.google.gson.reflect.TypeToken +import {{ sdk.namespace | caseDot }}.json.PreciseNumberAdapter + +val gson = GsonBuilder().registerTypeAdapter( + object : TypeToken>(){}.type, + PreciseNumberAdapter() +).create() fun Any.toJson(): String = gson.toJson(this) From 7738cff0289a831396341b94ffc1e286d4fa6727 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:42:44 +0000 Subject: [PATCH 07/20] fix: dotnet --- templates/dotnet/src/Appwrite/Query.cs.twig | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/templates/dotnet/src/Appwrite/Query.cs.twig b/templates/dotnet/src/Appwrite/Query.cs.twig index 99eb2eec9..3b26a02a1 100644 --- a/templates/dotnet/src/Appwrite/Query.cs.twig +++ b/templates/dotnet/src/Appwrite/Query.cs.twig @@ -17,10 +17,16 @@ namespace Appwrite this.method = method; this.attribute = attribute; - if (values == null || values is IList) + if (values is IList valuesList) + { + this.values = new List(); + foreach (var value in valuesList) + { + this.values.Add(value); // Automatically boxes if value is a value type + } + } + else if (values != null) { - this.values = (List?)values; - } else { this.values = new List { values }; } } From e90079423dbac233e92726a3a16073b3584eaabc Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:43:15 +0000 Subject: [PATCH 08/20] chore: revert kotlin fix --- .../io/appwrite/extensions/JsonExtensions.kt.twig | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig index 74e98a4ab..48e536b3a 100644 --- a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig +++ b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig @@ -1,14 +1,9 @@ package {{ sdk.namespace | caseDot }}.extensions import com.google.gson.Gson -import com.google.gson.GsonBuilder -import com.google.gson.reflect.TypeToken -import {{ sdk.namespace | caseDot }}.json.PreciseNumberAdapter - -val gson = GsonBuilder().registerTypeAdapter( - object : TypeToken>(){}.type, - PreciseNumberAdapter() -).create() + +val gson = Gson() + fun Any.toJson(): String = gson.toJson(this) From 55c40dd5390cb9135e05670de085d796d798f7ef Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 14 Feb 2024 21:50:51 +1300 Subject: [PATCH 09/20] JSON improvements for Kotlin --- .../package/json/PreciseNumberAdapter.kt.twig | 5 ++-- templates/kotlin/build.gradle.twig | 2 +- .../main/kotlin/io/appwrite/Client.kt.twig | 23 +++++-------------- .../extensions/JsonExtensions.kt.twig | 12 ++++++++-- .../json/PreciseNumberAdapter.kt.twig | 5 ++-- 5 files changed, 21 insertions(+), 26 deletions(-) diff --git a/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig b/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig index 09cb786cf..4d62cb936 100644 --- a/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig +++ b/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig @@ -1,16 +1,15 @@ package {{ sdk.namespace | caseDot }}.json -import com.google.gson.Gson import com.google.gson.TypeAdapter import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonToken.* import com.google.gson.stream.JsonWriter +import {{ sdk.namespace | caseDot }}.extensions.gson import java.io.IOException internal class PreciseNumberAdapter : TypeAdapter() { - private val delegate = Gson() - .getAdapter(Any::class.java) + private val delegate = gson.getAdapter(Any::class.java) @Throws(IOException::class) override fun write(out: JsonWriter?, value: Any?) { diff --git a/templates/kotlin/build.gradle.twig b/templates/kotlin/build.gradle.twig index 2eb330f26..b5feaed62 100644 --- a/templates/kotlin/build.gradle.twig +++ b/templates/kotlin/build.gradle.twig @@ -38,7 +38,7 @@ dependencies { implementation("com.squareup.okhttp3:logging-interceptor") implementation("com.google.code.gson:gson:2.9.0") - testImplementation 'org.jetbrains.kotlin:kotlin-test-junit' + testImplementation("org.jetbrains.kotlin:kotlin-test-junit") } test { diff --git a/templates/kotlin/src/main/kotlin/io/appwrite/Client.kt.twig b/templates/kotlin/src/main/kotlin/io/appwrite/Client.kt.twig index 7181175ca..6be1ed132 100644 --- a/templates/kotlin/src/main/kotlin/io/appwrite/Client.kt.twig +++ b/templates/kotlin/src/main/kotlin/io/appwrite/Client.kt.twig @@ -1,10 +1,8 @@ package {{ sdk.namespace | caseDot }} -import com.google.gson.GsonBuilder -import com.google.gson.reflect.TypeToken import {{ sdk.namespace | caseDot }}.exceptions.{{ spec.title | caseUcfirst }}Exception import {{ sdk.namespace | caseDot }}.extensions.fromJson -import {{ sdk.namespace | caseDot }}.json.PreciseNumberAdapter +import {{ sdk.namespace | caseDot }}.extensions.toJson import {{ sdk.namespace | caseDot }}.models.InputFile import {{ sdk.namespace | caseDot }}.models.UploadProgress import kotlinx.coroutines.CoroutineScope @@ -47,11 +45,6 @@ class Client @JvmOverloads constructor( private val job = Job() - private val gson = GsonBuilder().registerTypeAdapter( - object : TypeToken>(){}.type, - PreciseNumberAdapter() - ).create() - lateinit var http: OkHttpClient private val headers: MutableMap @@ -252,7 +245,8 @@ class Client @JvmOverloads constructor( } builder.build() } else { - gson.toJson(filteredParams) + filteredParams + .toJson() .toRequestBody("application/json".toMediaType()) } @@ -422,10 +416,8 @@ class Client @JvmOverloads constructor( .use(BufferedReader::readText) val error = if (response.headers["content-type"]?.contains("application/json") == true) { - val map = gson.fromJson>( - body, - object : TypeToken>(){}.type - ) + val map = body.fromJson>() + {{ spec.title | caseUcfirst }}Exception( map["message"] as? String ?: "", (map["code"] as Number).toInt(), @@ -464,10 +456,7 @@ class Client @JvmOverloads constructor( it.resume(true as T) return } - val map = gson.fromJson>( - body, - object : TypeToken>(){}.type - ) + val map = body.fromJson>() it.resume( converter?.invoke(map) ?: map as T ) diff --git a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig index 48e536b3a..9f6faec45 100644 --- a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig +++ b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig @@ -1,8 +1,16 @@ package {{ sdk.namespace | caseDot }}.extensions import com.google.gson.Gson - -val gson = Gson() +import com.google.gson.GsonBuilder +import com.google.gson.reflect.TypeToken +import {{ sdk.namespace | caseDot }}.json.PreciseNumberAdapter + +val gson: Gson = GsonBuilder() + .registerTypeAdapter( + object : TypeToken>() {}.type, + PreciseNumberAdapter() + ) + .create() fun Any.toJson(): String = gson.toJson(this) diff --git a/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig b/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig index 09cb786cf..4d62cb936 100644 --- a/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig +++ b/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig @@ -1,16 +1,15 @@ package {{ sdk.namespace | caseDot }}.json -import com.google.gson.Gson import com.google.gson.TypeAdapter import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonToken.* import com.google.gson.stream.JsonWriter +import {{ sdk.namespace | caseDot }}.extensions.gson import java.io.IOException internal class PreciseNumberAdapter : TypeAdapter() { - private val delegate = Gson() - .getAdapter(Any::class.java) + private val delegate = gson.getAdapter(Any::class.java) @Throws(IOException::class) override fun write(out: JsonWriter?, value: Any?) { From acbe91eceb6612ae2d0ca63a4bdcf76bc1d1efd2 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 14 Feb 2024 21:59:05 +1300 Subject: [PATCH 10/20] Custom `Package.swift` for Apple --- .github/workflows/tests.yml | 2 +- src/SDK/Language/Apple.php | 2 +- templates/apple/Package.swift.twig | 69 +++++++++++++++++++ templates/swift/Package.swift.twig | 2 - ...leSwift55Test.php => AppleSwift56Test.php} | 2 +- tests/{Swift55Test.php => Swift56Test.php} | 4 +- 6 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 templates/apple/Package.swift.twig rename tests/{AppleSwift55Test.php => AppleSwift56Test.php} (96%) rename tests/{Swift55Test.php => Swift56Test.php} (90%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d7ecb637d..1fd0cb6be 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: php-version: ['8.2'] - sdk: [Android5Java17, Android14Java17, CLINode16, CLINode18, DartBeta, DartStable, Deno1193, Deno1303, DotNet60, DotNet70, FlutterStable, FlutterBeta, Go112, Go118, KotlinJava8, KotlinJava11, KotlinJava17, Node16, Node18, Node20, PHP74, PHP80, Python38, Python39, Python310, Ruby27, Ruby30, Ruby31, AppleSwift55, Swift55, WebChromium, WebNode] + sdk: [Android5Java17, Android14Java17, CLINode16, CLINode18, DartBeta, DartStable, Deno1193, Deno1303, DotNet60, DotNet70, FlutterStable, FlutterBeta, Go112, Go118, KotlinJava8, KotlinJava11, KotlinJava17, Node16, Node18, Node20, PHP74, PHP80, Python38, Python39, Python310, Ruby27, Ruby30, Ruby31, AppleSwift56, Swift56, WebChromium, WebNode] steps: - name: Checkout repository diff --git a/src/SDK/Language/Apple.php b/src/SDK/Language/Apple.php index 0e17c47f9..7ecb6c626 100644 --- a/src/SDK/Language/Apple.php +++ b/src/SDK/Language/Apple.php @@ -33,7 +33,7 @@ public function getFiles(): array [ 'scope' => 'default', 'destination' => 'Package.swift', - 'template' => 'swift/Package.swift.twig', + 'template' => 'apple/Package.swift.twig', ], [ 'scope' => 'method', diff --git a/templates/apple/Package.swift.twig b/templates/apple/Package.swift.twig new file mode 100644 index 000000000..7a1a09a3d --- /dev/null +++ b/templates/apple/Package.swift.twig @@ -0,0 +1,69 @@ +// swift-tools-version:5.1 + +import PackageDescription + +let package = Package( + name: "{{spec.title | caseUcfirst}}", + platforms: [ + .iOS("15.0"), + .macOS("11.0"), + .watchOS("7.0"), + .tvOS("13.0"), + ], + products: [ + .library( + name: "{{spec.title | caseUcfirst}}", + targets: [ + "{{spec.title | caseUcfirst}}", + "{{spec.title | caseUcfirst}}Enums", + "{{spec.title | caseUcfirst}}Models", + "JSONCodable" + ] + ), + ], + dependencies: [ + .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.9.0"), + .package(url: "https://github.com/apple/swift-nio.git", from: "2.32.0"), + .package(url: "https://github.com/firebase/firebase-ios-sdk.git", from: "10.4.0") + ], + targets: [ + .target( + name: "{{spec.title | caseUcfirst}}", + dependencies: [ + .product(name: "AsyncHTTPClient", package: "async-http-client"), + .product(name: "NIOWebSocket", package: "swift-nio"), + .product(name: "FirebaseMessaging", package: "firebase-ios-sdk"), + {%~ if spec.definitions is not empty %} + "{{spec.title | caseUcfirst}}Models", + {%~ endif %} + {%~ if spec.enums is not empty %} + "{{spec.title | caseUcfirst}}Enums", + {%~ endif %} + "JSONCodable" + ] + ), + {%~ if spec.definitions is not empty %} + .target( + name: "{{spec.title | caseUcfirst}}Models", + dependencies: [ + "JSONCodable" + ] + ), + {%~ endif %} + {%~ if spec.enums is not empty %} + .target( + name: "{{spec.title | caseUcfirst}}Enums" + ), + {%~ endif %} + .target( + name: "JSONCodable" + ), + .testTarget( + name: "{{spec.title | caseUcfirst}}Tests", + dependencies: [ + "{{ spec.title | caseUcfirst }}" + ] + ) + ], + swiftLanguageVersions: [.v5] +) \ No newline at end of file diff --git a/templates/swift/Package.swift.twig b/templates/swift/Package.swift.twig index 7a1a09a3d..132ae387f 100644 --- a/templates/swift/Package.swift.twig +++ b/templates/swift/Package.swift.twig @@ -24,7 +24,6 @@ let package = Package( dependencies: [ .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.9.0"), .package(url: "https://github.com/apple/swift-nio.git", from: "2.32.0"), - .package(url: "https://github.com/firebase/firebase-ios-sdk.git", from: "10.4.0") ], targets: [ .target( @@ -32,7 +31,6 @@ let package = Package( dependencies: [ .product(name: "AsyncHTTPClient", package: "async-http-client"), .product(name: "NIOWebSocket", package: "swift-nio"), - .product(name: "FirebaseMessaging", package: "firebase-ios-sdk"), {%~ if spec.definitions is not empty %} "{{spec.title | caseUcfirst}}Models", {%~ endif %} diff --git a/tests/AppleSwift55Test.php b/tests/AppleSwift56Test.php similarity index 96% rename from tests/AppleSwift55Test.php rename to tests/AppleSwift56Test.php index c49fbc9eb..cfca2c18e 100644 --- a/tests/AppleSwift55Test.php +++ b/tests/AppleSwift56Test.php @@ -2,7 +2,7 @@ namespace Tests; -class AppleSwift55Test extends Base +class AppleSwift56Test extends Base { protected string $sdkName = 'swift'; protected string $sdkPlatform = 'client'; diff --git a/tests/Swift55Test.php b/tests/Swift56Test.php similarity index 90% rename from tests/Swift55Test.php rename to tests/Swift56Test.php index f10c97955..ac16de1b4 100644 --- a/tests/Swift55Test.php +++ b/tests/Swift56Test.php @@ -2,7 +2,7 @@ namespace Tests; -class Swift55Test extends Base +class Swift56Test extends Base { protected string $sdkName = 'swift'; protected string $sdkPlatform = 'server'; @@ -16,7 +16,7 @@ class Swift55Test extends Base 'cp tests/languages/swift/Tests.swift tests/sdks/swift/Tests/AppwriteTests/Tests.swift', ]; protected string $command = - 'docker run --network="mockapi" --rm -v $(pwd):/app -w /app/tests/sdks/swift swiftarm/swift:5.5.2-focal-multi-arch swift test'; + 'docker run --network="mockapi" --rm -v $(pwd):/app -w /app/tests/sdks/swift swift:5.6 swift test'; protected array $expectedOutput = [ ...Base::FOO_RESPONSES, From 3185ab12644e27110fc68a86d32678913a29477e Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 14 Feb 2024 22:11:55 +1300 Subject: [PATCH 11/20] Fix dependency cycle --- .../main/java/io/package/json/PreciseNumberAdapter.kt.twig | 4 ++-- .../main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig b/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig index 4d62cb936..3c131edac 100644 --- a/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig +++ b/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig @@ -1,15 +1,15 @@ package {{ sdk.namespace | caseDot }}.json +import com.google.gson.Gson import com.google.gson.TypeAdapter import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonToken.* import com.google.gson.stream.JsonWriter -import {{ sdk.namespace | caseDot }}.extensions.gson import java.io.IOException internal class PreciseNumberAdapter : TypeAdapter() { - private val delegate = gson.getAdapter(Any::class.java) + private val delegate = Gson().getAdapter(Any::class.java) @Throws(IOException::class) override fun write(out: JsonWriter?, value: Any?) { diff --git a/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig b/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig index 4d62cb936..3c131edac 100644 --- a/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig +++ b/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig @@ -1,15 +1,15 @@ package {{ sdk.namespace | caseDot }}.json +import com.google.gson.Gson import com.google.gson.TypeAdapter import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonToken.* import com.google.gson.stream.JsonWriter -import {{ sdk.namespace | caseDot }}.extensions.gson import java.io.IOException internal class PreciseNumberAdapter : TypeAdapter() { - private val delegate = gson.getAdapter(Any::class.java) + private val delegate = Gson().getAdapter(Any::class.java) @Throws(IOException::class) override fun write(out: JsonWriter?, value: Any?) { From 038b88bb6789b315eaa069cdffe5336de42b0306 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 14 Feb 2024 22:57:10 +1300 Subject: [PATCH 12/20] Fix Android/Kotlin number serialization --- src/SDK/Language/Android.php | 5 -- src/SDK/Language/Kotlin.php | 5 -- .../package/extensions/JsonExtensions.kt.twig | 7 +-- .../package/json/PreciseNumberAdapter.kt.twig | 63 ------------------- .../extensions/JsonExtensions.kt.twig | 7 +-- .../json/PreciseNumberAdapter.kt.twig | 63 ------------------- 6 files changed, 6 insertions(+), 144 deletions(-) delete mode 100644 templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig delete mode 100644 templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig diff --git a/src/SDK/Language/Android.php b/src/SDK/Language/Android.php index 5bbd8f724..0dec10358 100644 --- a/src/SDK/Language/Android.php +++ b/src/SDK/Language/Android.php @@ -145,11 +145,6 @@ public function getFiles(): array 'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/extensions/CollectionExtensions.kt', 'template' => '/android/library/src/main/java/io/package/extensions/CollectionExtensions.kt.twig', ], - [ - 'scope' => 'default', - 'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/json/PreciseNumberAdapter.kt', - 'template' => '/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig', - ], [ 'scope' => 'default', 'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/models/InputFile.kt', diff --git a/src/SDK/Language/Kotlin.php b/src/SDK/Language/Kotlin.php index 1331d8617..ac423e356 100644 --- a/src/SDK/Language/Kotlin.php +++ b/src/SDK/Language/Kotlin.php @@ -386,11 +386,6 @@ public function getFiles(): array 'template' => '/kotlin/src/main/kotlin/io/appwrite/extensions/TypeExtensions.kt.twig', 'minify' => false, ], - [ - 'scope' => 'default', - 'destination' => '/src/main/kotlin/{{ sdk.namespace | caseSlash }}/json/PreciseNumberAdapter.kt', - 'template' => '/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig', - ], [ 'scope' => 'default', 'destination' => '/src/main/kotlin/{{ sdk.namespace | caseSlash }}/services/Service.kt', diff --git a/templates/android/library/src/main/java/io/package/extensions/JsonExtensions.kt.twig b/templates/android/library/src/main/java/io/package/extensions/JsonExtensions.kt.twig index 9f6faec45..41be4a997 100644 --- a/templates/android/library/src/main/java/io/package/extensions/JsonExtensions.kt.twig +++ b/templates/android/library/src/main/java/io/package/extensions/JsonExtensions.kt.twig @@ -2,14 +2,13 @@ package {{ sdk.namespace | caseDot }}.extensions import com.google.gson.Gson import com.google.gson.GsonBuilder +import com.google.gson.ToNumberPolicy import com.google.gson.reflect.TypeToken import {{ sdk.namespace | caseDot }}.json.PreciseNumberAdapter val gson: Gson = GsonBuilder() - .registerTypeAdapter( - object : TypeToken>() {}.type, - PreciseNumberAdapter() - ) + .setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) + .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) .create() fun Any.toJson(): String = diff --git a/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig b/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig deleted file mode 100644 index 3c131edac..000000000 --- a/templates/android/library/src/main/java/io/package/json/PreciseNumberAdapter.kt.twig +++ /dev/null @@ -1,63 +0,0 @@ -package {{ sdk.namespace | caseDot }}.json - -import com.google.gson.Gson -import com.google.gson.TypeAdapter -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonToken.* -import com.google.gson.stream.JsonWriter -import java.io.IOException - -internal class PreciseNumberAdapter : TypeAdapter() { - - private val delegate = Gson().getAdapter(Any::class.java) - - @Throws(IOException::class) - override fun write(out: JsonWriter?, value: Any?) { - delegate.write(out, value) - } - - @Throws(IOException::class) - override fun read(input: JsonReader): Any? { - return when (input.peek()) { - BEGIN_ARRAY -> { - val list = mutableListOf() - input.beginArray() - while (input.hasNext()) { - list.add(read(input)) - } - input.endArray() - list - } - BEGIN_OBJECT -> { - val map = mutableMapOf() - input.beginObject() - while (input.hasNext()) { - map[input.nextName()] = read(input) - } - input.endObject() - map - } - STRING -> { - input.nextString() - } - NUMBER -> { - val numberString = input.nextString() - if (numberString.indexOf('.') != -1) { - numberString.toDouble() - } else { - numberString.toLong() - } - } - BOOLEAN -> { - input.nextBoolean() - } - NULL -> { - input.nextNull() - null - } - else -> { - throw IllegalStateException() - } - } - } -} \ No newline at end of file diff --git a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig index 9f6faec45..41be4a997 100644 --- a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig +++ b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig @@ -2,14 +2,13 @@ package {{ sdk.namespace | caseDot }}.extensions import com.google.gson.Gson import com.google.gson.GsonBuilder +import com.google.gson.ToNumberPolicy import com.google.gson.reflect.TypeToken import {{ sdk.namespace | caseDot }}.json.PreciseNumberAdapter val gson: Gson = GsonBuilder() - .registerTypeAdapter( - object : TypeToken>() {}.type, - PreciseNumberAdapter() - ) + .setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) + .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) .create() fun Any.toJson(): String = diff --git a/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig b/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig deleted file mode 100644 index 3c131edac..000000000 --- a/templates/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig +++ /dev/null @@ -1,63 +0,0 @@ -package {{ sdk.namespace | caseDot }}.json - -import com.google.gson.Gson -import com.google.gson.TypeAdapter -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonToken.* -import com.google.gson.stream.JsonWriter -import java.io.IOException - -internal class PreciseNumberAdapter : TypeAdapter() { - - private val delegate = Gson().getAdapter(Any::class.java) - - @Throws(IOException::class) - override fun write(out: JsonWriter?, value: Any?) { - delegate.write(out, value) - } - - @Throws(IOException::class) - override fun read(input: JsonReader): Any? { - return when (input.peek()) { - BEGIN_ARRAY -> { - val list = mutableListOf() - input.beginArray() - while (input.hasNext()) { - list.add(read(input)) - } - input.endArray() - list - } - BEGIN_OBJECT -> { - val map = mutableMapOf() - input.beginObject() - while (input.hasNext()) { - map[input.nextName()] = read(input) - } - input.endObject() - map - } - STRING -> { - input.nextString() - } - NUMBER -> { - val numberString = input.nextString() - if (numberString.indexOf('.') != -1) { - numberString.toDouble() - } else { - numberString.toLong() - } - } - BOOLEAN -> { - input.nextBoolean() - } - NULL -> { - input.nextNull() - null - } - else -> { - throw IllegalStateException() - } - } - } -} \ No newline at end of file From eef82737297957a349e12ca83a507863c956d8da Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 14 Feb 2024 23:02:04 +1300 Subject: [PATCH 13/20] Fix imports --- .../src/main/java/io/package/extensions/JsonExtensions.kt.twig | 1 - .../main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig | 1 - 2 files changed, 2 deletions(-) diff --git a/templates/android/library/src/main/java/io/package/extensions/JsonExtensions.kt.twig b/templates/android/library/src/main/java/io/package/extensions/JsonExtensions.kt.twig index 41be4a997..14ad26726 100644 --- a/templates/android/library/src/main/java/io/package/extensions/JsonExtensions.kt.twig +++ b/templates/android/library/src/main/java/io/package/extensions/JsonExtensions.kt.twig @@ -4,7 +4,6 @@ import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.ToNumberPolicy import com.google.gson.reflect.TypeToken -import {{ sdk.namespace | caseDot }}.json.PreciseNumberAdapter val gson: Gson = GsonBuilder() .setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) diff --git a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig index 41be4a997..14ad26726 100644 --- a/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig +++ b/templates/kotlin/src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt.twig @@ -4,7 +4,6 @@ import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.ToNumberPolicy import com.google.gson.reflect.TypeToken -import {{ sdk.namespace | caseDot }}.json.PreciseNumberAdapter val gson: Gson = GsonBuilder() .setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) From 5f7b1b17c1199585ad3ca1913f4672c47529ba8a Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 14 Feb 2024 23:23:23 +1300 Subject: [PATCH 14/20] Revert gradle for implicit JDK version usage --- templates/kotlin/gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/kotlin/gradle/wrapper/gradle-wrapper.properties b/templates/kotlin/gradle/wrapper/gradle-wrapper.properties index 2bbac7dd7..60c76b340 100644 --- a/templates/kotlin/gradle/wrapper/gradle-wrapper.properties +++ b/templates/kotlin/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists \ No newline at end of file From 8d6667f00154cfe028389fea266df32aac2f817e Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 14 Feb 2024 23:49:46 +1300 Subject: [PATCH 15/20] Fix Swift query values --- templates/swift/Sources/Query.swift.twig | 43 ++++++++++++------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/templates/swift/Sources/Query.swift.twig b/templates/swift/Sources/Query.swift.twig index ccdd3d150..754744acf 100644 --- a/templates/swift/Sources/Query.swift.twig +++ b/templates/swift/Sources/Query.swift.twig @@ -5,7 +5,6 @@ enum QueryValue: Codable { case int(Int) case double(Double) case bool(Bool) - case query(Query) init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() @@ -18,8 +17,6 @@ enum QueryValue: Codable { self = .double(doubleValue) } else if let boolValue = try? container.decode(Bool.self) { self = .bool(boolValue) - } else if let queryValue = try? container.decode(Query.self) { - self = .query(queryValue) } else { throw DecodingError.dataCorruptedError(in: container, debugDescription: "QueryValue cannot be decoded") } @@ -36,8 +33,6 @@ enum QueryValue: Codable { try container.encode(value) case .bool(let value): try container.encode(value) - case .query(let value): - try container.encode(value) } } } @@ -66,15 +61,13 @@ public struct Query : Codable, CustomStringConvertible { case let valueArray as [QueryValue]: return valueArray case let stringArray as [String]: - return stringArray.map { QueryValue.string($0) } + return stringArray.map { .string($0) } case let intArray as [Int]: - return intArray.map { QueryValue.int($0) } + return intArray.map { .int($0) } case let doubleArray as [Double]: - return doubleArray.map { QueryValue.double($0) } + return doubleArray.map { .double($0) } case let boolArray as [Bool]: - return boolArray.map { QueryValue.bool($0) } - case let queryArray as [Query]: - return queryArray.map { QueryValue.query($0) } + return boolArray.map { .bool($0) } case let stringValue as String: return [.string(stringValue)] case let intValue as Int: @@ -83,13 +76,11 @@ public struct Query : Codable, CustomStringConvertible { return [.double(doubleValue)] case let boolValue as Bool: return [.bool(boolValue)] - case let queryValue as Query: - return [.query(queryValue)] default: return nil } } - + enum CodingKeys: String, CodingKey { case method case attribute @@ -121,7 +112,7 @@ public struct Query : Codable, CustomStringConvertible { return Query( method: "equal", attribute: attribute, - values: [value] + values: Query.parseValue(value) ).description } @@ -129,7 +120,7 @@ public struct Query : Codable, CustomStringConvertible { return Query( method: "notEqual", attribute: attribute, - values: [value] + values: Query.parseValue(value) ).description } @@ -137,7 +128,7 @@ public struct Query : Codable, CustomStringConvertible { return Query( method: "lessThan", attribute: attribute, - values: [value] + values: Query.parseValue(value) ).description } @@ -145,7 +136,7 @@ public struct Query : Codable, CustomStringConvertible { return Query( method: "lessThanEqual", attribute: attribute, - values: [value] + values: Query.parseValue(value) ).description } @@ -153,7 +144,7 @@ public struct Query : Codable, CustomStringConvertible { return Query( method: "greaterThan", attribute: attribute, - values: [value] + values: Query.parseValue(value) ).description } @@ -161,7 +152,7 @@ public struct Query : Codable, CustomStringConvertible { return Query( method: "greaterThanEqual", attribute: attribute, - values: [value] + values: Query.parseValue(value) ).description } @@ -280,7 +271,7 @@ public struct Query : Codable, CustomStringConvertible { return Query( method: "contains", attribute: attribute, - values: value + values: Query.parseValue(value) ).description } @@ -313,4 +304,12 @@ public struct Query : Codable, CustomStringConvertible { values: decodedQueries ).description } -} \ No newline at end of file + + private static func parseValue(_ value: Any) -> [Any] { + if let value = value as? [Any] { + return value + } else { + return [value] + } + } +} From 5e3d016c6d1d43ddf557e8bb974aeedc4aba5e06 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 15 Feb 2024 00:00:03 +1300 Subject: [PATCH 16/20] Revert removal of sub query encoding --- templates/swift/Sources/Query.swift.twig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/templates/swift/Sources/Query.swift.twig b/templates/swift/Sources/Query.swift.twig index 754744acf..20c499eea 100644 --- a/templates/swift/Sources/Query.swift.twig +++ b/templates/swift/Sources/Query.swift.twig @@ -5,6 +5,7 @@ enum QueryValue: Codable { case int(Int) case double(Double) case bool(Bool) + case query(Query) init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() @@ -17,6 +18,8 @@ enum QueryValue: Codable { self = .double(doubleValue) } else if let boolValue = try? container.decode(Bool.self) { self = .bool(boolValue) + } else if let queryValue = try? container.decode(Query.self) { + self = .query(queryValue) } else { throw DecodingError.dataCorruptedError(in: container, debugDescription: "QueryValue cannot be decoded") } @@ -33,6 +36,8 @@ enum QueryValue: Codable { try container.encode(value) case .bool(let value): try container.encode(value) + case .query(let value): + try container.encode(value) } } } @@ -68,6 +73,8 @@ public struct Query : Codable, CustomStringConvertible { return doubleArray.map { .double($0) } case let boolArray as [Bool]: return boolArray.map { .bool($0) } + case let queryArray as [Query]: + return queryArray.map { .query($0) } case let stringValue as String: return [.string(stringValue)] case let intValue as Int: @@ -76,6 +83,8 @@ public struct Query : Codable, CustomStringConvertible { return [.double(doubleValue)] case let boolValue as Bool: return [.bool(boolValue)] + case let queryValue as Query: + return [.query(queryValue)] default: return nil } From 8b2a917d639f759a155d570d9d8492315da93e69 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 15 Feb 2024 01:02:09 +1300 Subject: [PATCH 17/20] Test JSON strings by decoding as order is undefined --- tests/Base.php | 11 ++++++++++- tests/Swift56Test.php | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/Base.php b/tests/Base.php index a24f3246a..00af48a99 100644 --- a/tests/Base.php +++ b/tests/Base.php @@ -204,7 +204,16 @@ public function testHTTPSuccess(): void echo \implode("\n", $output); - $this->assertEquals([], \array_diff($this->expectedOutput, $output)); + foreach ($this->expectedOutput as $index => $expected) { + if (\str_starts_with($expected, '{')) { + $this->assertEquals( + \json_decode($expected, true), + \json_decode($output[$index], true) + ); + } else { + $this->assertEquals($expected, $output[$index]); + } + } } private function rmdirRecursive($dir): void diff --git a/tests/Swift56Test.php b/tests/Swift56Test.php index ac16de1b4..22172ed0f 100644 --- a/tests/Swift56Test.php +++ b/tests/Swift56Test.php @@ -16,7 +16,7 @@ class Swift56Test extends Base 'cp tests/languages/swift/Tests.swift tests/sdks/swift/Tests/AppwriteTests/Tests.swift', ]; protected string $command = - 'docker run --network="mockapi" --rm -v $(pwd):/app -w /app/tests/sdks/swift swift:5.6 swift test'; + 'docker run --network="mockapi" --rm -v $(pwd):/app -w /app/tests/sdks/swift swift:5.6-focal swift test'; protected array $expectedOutput = [ ...Base::FOO_RESPONSES, From fd89ec2698e041609ae65ae70412df45298e0a6f Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 15 Feb 2024 01:09:42 +1300 Subject: [PATCH 18/20] Fix ordered tests --- tests/Base.php | 4 ++++ tests/Go112Test.php | 1 + tests/WebNodeTest.php | 2 +- tests/languages/kotlin/Tests.kt | 3 --- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/Base.php b/tests/Base.php index 00af48a99..7d8dc0392 100644 --- a/tests/Base.php +++ b/tests/Base.php @@ -49,6 +49,10 @@ abstract class Base extends TestCase 'POST:/v1/mock/tests/general/enum:passed', ]; + protected const UPLOAD_RESPONSE = [ + 'POST:/v1/mock/tests/general/upload:passed', + ]; + protected const UPLOAD_RESPONSES = [ 'POST:/v1/mock/tests/general/upload:passed', 'POST:/v1/mock/tests/general/upload:passed', diff --git a/tests/Go112Test.php b/tests/Go112Test.php index 58b2a0898..ab3e11601 100644 --- a/tests/Go112Test.php +++ b/tests/Go112Test.php @@ -21,6 +21,7 @@ class Go112Test extends Base ...Base::FOO_RESPONSES, ...Base::BAR_RESPONSES, ...Base::GENERAL_RESPONSES, + ...Base::UPLOAD_RESPONSE, ...Base::DOWNLOAD_RESPONSES, ...Base::EXCEPTION_RESPONSES, ]; diff --git a/tests/WebNodeTest.php b/tests/WebNodeTest.php index fd9a4e03f..afeb0eb8b 100644 --- a/tests/WebNodeTest.php +++ b/tests/WebNodeTest.php @@ -25,8 +25,8 @@ class WebNodeTest extends Base ...Base::FOO_RESPONSES, ...Base::BAR_RESPONSES, ...Base::GENERAL_RESPONSES, - ...Base::ENUM_RESPONSES, ...Base::UPLOAD_RESPONSES, + ...Base::ENUM_RESPONSES, ...Base::EXCEPTION_RESPONSES, ...Base::REALTIME_RESPONSES, ...Base::QUERY_HELPER_RESPONSES, diff --git a/tests/languages/kotlin/Tests.kt b/tests/languages/kotlin/Tests.kt index 890ededb2..2aff972de 100644 --- a/tests/languages/kotlin/Tests.kt +++ b/tests/languages/kotlin/Tests.kt @@ -74,9 +74,6 @@ class ServiceTest { val result = general.redirect() writeToFile((result as Map)["result"] as String) - mock = general.enum(MockType.FIRST) - writeToFile(mock.result) - try { mock = general.upload("string", 123, listOf("string in array"), InputFile.fromPath("../../resources/file.png")) writeToFile(mock.result) From 72b8f72c0a46939c4e95d78a7bee49cb0fe0d0ac Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 15 Feb 2024 01:11:02 +1300 Subject: [PATCH 19/20] Fix go 118 test --- tests/Go118Test.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Go118Test.php b/tests/Go118Test.php index 70e03f069..3b21030f0 100644 --- a/tests/Go118Test.php +++ b/tests/Go118Test.php @@ -21,6 +21,7 @@ class Go118Test extends Base ...Base::FOO_RESPONSES, ...Base::BAR_RESPONSES, ...Base::GENERAL_RESPONSES, + ...Base::UPLOAD_RESPONSE, ...Base::DOWNLOAD_RESPONSES, ...Base::EXCEPTION_RESPONSES, ]; From d7db297cd27119e80a24649cc85b9a9d879242be Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 15 Feb 2024 01:29:50 +1300 Subject: [PATCH 20/20] Remove redundant notification packages --- src/SDK/Language/Apple.php | 10 - templates/apple/Package.swift.twig | 2 - templates/apple/Sources/Client.swift.twig | 16 - templates/swift/Sources/Delegate.swift.twig | 4 - .../Sources/NotificationHandler.swift.twig | 275 ------------------ 5 files changed, 307 deletions(-) delete mode 100644 templates/swift/Sources/Delegate.swift.twig delete mode 100644 templates/swift/Sources/NotificationHandler.swift.twig diff --git a/src/SDK/Language/Apple.php b/src/SDK/Language/Apple.php index 7ecb6c626..9beff4b80 100644 --- a/src/SDK/Language/Apple.php +++ b/src/SDK/Language/Apple.php @@ -246,16 +246,6 @@ public function getFiles(): array 'destination' => '/Sources/{{ spec.title | caseUcfirst}}/WebSockets/WebSocketClientError.swift', 'template' => '/swift/Sources/WebSockets/WebSocketClientError.swift.twig', ], - [ - 'scope' => 'default', - 'destination' => '/Sources/{{ spec.title | caseUcfirst}}/{{ spec.title | caseUcfirst }}Delegate.swift', - 'template' => '/swift/Sources/Delegate.swift.twig', - ], - [ - 'scope' => 'default', - 'destination' => '/Sources/{{ spec.title | caseUcfirst}}/NotificationHandler.swift', - 'template' => '/swift/Sources/NotificationHandler.swift.twig', - ], // Config for project example-swiftui [ 'scope' => 'default', diff --git a/templates/apple/Package.swift.twig b/templates/apple/Package.swift.twig index 7a1a09a3d..132ae387f 100644 --- a/templates/apple/Package.swift.twig +++ b/templates/apple/Package.swift.twig @@ -24,7 +24,6 @@ let package = Package( dependencies: [ .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.9.0"), .package(url: "https://github.com/apple/swift-nio.git", from: "2.32.0"), - .package(url: "https://github.com/firebase/firebase-ios-sdk.git", from: "10.4.0") ], targets: [ .target( @@ -32,7 +31,6 @@ let package = Package( dependencies: [ .product(name: "AsyncHTTPClient", package: "async-http-client"), .product(name: "NIOWebSocket", package: "swift-nio"), - .product(name: "FirebaseMessaging", package: "firebase-ios-sdk"), {%~ if spec.definitions is not empty %} "{{spec.title | caseUcfirst}}Models", {%~ endif %} diff --git a/templates/apple/Sources/Client.swift.twig b/templates/apple/Sources/Client.swift.twig index 7a07a5a83..54db98633 100644 --- a/templates/apple/Sources/Client.swift.twig +++ b/templates/apple/Sources/Client.swift.twig @@ -53,8 +53,6 @@ open class Client { http = Client.createHTTP() addUserAgentHeader() addOriginHeader() - - NotificationHandler.shared.client = self } private static func createHTTP( @@ -88,7 +86,6 @@ open class Client { decompression: .enabled(limit: .none) ) ) - } deinit { @@ -165,19 +162,6 @@ open class Client { return self } - /// - /// Set push provider ID. - /// - /// @param String endpoint - /// - /// @return this - /// - open func setPushProviderId(_ providerId: String) -> Client { - NotificationHandler.shared.providerId = providerId - - return self - } - /// /// Add header /// diff --git a/templates/swift/Sources/Delegate.swift.twig b/templates/swift/Sources/Delegate.swift.twig deleted file mode 100644 index fad2d1f23..000000000 --- a/templates/swift/Sources/Delegate.swift.twig +++ /dev/null @@ -1,4 +0,0 @@ -import SwiftUI -import FirebaseMessaging - -@objc public protocol AppwriteDelegate: UNUserNotificationCenterDelegate, MessagingDelegate {} diff --git a/templates/swift/Sources/NotificationHandler.swift.twig b/templates/swift/Sources/NotificationHandler.swift.twig deleted file mode 100644 index 9fb79fcf2..000000000 --- a/templates/swift/Sources/NotificationHandler.swift.twig +++ /dev/null @@ -1,275 +0,0 @@ -import JSONCodable -import FirebaseCore -import FirebaseMessaging -import AsyncHTTPClient - -#if os(iOS) || os(tvOS) -import UIKit -public typealias Application = UIApplication -#elseif os(macOS) -import AppKit -public typealias Application = NSApplication -#elseif os(watchOS) -import WatchKit -public typealias Application = WKApplication -#endif - -public enum Provider { - case fcm, apns -} - -open class NotificationHandler { - public static let shared = NotificationHandler() - - internal var provider: Provider = .apns - internal var client: Client? = nil - internal var account: Account? = nil - internal var providerId: String? = nil - - public func setup( - _ application: Application, - delegate: AppwriteDelegate, - provider: Provider - ) { - self.provider = provider - - FirebaseApp.configure() - - FirebaseMessaging.Messaging.messaging().delegate = delegate - - UNUserNotificationCenter.current().delegate = delegate - - NotificationCenter.default.addObserver( - self, - selector: #selector(tokenRefreshNotification), - name: Notification.Name.MessagingRegistrationTokenRefreshed, - object: nil - ) - - Client.cookieListener = { (existing, new) in - let group = DispatchGroup() - - group.enter() - - Task { - guard let token = try? await FirebaseMessaging.Messaging.messaging().token() else { - return - } - - await self.updateTarget( - existingCookies: existing, - newCookies: new, - token: token - ) - - group.leave() - } - - group.wait() - } - - let options: UNAuthorizationOptions = [.alert, .badge, .sound] - - UNUserNotificationCenter.current().requestAuthorization( - options: options, - completionHandler: { granted, error in - if (granted) { - DispatchQueue.main.async { - application.registerForRemoteNotifications() - } - } - } - ) - } - - @objc func tokenRefreshNotification(_ notification: Notification) { - guard let token = notification.object as? String else { - return - } - - handleFCMToken(token) - } - - public func handleAPNSToken(_ token: Data) { - switch (provider) { - case .fcm: - FirebaseMessaging.Messaging.messaging().apnsToken = token - case .apns: - Task { - await self.updateTarget( - existingCookies: [], - newCookies: [], - token: token.map { String(format: "%.2hhx", $0) }.joined() - - ) - } - } - } - - public func handleFCMToken(_ token: String) { - Task { - await self.updateTarget( - existingCookies: [], - newCookies: [], - token: token - ) - } - } - - public func updateTarget( - existingCookies: [String], - newCookies: [String], - token: String - ) async { - if (client == nil) { - return - } - - if (account == nil) { - account = Account(client!) - } - - let currentToken = UserDefaults.standard.string(forKey: "pushToken") - var currentTargetId = UserDefaults.standard.string(forKey: "targetId") ?? "" - - var existing = [String]() - if (existingCookies.isEmpty) { - let domain = URL(string: client!.endPoint)!.host! - let cookies = UserDefaults.standard.stringArray(forKey: domain) ?? [] - - cookies.forEach { - existing.append($0) - } - } - - var existingUser: [String: Any]? = nil - if (existing.isEmpty && !newCookies.isEmpty) { - existingUser = try? await request( - method: "GET", - path: "/account", - headers: ["cookie": newCookies.joined(separator: "; ")] - ) - } else if (!existing.isEmpty) { - existingUser = try? await request( - method: "GET", - path: "/account", - headers: ["cookie": existingCookies.joined(separator: "; ")] - ) - } - - if (existingUser == nil) { - return - } - - var newUser: [String: Any]? = nil - if (!newCookies.isEmpty) { - newUser = try? await request( - method: "GET", - path: "/account", - headers: ["cookie": newCookies.joined(separator: "; ")] - ) - } - - let existingUserId = existingUser?["$id"] as? String - let newUserId = newUser?["$id"] as? String - - if ( - token == currentToken - && (!existingCookies.isEmpty && existingUserId == newUserId) - ) { - return - } - - UserDefaults.standard.set(token, forKey: "pushToken") - - if (!existing.isEmpty && existingUserId != newUserId) { - if (!currentTargetId.isEmpty) { - let result = try? await request( - method: "DELETE", - path: "/account/targets/$currentTargetId/push", - headers: ["cookie": existing.joined(separator: "; ")] - ) - - if (result == nil) { - return - } - - UserDefaults.standard.removeObject(forKey: "targetId") - currentTargetId = "" - } - } - - let target: [String: Any]? - - var params = [ - "targetId": ID.unique(), - "identifier": token - ] - - if (providerId != nil) { - params["providerId"] = providerId! - } - - if ((currentTargetId.isEmpty && existing.isEmpty) || existingUserId != newUserId) { - target = try? await request( - method: "POST", - path: "/account/targets/push", - headers: ["cookie": newCookies.joined(separator: "; ")], - body: params - ) - } else { - target = try? await request( - method: "POST", - path: "/account/targets/push", - headers: ["cookie": existing.joined(separator: "; ")], - body: params - ) - } - - if (target == nil) { - return - } - - UserDefaults.standard.set(target?["$id"] ?? "", forKey: "targetId") - } - - private func request( - method: String, - path: String, - headers: [String: String], - body: [String: Any]? = nil - ) async throws -> [String: Any]? { - var request = HTTPClientRequest(url: client!.endPoint + path) - - request.method = .RAW(value: method) - - for (key, value) in client!.headers.merging(headers, uniquingKeysWith: { $1 }) { - request.headers.add(name: key, value: value) - } - - if (body != nil) { - guard let json = try? JSONSerialization.data(withJSONObject: body!, options: []) else { - return nil - } - - request.body = .bytes(json) - } - - guard let response = try? await client!.http.execute( - request, - timeout: .seconds(30) - ) else { - return nil - } - - guard let data = try? await response.body.collect(upTo: Int.max) else { - return nil - } - - guard let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - return nil - } - - return dict - } -}