index.tag simplification

This commit is contained in:
Zef Hemel
2025-03-22 07:53:24 +01:00
parent ac5a839ea8
commit 63f7314256
7 changed files with 18 additions and 140 deletions
+1 -15
View File
@@ -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"]);
});
+1 -70
View File
@@ -55,75 +55,6 @@ export type LuaCollectionQuery = {
distinct?: boolean;
};
export function findAllQueryVariables(query: LuaCollectionQuery): string[] {
const variables = new Set<string>();
// 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<T>(
export async function queryLua<T = any>(
kv: KvPrimitives,
prefix: KvKey,
query: LuaCollectionQuery,
+6 -48
View File
@@ -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<any[]> => {
const global = commonSystem.spaceLuaEnv.env;
const localVars = findAllQueryVariables(query).filter((v) =>
!global.has(v) && v !== "_"
);
const scopedVariables: Record<string, any> = {};
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);
},
};
},
+7 -4
View File
@@ -47,14 +47,17 @@ export function dataStoreReadSyscalls(
_ctx,
prefix: string[],
query: LuaCollectionQuery,
scopeVariables: Record<string, any> = {},
scopeVariables?: Record<string, any>,
): Promise<any[]> => {
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<any>(ds.kv, prefix, query, env, sf)).map((item) =>
luaValueToJS(item, sf)
+1 -1
View File
@@ -65,7 +65,7 @@ export function query(options: KvQuery): Promise<KV[]> {
export function queryLua(
prefix: string[],
query: LuaCollectionQuery,
scopeVariables: Record<string, any>,
scopeVariables?: Record<string, any>,
): Promise<any[]> {
return syscall("datastore.queryLua", prefix, query, scopeVariables);
}
+1 -1
View File
@@ -115,7 +115,7 @@ function cleanKey(ref: string, page: string) {
export function queryLuaObjects<T>(
tag: string,
query: LuaCollectionQuery,
scopedVariables: Record<string, any> = {},
scopedVariables?: Record<string, any>,
ttlSecs?: number,
): Promise<ObjectValue<T>[]> {
return ttlCache(query, () => {
+1 -1
View File
@@ -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),