Lua query fixes
parent
396c9fc60a
commit
55f5a465c8
|
@ -583,7 +583,12 @@ export async function evalStatement(
|
||||||
.map((lval) => evalLValue(lval, env, sf)));
|
.map((lval) => evalLValue(lval, env, sf)));
|
||||||
|
|
||||||
for (let i = 0; i < lvalues.length; i++) {
|
for (let i = 0; i < lvalues.length; i++) {
|
||||||
luaSet(lvalues[i].env, lvalues[i].key, values[i], sf.withCtx(s.ctx));
|
await luaSet(
|
||||||
|
lvalues[i].env,
|
||||||
|
lvalues[i].key,
|
||||||
|
values[i],
|
||||||
|
sf.withCtx(s.ctx),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -142,7 +142,9 @@ assert_equal(t.foo, "Key not found: foo")
|
||||||
t = setmetatable(
|
t = setmetatable(
|
||||||
{}, {
|
{}, {
|
||||||
__newindex = function(table, key, value)
|
__newindex = function(table, key, value)
|
||||||
|
print("Raw set", key, value)
|
||||||
rawset(table, key, "Value: " .. value)
|
rawset(table, key, "Value: " .. value)
|
||||||
|
print("Raw set done")
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -150,8 +152,8 @@ t = setmetatable(
|
||||||
t.name = "John"
|
t.name = "John"
|
||||||
-- rawset ignores the metamethod
|
-- rawset ignores the metamethod
|
||||||
rawset(t, "age", 100)
|
rawset(t, "age", 100)
|
||||||
assert(t.name == "Value: John")
|
assert_equal(t.name, "Value: John")
|
||||||
assert(t.age == 100)
|
assert_equal(t.age, 100)
|
||||||
|
|
||||||
-- Test some of the operator metamethods
|
-- Test some of the operator metamethods
|
||||||
t = setmetatable(
|
t = setmetatable(
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import { parseExpressionString } from "$common/space_lua/parse.ts";
|
import { parseExpressionString } from "$common/space_lua/parse.ts";
|
||||||
import { ArrayQueryCollection } from "./query_collection.ts";
|
import {
|
||||||
|
ArrayQueryCollection,
|
||||||
|
findAllQueryVariables,
|
||||||
|
} from "./query_collection.ts";
|
||||||
import {
|
import {
|
||||||
LuaEnv,
|
LuaEnv,
|
||||||
LuaNativeJSFunction,
|
LuaNativeJSFunction,
|
||||||
|
@ -137,3 +140,13 @@ Deno.test("ArrayQueryCollection", async () => {
|
||||||
assertEquals(result9[2], "Jane Doe");
|
assertEquals(result9[2], "Jane Doe");
|
||||||
assertEquals(result9[3], "Bob Johnson");
|
assertEquals(result9[3], "Bob Johnson");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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 }],
|
||||||
|
};
|
||||||
|
const variables = findAllQueryVariables(query);
|
||||||
|
assertEquals(variables, ["p", "b", "q"]);
|
||||||
|
});
|
||||||
|
|
|
@ -51,6 +51,73 @@ export type LuaCollectionQuery = {
|
||||||
offset?: number;
|
offset?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(variables);
|
||||||
|
}
|
||||||
|
|
||||||
export interface LuaQueryCollection {
|
export interface LuaQueryCollection {
|
||||||
query(
|
query(
|
||||||
query: LuaCollectionQuery,
|
query: LuaCollectionQuery,
|
||||||
|
|
|
@ -48,4 +48,6 @@ Deno.test("Test Lua Rutime", async () => {
|
||||||
assertEquals(await luaToString(new Promise((resolve) => resolve(1))), "1");
|
assertEquals(await luaToString(new Promise((resolve) => resolve(1))), "1");
|
||||||
assertEquals(await luaToString({ a: 1 }), "{a = 1}");
|
assertEquals(await luaToString({ a: 1 }), "{a = 1}");
|
||||||
assertEquals(await luaToString([{ a: 1 }]), "{{a = 1}}");
|
assertEquals(await luaToString([{ a: 1 }]), "{{a = 1}}");
|
||||||
|
// Ensure simple cases are not returning promises
|
||||||
|
assertEquals(luaToString(10), "10");
|
||||||
});
|
});
|
||||||
|
|
|
@ -328,7 +328,13 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rawSet(key: LuaValue, value: LuaValue) {
|
rawSet(key: LuaValue, value: LuaValue): void | Promise<void> {
|
||||||
|
if (key instanceof Promise) {
|
||||||
|
return key.then((key) => this.rawSet(key, value));
|
||||||
|
}
|
||||||
|
if (value instanceof Promise) {
|
||||||
|
return value.then(() => this.rawSet(key, value));
|
||||||
|
}
|
||||||
if (typeof key === "string") {
|
if (typeof key === "string") {
|
||||||
this.stringKeys[key] = value;
|
this.stringKeys[key] = value;
|
||||||
} else if (Number.isInteger(key) && key >= 1) {
|
} else if (Number.isInteger(key) && key >= 1) {
|
||||||
|
@ -360,7 +366,7 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just set the value
|
// Just set the value
|
||||||
this.rawSet(key, value);
|
return this.rawSet(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
rawGet(key: LuaValue): LuaValue | null {
|
rawGet(key: LuaValue): LuaValue | null {
|
||||||
|
@ -480,7 +486,12 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
||||||
|
|
||||||
export type LuaLValueContainer = { env: ILuaSettable; key: LuaValue };
|
export type LuaLValueContainer = { env: ILuaSettable; key: LuaValue };
|
||||||
|
|
||||||
export function luaSet(obj: any, key: any, value: any, sf: LuaStackFrame) {
|
export async function luaSet(
|
||||||
|
obj: any,
|
||||||
|
key: any,
|
||||||
|
value: any,
|
||||||
|
sf: LuaStackFrame,
|
||||||
|
): Promise<void> {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
throw new LuaRuntimeError(
|
throw new LuaRuntimeError(
|
||||||
`Not a settable object: nil`,
|
`Not a settable object: nil`,
|
||||||
|
@ -489,7 +500,7 @@ export function luaSet(obj: any, key: any, value: any, sf: LuaStackFrame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof LuaTable || obj instanceof LuaEnv) {
|
if (obj instanceof LuaTable || obj instanceof LuaEnv) {
|
||||||
obj.set(key, value, sf);
|
await obj.set(key, value, sf);
|
||||||
} else {
|
} else {
|
||||||
obj[key] = value;
|
obj[key] = value;
|
||||||
}
|
}
|
||||||
|
@ -678,18 +689,19 @@ export function luaTruthy(value: any): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function luaToString(value: any): Promise<string> {
|
export function luaToString(value: any): string | Promise<string> {
|
||||||
if (value === null || value === undefined) {
|
if (value === null || value === undefined) {
|
||||||
return "nil";
|
return "nil";
|
||||||
}
|
}
|
||||||
if (value instanceof Promise) {
|
if (value instanceof Promise) {
|
||||||
return luaToString(await value);
|
return value.then(luaToString);
|
||||||
}
|
}
|
||||||
if (value.toStringAsync) {
|
if (value.toStringAsync) {
|
||||||
return value.toStringAsync();
|
return value.toStringAsync();
|
||||||
}
|
}
|
||||||
// Handle plain JavaScript objects in a Lua-like format
|
// Handle plain JavaScript objects in a Lua-like format
|
||||||
if (typeof value === "object") {
|
if (typeof value === "object") {
|
||||||
|
return (async () => {
|
||||||
let result = "{";
|
let result = "{";
|
||||||
let first = true;
|
let first = true;
|
||||||
|
|
||||||
|
@ -726,6 +738,7 @@ export async function luaToString(value: any): Promise<string> {
|
||||||
}
|
}
|
||||||
result += "}";
|
result += "}";
|
||||||
return result;
|
return result;
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
return String(value);
|
return String(value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
luaToString,
|
luaToString,
|
||||||
luaTypeOf,
|
luaTypeOf,
|
||||||
type LuaValue,
|
type LuaValue,
|
||||||
|
luaValueToJS,
|
||||||
} from "$common/space_lua/runtime.ts";
|
} from "$common/space_lua/runtime.ts";
|
||||||
import { stringApi } from "$common/space_lua/stdlib/string.ts";
|
import { stringApi } from "$common/space_lua/stdlib/string.ts";
|
||||||
import { tableApi } from "$common/space_lua/stdlib/table.ts";
|
import { tableApi } from "$common/space_lua/stdlib/table.ts";
|
||||||
|
@ -20,11 +21,13 @@ import {
|
||||||
interpolateLuaString,
|
interpolateLuaString,
|
||||||
spaceLuaApi,
|
spaceLuaApi,
|
||||||
} from "$common/space_lua/stdlib/space_lua.ts";
|
} from "$common/space_lua/stdlib/space_lua.ts";
|
||||||
import type {
|
import {
|
||||||
LuaCollectionQuery,
|
findAllQueryVariables,
|
||||||
LuaQueryCollection,
|
type LuaCollectionQuery,
|
||||||
|
type LuaQueryCollection,
|
||||||
} from "$common/space_lua/query_collection.ts";
|
} from "$common/space_lua/query_collection.ts";
|
||||||
import { templateApi } from "$common/space_lua/stdlib/template.ts";
|
import { templateApi } from "$common/space_lua/stdlib/template.ts";
|
||||||
|
import { json } from "@codemirror/legacy-modes/X-ZUBjb2RlbWlycm9yL2xhbmd1YWdl/mode/javascript.d.ts";
|
||||||
|
|
||||||
const printFunction = new LuaBuiltinFunction(async (_sf, ...args) => {
|
const printFunction = new LuaBuiltinFunction(async (_sf, ...args) => {
|
||||||
console.log("[Lua]", ...(await Promise.all(args.map(luaToString))));
|
console.log("[Lua]", ...(await Promise.all(args.map(luaToString))));
|
||||||
|
@ -135,8 +138,7 @@ const setmetatableFunction = new LuaBuiltinFunction(
|
||||||
|
|
||||||
const rawsetFunction = new LuaBuiltinFunction(
|
const rawsetFunction = new LuaBuiltinFunction(
|
||||||
(_sf, table: LuaTable, key: LuaValue, value: LuaValue) => {
|
(_sf, table: LuaTable, key: LuaValue, value: LuaValue) => {
|
||||||
table.rawSet(key, value);
|
return table.rawSet(key, value);
|
||||||
return table;
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -152,7 +154,28 @@ const tagFunction = new LuaBuiltinFunction(
|
||||||
throw new LuaRuntimeError("Global not found", sf);
|
throw new LuaRuntimeError("Global not found", sf);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
query: async (query: LuaCollectionQuery): Promise<any[]> => {
|
query: async (query: LuaCollectionQuery, env: LuaEnv): Promise<any[]> => {
|
||||||
|
const localVars = findAllQueryVariables(query).filter((v) =>
|
||||||
|
!global.has(v) && v !== "_"
|
||||||
|
);
|
||||||
|
const scopedVariables: Record<string, any> = {};
|
||||||
|
for (const v of localVars) {
|
||||||
|
try {
|
||||||
|
const jsonValue = await luaValueToJS(env.get(v));
|
||||||
|
// Ensure this is JSON serializable
|
||||||
|
JSON.stringify(jsonValue);
|
||||||
|
scopedVariables[v] = jsonValue;
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(
|
||||||
|
"Failed to JSON serialize variable",
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
throw new LuaRuntimeError(
|
||||||
|
`Failed to JSON serialize variable ${v} in query`,
|
||||||
|
sf,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
return (await global.get("datastore").get("query_lua").call(
|
return (await global.get("datastore").get("query_lua").call(
|
||||||
sf,
|
sf,
|
||||||
[
|
[
|
||||||
|
@ -160,6 +183,7 @@ const tagFunction = new LuaBuiltinFunction(
|
||||||
tagName,
|
tagName,
|
||||||
],
|
],
|
||||||
query,
|
query,
|
||||||
|
scopedVariables,
|
||||||
)).toJSArray();
|
)).toJSArray();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,43 @@ import {
|
||||||
luaToString,
|
luaToString,
|
||||||
} from "$common/space_lua/runtime.ts";
|
} from "$common/space_lua/runtime.ts";
|
||||||
|
|
||||||
|
function createLuaMatcher(pattern: string, global = false) {
|
||||||
|
const jsPattern = pattern
|
||||||
|
.replace(/%(.)/g, (_, char) => {
|
||||||
|
switch (char) {
|
||||||
|
case ".":
|
||||||
|
return "[.]";
|
||||||
|
case "%":
|
||||||
|
return "%";
|
||||||
|
case "d":
|
||||||
|
return "\\d";
|
||||||
|
case "D":
|
||||||
|
return "\\D";
|
||||||
|
case "s":
|
||||||
|
return "\\s";
|
||||||
|
case "S":
|
||||||
|
return "\\S";
|
||||||
|
case "w":
|
||||||
|
return "\\w";
|
||||||
|
case "a":
|
||||||
|
return "[A-Za-z]";
|
||||||
|
case "l":
|
||||||
|
return "[a-z]";
|
||||||
|
case "u":
|
||||||
|
return "[A-Z]";
|
||||||
|
case "p":
|
||||||
|
return "[\\p{P}]";
|
||||||
|
default:
|
||||||
|
return char;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const regex = new RegExp(jsPattern, global ? "g" : undefined);
|
||||||
|
return (s: string) => {
|
||||||
|
return regex.exec(s);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const stringApi = new LuaTable({
|
export const stringApi = new LuaTable({
|
||||||
byte: new LuaBuiltinFunction((_sf, s: string, i?: number, j?: number) => {
|
byte: new LuaBuiltinFunction((_sf, s: string, i?: number, j?: number) => {
|
||||||
i = i ?? 1;
|
i = i ?? 1;
|
||||||
|
@ -34,27 +71,9 @@ export const stringApi = new LuaTable({
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
gmatch: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
|
gmatch: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
|
||||||
const jsPattern = pattern
|
const matcher = createLuaMatcher(pattern, true);
|
||||||
.replace(/%(.)/g, (_, char) => {
|
|
||||||
switch (char) {
|
|
||||||
case ".":
|
|
||||||
return "[.]";
|
|
||||||
case "%":
|
|
||||||
return "%";
|
|
||||||
case "d":
|
|
||||||
return "\\d";
|
|
||||||
case "s":
|
|
||||||
return "\\s";
|
|
||||||
case "w":
|
|
||||||
return "\\w";
|
|
||||||
default:
|
|
||||||
return char;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const regex = new RegExp(jsPattern, "g");
|
|
||||||
return () => {
|
return () => {
|
||||||
const result = regex.exec(s);
|
const result = matcher(s);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -155,11 +174,12 @@ export const stringApi = new LuaTable({
|
||||||
match: new LuaBuiltinFunction(
|
match: new LuaBuiltinFunction(
|
||||||
(_sf, s: string, pattern: string, init?: number) => {
|
(_sf, s: string, pattern: string, init?: number) => {
|
||||||
init = init ?? 1;
|
init = init ?? 1;
|
||||||
const result = s.slice(init - 1).match(pattern);
|
const result = createLuaMatcher(pattern)(s.slice(init - 1));
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return new LuaMultiRes([]);
|
return new LuaMultiRes([]);
|
||||||
}
|
}
|
||||||
return new LuaMultiRes(result.slice(1));
|
const captures = result.slice(1);
|
||||||
|
return new LuaMultiRes(captures.length > 0 ? captures : [result[0]]);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
rep: new LuaBuiltinFunction((_sf, s: string, n: number, sep?: string) => {
|
rep: new LuaBuiltinFunction((_sf, s: string, n: number, sep?: string) => {
|
||||||
|
|
|
@ -106,4 +106,38 @@ assert_equal(string.startswith("hello world", "world"), false)
|
||||||
assert_equal(string.endswith("hello world", "world"), true)
|
assert_equal(string.endswith("hello world", "world"), true)
|
||||||
assert_equal(string.endswith("hello world", "hello"), false)
|
assert_equal(string.endswith("hello world", "hello"), false)
|
||||||
|
|
||||||
|
-- Extended string.match tests
|
||||||
|
-- Basic pattern matching
|
||||||
|
assert_equal(string.match("hello", "h"), "h")
|
||||||
|
assert_equal(string.match("hello", "hello"), "hello")
|
||||||
|
|
||||||
|
-- Test with no matches
|
||||||
|
assert_equal(string.match("hello", "x"), nil)
|
||||||
|
|
||||||
|
-- Test with captures
|
||||||
|
local m1, m2 = string.match("hello", "(h)(ello)")
|
||||||
|
assert_equal(m1, "h")
|
||||||
|
assert_equal(m2, "ello")
|
||||||
|
|
||||||
|
-- Test with init position
|
||||||
|
local init_match = string.match("hello world", "(world)", 7)
|
||||||
|
assert_equal(init_match, "world")
|
||||||
|
|
||||||
|
-- Test init position with no match
|
||||||
|
assert_equal(string.match("hello world", "hello", 7), nil)
|
||||||
|
|
||||||
|
-- Test pattern characters
|
||||||
|
assert_equal(string.match("123", "%d+"), "123")
|
||||||
|
assert_equal(string.match("abc123", "%a+"), "abc")
|
||||||
|
assert_equal(string.match(" abc", "%s+"), " ")
|
||||||
|
|
||||||
|
-- Test multiple captures
|
||||||
|
local day, month, year = string.match("2024-03-14", "(%d+)-(%d+)-(%d+)")
|
||||||
|
assert_equal(day, "2024")
|
||||||
|
assert_equal(month, "03")
|
||||||
|
assert_equal(year, "14")
|
||||||
|
|
||||||
|
-- Test optional captures
|
||||||
|
local word = string.match("The quick brown fox", "%s*(%w+)%s*")
|
||||||
|
assert_equal(word, "The")
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,9 @@ export const tableApi = new LuaTable({
|
||||||
*/
|
*/
|
||||||
includes: new LuaBuiltinFunction(
|
includes: new LuaBuiltinFunction(
|
||||||
(sf, tbl: LuaTable | Record<string, any>, value: LuaValue) => {
|
(sf, tbl: LuaTable | Record<string, any>, value: LuaValue) => {
|
||||||
|
if (!tbl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (tbl instanceof LuaTable) {
|
if (tbl instanceof LuaTable) {
|
||||||
// Iterate over the table
|
// Iterate over the table
|
||||||
for (const key of tbl.keys()) {
|
for (const key of tbl.keys()) {
|
||||||
|
|
|
@ -6,7 +6,12 @@ import type { CommonSystem } from "$common/common_system.ts";
|
||||||
import type { KV, KvKey, KvQuery } from "../../../plug-api/types.ts";
|
import type { KV, KvKey, KvQuery } from "../../../plug-api/types.ts";
|
||||||
import type { DataStore } from "../../data/datastore.ts";
|
import type { DataStore } from "../../data/datastore.ts";
|
||||||
import type { SysCallMapping } from "../system.ts";
|
import type { SysCallMapping } from "../system.ts";
|
||||||
import { LuaStackFrame, luaValueToJS } from "$common/space_lua/runtime.ts";
|
import {
|
||||||
|
jsToLuaValue,
|
||||||
|
LuaEnv,
|
||||||
|
LuaStackFrame,
|
||||||
|
luaValueToJS,
|
||||||
|
} from "$common/space_lua/runtime.ts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exposes the datastore API to plugs, but scoping everything to a prefix based on the plug's name
|
* Exposes the datastore API to plugs, but scoping everything to a prefix based on the plug's name
|
||||||
|
@ -41,11 +46,16 @@ export function dataStoreReadSyscalls(
|
||||||
_ctx,
|
_ctx,
|
||||||
prefix: string[],
|
prefix: string[],
|
||||||
query: LuaCollectionQuery,
|
query: LuaCollectionQuery,
|
||||||
|
scopeVariables: Record<string, any> = {},
|
||||||
): Promise<KV[]> => {
|
): Promise<KV[]> => {
|
||||||
const dsQueryCollection = new DataStoreQueryCollection(ds, prefix);
|
const dsQueryCollection = new DataStoreQueryCollection(ds, prefix);
|
||||||
|
const env = new LuaEnv(commonSystem.spaceLuaEnv.env);
|
||||||
|
for (const [key, value] of Object.entries(scopeVariables)) {
|
||||||
|
env.set(key, jsToLuaValue(value));
|
||||||
|
}
|
||||||
return (await dsQueryCollection.query(
|
return (await dsQueryCollection.query(
|
||||||
query,
|
query,
|
||||||
commonSystem.spaceLuaEnv.env,
|
env,
|
||||||
LuaStackFrame.lostFrame,
|
LuaStackFrame.lostFrame,
|
||||||
)).map((item) => luaValueToJS(item));
|
)).map((item) => luaValueToJS(item));
|
||||||
},
|
},
|
||||||
|
|
|
@ -74,8 +74,9 @@ export function query(
|
||||||
export function queryLua(
|
export function queryLua(
|
||||||
prefix: string[],
|
prefix: string[],
|
||||||
query: LuaCollectionQuery,
|
query: LuaCollectionQuery,
|
||||||
|
scopeVariables: Record<string, any>,
|
||||||
): Promise<KV[]> {
|
): Promise<KV[]> {
|
||||||
return syscall("datastore.queryLua", prefix, query);
|
return syscall("datastore.queryLua", prefix, query, scopeVariables);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -64,7 +64,7 @@ export class ServerSystem extends CommonSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always needs to be invoked right after construction
|
// Always needs to be invoked right after construction
|
||||||
async init(awaitIndex = false) {
|
async init(awaitIndex = false, performIndex = true) {
|
||||||
this.system = new System(
|
this.system = new System(
|
||||||
"server",
|
"server",
|
||||||
{
|
{
|
||||||
|
@ -219,11 +219,13 @@ export class ServerSystem extends CommonSystem {
|
||||||
|
|
||||||
space.updatePageList().catch(console.error);
|
space.updatePageList().catch(console.error);
|
||||||
|
|
||||||
|
if (performIndex) {
|
||||||
// Ensure a valid index
|
// Ensure a valid index
|
||||||
const indexPromise = ensureSpaceIndex(this.ds, this.system);
|
const indexPromise = ensureSpaceIndex(this.ds, this.system);
|
||||||
if (awaitIndex) {
|
if (awaitIndex) {
|
||||||
await indexPromise;
|
await indexPromise;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await this.eventHook.dispatchEvent("system:ready");
|
await this.eventHook.dispatchEvent("system:ready");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue