Skip to content

Commit 6025944

Browse files
authored
Merge Bunch of secondary features #9
2 parents 5805d86 + b503ffe commit 6025944

18 files changed

+942
-68
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import PackageDescription
66
let package = Package(
77
name: "Typesense",
88
platforms: [
9-
.iOS(.v15), .macOS(.v12)
9+
.iOS(.v13), .macOS(.v12)
1010
],
1111
products: [
1212
// Products define the executables and libraries a package produces, and make them visible to other packages.

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,16 @@ sh get-models.sh
9292
```
9393

9494
The generated Models (inside the Models directory) are to be used inside the Models directory of the source code as well. Models need to be generated as and when the [Typesense-Api-Spec](https://github.com/typesense/typesense-api-spec) is updated.
95+
96+
## TODO: Features
97+
98+
- Curation API
99+
- Multisearch
100+
- Dealing with Dirty Data
101+
- Scoped Search Key
102+
103+
## TODO: Testing
104+
105+
- Geosearch
106+
- Auto schema detection
107+
- Importing a .jsonl file

Sources/Typesense/Alias.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import Foundation
2+
3+
public struct Alias {
4+
var apiCall: ApiCall
5+
let RESOURCEPATH = "aliases"
6+
var config: Configuration
7+
8+
public init(config: Configuration) {
9+
apiCall = ApiCall(config: config)
10+
self.config = config
11+
}
12+
13+
public func upsert(name: String, collection: CollectionAliasSchema) async throws -> (CollectionAlias?, URLResponse?) {
14+
let schemaData: Data?
15+
16+
schemaData = try encoder.encode(collection)
17+
18+
if let validSchema = schemaData {
19+
let (data, response) = try await apiCall.put(endPoint: "\(RESOURCEPATH)/\(name)", body: validSchema)
20+
if let result = data {
21+
let alias = try decoder.decode(CollectionAlias.self, from: result)
22+
return (alias, response)
23+
}
24+
}
25+
return (nil, nil)
26+
}
27+
28+
public func retrieve(name: String) async throws -> (CollectionAlias?, URLResponse?) {
29+
let (data, response) = try await apiCall.get(endPoint: "\(RESOURCEPATH)/\(name)")
30+
if let result = data {
31+
if let notExists = try? decoder.decode(ApiResponse.self, from: result) {
32+
throw ResponseError.aliasNotFound(desc: "Alias \(notExists.message)")
33+
}
34+
let alias = try decoder.decode(CollectionAlias.self, from: result)
35+
return (alias, response)
36+
}
37+
return (nil, nil)
38+
}
39+
40+
public func retrieve() async throws -> (CollectionAliasesResponse?, URLResponse?) {
41+
let (data, response) = try await apiCall.get(endPoint: "\(RESOURCEPATH)")
42+
if let result = data {
43+
let aliases = try decoder.decode(CollectionAliasesResponse.self, from: result)
44+
return (aliases, response)
45+
}
46+
return (nil, nil)
47+
}
48+
49+
public func delete(name: String) async throws -> (CollectionAlias?, URLResponse?) {
50+
let (data, response) = try await apiCall.delete(endPoint: "\(RESOURCEPATH)/\(name)")
51+
if let result = data {
52+
if let notExists = try? decoder.decode(ApiResponse.self, from: result) {
53+
throw ResponseError.aliasNotFound(desc: "Alias \(notExists.message)")
54+
}
55+
let alias = try decoder.decode(CollectionAlias.self, from: result)
56+
return (alias, response)
57+
}
58+
return (nil, nil)
59+
}
60+
61+
62+
}

Sources/Typesense/ApiKeys.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import Foundation
2+
3+
public struct ApiKeys {
4+
var apiCall: ApiCall
5+
let RESOURCEPATH = "keys"
6+
7+
public init(config: Configuration) {
8+
apiCall = ApiCall(config: config)
9+
}
10+
11+
public func create(_ keySchema: ApiKeySchema) async throws -> (ApiKey?, URLResponse?) {
12+
var schemaData: Data? = nil
13+
14+
schemaData = try encoder.encode(keySchema)
15+
16+
if let validSchema = schemaData {
17+
let (data, response) = try await apiCall.post(endPoint: "\(RESOURCEPATH)", body: validSchema)
18+
if let result = data {
19+
let keyResponse = try decoder.decode(ApiKey.self, from: result)
20+
return (keyResponse, response)
21+
}
22+
}
23+
24+
return (nil, nil)
25+
}
26+
27+
public func retrieve(id: Int) async throws -> (ApiKey?, URLResponse?) {
28+
29+
let (data, response) = try await apiCall.get(endPoint: "\(RESOURCEPATH)/\(id)")
30+
if let result = data {
31+
if let notFound = try? decoder.decode(ApiResponse.self, from: result) {
32+
throw ResponseError.apiKeyNotFound(desc: notFound.message)
33+
}
34+
let keyResponse = try decoder.decode(ApiKey.self, from: result)
35+
return (keyResponse, response)
36+
}
37+
38+
return (nil, nil)
39+
}
40+
41+
public func retrieve() async throws -> (ApiKeysResponse?, URLResponse?) {
42+
43+
let (data, response) = try await apiCall.get(endPoint: "\(RESOURCEPATH)")
44+
if let result = data {
45+
let keyResponse = try decoder.decode(ApiKeysResponse.self, from: result)
46+
return (keyResponse, response)
47+
}
48+
49+
return (nil, nil)
50+
}
51+
52+
public func delete(id: Int) async throws -> (Data?, URLResponse?) {
53+
54+
let (data, response) = try await apiCall.delete(endPoint: "\(RESOURCEPATH)/\(id)")
55+
if let result = data {
56+
if let notFound = try? decoder.decode(ApiResponse.self, from: result) {
57+
throw ResponseError.apiKeyNotFound(desc: notFound.message)
58+
}
59+
}
60+
return (data, response)
61+
}
62+
}

Sources/Typesense/Client.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,16 @@ public struct Client {
1515
public func collection(name: String) -> Collection {
1616
return Collection(config: self.configuration, collectionName: name)
1717
}
18+
19+
public func keys() -> ApiKeys {
20+
return ApiKeys(config: self.configuration)
21+
}
22+
23+
public func aliases() -> Alias {
24+
return Alias(config: self.configuration)
25+
}
26+
27+
public func operations() -> Operations {
28+
return Operations(config: self.configuration)
29+
}
1830
}

Sources/Typesense/Collection.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,8 @@ public struct Collection {
4444
}
4545
return (nil, response)
4646
}
47+
48+
public func synonyms() -> Synonyms {
49+
return Synonyms(config: self.config, collectionName: self.collectionName)
50+
}
4751
}

Sources/Typesense/Document.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,40 @@ public struct Document {
1515

1616
public func delete() async throws -> (Data?, URLResponse?) {
1717
let (data, response) = try await apiCall.delete(endPoint: "\(RESOURCEPATH)/\(self.id)")
18+
if let result = data {
19+
if let responseErr = try? decoder.decode(ApiResponse.self, from: result) {
20+
if (responseErr.message == "Not Found") {
21+
throw ResponseError.invalidCollection(desc: "Collection \(self.collectionName) \(responseErr.message)")
22+
}
23+
throw ResponseError.documentDoesNotExist(desc: responseErr.message)
24+
}
25+
}
1826
return (data, response)
1927
}
2028

2129
public func retrieve() async throws -> (Data?, URLResponse?) {
2230
let (data, response) = try await apiCall.get(endPoint: "\(RESOURCEPATH)/\(self.id)")
31+
if let result = data {
32+
if let responseErr = try? decoder.decode(ApiResponse.self, from: result) {
33+
if (responseErr.message == "Not Found") {
34+
throw ResponseError.invalidCollection(desc: "Collection \(self.collectionName) \(responseErr.message)")
35+
}
36+
throw ResponseError.documentDoesNotExist(desc: responseErr.message)
37+
}
38+
}
2339
return (data, response)
2440
}
2541

2642
public func update(newDocument: Data) async throws -> (Data?, URLResponse?) {
2743
let (data, response) = try await apiCall.patch(endPoint: "\(RESOURCEPATH)/\(self.id)", body: newDocument)
44+
if let result = data {
45+
if let responseErr = try? decoder.decode(ApiResponse.self, from: result) {
46+
if (responseErr.message == "Not Found") {
47+
throw ResponseError.invalidCollection(desc: "Collection \(self.collectionName) \(responseErr.message)")
48+
}
49+
throw ResponseError.documentDoesNotExist(desc: responseErr.message)
50+
}
51+
}
2852
return (data, response)
2953
}
3054

Sources/Typesense/Documents.swift

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Foundation
22

33
public struct Documents {
44
var apiCall: ApiCall
5-
var collectionName: String?
5+
var collectionName: String
66
let RESOURCEPATH: String
77

88
public init(config: Configuration, collectionName: String) {
@@ -13,13 +13,42 @@ public struct Documents {
1313

1414
public func create(document: Data) async throws -> (Data?, URLResponse?) {
1515
let (data, response) = try await apiCall.post(endPoint: RESOURCEPATH, body: document)
16+
if let result = data {
17+
if let responseErr = try? decoder.decode(ApiResponse.self, from: result) {
18+
if (responseErr.message == "Not Found") {
19+
throw ResponseError.invalidCollection(desc: "Collection \(self.collectionName) \(responseErr.message)")
20+
}
21+
throw ResponseError.documentAlreadyExists(desc: responseErr.message)
22+
}
23+
}
1624
return (data, response)
1725
}
1826

1927
public func upsert(document: Data) async throws -> (Data?, URLResponse?) {
2028
let upsertAction = URLQueryItem(name: "action", value: "upsert")
2129
let (data, response) = try await apiCall.post(endPoint: RESOURCEPATH, body: document, queryParameters: [upsertAction])
30+
if let result = data {
31+
if let responseErr = try? decoder.decode(ApiResponse.self, from: result) {
32+
if (responseErr.message == "Not Found") {
33+
throw ResponseError.invalidCollection(desc: "Collection \(self.collectionName) \(responseErr.message)")
34+
}
35+
throw ResponseError.documentAlreadyExists(desc: responseErr.message)
36+
}
37+
}
38+
return (data, response)
39+
}
40+
41+
public func delete(filter: String, batchSize: Int? = nil) async throws -> (Data?, URLResponse?) {
42+
var deleteQueryParams: [URLQueryItem] =
43+
[
44+
URLQueryItem(name: "filter_by", value: filter)
45+
]
46+
if let givenBatchSize = batchSize {
47+
deleteQueryParams.append(URLQueryItem(name: "batch_size", value: String(givenBatchSize)))
48+
}
49+
let (data, response) = try await apiCall.delete(endPoint: "\(RESOURCEPATH)", queryParameters: deleteQueryParams)
2250
return (data, response)
51+
2352
}
2453

2554
public func search<T>(_ searchParameters: SearchParameters, for: T.Type) async throws -> (SearchResult<T>?, URLResponse?) {
@@ -190,4 +219,9 @@ public struct Documents {
190219
let (data, response) = try await apiCall.post(endPoint: "\(RESOURCEPATH)/import", body: documents, queryParameters: [importAction])
191220
return (data, response)
192221
}
222+
223+
public func export() async throws -> (Data?, URLResponse?) {
224+
let (data, response) = try await apiCall.get(endPoint: "\(RESOURCEPATH)/export")
225+
return (data, response)
226+
}
193227
}

Sources/Typesense/Errors.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ public enum DataError: Error {
1616
public enum ResponseError: Error {
1717
case collectionAlreadyExists(desc: String)
1818
case collectionDoesNotExist(desc: String)
19+
case documentAlreadyExists(desc: String)
20+
case documentDoesNotExist(desc: String)
21+
case invalidCollection(desc: String)
22+
case apiKeyNotFound(desc: String)
23+
case aliasNotFound(desc: String)
1924
}

Sources/Typesense/Models/ApiKey.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ public struct ApiKey: Codable {
1616
public var collections: [String]
1717
public var expiresAt: Int64?
1818
public var _id: Int64
19-
public var value: String
20-
public var valuePrefix: String
19+
public var value: String?
20+
public var valuePrefix: String?
2121

22-
public init(_description: String? = nil, actions: [String], collections: [String], expiresAt: Int64? = nil, _id: Int64, value: String, valuePrefix: String) {
22+
public init(_description: String? = nil, actions: [String], collections: [String], expiresAt: Int64? = nil, _id: Int64, value: String? = nil, valuePrefix: String? = nil) {
2323
self._description = _description
2424
self.actions = actions
2525
self.collections = collections

0 commit comments

Comments
 (0)