An open API service indexing awesome lists of open source software.

https://github.com/typesense/typesense-swift

Swift Client for Typesense ⚡️🔎
https://github.com/typesense/typesense-swift

ios search swift typesense

Last synced: about 2 months ago
JSON representation

Swift Client for Typesense ⚡️🔎

Awesome Lists containing this project

README

          

# Typesense Swift

A great new way to implement your searches on iOS using [Typesense](https://github.com/typesense/typesense) ⚡️🔍✨ Typesense Swift is a high level wrapper that helps you easily implement searching using Typesense.

## Installation

Add `Typesense Swift` Swift Package to your project. You can refer [Apple's Documentation](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app) to add Typesense Swift as a dependency to your iOS Project. You can also import Typesense into your own Swift Package by adding this line to dependencies array of `Package.swift`:

```swift
...
dependencies: [
.package(url: "https://github.com/typesense/typesense-swift", .upToNextMajor(from: "1.0.0"),
],
...
```

## Usage

### Setting up the client

Import Typesense onto your Swift Project:

```swift
import Typesense
```

Declare the Typesense nodes that are available as `Node` members:

```swift
let node1 = Node(url: "http://localhost:8108") // or
let node2 = Node(host: "xxx-1.a1.typesense.net", port: "443", nodeProtocol: "https")
```

Create a configuration and hence a client with the Nodes mentioned:

```swift
let myConfig = Configuration(nodes: [node1, node2], apiKey: "coolstuff")

let client = Client(config: myConfig)
```

You can use Typesense parameters like `nearestNode` and `connectionTimeoutSeconds` while creating the configuration. You can also pass in a `logger` parameter to debug the code like this:

```swift
let myConfig = Configuration(nodes: [node1, node2], apiKey: "coolstuff", logger: Logger(debugMode: true))
```

### Indexing documents

You can create a collection by first defining a collection schema:

```swift
let myCoolSchema = CollectionSchema(name: "schools", fields: [Field(name: "school_name", type: "string"), Field(name: "num_students", type: "int32"), Field(name: "country", type: "string", facet: true)], defaultSortingField: "num_students")

let (data, response) = try await client.collections.create(schema: myCoolSchema)
```

Define the structure of your document as per your collection, and index it by inserting/upserting it to the collection:

```swift
struct School: Codable {
var id: String
var school_name: String
var num_students: Int
var country: String
}

let document = School(id: "7", school_name: "Hogwarts", num_students: 600, country: "United Kingdom")
let documentData = try JSONEncoder().encode(document)
let (data, response) = try await client.collection(name: "schools").documents().create(document: documentData)
//or
let (data, response) = try await client.collection(name: "schools").documents().upsert(document: documentData)
```

You can perform CRUD actions to `Collections` and `Documents` that belong to a certain collection. You can also use `.importBatch()` on the `documents()` method to import and index a batch of documents (in .jsonl format).

### Searching

Define your [search parameters](https://typesense.org/docs/27.0/api/search.html#search-parameters) clearly and then perform the search operation by mentioning your Document Type:

```swift
let searchParameters = SearchParameters(q: "hog", queryBy: "school_name", filterBy: "num_students:>500", sortBy: "num_students:desc")

let (data, response) = try await client.collection(name: "schools").documents().search(searchParameters, for: School.self)
```

This returns a `SearchResult` object as the data, which can be further parsed as desired.

### Bulk import documents

```swift
let jsonL = Data("{}".utf8)
let (data, response) = try await client.collection(name: "companies").documents().importBatch(jsonL, options: ImportDocumentsParameters(
action: .upsert,
batchSize: 10,
dirtyValues: .drop,
remoteEmbeddingBatchSize: 10,
returnDoc: true,
returnId: false
))
```

### Update multiple documents by query

```swift
let (data, response) = try await client.collection(name: "companies").documents().update(
document: ["company_size": "large"],
options: UpdateDocumentsByFilterParameters(filterBy: "num_employees:>1000")
)
```

### Delete multiple documents by query

```swift
let (data, response) = try await client.collection(name: "companies").documents().delete(
options: DeleteDocumentsParameters(filterBy: "num_employees:>100")
)
```

### Export documents

```swift
let (data, response) = try await client.collection(name: "companies").documents().export(options: ExportDocumentsParameters(excludeFields: "country"))
```

### Create or update a collection alias

```swift
let schema = CollectionAliasSchema(collectionName: "companies_june")
let (data, response) = try await client.aliases().upsert(name: "companies", collection: schema)
```

### Retrieve all aliases

```swift
let (data, response) = try await client.aliases().retrieve()
```

### Retrieve an alias

```swift
let (data, response) = try await client.aliases().retrieve(name: "companies")
```

### Delete an alias

```swift
let (data, response) = try await client.aliases().delete(name: "companies")
```

### Create an API key

```swift
let adminKey = ApiKeySchema(_description: "Test key with all privileges", actions: ["*"], collections: ["*"])
let (data, response) = try await client.keys().create(adminKey)
```

### Retrieve all API keys

```swift
let (data, response) = try await client.keys().retrieve()
```

### Retrieve an API key

```swift
let (data, response) = try await client.keys().retrieve(id: 1)
```

### Delete an API key

```swift
let (data, response) = try await client.keys().delete(id: 1)
```

### Create a conversation model

```swift
let schema = ConversationModelCreateSchema(
_id: "conv-model-1",
modelName: "openai/gpt-3.5-turbo",
apiKey: "OPENAI_API_KEY",
historyCollection: "conversation_store",
systemPrompt: "You are an assistant for question-answering...",
ttl: 10000,
maxBytes: 16384
)
let (data, response) = try await client.conversations().models().create(params: schema)
```

### Retrieve all conversation models

```swift
let (data, response) = try await client.conversations().models().retrieve()
```

### Retrieve a conversation model

```swift
let (data, response) = try await client.conversations().model(modelId: "conv-model-1").retrieve()
```

### Update a conversation model

```swift
let (data, response) = try await client.conversations().model(modelId: "conv-model-1").update(params: ConversationModelUpdateSchema(
systemPrompt: "..."
))
```

### Delete a conversation model

```swift
let (data, response) = try await client.conversations().model(modelId: "conv-model-1").delete()
```

### Create or update an override

```swift
let schema = SearchOverrideSchema(
rule: SearchOverrideRule(tags: ["test"], query: "apple", match: SearchOverrideRule.Match.exact, filterBy: "employees:=50"),
includes: [SearchOverrideInclude(_id: "include-id", position: 1)],
excludes: [SearchOverrideExclude(_id: "exclude-id")],
filterBy: "test:=true",
removeMatchedTokens: false,
metadata: MetadataType(message: "test-json"),
sortBy: "num_employees:desc",
replaceQuery: "test",
filterCuratedHits: false,
effectiveFromTs: 123,
effectiveToTs: 456,
stopProcessing: false
)
let (data, response) = try await client.collection(name: "books").overrides().upsert(overrideId: "test-id", params: schema)
```

### Retrieve all overrides

```swift
let (data, response) = try await client.collection(name: "books").overrides().retrieve(metadataType: Never.self)
```

### Retrieve an override

```swift
let (data, response) = try await client.collection(name: "books").override("test-id").retrieve(metadataType: MetadataType.self)
```

### Delete an override

```swift
let (data, response) = try await client.collection(name: "books").override("test-id").delete()
```

### Create or update a preset

```swift
let schema = PresetUpsertSchema(
value: PresetValue.singleCollectionSearch(SearchParameters(q: "apple"))
// or: value: PresetValue.multiSearch(MultiSearchSearchesParameter(searches: [MultiSearchCollectionParameters(q: "apple")]))
)
let (data, response) = try await client.presets().upsert(presetName: "listing_view", params: schema)
```

### Retrieve all presets

```swift
let (data, response) = try await client.presets().retrieve()
```

### Retrieve a preset

```swift
let (data, response) = try await client.preset("listing_view").retrieve()

switch data?.value {
case .singleCollectionSearch(let value):
print(value)
case .multiSearch(let value):
print(value)
}
```

### Delete a preset

```swift
let (data, response) = try await client.preset("listing_view").delete()
```

### Create or update a stopwords set

```swift
let schema = StopwordsSetUpsertSchema(
stopwords: ["states","united"],
locale: "en"
)
let (data, response) = try await client.stopwords().upsert(stopwordsSetId: "stopword_set1", params: schema)
```

### Retrieve all stopwords sets

```swift
let (data, response) = try await client.stopwords().retrieve()
```

### Retrieve a stopwords set

```swift
let (data, response) = try await client.stopword("stopword_set1").retrieve()
```

### Delete a stopwords set

```swift
let (data, response) = try await client.stopword("stopword_set1").delete()
```

### Create or update a synonym

```swift
let schema = SearchSynonymSchema(synonyms: ["blazer", "coat", "jacket"])
let (data, response) = try await client.collection(name: "products").synonyms().upsert(id: "coat-synonyms", schema)
```

### Retrieve all synonyms

```swift
let (data, response) = try await client.collection(name: "products").synonyms().retrieve()
```

### Retrieve a synonym

```swift
let (data, response) = try await client.collection(name: "products").synonyms().retrieve(id: "coat-synonyms")
```

### Delete a synonym

```swift
let (data, response) = try await myClient.collection(name: "products").synonyms().delete(id: "coat-synonyms")
```

### Retrieve debug information

```swift
let (data, response) = try await client.operations().getDebug()
```

### Retrieve health status

```swift
let (data, response) = try await client.operations().getHealth()
```

### Retrieve API stats

```swift
let (data, response) = try await client.operations().getStats()
```

### Retrieve Cluster Metrics

```swift
let (data, response) = try await client.operations().getMetrics()
```

### Re-elect Leader

```swift
let (data, response) = try await client.operations().vote()
```

### Toggle Slow Request Log

```swift
let (data, response) = try await client.operations().toggleSlowRequestLog(seconds: 2)
```

### Clear cache

```swift
let (data, response) = try await client.operations().clearCache()
```

### Create Snapshot (for backups)

```swift
let (data, response) = try await client.operations().snapshot(path: "/tmp/typesense-data-snapshot")
```

## Contributing

Issues and pull requests are welcome on GitHub at [Typesense Swift](https://github.com/typesense/typesense-swift). Do note that the Models used in the Swift client are generated by [Swagger-Codegen](https://github.com/swagger-api/swagger-codegen) and are automated to be modified in order to prevent major errors. So please do use the shell script that is provided in the repo to generate the models:

```shell
sh get-models.sh
```

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.

## TODO: Features

- Scoped Search Key