@gonvex/cli 0.5.2-staging.13 → 0.5.2-staging.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +24 -5
- package/dist/index.js.map +1 -1
- package/dist/lazy-reference-bindings.d.ts +3 -0
- package/dist/lazy-reference-bindings.js +22 -0
- package/dist/lazy-reference-bindings.js.map +1 -0
- package/dist/local-bindings.d.ts +1 -1
- package/dist/local-bindings.js +35 -6
- package/dist/local-bindings.js.map +1 -1
- package/dist/local-schema.d.ts +6 -0
- package/dist/local-schema.js +55 -0
- package/dist/local-schema.js.map +1 -0
- package/dist/manifest-types.d.ts +28 -1
- package/dist/module-artifact.js +77 -4
- package/dist/module-artifact.js.map +1 -1
- package/dist/native-local-bindings.d.ts +2 -2
- package/dist/native-local-bindings.js +17 -76
- package/dist/native-local-bindings.js.map +1 -1
- package/dist/pglite-browser-bundle.d.ts +3 -0
- package/dist/pglite-browser-bundle.js +35 -0
- package/dist/pglite-browser-bundle.js.map +1 -0
- package/package.json +5 -4
package/dist/local-bindings.js
CHANGED
|
@@ -3,7 +3,7 @@ import { rolldown } from "rolldown";
|
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { readFile, readdir, writeFile, mkdir } from "node:fs/promises";
|
|
5
5
|
import { dirname, join, relative, resolve } from "node:path";
|
|
6
|
-
import { compileLocalSchema } from "
|
|
6
|
+
import { compileLocalSchema } from "./local-schema.js";
|
|
7
7
|
export async function projectLocalSchema(root) {
|
|
8
8
|
const migrationDirectory = join(root, "migrations");
|
|
9
9
|
const names = (await readdir(migrationDirectory).catch(() => [])).filter((name) => name.endsWith(".sql")).sort();
|
|
@@ -39,15 +39,44 @@ export async function localBindings(root, manifest) {
|
|
|
39
39
|
await writeFile(entryFile, `${imports.join("\n")}\nexport const localReducers = {${reducers.map(([path], index) => `${JSON.stringify(path)}: reducer${index}`).join(",")}};`);
|
|
40
40
|
const bundle = await rolldown({
|
|
41
41
|
input: entryFile, cwd: root, platform: "browser", tsconfig: false,
|
|
42
|
-
|
|
42
|
+
// These declarations describe server entry points. Their definitions and
|
|
43
|
+
// schema construction are unnecessary when only Reducer exports are used.
|
|
44
|
+
treeshake: { manualPureFunctions: ["action", "internalReducer", "query", "internalQuery", "liveQuery", "replicaCollection", "visibility", "cron", "tenantCron", "schema"] },
|
|
43
45
|
resolve: { conditionNames: ["browser", "import", "default"], mainFields: ["browser", "module", "main"] },
|
|
44
46
|
});
|
|
45
47
|
let localCode;
|
|
48
|
+
const webChunks = {};
|
|
46
49
|
try {
|
|
47
50
|
const output = await bundle.generate({ format: "esm", codeSplitting: false });
|
|
48
51
|
if (output.output.length !== 1 || output.output[0]?.type !== "chunk")
|
|
49
52
|
throw new Error("Local Reducers must compile into one self-contained module");
|
|
50
53
|
localCode = output.output[0].code;
|
|
54
|
+
// Browser controls preload their own Reducers. Unopened features keep
|
|
55
|
+
// their code on disk instead of importing every application module at boot.
|
|
56
|
+
const lazyEntry = join(root, 'gonvex', '_build', 'local-lazy-entry.ts');
|
|
57
|
+
const loaders = reducers.map(([path, entry]) => {
|
|
58
|
+
let file = relative(dirname(lazyEntry), resolve(root, entry.file)).replaceAll('\\', '/').replace(/\.(?:tsx?|mts|cts)$/, '.js');
|
|
59
|
+
if (!file.startsWith('.'))
|
|
60
|
+
file = `./${file}`;
|
|
61
|
+
return `${JSON.stringify(path)}: () => import(${JSON.stringify(file)}).then(module => module.${entry.handler})`;
|
|
62
|
+
});
|
|
63
|
+
await writeFile(lazyEntry, `export const localReducers = {${loaders.join(',')}};`);
|
|
64
|
+
const lazyBundle = await rolldown({ input: lazyEntry, cwd: root, platform: 'browser', tsconfig: false,
|
|
65
|
+
treeshake: { manualPureFunctions: ['action', 'internalReducer', 'query', 'internalQuery', 'liveQuery', 'replicaCollection', 'visibility', 'cron', 'tenantCron', 'schema'] },
|
|
66
|
+
resolve: { conditionNames: ['browser', 'import', 'default'], mainFields: ['browser', 'module', 'main'] },
|
|
67
|
+
});
|
|
68
|
+
let web;
|
|
69
|
+
try {
|
|
70
|
+
web = await lazyBundle.generate({ format: 'esm', entryFileNames: 'local-reducers.js', chunkFileNames: 'local-reducer-[name]-[hash].js' });
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
await lazyBundle.close();
|
|
74
|
+
}
|
|
75
|
+
for (const chunk of web.output) {
|
|
76
|
+
if (chunk.type !== "chunk")
|
|
77
|
+
throw new Error("Unexpected local Reducer asset");
|
|
78
|
+
webChunks[chunk.fileName] = chunk.code;
|
|
79
|
+
}
|
|
51
80
|
}
|
|
52
81
|
finally {
|
|
53
82
|
await bundle.close();
|
|
@@ -62,10 +91,10 @@ export async function localBindings(root, manifest) {
|
|
|
62
91
|
return {
|
|
63
92
|
...native,
|
|
64
93
|
"local-schema.ts": `${header}export const localSchema = ${JSON.stringify(schema)} as const;\n`,
|
|
65
|
-
|
|
66
|
-
"local-reducers.d.ts": `${header}import type { ReducerDefinition } from "@gonvex/module-sdk";\nexport declare const localReducers: Readonly<Record<string, ReducerDefinition<any, any
|
|
67
|
-
"local-
|
|
68
|
-
"local-
|
|
94
|
+
...Object.fromEntries(Object.entries(webChunks).map(([name, code]) => [name, header + code])),
|
|
95
|
+
"local-reducers.d.ts": `${header}import type { ReducerDefinition } from "@gonvex/module-sdk";\nexport declare const localReducers: Readonly<Record<string, () => Promise<ReducerDefinition<any, any>>>>;\n`,
|
|
96
|
+
"local-runtime.ts": `${header}export {localRuntime} from "./local-executor.js";\n`,
|
|
97
|
+
"local-executor.ts": `${header}import { createPortableReducer } from "@gonvex/local-runtime/portable-client";\nimport { localSchema } from "./local-schema.js";\nimport { localReducers } from "./local-reducers.js";\nexport const localRuntime = { mode: "portable" as const, clientContract: ${JSON.stringify(clientContract)}, artifactHash: ${JSON.stringify(manifest.module.hash)}, tables: ${JSON.stringify(Object.keys(schema))}, collections: ${JSON.stringify(Object.entries(manifest.functions).filter(([path]) => path.startsWith("__local.")).map(([path, entry]) => ({ kind: "query", path, delivery: "replica", replica: entry.replica })))} as const, create: () => createPortableReducer({schema: localSchema, reducers: localReducers, artifactHash: ${JSON.stringify(manifest.module.hash)}}) };\n`,
|
|
69
98
|
};
|
|
70
99
|
}
|
|
71
100
|
//# sourceMappingURL=local-bindings.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-bindings.js","sourceRoot":"","sources":["../src/local-bindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"local-bindings.js","sourceRoot":"","sources":["../src/local-bindings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { LocalSchema } from "@gonvex/local-runtime/schema";
|
|
2
|
+
/** Compile schema using PostgreSQL itself, without connecting to a service. */
|
|
3
|
+
export declare function compileLocalSchema(migrations: readonly {
|
|
4
|
+
name: string;
|
|
5
|
+
sql: string;
|
|
6
|
+
}[]): Promise<LocalSchema>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { PGlite } from "@electric-sql/pglite";
|
|
2
|
+
import { pg_trgm } from "@electric-sql/pglite/contrib/pg_trgm";
|
|
3
|
+
// The framework's tenant identity table exists before application migrations.
|
|
4
|
+
// Keep this in parity with TENANT_IDENTITY_SQL in postgres/src/provision.rs.
|
|
5
|
+
const identitySchema = `CREATE TABLE members (
|
|
6
|
+
id text PRIMARY KEY, account_id text NOT NULL UNIQUE, status text NOT NULL DEFAULT 'active',
|
|
7
|
+
display_name text NOT NULL DEFAULT '', avatar_url text NOT NULL DEFAULT '',
|
|
8
|
+
role text NOT NULL DEFAULT 'member', permissions jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
9
|
+
membership_revision bigint NOT NULL DEFAULT 1,
|
|
10
|
+
created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now()
|
|
11
|
+
)`;
|
|
12
|
+
/** Compile schema using PostgreSQL itself, without connecting to a service. */
|
|
13
|
+
export async function compileLocalSchema(migrations) {
|
|
14
|
+
const db = new PGlite({ extensions: { pg_trgm } });
|
|
15
|
+
try {
|
|
16
|
+
await db.exec(identitySchema);
|
|
17
|
+
for (const migration of migrations) {
|
|
18
|
+
// gen_random_uuid is built into modern PostgreSQL. PGlite does not ship
|
|
19
|
+
// pgcrypto's OpenSSL extension; remaining references fail explicitly.
|
|
20
|
+
const sql = migration.sql.replace(/CREATE\s+EXTENSION\s+(?:IF\s+NOT\s+EXISTS\s+)?["']?pgcrypto["']?\s*;/gi, "");
|
|
21
|
+
try {
|
|
22
|
+
await db.exec(sql);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
throw new Error(`Local schema compilation failed in ${migration.name}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const { rows } = await db.query(`SELECT c.relname AS table_name, a.attname AS column_name,
|
|
29
|
+
format_type(a.atttypid, a.atttypmod) AS type, NOT a.attnotnull AS nullable,
|
|
30
|
+
pg_get_expr(d.adbin, d.adrelid) AS column_default,
|
|
31
|
+
EXISTS (SELECT 1 FROM pg_index i WHERE i.indrelid=c.oid AND i.indisprimary AND a.attnum=ANY(i.indkey)) AS primary_key
|
|
32
|
+
FROM pg_class c JOIN pg_namespace n ON c.relnamespace=n.oid
|
|
33
|
+
JOIN pg_attribute a ON a.attrelid=c.oid AND a.attnum>0 AND NOT a.attisdropped
|
|
34
|
+
LEFT JOIN pg_attrdef d ON d.adrelid=c.oid AND d.adnum=a.attnum
|
|
35
|
+
WHERE n.nspname='public' AND c.relkind='r'
|
|
36
|
+
ORDER BY c.relname, a.attnum`);
|
|
37
|
+
const schema = {};
|
|
38
|
+
for (const row of rows) {
|
|
39
|
+
if (row.table_name.startsWith("_gonvex"))
|
|
40
|
+
continue;
|
|
41
|
+
const table = schema[row.table_name] ??= { key: "_id", columns: {} };
|
|
42
|
+
if (row.primary_key)
|
|
43
|
+
table.key = row.column_name;
|
|
44
|
+
table.columns[row.column_name] = {
|
|
45
|
+
type: row.type, nullable: row.nullable,
|
|
46
|
+
...(row.column_default ? { default: row.column_default } : {}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return schema;
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
await db.close();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=local-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-schema.js","sourceRoot":"","sources":["../src/local-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAI/D,8EAA8E;AAC9E,6EAA6E;AAC7E,MAAM,cAAc,GAAG;;;;;;EAMrB,CAAC;AAEH,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,UAAoD;IAC3F,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC9B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,wEAAwE;YACxE,sEAAsE;YACtE,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,wEAAwE,EAAE,EAAE,CAAC,CAAC;YAChH,IAAI,CAAC;gBAAC,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAAC,CAAC;YAC3B,OAAO,KAAK,EAAE,CAAC;gBAAC,MAAM,IAAI,KAAK,CAAC,sCAAsC,SAAS,CAAC,IAAI,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YAAC,CAAC;QACzK,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,KAAK,CAG5B;;;;;;;;mCAQ4B,CAAC,CAAC;QACjC,MAAM,MAAM,GAAgB,EAAE,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC;gBAAE,SAAS;YACnD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACrE,IAAI,GAAG,CAAC,WAAW;gBAAE,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC;YACjD,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG;gBAC/B,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/D,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AACjC,CAAC"}
|
package/dist/manifest-types.d.ts
CHANGED
|
@@ -75,6 +75,27 @@ export type LiveQueryPlan = {
|
|
|
75
75
|
search?: {
|
|
76
76
|
argument: string;
|
|
77
77
|
columns: string[];
|
|
78
|
+
booleanTerms?: boolean;
|
|
79
|
+
offlineColumns?: string[];
|
|
80
|
+
sources?: {
|
|
81
|
+
table: string;
|
|
82
|
+
key: string;
|
|
83
|
+
column: string;
|
|
84
|
+
dependencies?: string[];
|
|
85
|
+
}[];
|
|
86
|
+
};
|
|
87
|
+
index?: {
|
|
88
|
+
table: string;
|
|
89
|
+
key: string;
|
|
90
|
+
columns: string[];
|
|
91
|
+
sortColumns?: Record<string, string[]>;
|
|
92
|
+
dependencies?: string[];
|
|
93
|
+
referenceFields?: Record<string, {
|
|
94
|
+
table: string;
|
|
95
|
+
foreignKey: string;
|
|
96
|
+
column: string;
|
|
97
|
+
fallback?: JsonValue;
|
|
98
|
+
}>;
|
|
78
99
|
};
|
|
79
100
|
filters?: {
|
|
80
101
|
argument: string;
|
|
@@ -100,13 +121,19 @@ export type LiveQueryPlan = {
|
|
|
100
121
|
};
|
|
101
122
|
export type FilterOperator = "contains" | "notContains" | "equals" | "notEquals" | "startsWith" | "endsWith" | "empty" | "notEmpty" | "oneOf" | "lessThan" | "lessThanOrEqual" | "greaterThan" | "greaterThanOrEqual" | "inRange";
|
|
102
123
|
export type LiveExpression = {
|
|
103
|
-
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "contains" | "containsInsensitive" | "range" | "and" | "or" | "not" | "server";
|
|
124
|
+
operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "contains" | "containsInsensitive" | "range" | "and" | "or" | "not" | "server" | "inRelation" | "arrayContains";
|
|
104
125
|
column?: string;
|
|
105
126
|
value?: LiveValue;
|
|
106
127
|
valueTo?: LiveValue;
|
|
107
128
|
children?: LiveExpression[];
|
|
129
|
+
relation?: {
|
|
130
|
+
table: string;
|
|
131
|
+
column: string;
|
|
132
|
+
where?: LiveExpression;
|
|
133
|
+
};
|
|
108
134
|
};
|
|
109
135
|
export type LiveValue = {
|
|
136
|
+
context?: "account.id" | "member.id" | "tenant.id";
|
|
110
137
|
argument?: string;
|
|
111
138
|
literal?: unknown;
|
|
112
139
|
};
|
package/dist/module-artifact.js
CHANGED
|
@@ -1040,7 +1040,11 @@ function normalizeDelivery(value) {
|
|
|
1040
1040
|
return undefined;
|
|
1041
1041
|
}
|
|
1042
1042
|
function liveQueryPlanFromOptions(options) {
|
|
1043
|
-
|
|
1043
|
+
const declared = options.get("liveQueryPlan");
|
|
1044
|
+
const plan = parseLiveQueryPlan(declared?.value);
|
|
1045
|
+
if (declared && !plan)
|
|
1046
|
+
throw new Error('liveQueryPlan must be a literal object, including nested metadata');
|
|
1047
|
+
return plan;
|
|
1044
1048
|
}
|
|
1045
1049
|
function parseLiveQueryPlan(value) {
|
|
1046
1050
|
const table = stringMember(value, "table");
|
|
@@ -1061,9 +1065,62 @@ function parseLiveQueryPlan(value) {
|
|
|
1061
1065
|
plan.where = where;
|
|
1062
1066
|
const searchValue = readMember(value, "search");
|
|
1063
1067
|
const searchArgument = stringMember(searchValue, "argument");
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1068
|
+
const rawSearchColumns = readMember(searchValue, "columns");
|
|
1069
|
+
const searchColumns = Array.isArray(rawSearchColumns) && rawSearchColumns.length === 0 ? [] : stringArray(rawSearchColumns);
|
|
1070
|
+
if (searchArgument && searchColumns) {
|
|
1066
1071
|
plan.search = { argument: searchArgument, columns: searchColumns };
|
|
1072
|
+
if (readMember(searchValue, 'booleanTerms') === true)
|
|
1073
|
+
plan.search.booleanTerms = true;
|
|
1074
|
+
const offlineColumns = stringArray(readMember(searchValue, 'offlineColumns'));
|
|
1075
|
+
if (offlineColumns)
|
|
1076
|
+
plan.search.offlineColumns = offlineColumns;
|
|
1077
|
+
const sources = readMember(searchValue, 'sources');
|
|
1078
|
+
if (sources !== undefined) {
|
|
1079
|
+
if (!Array.isArray(sources))
|
|
1080
|
+
throw new Error('Search sources must be a literal array');
|
|
1081
|
+
plan.search.sources = sources.map(source => {
|
|
1082
|
+
const table = stringMember(source, 'table'), key = stringMember(source, 'key'), column = stringMember(source, 'column');
|
|
1083
|
+
if (!table || !key || !column)
|
|
1084
|
+
throw new Error('Search sources require table, key and column');
|
|
1085
|
+
const dependencies = stringArray(readMember(source, 'dependencies'));
|
|
1086
|
+
return { table, key, column, ...(dependencies ? { dependencies } : {}) };
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
const indexValue = readMember(value, 'index');
|
|
1091
|
+
if (indexValue !== undefined) {
|
|
1092
|
+
const table = stringMember(indexValue, 'table'), key = stringMember(indexValue, 'key');
|
|
1093
|
+
const columns = stringArray(readMember(indexValue, 'columns'));
|
|
1094
|
+
if (!table || !key || !columns)
|
|
1095
|
+
throw new Error('Live Query indexes require literal table, key and columns');
|
|
1096
|
+
plan.index = { table, key, columns };
|
|
1097
|
+
const referenceFields = readMember(indexValue, 'referenceFields');
|
|
1098
|
+
if (referenceFields !== undefined) {
|
|
1099
|
+
if (!isJsonObject(referenceFields))
|
|
1100
|
+
throw new Error('Index referenceFields must be a literal object');
|
|
1101
|
+
plan.index.referenceFields = Object.fromEntries(Object.entries(referenceFields).map(([name, field]) => {
|
|
1102
|
+
const table = stringMember(field, 'table'), foreignKey = stringMember(field, 'foreignKey'), column = stringMember(field, 'column');
|
|
1103
|
+
if (!table || !foreignKey || !column)
|
|
1104
|
+
throw new Error('Index reference fields require table, foreignKey and column');
|
|
1105
|
+
const fallback = readMember(field, 'fallback');
|
|
1106
|
+
return [name, { table, foreignKey, column, ...(fallback !== undefined ? { fallback } : {}) }];
|
|
1107
|
+
}));
|
|
1108
|
+
}
|
|
1109
|
+
const dependencies = stringArray(readMember(indexValue, 'dependencies'));
|
|
1110
|
+
if (dependencies)
|
|
1111
|
+
plan.index.dependencies = dependencies;
|
|
1112
|
+
const sortColumns = readMember(indexValue, 'sortColumns');
|
|
1113
|
+
if (sortColumns !== undefined) {
|
|
1114
|
+
if (!isJsonObject(sortColumns))
|
|
1115
|
+
throw new Error('Index sortColumns must be a literal object');
|
|
1116
|
+
plan.index.sortColumns = Object.fromEntries(Object.entries(sortColumns).map(([column, value]) => {
|
|
1117
|
+
const fields = stringArray(value);
|
|
1118
|
+
if (!fields?.length)
|
|
1119
|
+
throw new Error('Index sort columns must be a nonempty string array');
|
|
1120
|
+
return [column, fields];
|
|
1121
|
+
}));
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1067
1124
|
const filtersValue = readMember(value, "filters");
|
|
1068
1125
|
const filtersArgument = stringMember(filtersValue, "argument");
|
|
1069
1126
|
const filtersColumns = stringArray(readMember(filtersValue, "allowedColumns"));
|
|
@@ -1112,10 +1169,20 @@ function parseLiveExpression(value) {
|
|
|
1112
1169
|
const operator = stringMember(value, "operator");
|
|
1113
1170
|
if (!operator || ![
|
|
1114
1171
|
"eq", "neq", "gt", "gte", "lt", "lte", "in", "contains",
|
|
1115
|
-
"containsInsensitive", "range", "and", "or", "not", "server",
|
|
1172
|
+
"containsInsensitive", "range", "and", "or", "not", "server", "inRelation", "arrayContains",
|
|
1116
1173
|
].includes(operator))
|
|
1117
1174
|
return undefined;
|
|
1118
1175
|
const expression = { operator: operator };
|
|
1176
|
+
if (operator === 'inRelation') {
|
|
1177
|
+
const relation = readMember(value, 'relation');
|
|
1178
|
+
const table = stringMember(relation, 'table'), column = stringMember(relation, 'column');
|
|
1179
|
+
if (!table || !column)
|
|
1180
|
+
throw new Error('Related query scopes require a literal table and column');
|
|
1181
|
+
const where = parseLiveExpression(readMember(relation, 'where'));
|
|
1182
|
+
if (readMember(relation, 'where') !== undefined && !where)
|
|
1183
|
+
throw new Error('Invalid related query predicate');
|
|
1184
|
+
expression.relation = { table, column, ...(where ? { where } : {}) };
|
|
1185
|
+
}
|
|
1119
1186
|
const column = stringMember(value, "column");
|
|
1120
1187
|
if (column)
|
|
1121
1188
|
expression.column = column;
|
|
@@ -1134,6 +1201,12 @@ function parseLiveExpression(value) {
|
|
|
1134
1201
|
return expression;
|
|
1135
1202
|
}
|
|
1136
1203
|
function parseLiveValue(value) {
|
|
1204
|
+
const context = stringMember(value, 'context');
|
|
1205
|
+
if (context) {
|
|
1206
|
+
if (!['account.id', 'member.id', 'tenant.id'].includes(context))
|
|
1207
|
+
throw new Error('Invalid query identity context');
|
|
1208
|
+
return { context: context };
|
|
1209
|
+
}
|
|
1137
1210
|
const argument = stringMember(value, "argument");
|
|
1138
1211
|
if (argument)
|
|
1139
1212
|
return { argument };
|