Skip to content

Instantly share code, notes, and snippets.

@tmilewski
Created March 8, 2023 18:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmilewski/805bff212a130b2e4532a24169160494 to your computer and use it in GitHub Desktop.
Save tmilewski/805bff212a130b2e4532a24169160494 to your computer and use it in GitHub Desktop.
Quick and dirty pseudo-code for a typed search (Algolia) index
import { SearchIndex } from './search-index.ts'
import { SearchService } from './search-service.ts'
// ==========================================================
// Index Contents Shape
// ==========================================================
export interface Collab {
id: string
name: string
description: string
profileId: string
// etc...
}
// ==========================================================
// Generic Usage
// ==========================================================
const searchService = new SearchService()
export const collabsIdx = new SearchIndex<Collab>(searchService, 'collabs')
collabsIdx.save({ id: '123', name: 'test1', description: 'test1', profileId: 'abc' })
collabsIdx.save<Partial<Collab>>({ id: '000', name: 'test1', profileId: 'yxz' }) // Override input type
collabsIdx.saveMany([
{ id: '456', name: 'test2', description: 'test2', profileId: 'def' },
{ id: '789', name: 'test3', description: 'test3', profileId: 'ghi' },
])
collabsIdx.get('123')
collabsIdx.getMany(['456', '789'])
collabsIdx.delete('123')
// ==========================================================
// Usage via `extends`
// ==========================================================
export class CollabsSearchIndex extends SearchIndex<Collab> {
constructor(protected service: AlgoliaService) {
super(service, 'collabs')
}
}
const collabsIdxExt = new CollabsSearchIndex(searchService)
collabsIdxExt.save({ id: '123', name: 'test1', description: 'test1', profileId: 'abc' })
collabsIdxExt.save<Partial<Collab>>({ id: '000', name: 'test1', profileId: 'yxz' }) // Override input type
collabsIdxExt.saveMany([
{ id: '456', name: 'test2', description: 'test2', profileId: 'def' },
{ id: '789', name: 'test3', description: 'test3', profileId: 'ghi' },
])
collabsIdxExt.get('123')
collabsIdxExt.getMany(['456', '789'])
collabsIdxExt.delete('123')
import { type SearchIndex as AlgoliaSearchIndex } from 'algoliasearch'
// ==========================================================
// Generic Index (allowing for type safety)
// ==========================================================
// TODO: Create "generic" responses from the Algolia specific ones
export class SearchIndex<T extends Record<string, any>> {
protected readonly index: AlgoliaSearchIndex
constructor(protected service: AlgoliaService, protected readonly indexName: string) {
this.index = this.service.client.initIndex(indexName)
}
async get<R = T>(id: string) {
return this.index.getObject<R>(id)
}
async getMany<R = T>(ids: string[]) {
return this.index.getObjects<R>(ids)
}
async save<R = T>(object: Readonly<R>) {
return this.index.saveObject(object)
}
async saveMany<R = T>(objects: ReadonlyArray<Readonly<R>>) {
return this.index.saveObjects(objects)
}
async delete(id: string) {
return this.index.deleteObject(id)
}
async deleteBy(filters: string) {
return this.index.deleteBy({ filters })
}
}
import algoliasearch, { type SearchClient } from 'algoliasearch'
// ==========================================================
// Generic Search Service
// ==========================================================
class SearchService {
readonly client: SearchClient
// TODO: Use actual config; Validate/parse with Zod
constructor(id = process.env.ALGOLIA_APP_ID, key = process.env.ALGOLIA_API_KEY) {
if (!id) throw new Error('App ID not specified')
if (!key) throw new Error('API Key not specified')
this.client = algoliasearch(id, key)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment