index.tag simplification
This commit is contained in:
@@ -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"]);
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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, () => {
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user