Skip to main content

Overview

Orama provides a comprehensive hook system that allows you to intercept and modify behavior at various points in the document lifecycle and search process. Components include callback hooks and core component implementations.

Callback Hooks

SingleCallbackComponent

Callback for operations on a single document.
type SingleCallbackComponent<T extends AnyOrama> = (
  orama: T,
  id: string,
  doc?: TypedDocument<T>
) => SyncOrAsyncValue
orama
T extends AnyOrama
The Orama database instance.
id
string
The document ID.
doc
TypedDocument<T>
The document (may not have correct type, cast if needed).
returns
SyncOrAsyncValue
Can return void or a Promise.

Used in:

  • beforeInsert / afterInsert
  • beforeRemove / afterRemove
  • beforeUpdate / afterUpdate
  • beforeUpsert / afterUpsert

MultipleCallbackComponent

Callback for bulk operations on multiple documents.
type MultipleCallbackComponent<T extends AnyOrama> = (
  orama: T,
  doc: TypedDocument<T>[] | string[]
) => SyncOrAsyncValue
orama
T extends AnyOrama
The Orama database instance.
doc
TypedDocument<T>[] | string[]
Array of documents or document IDs.

Used in:

  • beforeInsertMultiple / afterInsertMultiple
  • beforeRemoveMultiple / afterRemoveMultiple
  • beforeUpdateMultiple / afterUpdateMultiple
  • beforeUpsertMultiple / afterUpsertMultiple

BeforeSearch

Callback before executing a search.
type BeforeSearch<T extends AnyOrama> = (
  db: T,
  params: SearchParams<T>,
  language: string | undefined
) => SyncOrAsyncValue
db
T extends AnyOrama
The Orama database instance.
params
SearchParams<T>
The search parameters.
language
string | undefined
The search language, if specified.

AfterSearch

Callback after search execution.
type AfterSearch<T extends AnyOrama, ResultDocument = TypedDocument<T>> = (
  db: T,
  params: SearchParams<T, ResultDocument>,
  language: string | undefined,
  results: Results<ResultDocument>
) => SyncOrAsyncValue
db
T extends AnyOrama
The Orama database instance.
params
SearchParams<T, ResultDocument>
The search parameters.
language
string | undefined
The search language.
results
Results<ResultDocument>
The search results.

AfterCreate

Callback after database creation.
type AfterCreate<T extends AnyOrama> = (db: T) => SyncOrAsyncValue
db
T extends AnyOrama
The newly created Orama database instance.

Hook Configuration

SingleOrArrayCallbackComponents

Configuration interface for all available hooks (can be single function or array).
interface SingleOrArrayCallbackComponents<T extends AnyOrama> {
  beforeInsert: SingleOrArray<SingleCallbackComponent<T>>
  afterInsert: SingleOrArray<SingleCallbackComponent<T>>
  beforeRemove: SingleOrArray<SingleCallbackComponent<T>>
  afterRemove: SingleOrArray<SingleCallbackComponent<T>>
  beforeUpdate: SingleOrArray<SingleCallbackComponent<T>>
  afterUpdate: SingleOrArray<SingleCallbackComponent<T>>
  beforeUpsert: SingleOrArray<SingleCallbackComponent<T>>
  afterUpsert: SingleOrArray<SingleCallbackComponent<T>>
  beforeSearch: SingleOrArray<BeforeSearch<T>>
  afterSearch: SingleOrArray<AfterSearch<T>>
  beforeInsertMultiple: SingleOrArray<MultipleCallbackComponent<T>>
  afterInsertMultiple: SingleOrArray<MultipleCallbackComponent<T>>
  beforeRemoveMultiple: SingleOrArray<MultipleCallbackComponent<T>>
  afterRemoveMultiple: SingleOrArray<MultipleCallbackComponent<T>>
  beforeUpdateMultiple: SingleOrArray<MultipleCallbackComponent<T>>
  afterUpdateMultiple: SingleOrArray<MultipleCallbackComponent<T>>
  beforeUpsertMultiple: SingleOrArray<MultipleCallbackComponent<T>>
  afterUpsertMultiple: SingleOrArray<MultipleCallbackComponent<T>>
  afterCreate: SingleOrArray<AfterCreate<T>>
}

Example: Using Hooks

import { create } from '@orama/orama';

