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
The Orama database instance.
The document (may not have correct type, cast if needed).
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
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
The Orama database instance.
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
The Orama database instance.
params
SearchParams<T, ResultDocument>
The search parameters.
AfterCreate
Callback after database creation.
type AfterCreate < T extends AnyOrama > = ( db : T ) => SyncOrAsyncValue
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. Show DefaultTokenizerConfig properties
Language for tokenization and stemming.
Enable stemming. Default: true.
Properties to skip stemming.
Properties to skip tokenization.
stopWords
boolean | string[] | ((stopWords: string[]) => string[])
Stop words configuration. Can be boolean, array, or function.
Index implementation (IIndex interface).
Document storage implementation (IDocumentsStore interface).
Sorter implementation (ISorter interface).
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"