A great new way to implement your searches on iOS using Typesense ⚡️🔍✨ Typesense Swift is a high level wrapper that helps you easily implement searching using Typesense.
Add Typesense Swift
Swift Package to your project. You can refer Apple's Documentation 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
:
...
dependencies: [
.package(url: "https://github.com/typesense/typesense-swift", .upToNextMajor(from: "1.0.0"),
],
...
Import Typesense onto your Swift Project:
import Typesense
Declare the Typesense nodes that are available as Node
members:
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:
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:
let myConfig = Configuration(nodes: [node1, node2], apiKey: "coolstuff", logger: Logger(debugMode: true))
You can create a collection by first defining a collection schema:
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:
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).
Define your search parameters clearly and then perform the search operation by mentioning your Document Type:
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.
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
))
let (data, response) = try await client.collection(name: "companies").documents().update(
document: ["company_size": "large"],
options: UpdateDocumentsByFilterParameters(filterBy: "num_employees:>1000")
)
let (data, response) = try await client.collection(name: "companies").documents().delete(
options: DeleteDocumentsParameters(filterBy: "num_employees:>100")
)
let (data, response) = try await client.collection(name: "companies").documents().export(options: ExportDocumentsParameters(excludeFields: "country"))
let schema = CollectionAliasSchema(collectionName: "companies_june")
let (data, response) = try await client.aliases().upsert(name: "companies", collection: schema)
let (data, response) = try await client.aliases().retrieve()
let (data, response) = try await client.aliases().retrieve(name: "companies")
let (data, response) = try await client.aliases().delete(name: "companies")
let adminKey = ApiKeySchema(_description: "Test key with all privileges", actions: ["*"], collections: ["*"])
let (data, response) = try await client.keys().create(adminKey)
let (data, response) = try await client.keys().retrieve()
let (data, response) = try await client.keys().retrieve(id: 1)
let (data, response) = try await client.keys().delete(id: 1)
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)
let (data, response) = try await client.conversations().models().retrieve()
let (data, response) = try await client.conversations().model(modelId: "conv-model-1").retrieve()
let (data, response) = try await client.conversations().model(modelId: "conv-model-1").update(params: ConversationModelUpdateSchema(
systemPrompt: "..."
))
let (data, response) = try await client.conversations().model(modelId: "conv-model-1").delete()
let schema = SearchOverrideSchema<MetadataType>(
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)
let (data, response) = try await client.collection(name: "books").overrides().retrieve(metadataType: Never.self)
let (data, response) = try await client.collection(name: "books").override("test-id").retrieve(metadataType: MetadataType.self)
let (data, response) = try await client.collection(name: "books").override("test-id").delete()
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)
let (data, response) = try await client.presets().retrieve()
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)
}
let (data, response) = try await client.preset("listing_view").delete()
let schema = StopwordsSetUpsertSchema(
stopwords: ["states","united"],
locale: "en"
)
let (data, response) = try await client.stopwords().upsert(stopwordsSetId: "stopword_set1", params: schema)
let (data, response) = try await client.stopwords().retrieve()
let (data, response) = try await client.stopword("stopword_set1").retrieve()
let (data, response) = try await client.stopword("stopword_set1").delete()
let schema = SearchSynonymSchema(synonyms: ["blazer", "coat", "jacket"])
let (data, response) = try await client.collection(name: "products").synonyms().upsert(id: "coat-synonyms", schema)
let (data, response) = try await client.collection(name: "products").synonyms().retrieve()
let (data, response) = try await client.collection(name: "products").synonyms().retrieve(id: "coat-synonyms")
let (data, response) = try await myClient.collection(name: "products").synonyms().delete(id: "coat-synonyms")
let (data, response) = try await client.operations().getDebug()
let (data, response) = try await client.operations().getHealth()
let (data, response) = try await client.operations().getStats()
let (data, response) = try await client.operations().getMetrics()
let (data, response) = try await client.operations().vote()
let (data, response) = try await client.operations().toggleSlowRequestLog(seconds: 2)
let (data, response) = try await client.operations().clearCache()
let (data, response) = try await client.operations().snapshot(path: "/tmp/typesense-data-snapshot")
Issues and pull requests are welcome on GitHub at Typesense Swift. Do note that the Models used in the Swift client are generated by 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:
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 is updated.
- Scoped Search Key