Overview
The Data API allows you to store custom data in collections with powerful semantic search capabilities using vector embeddings. Returns DataEntryInstance objects with direct property access.
import { Data } from 'lua-cli' ;
// Create with search indexing - returns DataEntryInstance
const entry = await Data . create ( 'movies' , {
title: 'Inception' ,
director: 'Christopher Nolan'
}, 'Inception Christopher Nolan sci-fi thriller dreams' );
// Direct property access
console . log ( entry . title ); // "Inception"
console . log ( entry . director ); // "Christopher Nolan"
console . log ( entry . id ); // "entry_abc123"
// Instance methods
await entry . update ({ rating: 9.5 }, 'inception nolan 9.5 rating' );
await entry . save ();
await entry . delete ();
// Semantic search - returns array of DataEntryInstance
const results = await Data . search ( 'movies' , 'mind-bending thriller' , 10 , 0.7 );
// Direct array methods and property access
results . forEach ( entry => {
console . log ( ` ${ entry . title } : ${ entry . score * 100 } % match` );
});
const highScoring = results . filter ( entry => entry . score > 0.8 );
const titles = results . map ( entry => entry . title );
Direct Access Access entry.title not entry.data.title
Search Scores Results include relevance scores
Instance Methods Built-in update(), save(), and delete()
Array Methods Use .map(), .filter() on search results
Key Features
Custom Collections Store any JSON data in named collections
Vector Search Semantic similarity search using AI embeddings
Flexible Schema No fixed schema - store any structure
Filtering Query by field values with operators
Methods
create()
Create a new entry in a collection.
Data . create (
collectionName : string ,
data : object ,
searchText ?: string
): Promise < Entry >
Name of the collection (e.g., ‘movies’, ‘customers’, ‘articles’)
Any JSON-serializable object to store
Text to index for vector search. Include all searchable content.
Returns:
{
id : string ;
data : object ;
createdAt : number ;
updatedAt : number ;
searchText ?: string ;
}
Example:
const movie = await Data . create ( 'movies' , {
title: 'The Matrix' ,
year: 1999 ,
director: 'Wachowski Sisters' ,
genre: 'Sci-Fi' ,
rating: 8.7
}, 'The Matrix 1999 Wachowski sci-fi action cyberpunk reality virtual' );
console . log ( movie . id ); // "entry_abc123"
search()
Semantic search using vector embeddings.
Data . search (
collectionName : string ,
query : string ,
limit ?: number ,
scoreThreshold ?: number
): Promise < DataEntryInstance [] >
Name of the collection to search
Search query (natural language)
Maximum number of results to return
Minimum similarity score (0-1). Higher = more similar.
Returns: Array of DataEntryInstance objects, each with a score property.
Similarity Scores:
1.0 = Perfect match
0.8-0.9 = Very similar
0.6-0.7 = Somewhat similar
<0.6 = Low similarity
Example:
// Finds movies even if query doesn't match exact words!
const results = await Data . search ( 'movies' , 'mind-bending thriller' , 5 , 0.7 );
results . forEach ( entry => {
console . log ( ` ${ entry . title } - Relevance: ${ entry . score } ` );
});
// Output:
// Inception - Relevance: 0.92
// The Matrix - Relevance: 0.85
// Interstellar - Relevance: 0.78
get()
Retrieve entries with optional filtering and pagination.
Data . get (
collectionName : string ,
filter ?: object ,
page ?: number ,
limit ?: number
): Promise < GetResult >
Filter criteria (MongoDB-style queries)
Returns:
{
data : Entry [];
pagination : {
currentPage : number ;
totalPages : number ;
totalCount : number ;
limit : number ;
hasNextPage : boolean ;
hasPrevPage : boolean ;
nextPage : number | null ;
prevPage : number | null ;
};
}
Examples:
// Get all
const all = await Data . get ( 'movies' );
// With pagination
const page2 = await Data . get ( 'movies' , {}, 2 , 20 );
// With filter
const recent = await Data . get ( 'movies' , {
year: { $gte: 2020 }
});
// Complex filter
const sciFi = await Data . get ( 'movies' , {
genre: 'Sci-Fi' ,
rating: { $gte: 8.0 },
year: { $gte: 2000 , $lte: 2020 }
});
getEntry()
Retrieve a specific entry by ID.
Data . getEntry (
collectionName : string ,
entryId : string
): Promise < Entry >
Example:
const movie = await Data . getEntry ( 'movies' , 'entry_abc123' );
console . log ( movie . data . title ); // "Inception"
update()
Update an existing entry.
Data . update (
collectionName : string ,
entryId : string ,
data : object ,
searchText ?: string
): Promise < UpdateResponse >
ID of the entry to update
Data to merge with existing entry
Optional new text for vector search indexing
Returns:
{
status : string ; // "success"
message : string ; // "Custom data entry updated"
}
Example:
// Update data and search text
const result = await Data . update ( 'movies' , 'entry_abc123' , {
rating: 8.8 , // Updated rating
awards: [ 'Oscar' ] // New field
}, 'Inception Christopher Nolan oscar winner' );
// Update data only
await Data . update ( 'movies' , 'entry_abc123' , {
views: 1500
});
Updates merge with existing data. Only the specified fields are updated; other fields are preserved.
DataEntryInstance Methods
When you retrieve or create data entries, you get a DataEntryInstance object with convenient instance methods.
save()
Save the current state of the data entry to the server. This is a convenience method that persists all changes made to the entry.
entry . save ( searchText ?: string ): Promise < boolean >
Optional new text for vector search indexing
Returns: Promise resolving to true if successful
Example:
const entry = await Data . getEntry ( 'movies' , 'entry_abc123' );
// Modify properties directly
entry . title = "Inception" ;
entry . rating = 9.0 ;
entry . year = 2010 ;
// Save all changes at once
await entry . save ();
// Or save with updated search text
await entry . save ( 'Inception 2010 Nolan sci-fi thriller dreams' );
The save() method provides a simpler workflow - modify properties then save, rather than calling Data.update() with the collection name and entry ID.
update() (Instance Method)
Update the entry using the instance method.
entry . update ( data : object , searchText ?: string ): Promise < object >
Returns: Promise resolving to the updated data object
Example:
const entry = await Data . getEntry ( 'movies' , 'entry_abc123' );
// Update with new search text
const updatedData = await entry . update (
{ rating: 9.5 , review: 'Mind-bending masterpiece' },
'inception nolan 9.5 rating masterpiece'
);
console . log ( updatedData . rating ); // 9.5
// Update data only (keeps existing search text)
await entry . update ({ views: 1000 });
delete() (Instance Method)
Delete the entry using the instance method.
entry . delete (): Promise < void >
Example:
const entry = await Data . getEntry ( 'movies' , 'entry_abc123' );
await entry . delete ();
Static Methods
delete()
Delete an entry using the static method.
Data . delete (
collectionName : string ,
entryId : string
): Promise < void >
Example:
await Data . delete ( 'movies' , 'entry_abc123' );
Use Cases
Knowledge Base
export class CreateArticleTool implements LuaTool {
async execute ( input : any ) {
// Create searchable article
const article = await Data . create ( 'kb_articles' , {
title: input . title ,
content: input . content ,
category: input . category ,
tags: input . tags
}, ` ${ input . title } ${ input . content } ${ input . tags . join ( ' ' ) } ` );
return { articleId: article . id };
}
}
export class SearchArticlesTool implements LuaTool {
async execute ( input : any ) {
// Semantic search
const results = await Data . search (
'kb_articles' ,
input . query ,
10 ,
0.7
);
return {
articles: results . data . map ( entry => ({
id: entry . id ,
title: entry . data . title ,
content: entry . data . content . substring ( 0 , 200 ),
relevance: Math . round ( entry . score * 100 ) + '%'
}))
};
}
}
Customer CRM
export class CreateCustomerTool implements LuaTool {
async execute ( input : any ) {
const customer = await Data . create ( 'customers' , {
name: input . name ,
email: input . email ,
company: input . company ,
status: 'active' ,
createdAt: new Date (). toISOString ()
}, ` ${ input . name } ${ input . company } ${ input . email } ` );
// Log interaction
await Data . create ( 'interactions' , {
customerId: customer . id ,
type: 'created' ,
notes: 'Initial contact' ,
timestamp: new Date (). toISOString ()
});
return { customerId: customer . id };
}
}
Task Management
export class CreateTaskTool implements LuaTool {
async execute ( input : any ) {
const task = await Data . create ( 'tasks' , {
title: input . title ,
description: input . description ,
status: 'pending' ,
priority: input . priority ,
createdAt: new Date (). toISOString ()
}, ` ${ input . title } ${ input . description } ` );
return { taskId: task . id };
}
}
export class SearchTasksTool implements LuaTool {
async execute ( input : any ) {
const results = await Data . search ( 'tasks' , input . query , 20 , 0.6 );
return {
tasks: results . data . map ( entry => ({
id: entry . id ,
... entry . data ,
relevance: entry . score
}))
};
}
}
Filter Operators
The Data API supports MongoDB-style filter operators:
// Comparison
{ age : { $eq : 25 } } // Equal
{ age : { $ne : 25 } } // Not equal
{ age : { $gt : 25 } } // Greater than
{ age : { $gte : 25 } } // Greater than or equal
{ age : { $lt : 25 } } // Less than
{ age : { $lte : 25 } } // Less than or equal
// Logical
{ $and : [{ age: { $gte: 18 } }, { age: { $lte: 65 } }] }
{ $or : [{ status: 'active' }, { status: 'pending' }] }
// Array
{ tags : { $in : [ 'urgent' , 'important' ] } }
{ tags : { $nin : [ 'spam' , 'archived' ] } }
// Existence
{ email : { $exists : true } }
Best Practices
Include all searchable content in searchText: const searchText = [
item . title ,
item . description ,
item . category ,
item . tags . join ( ' ' ),
item . author
]. filter ( Boolean ). join ( ' ' );
await Data . create ( 'items' , item , searchText );
Use Appropriate Score Thresholds
0.8+: High precision, few results
0.7: Balanced (recommended default)
0.6: More results, lower precision
<0.6: May return irrelevant results
Structure Data Consistently
Use consistent field names across entries: // ✅ Good - Consistent
await Data . create ( 'items' , {
name: 'Item 1' ,
price: 10.99 ,
inStock: true
});
// ❌ Bad - Inconsistent
await Data . create ( 'items' , {
title: 'Item 2' , // Different field name
cost: 15.99 , // Different field name
available: true // Different field name
});
Track when entries are created/modified: await Data . create ( 'items' , {
... data ,
createdAt: new Date (). toISOString (),
updatedAt: new Date (). toISOString ()
});
Vector Search Tips
Vector search uses AI to understand meaning, not just match keywords. Example:
Query: “affordable laptop for students”
Finds: “budget-friendly notebook for college”
Even though no words match exactly!
Knowledge bases
FAQs
Product recommendations
Content discovery
Document search
Include synonyms in searchText
Use natural language queries
Adjust threshold based on results
Test with real user queries
Next Steps