diff --git a/README.md b/README.md index 417f505..7de6f65 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![Swift Package Manager](https://img.shields.io/github/v/release/appwrite/sdk-for-swift.svg?color=green&style=flat-square) ![License](https://img.shields.io/github/license/appwrite/sdk-for-swift.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-1.7.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-1.7.4-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![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) @@ -33,7 +33,7 @@ Add the package to your `Package.swift` dependencies: ```swift dependencies: [ - .package(url: "git@github.com:appwrite/sdk-for-swift.git", from: "10.0.0"), + .package(url: "git@github.com:appwrite/sdk-for-swift.git", from: "10.1.0"), ], ``` diff --git a/Sources/Appwrite/Client.swift b/Sources/Appwrite/Client.swift index 3829171..0436599 100644 --- a/Sources/Appwrite/Client.swift +++ b/Sources/Appwrite/Client.swift @@ -21,7 +21,7 @@ open class Client { "x-sdk-name": "Swift", "x-sdk-platform": "server", "x-sdk-language": "swift", - "x-sdk-version": "10.0.0", + "x-sdk-version": "10.1.0", "x-appwrite-response-format": "1.7.0" ] @@ -257,7 +257,7 @@ open class Client { return output.addingPercentEncoding( withAllowedCharacters: .urlHostAllowed - ) ?? "" + )?.replacingOccurrences(of: "+", with: "%2B") ?? "" // since urlHostAllowed doesn't include + } /// diff --git a/Sources/Appwrite/Services/Databases.swift b/Sources/Appwrite/Services/Databases.swift index eb40d2a..aae760f 100644 --- a/Sources/Appwrite/Services/Databases.swift +++ b/Sources/Appwrite/Services/Databases.swift @@ -1656,6 +1656,10 @@ open class Databases: Service { } /// + /// **WARNING: Experimental Feature** - This endpoint is experimental and not + /// yet officially supported. It may be subject to breaking changes or removal + /// in future versions. + /// /// Create new Documents. Before using this route, you should create a new /// collection resource using either a [server /// integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) @@ -1699,6 +1703,10 @@ open class Databases: Service { } /// + /// **WARNING: Experimental Feature** - This endpoint is experimental and not + /// yet officially supported. It may be subject to breaking changes or removal + /// in future versions. + /// /// Create new Documents. Before using this route, you should create a new /// collection resource using either a [server /// integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) @@ -1724,6 +1732,10 @@ open class Databases: Service { } /// + /// **WARNING: Experimental Feature** - This endpoint is experimental and not + /// yet officially supported. It may be subject to breaking changes or removal + /// in future versions. + /// /// Create or update Documents. Before using this route, you should create a /// new collection resource using either a [server /// integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) @@ -1768,6 +1780,10 @@ open class Databases: Service { } /// + /// **WARNING: Experimental Feature** - This endpoint is experimental and not + /// yet officially supported. It may be subject to breaking changes or removal + /// in future versions. + /// /// Create or update Documents. Before using this route, you should create a /// new collection resource using either a [server /// integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) @@ -1866,6 +1882,10 @@ open class Databases: Service { } /// + /// **WARNING: Experimental Feature** - This endpoint is experimental and not + /// yet officially supported. It may be subject to breaking changes or removal + /// in future versions. + /// /// Bulk delete documents using queries, if no queries are passed then all /// documents are deleted. /// @@ -1907,6 +1927,10 @@ open class Databases: Service { } /// + /// **WARNING: Experimental Feature** - This endpoint is experimental and not + /// yet officially supported. It may be subject to breaking changes or removal + /// in future versions. + /// /// Bulk delete documents using queries, if no queries are passed then all /// documents are deleted. /// @@ -1997,6 +2021,94 @@ open class Databases: Service { ) } + /// + /// **WARNING: Experimental Feature** - This endpoint is experimental and not + /// yet officially supported. It may be subject to breaking changes or removal + /// in future versions. + /// + /// Create or update a Document. Before using this route, you should create a + /// new collection resource using either a [server + /// integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) + /// API or directly from your database console. + /// + /// @param String databaseId + /// @param String collectionId + /// @param String documentId + /// @param Any data + /// @param [String] permissions + /// @throws Exception + /// @return array + /// + open func upsertDocument( + databaseId: String, + collectionId: String, + documentId: String, + data: Any, + permissions: [String]? = nil, + nestedType: T.Type + ) async throws -> AppwriteModels.Document { + let apiPath: String = "/databases/{databaseId}/collections/{collectionId}/documents/{documentId}" + .replacingOccurrences(of: "{databaseId}", with: databaseId) + .replacingOccurrences(of: "{collectionId}", with: collectionId) + .replacingOccurrences(of: "{documentId}", with: documentId) + + let apiParams: [String: Any?] = [ + "data": data, + "permissions": permissions + ] + + let apiHeaders: [String: String] = [ + "content-type": "application/json" + ] + + let converter: (Any) -> AppwriteModels.Document = { response in + return AppwriteModels.Document.from(map: response as! [String: Any]) + } + + return try await client.call( + method: "PUT", + path: apiPath, + headers: apiHeaders, + params: apiParams, + converter: converter + ) + } + + /// + /// **WARNING: Experimental Feature** - This endpoint is experimental and not + /// yet officially supported. It may be subject to breaking changes or removal + /// in future versions. + /// + /// Create or update a Document. Before using this route, you should create a + /// new collection resource using either a [server + /// integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) + /// API or directly from your database console. + /// + /// @param String databaseId + /// @param String collectionId + /// @param String documentId + /// @param Any data + /// @param [String] permissions + /// @throws Exception + /// @return array + /// + open func upsertDocument( + databaseId: String, + collectionId: String, + documentId: String, + data: Any, + permissions: [String]? = nil + ) async throws -> AppwriteModels.Document<[String: AnyCodable]> { + return try await upsertDocument( + databaseId: databaseId, + collectionId: collectionId, + documentId: documentId, + data: data, + permissions: permissions, + nestedType: [String: AnyCodable].self + ) + } + /// /// Update a document by its unique ID. Using the patch method you can pass /// only specific fields that will get updated. diff --git a/Sources/Appwrite/Services/Tokens.swift b/Sources/Appwrite/Services/Tokens.swift index 223a2a5..b579e0f 100644 --- a/Sources/Appwrite/Services/Tokens.swift +++ b/Sources/Appwrite/Services/Tokens.swift @@ -48,7 +48,7 @@ open class Tokens: Service { /// /// Create a new token. A token is linked to a file. Token can be passed as a - /// header or request get parameter. + /// request URL search parameter. /// /// @param String bucketId /// @param String fileId diff --git a/Sources/AppwriteModels/AttributeList.swift b/Sources/AppwriteModels/AttributeList.swift index 2116477..8789c6c 100644 --- a/Sources/AppwriteModels/AttributeList.swift +++ b/Sources/AppwriteModels/AttributeList.swift @@ -48,7 +48,7 @@ open class AttributeList: Codable { public static func from(map: [String: Any] ) -> AttributeList { return AttributeList( total: map["total"] as! Int, - attributes: map["attributes"] as! [AnyCodable] + attributes: (map["attributes"] as! [Any]).map { AnyCodable($0) } ) } } diff --git a/Sources/AppwriteModels/AttributeString.swift b/Sources/AppwriteModels/AttributeString.swift index 5aeead7..9ed9acc 100644 --- a/Sources/AppwriteModels/AttributeString.swift +++ b/Sources/AppwriteModels/AttributeString.swift @@ -15,6 +15,7 @@ open class AttributeString: Codable { case updatedAt = "$updatedAt" case size = "size" case `default` = "default" + case encrypt = "encrypt" } /// Attribute Key. @@ -47,6 +48,9 @@ open class AttributeString: Codable { /// Default value for attribute when not provided. Cannot be set when attribute is required. public let `default`: String? + /// Defines whether this attribute is encrypted or not. + public let encrypt: Bool? + init( key: String, @@ -58,7 +62,8 @@ open class AttributeString: Codable { createdAt: String, updatedAt: String, size: Int, - `default`: String? + `default`: String?, + encrypt: Bool? ) { self.key = key self.type = type @@ -70,6 +75,7 @@ open class AttributeString: Codable { self.updatedAt = updatedAt self.size = size self.`default` = `default` + self.encrypt = encrypt } public required init(from decoder: Decoder) throws { @@ -85,6 +91,7 @@ open class AttributeString: Codable { self.updatedAt = try container.decode(String.self, forKey: .updatedAt) self.size = try container.decode(Int.self, forKey: .size) self.`default` = try container.decodeIfPresent(String.self, forKey: .`default`) + self.encrypt = try container.decodeIfPresent(Bool.self, forKey: .encrypt) } public func encode(to encoder: Encoder) throws { @@ -100,6 +107,7 @@ open class AttributeString: Codable { try container.encode(updatedAt, forKey: .updatedAt) try container.encode(size, forKey: .size) try container.encodeIfPresent(`default`, forKey: .`default`) + try container.encodeIfPresent(encrypt, forKey: .encrypt) } public func toMap() -> [String: Any] { @@ -113,7 +121,8 @@ open class AttributeString: Codable { "$createdAt": createdAt as Any, "$updatedAt": updatedAt as Any, "size": size as Any, - "`default`": `default` as Any + "`default`": `default` as Any, + "encrypt": encrypt as Any ] } @@ -128,7 +137,8 @@ open class AttributeString: Codable { createdAt: map["$createdAt"] as! String, updatedAt: map["$updatedAt"] as! String, size: map["size"] as! Int, - `default`: map["default"] as? String + `default`: map["default"] as? String, + encrypt: map["encrypt"] as? Bool ) } } diff --git a/Sources/AppwriteModels/Collection.swift b/Sources/AppwriteModels/Collection.swift index 548af2f..ad7ab94 100644 --- a/Sources/AppwriteModels/Collection.swift +++ b/Sources/AppwriteModels/Collection.swift @@ -127,7 +127,7 @@ open class Collection: Codable { name: map["name"] as! String, enabled: map["enabled"] as! Bool, documentSecurity: map["documentSecurity"] as! Bool, - attributes: map["attributes"] as! [AnyCodable], + attributes: (map["attributes"] as! [Any]).map { AnyCodable($0) }, indexes: (map["indexes"] as! [[String: Any]]).map { Index.from(map: $0) } ) } diff --git a/Sources/AppwriteModels/Document.swift b/Sources/AppwriteModels/Document.swift index a1c0326..744a03e 100644 --- a/Sources/AppwriteModels/Document.swift +++ b/Sources/AppwriteModels/Document.swift @@ -91,12 +91,12 @@ open class Document: Codable { public static func from(map: [String: Any] ) -> Document { return Document( - id: map["$id"] as! String, - collectionId: map["$collectionId"] as! String, - databaseId: map["$databaseId"] as! String, - createdAt: map["$createdAt"] as! String, - updatedAt: map["$updatedAt"] as! String, - permissions: map["$permissions"] as! [String], + id: map["$id"] as? String ?? "", + collectionId: map["$collectionId"] as? String ?? "", + databaseId: map["$databaseId"] as? String ?? "", + createdAt: map["$createdAt"] as? String ?? "", + updatedAt: map["$updatedAt"] as? String ?? "", + permissions: map["$permissions"] as? [String] ?? [], data: try! JSONDecoder().decode(T.self, from: JSONSerialization.data(withJSONObject: map, options: [])) ) } diff --git a/docs/examples/databases/upsert-document.md b/docs/examples/databases/upsert-document.md new file mode 100644 index 0000000..e78bd45 --- /dev/null +++ b/docs/examples/databases/upsert-document.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setSession("") // The user session to authenticate with + +let databases = Databases(client) + +let document = try await databases.upsertDocument( + databaseId: "", + collectionId: "", + documentId: "", + data: [:], + permissions: ["read("any")"] // optional +) +