CogniGraph / Lua Sandbox
Program
your graph.
CogniGraph's Lua Sandbox lets you combine database operations into one server-side program. Query documents, follow relationships, search, transform the results and return JSON to your application. Lua scripting is part of Community.
01 / More than one query
Keep the steps together.
Some questions need a sequence: find a starting point, follow its connections, apply a rule and shape the answer. Lua keeps that sequence on the server, while your application makes one HTTP request.
- Assemble retrieval context. Combine text or vector hits with graph traversal, remove duplicate records and return the passages your application needs.
- Enrich connected records. Read documents, apply your own conditions and make authorized document or relationship updates.
- Build a focused response. Filter, group and sort results using Lua tables, strings and arithmetic, then return a JSON object.
Use CGQL when the question fits a query. Add Lua when the surrounding control flow belongs with the data. Lua itself does not require a language model.
02 / Three accounts. Two handsets.
Follow the link. Return the answer.
This synthetic Native-backend example uses the homepage case: rook_77, marla.v and dispatch-04 in accounts, all in case CS-0412. The first two are registered on Handset 8813; dispatch-04 on Handset 2207. Directed edges live in registered_on, and handset records carry kind: "handset".
- 01 Select the case’s accounts
- 02 Follow registered_on edges
- 03 Deduplicate and return
local accounts = graph.query([[
FOR a IN accounts
FILTER a.case == @case
SORT a.handle ASC
RETURN a
]], { case = "CS-0412" })
local handsets, seen = {}, {}
for _, account in ipairs(accounts) do
local paths = graph.traverse(account._id, {
edge_collection = "registered_on",
direction = "outbound",
max_depth = 1
})
for _, path in ipairs(paths) do
local handset = path.vertices[#path.vertices]
if handset.kind == "handset" and not seen[handset._id] then
seen[handset._id] = true
table.insert(handsets, {
id = handset._id, label = handset.label
})
end
end
end
table.sort(handsets, function(a, b) return a.label < b.label end)
return { account_count = #accounts, handsets = handsets }Send the script as the script string in a JSON body to POST /api/lua/execute on your CogniGraph server. With this dataset, the HTTP response is:
{
"result": {
"account_count": 3,
"handsets": [
{
"id": "handsets/2207",
"label": "Handset 2207"
},
{
"id": "handsets/8813",
"label": "Handset 8813"
}
]
}
}Both accounts registered on Handset 8813 contribute to one handset result. The returned object has the shape chosen by the script; the HTTP endpoint wraps it in result.
03 / A database API inside Lua
Read. Search. Traverse. Write.
- Documents
get_documentandfind_documentsread records.create_document,update_document,replace_documentanddelete_documentprovide authorized writes.- Relationships
neighborsreads adjacent edges,traversefollows paths, andupsert_edgecreates or updates an authorized relationship.- Search and queries
text_searchperforms BM25 retrieval;similaritysearches with a supplied vector.queryruns parsed CGQL on the Native backend.- Atomic batches
batchgroups supported writes into one atomic operation on Native. A whole Lua script is not automatically a transaction: earlier writes can remain if a later step fails.
These functions live on the graph table. Backend capabilities still apply: opaque AQL is unavailable through the public Lua endpoint. Consult the full reference for arguments, return values and supported operations.
04 / Explicit execution boundaries
A program with limits.
- Restricted environment. System and file I/O libraries, the debug library, module loading and dynamic code loading are removed. Scripts are loaded as text.
- Instruction budget. The default is one million instructions, accounted in 1,000-instruction intervals. JIT compilation is disabled so compiled loops cannot bypass the hook.
- Time and cancellation. Configured time budgets are shared across the script and graph callbacks. Dropped requests signal cancellation to the worker. Backend work stops cooperatively when it yields or returns.
- Separate write authority. Script execution permission does not grant writes. Mutations require
documents:write; with authentication disabled, Lua mutations remain disabled.
The sandbox runs inside the server process. Instruction and time controls do not imply a separate container or a per-script memory quota. Enterprise execution also keeps graph operations within the caller's tenant.
Start with a read-only workflow.
Choose a small dataset and a result you can check. Keep CGQL bind values separate from query text, and expand permissions only when the workflow needs them.
Set up your first integration