diff --git a/common/space_lua/query_collection.test.ts b/common/space_lua/query_collection.test.ts index 2a7a415f..1b3461ab 100644 --- a/common/space_lua/query_collection.test.ts +++ b/common/space_lua/query_collection.test.ts @@ -1,8 +1,5 @@ import { parseExpressionString } from "$common/space_lua/parse.ts"; -import { - ArrayQueryCollection, - findAllQueryVariables, -} from "./query_collection.ts"; +import { ArrayQueryCollection } from "./query_collection.ts"; import { LuaEnv, LuaNativeJSFunction, @@ -178,14 +175,3 @@ Deno.test("ArrayQueryCollection", async () => { ); assertEquals(distinctObjectsResult.length, 4); }); - -Deno.test("findAllQueryVariables", () => { - const query = { - where: parseExpressionString("p.x >= 2 and b.x >= 2"), - select: parseExpressionString("p.x + b.x"), - orderBy: [{ expr: parseExpressionString("q.x"), desc: false }], - distinct: true, - }; - const variables = findAllQueryVariables(query); - assertEquals(variables, ["p", "b", "q"]); -}); diff --git a/common/space_lua/query_collection.ts b/common/space_lua/query_collection.ts index c5c61b0d..d22913db 100644 --- a/common/space_lua/query_collection.ts +++ b/common/space_lua/query_collection.ts @@ -55,75 +55,6 @@ export type LuaCollectionQuery = { distinct?: boolean; }; -export function findAllQueryVariables(query: LuaCollectionQuery): string[] { - const variables = new Set(); - - // Helper to traverse an expression and collect variables - function findVariables(expr: LuaExpression) { - if (!expr) return; - - switch (expr.type) { - case "Variable": - variables.add(expr.name); - break; - case "Binary": - findVariables(expr.left); - findVariables(expr.right); - break; - case "Unary": - findVariables(expr.argument); - break; - case "TableAccess": - findVariables(expr.object); - findVariables(expr.key); - break; - case "FunctionCall": - findVariables(expr.prefix); - expr.args.forEach(findVariables); - break; - case "TableConstructor": - expr.fields.forEach((field) => { - switch (field.type) { - case "DynamicField": - findVariables(field.key); - findVariables(field.value); - break; - case "PropField": - findVariables(field.value); - break; - case "ExpressionField": - findVariables(field.value); - break; - } - }); - break; - case "PropertyAccess": - findVariables(expr.object); - break; - case "Parenthesized": - findVariables(expr.expression); - break; - } - } - - // Check all parts of the query that can contain expressions - if (query.where) { - findVariables(query.where); - } - - if (query.orderBy) { - query.orderBy.forEach((ob) => findVariables(ob.expr)); - } - - if (query.select) { - findVariables(query.select); - } - - // distinct doesn't introduce any new variables - - return Array.from(variables); -} - export interface LuaQueryCollection { query( query: LuaCollectionQuery, @@ -229,7 +160,7 @@ export async function applyTransforms( return result; } -export async function queryLua( +export async function queryLua( kv: KvPrimitives, prefix: KvKey, query: LuaCollectionQuery, diff --git a/common/syscalls/index.ts b/common/syscalls/index.ts index 76243475..17ad587d 100644 --- a/common/syscalls/index.ts +++ b/common/syscalls/index.ts @@ -1,65 +1,23 @@ import type { SysCallMapping } from "$lib/plugos/system.ts"; import { - findAllQueryVariables, type LuaCollectionQuery, type LuaQueryCollection, + queryLua, } from "$common/space_lua/query_collection.ts"; -import { - LuaEnv, - LuaRuntimeError, - type LuaStackFrame, - luaValueToJS, -} from "$common/space_lua/runtime.ts"; -import type { CommonSystem } from "$common/common_system.ts"; +import type { LuaEnv, LuaStackFrame } from "$common/space_lua/runtime.ts"; -// These are just wrappers around the system.invokeFunction calls, but they make it easier to use the index +import type { KvPrimitives } from "$lib/data/kv_primitives.ts"; -export function indexSyscalls(commonSystem: CommonSystem): SysCallMapping { +export function indexSyscalls(kv: KvPrimitives): SysCallMapping { return { "index.tag": (_ctx, tagName: string): LuaQueryCollection => { return { - query: async ( + query: ( query: LuaCollectionQuery, env: LuaEnv, sf: LuaStackFrame, ): Promise => { - const global = commonSystem.spaceLuaEnv.env; - const localVars = findAllQueryVariables(query).filter((v) => - !global.has(v) && v !== "_" - ); - const scopedVariables: Record = {}; - for (const v of localVars) { - try { - let value = env.get(v); - if (value instanceof LuaEnv) { - // We don't want to include the global environment in the serialized value - value = value.toJSON(["_GLOBAL"]); - } - const jsonValue = await luaValueToJS(value, sf); - // Ensure this is JSON serializable - JSON.stringify(jsonValue); - scopedVariables[v] = jsonValue; - } catch (e: any) { - console.error( - "Failed to JSON serialize variable", - v, - e, - ); - throw new LuaRuntimeError( - `Failed to JSON serialize variable ${v} in query`, - sf, - ); - } - } - return (await global.get("datastore").get("queryLua").call( - sf, - [ - "idx", - tagName, - ], - query, - scopedVariables, - )).toJSArray(); + return queryLua(kv, ["idx", tagName], query, env, sf); }, }; }, diff --git a/lib/plugos/syscalls/datastore.ts b/lib/plugos/syscalls/datastore.ts index 18509052..35181aae 100644 --- a/lib/plugos/syscalls/datastore.ts +++ b/lib/plugos/syscalls/datastore.ts @@ -47,14 +47,17 @@ export function dataStoreReadSyscalls( _ctx, prefix: string[], query: LuaCollectionQuery, - scopeVariables: Record = {}, + scopeVariables?: Record, ): Promise => { const sf = LuaStackFrame.createWithGlobalEnv( commonSystem.spaceLuaEnv.env, ); - const env = new LuaEnv(commonSystem.spaceLuaEnv.env); - for (const [key, value] of Object.entries(scopeVariables)) { - env.setLocal(key, jsToLuaValue(value)); + let env = commonSystem.spaceLuaEnv.env; + if (scopeVariables) { + env = new LuaEnv(commonSystem.spaceLuaEnv.env); + for (const [key, value] of Object.entries(scopeVariables)) { + env.setLocal(key, jsToLuaValue(value)); + } } return (await queryLua(ds.kv, prefix, query, env, sf)).map((item) => luaValueToJS(item, sf) diff --git a/plug-api/syscalls/datastore.ts b/plug-api/syscalls/datastore.ts index e96e3e63..765dee43 100644 --- a/plug-api/syscalls/datastore.ts +++ b/plug-api/syscalls/datastore.ts @@ -65,7 +65,7 @@ export function query(options: KvQuery): Promise { export function queryLua( prefix: string[], query: LuaCollectionQuery, - scopeVariables: Record, + scopeVariables?: Record, ): Promise { return syscall("datastore.queryLua", prefix, query, scopeVariables); } diff --git a/plugs/index/api.ts b/plugs/index/api.ts index 7c2466e6..8a56d5b2 100644 --- a/plugs/index/api.ts +++ b/plugs/index/api.ts @@ -115,7 +115,7 @@ function cleanKey(ref: string, page: string) { export function queryLuaObjects( tag: string, query: LuaCollectionQuery, - scopedVariables: Record = {}, + scopedVariables?: Record, ttlSecs?: number, ): Promise[]> { return ttlCache(query, () => { diff --git a/web/client_system.ts b/web/client_system.ts index 105fb41b..9921341f 100644 --- a/web/client_system.ts +++ b/web/client_system.ts @@ -159,7 +159,7 @@ export class ClientSystem extends CommonSystem { clientCodeWidgetSyscalls(), languageSyscalls(), jsonschemaSyscalls(), - indexSyscalls(this), + indexSyscalls(this.ds.kv), commandSyscalls(this), luaSyscalls(this), mqSyscalls(this.mq),