Merge pull request #107 from appwrite/dev

feat: Apple SDK update for version 15.0.0
This commit is contained in:
ArnabChatterjee20k
2026-03-03 16:49:31 +05:30
committed by GitHub
10 changed files with 65 additions and 43 deletions
+5 -4
View File
@@ -1,10 +1,11 @@
# Change Log
## 14.3.0
## 15.0.0
* Added upsert() support for RealtimeChannel on both Document and Row variants to perform upsert operations over real-time channels.
* Introduced new Query filter methods: contains(_:, value:), containsAny(_:, value: [Any]), containsAll(_:, value: [Any]) for enhanced querying capabilities (substring and multi-value containment).
* Documentation and packaging updates to align with the new release: README dependency example updated from 14.2.0 to 14.1.0, and server compatibility note updated to indicate Appwrite server version 1.8.x compatibility.
* Breaking: RealtimeChannel API required explicit IDs and threw errors.
* Added ttl parameter to listDocuments and listRows.
* Updated compatibility notes to latest server and SDK version.
* Updated Document and Row comments for clarity.
## 14.1.0
+2 -2
View File
@@ -7,7 +7,7 @@
[![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord)
**This SDK is compatible with Appwrite server version 1.8.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-apple/releases).**
**This SDK is compatible with Appwrite server version latest. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-apple/releases).**
Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Apple SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)
@@ -31,7 +31,7 @@ Add the package to your `Package.swift` dependencies:
```swift
dependencies: [
.package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "14.3.0"),
.package(url: "git@github.com:appwrite/sdk-for-apple.git", from: "15.0.0"),
],
```
+35 -28
View File
@@ -16,10 +16,17 @@ public struct _Team {}
public struct _Membership {}
public struct _Resolved {}
public enum ChannelValidationError: Swift.Error {
case invalidID
}
// Helper for normalizing IDs
private func normalize(_ id: String) -> String {
private func normalize(_ id: String) throws -> String {
let trimmed = id.trimmingCharacters(in: .whitespacesAndNewlines)
return trimmed.isEmpty ? "*" : trimmed
guard !trimmed.isEmpty else {
throw ChannelValidationError.invalidID
}
return trimmed
}
/// Channel class with generic type parameter for type-safe method chaining
@@ -31,9 +38,9 @@ public class RealtimeChannel<T> {
}
/// Internal helper to transition to next state with segment and optional ID
internal func next<N>(_ segment: String, _ id: String? = nil) -> RealtimeChannel<N> {
internal func next<N>(_ segment: String, _ id: String? = nil) throws -> RealtimeChannel<N> {
if let id = id {
return RealtimeChannel<N>(segments + [segment, normalize(id)])
return RealtimeChannel<N>(segments + [segment, try normalize(id)])
}
return RealtimeChannel<N>(segments + [segment])
@@ -55,32 +62,32 @@ public enum Channel {
// MARK: - Root Factories
public static func database(_ id: String = "*") -> RealtimeChannel<_Database> {
return RealtimeChannel<_Database>(["databases", normalize(id)])
public static func database(_ id: String) throws -> RealtimeChannel<_Database> {
return RealtimeChannel<_Database>(["databases", try normalize(id)])
}
public static func tablesdb(_ id: String = "*") -> RealtimeChannel<_TablesDB> {
return RealtimeChannel<_TablesDB>(["tablesdb", normalize(id)])
public static func tablesdb(_ id: String) throws -> RealtimeChannel<_TablesDB> {
return RealtimeChannel<_TablesDB>(["tablesdb", try normalize(id)])
}
public static func bucket(_ id: String = "*") -> RealtimeChannel<_Bucket> {
return RealtimeChannel<_Bucket>(["buckets", normalize(id)])
public static func bucket(_ id: String) throws -> RealtimeChannel<_Bucket> {
return RealtimeChannel<_Bucket>(["buckets", try normalize(id)])
}
public static func function(_ id: String = "*") -> RealtimeChannel<_Func> {
return RealtimeChannel<_Func>(["functions", normalize(id)])
public static func function(_ id: String) throws -> RealtimeChannel<_Func> {
return RealtimeChannel<_Func>(["functions", try normalize(id)])
}
public static func execution(_ id: String = "*") -> RealtimeChannel<_Execution> {
return RealtimeChannel<_Execution>(["executions", normalize(id)])
public static func execution(_ id: String) throws -> RealtimeChannel<_Execution> {
return RealtimeChannel<_Execution>(["executions", try normalize(id)])
}
public static func team(_ id: String = "*") -> RealtimeChannel<_Team> {
return RealtimeChannel<_Team>(["teams", normalize(id)])
public static func team(_ id: String) throws -> RealtimeChannel<_Team> {
return RealtimeChannel<_Team>(["teams", try normalize(id)])
}
public static func membership(_ id: String = "*") -> RealtimeChannel<_Membership> {
return RealtimeChannel<_Membership>(["memberships", normalize(id)])
public static func membership(_ id: String) throws -> RealtimeChannel<_Membership> {
return RealtimeChannel<_Membership>(["memberships", try normalize(id)])
}
public static func account() -> String {
@@ -101,15 +108,15 @@ public enum Channel {
/// Only available on RealtimeChannel<_Database>
extension RealtimeChannel where T == _Database {
public func collection(_ id: String? = nil) -> RealtimeChannel<_Collection> {
return self.next("collections", id ?? "*")
public func collection(_ id: String) throws -> RealtimeChannel<_Collection> {
return try self.next("collections", id)
}
}
/// Only available on RealtimeChannel<_Collection>
extension RealtimeChannel where T == _Collection {
public func document(_ id: String? = nil) -> RealtimeChannel<_Document> {
return self.next("documents", id)
public func document(_ id: String? = nil) throws -> RealtimeChannel<_Document> {
return try self.next("documents", id)
}
}
@@ -117,15 +124,15 @@ extension RealtimeChannel where T == _Collection {
/// Only available on RealtimeChannel<_TablesDB>
extension RealtimeChannel where T == _TablesDB {
public func table(_ id: String? = nil) -> RealtimeChannel<_Table> {
return self.next("tables", id ?? "*")
public func table(_ id: String) throws -> RealtimeChannel<_Table> {
return try self.next("tables", id)
}
}
/// Only available on RealtimeChannel<_Table>
extension RealtimeChannel where T == _Table {
public func row(_ id: String? = nil) -> RealtimeChannel<_Row> {
return self.next("rows", id)
public func row(_ id: String? = nil) throws -> RealtimeChannel<_Row> {
return try self.next("rows", id)
}
}
@@ -133,8 +140,8 @@ extension RealtimeChannel where T == _Table {
/// Only available on RealtimeChannel<_Bucket>
extension RealtimeChannel where T == _Bucket {
public func file(_ id: String? = nil) -> RealtimeChannel<_File> {
return self.next("files", id)
public func file(_ id: String? = nil) throws -> RealtimeChannel<_File> {
return try self.next("files", id)
}
}
+1 -1
View File
@@ -24,7 +24,7 @@ open class Client {
"x-sdk-name": "Apple",
"x-sdk-platform": "client",
"x-sdk-language": "apple",
"x-sdk-version": "14.3.0",
"x-sdk-version": "15.0.0",
"x-appwrite-response-format": "1.8.0"
]
+8 -2
View File
@@ -219,6 +219,7 @@ open class Databases: Service {
/// - queries: [String] (optional)
/// - transactionId: String (optional)
/// - total: Bool (optional)
/// - ttl: Int (optional)
/// - Throws: Exception if the request fails
/// - Returns: AppwriteModels.DocumentList<T>
///
@@ -229,6 +230,7 @@ open class Databases: Service {
queries: [String]? = nil,
transactionId: String? = nil,
total: Bool? = nil,
ttl: Int? = nil,
nestedType: T.Type
) async throws -> AppwriteModels.DocumentList<T> {
let apiPath: String = "/databases/{databaseId}/collections/{collectionId}/documents"
@@ -238,7 +240,8 @@ open class Databases: Service {
let apiParams: [String: Any?] = [
"queries": queries,
"transactionId": transactionId,
"total": total
"total": total,
"ttl": ttl
]
let apiHeaders: [String: String] = [:]
@@ -266,6 +269,7 @@ open class Databases: Service {
/// - queries: [String] (optional)
/// - transactionId: String (optional)
/// - total: Bool (optional)
/// - ttl: Int (optional)
/// - Throws: Exception if the request fails
/// - Returns: AppwriteModels.DocumentList<T>
///
@@ -275,7 +279,8 @@ open class Databases: Service {
collectionId: String,
queries: [String]? = nil,
transactionId: String? = nil,
total: Bool? = nil
total: Bool? = nil,
ttl: Int? = nil
) async throws -> AppwriteModels.DocumentList<[String: AnyCodable]> {
return try await listDocuments(
databaseId: databaseId,
@@ -283,6 +288,7 @@ open class Databases: Service {
queries: queries,
transactionId: transactionId,
total: total,
ttl: ttl,
nestedType: [String: AnyCodable].self
)
}
+8 -2
View File
@@ -219,6 +219,7 @@ open class TablesDB: Service {
/// - queries: [String] (optional)
/// - transactionId: String (optional)
/// - total: Bool (optional)
/// - ttl: Int (optional)
/// - Throws: Exception if the request fails
/// - Returns: AppwriteModels.RowList<T>
///
@@ -228,6 +229,7 @@ open class TablesDB: Service {
queries: [String]? = nil,
transactionId: String? = nil,
total: Bool? = nil,
ttl: Int? = nil,
nestedType: T.Type
) async throws -> AppwriteModels.RowList<T> {
let apiPath: String = "/tablesdb/{databaseId}/tables/{tableId}/rows"
@@ -237,7 +239,8 @@ open class TablesDB: Service {
let apiParams: [String: Any?] = [
"queries": queries,
"transactionId": transactionId,
"total": total
"total": total,
"ttl": ttl
]
let apiHeaders: [String: String] = [:]
@@ -265,6 +268,7 @@ open class TablesDB: Service {
/// - queries: [String] (optional)
/// - transactionId: String (optional)
/// - total: Bool (optional)
/// - ttl: Int (optional)
/// - Throws: Exception if the request fails
/// - Returns: AppwriteModels.RowList<T>
///
@@ -273,7 +277,8 @@ open class TablesDB: Service {
tableId: String,
queries: [String]? = nil,
transactionId: String? = nil,
total: Bool? = nil
total: Bool? = nil,
ttl: Int? = nil
) async throws -> AppwriteModels.RowList<[String: AnyCodable]> {
return try await listRows(
databaseId: databaseId,
@@ -281,6 +286,7 @@ open class TablesDB: Service {
queries: queries,
transactionId: transactionId,
total: total,
ttl: ttl,
nestedType: [String: AnyCodable].self
)
}
+1 -1
View File
@@ -17,7 +17,7 @@ open class Document<T : Codable>: Codable {
/// Document ID.
public let id: String
/// Document automatically incrementing ID.
/// Document sequence ID.
public let sequence: Int
/// Collection ID.
public let collectionId: String
+1 -1
View File
@@ -17,7 +17,7 @@ open class Row<T : Codable>: Codable {
/// Row ID.
public let id: String
/// Row automatically incrementing ID.
/// Row sequence ID.
public let sequence: Int
/// Table ID.
public let tableId: String
+2 -1
View File
@@ -12,7 +12,8 @@ let documentList = try await databases.listDocuments(
collectionId: "<COLLECTION_ID>",
queries: [], // optional
transactionId: "<TRANSACTION_ID>", // optional
total: false // optional
total: false, // optional
ttl: 0 // optional
)
```
+2 -1
View File
@@ -12,7 +12,8 @@ let rowList = try await tablesDB.listRows(
tableId: "<TABLE_ID>",
queries: [], // optional
transactionId: "<TRANSACTION_ID>", // optional
total: false // optional
total: false, // optional
ttl: 0 // optional
)
```