const db = await create({
  schema: {
    title: 'string',
    description: 'string',
    createdAt: 'number'
  },
  components: {
    // Single hook
    beforeInsert: async (orama, id, doc) => {
      console.log(`Inserting document ${id}`);
      // Modify document before insertion
      if (doc) {
        doc.createdAt = Date.now();
      }
    },
    
    // Multiple hooks as array
    afterInsert: [
      async (orama, id) => {
        console.log(`Document ${id} inserted`);
      },
      async (orama, id, doc) => {
        // Log to analytics
        await analytics.track('document_inserted', { id, title: doc?.title });
      }
    ],
    
    beforeSearch: async (orama, params) => {
      console.log(`Searching for: ${params.term}`);
    },
    
    afterSearch: async (orama, params, language, results) => {
      console.log(`Found ${results.count} results in ${results.elapsed.formatted}`);
    }
  }
});

Object Components

Core components that power Orama’s functionality.

ObjectComponents

interface ObjectComponents<I, D, So, Pi> {
  tokenizer: Tokenizer | DefaultTokenizerConfig
  index: I
  documentsStore: D
  sorter: So
  pinning: Pi
}
tokenizer
Tokenizer | DefaultTokenizerConfig
Tokenizer for text processing.
index
I
Index implementation (IIndex interface).
documentsStore
D
Document storage implementation (IDocumentsStore interface).
sorter
So
Sorter implementation (ISorter interface).
pinning
Pi
Pinning implementation (IPinning interface).

Example: Custom Tokenizer

const db = await create({
  schema: {
    title: 'string',
    description: 'string',
    code: 'string'
  },
  components: {
    tokenizer: {
      language: 'english',
      stemming: true,
      stemmerSkipProperties: ['code'], // Don't stem code blocks
      stopWords: true
    }
  }
});

Function Components

Utility functions for document processing.

FunctionComponents

interface FunctionComponents<S> {
  validateSchema(doc: AnyDocument, schema: S): string | undefined
  getDocumentIndexId(doc: AnyDocument): string
  getDocumentProperties(doc: AnyDocument, paths: string[]): Record<string, string | number | boolean>
  formatElapsedTime(number: bigint): number | string | object | ElapsedTime
}
validateSchema
(doc: AnyDocument, schema: S) => string | undefined
Validates document against schema. Returns error message or undefined.
getDocumentIndexId
(doc: AnyDocument) => string
Extracts document ID.
getDocumentProperties
(doc: AnyDocument, paths: string[]) => Record<string, SearchableValue>
Extracts specific properties from document.
formatElapsedTime
(number: bigint) => ElapsedTime
Formats nanoseconds to readable time.

Complete Components Example

import { create } from '@orama/orama';

const db = await create({
  schema: {
    title: 'string',
    description: 'string',
    price: 'number',
    createdAt: 'number',
    updatedAt: 'number'
  },
  components: {
    // Tokenizer configuration
    tokenizer: {
      language: 'english',
      stemming: true,
      stopWords: true
    },
    
    // Document lifecycle hooks
    beforeInsert: async (orama, id, doc) => {
      if (doc) {
        doc.createdAt = Date.now();
        doc.updatedAt = Date.now();
      }
    },
    
    afterInsert: [
      async (orama, id) => {
        console.log(`Inserted: ${id}`);
      },
      async (orama, id, doc) => {
        await cache.invalidate('products');
      }
    ],
    
    beforeUpdate: async (orama, id, doc) => {
      if (doc) {
        doc.updatedAt = Date.now();
      }
    },
    
    beforeRemove: async (orama, id) => {
      console.log(`Removing: ${id}`);
    },
    
    afterRemove: async (orama, id) => {
      await cache.invalidate(`product:${id}`);
    },
    
    // Search hooks
    beforeSearch: async (orama, params) => {
      const start = Date.now();
      console.log(`Search started: ${params.term}`);
    },
    
    afterSearch: async (orama, params, language, results) => {
      console.log(`Found ${results.count} results in ${results.elapsed.formatted}`);
      
      // Log slow queries
      if (results.elapsed.raw > 100_000_000) { // 100ms in nanoseconds
        console.warn(`Slow query detected: ${params.term}`);
      }
    },
    
    // Database lifecycle
    afterCreate: async (orama) => {
      console.log('Database created:', orama.id);
    }
  }
});

// Insert with hooks
await db.insert({
  id: '1',
  title: 'Laptop',
  description: 'High-performance laptop',
  price: 999.99
});
// Logs: "Inserted: 1"
// Cache invalidated

// Update with hooks
await db.update('1', {
  price: 899.99
});
// updatedAt timestamp automatically set

// Search with hooks
const results = await search(db, {
  term: 'laptop'
});
// Logs: "Search started: laptop"
// Logs: "Found 1 results in 2ms"

Build docs developers (and LLMs) love