@ai-matrx/records 0.73.3 → 0.73.5
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/CHANGELOG.md +12 -0
- package/dist/memory/index.cjs +310 -79
- package/dist/memory/index.cjs.map +1 -1
- package/dist/memory/index.d.cts +65 -1
- package/dist/memory/index.d.ts +65 -1
- package/dist/memory/index.js +310 -79
- package/dist/memory/index.js.map +1 -1
- package/package.json +3 -3
package/dist/memory/index.js
CHANGED
|
@@ -1,3 +1,171 @@
|
|
|
1
|
+
// src/memory/entity.ts
|
|
2
|
+
var ok = (data) => ({ data, error: null });
|
|
3
|
+
var refuse = (message, code = "22023", hint = null) => ({
|
|
4
|
+
data: null,
|
|
5
|
+
error: { code, message, details: null, hint }
|
|
6
|
+
});
|
|
7
|
+
function memoryEntityDescribe(e) {
|
|
8
|
+
const dimensions = e.columns.filter((c) => c.type === "choice" && Array.isArray(c.choices)).map((c) => ({
|
|
9
|
+
key: c.api_name,
|
|
10
|
+
label: c.name,
|
|
11
|
+
from: c.api_name,
|
|
12
|
+
kind: "choice",
|
|
13
|
+
cardinality: "low",
|
|
14
|
+
choices: (c.choices ?? []).map((w) => ({ value: w, label: w }))
|
|
15
|
+
}));
|
|
16
|
+
const measures = [
|
|
17
|
+
{ key: "count", label: `Number of ${e.label.toLowerCase()}`, op: "count", unit: "count", additive: true },
|
|
18
|
+
...e.columns.filter((c) => c.type === "number").map((c) => ({
|
|
19
|
+
key: `sum_${c.api_name}`,
|
|
20
|
+
label: `Total ${c.name.toLowerCase()}`,
|
|
21
|
+
op: "sum",
|
|
22
|
+
of: c.api_name,
|
|
23
|
+
additive: true
|
|
24
|
+
}))
|
|
25
|
+
];
|
|
26
|
+
return {
|
|
27
|
+
key: e.token,
|
|
28
|
+
label: e.label,
|
|
29
|
+
grain: `one row per ${e.label.toLowerCase()}`,
|
|
30
|
+
lanes: ["organization", "platform"],
|
|
31
|
+
dimensions,
|
|
32
|
+
measures,
|
|
33
|
+
paths: [],
|
|
34
|
+
inferred: [],
|
|
35
|
+
detail: { columns: e.columns.map((c) => c.api_name) },
|
|
36
|
+
source: { kind: "entity", token: e.token },
|
|
37
|
+
mode: "invoker",
|
|
38
|
+
api: { label: e.label, reach: "read_write", columns: e.columns },
|
|
39
|
+
calendar: { time_zone: "UTC", week_start: "monday" }
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function matches(row, where) {
|
|
43
|
+
for (const [k, want] of Object.entries(where ?? {})) {
|
|
44
|
+
const have = row[k] ?? null;
|
|
45
|
+
if (Array.isArray(want)) {
|
|
46
|
+
if (!want.includes(have)) return false;
|
|
47
|
+
} else if (want === null) {
|
|
48
|
+
if (have !== null) return false;
|
|
49
|
+
} else if (typeof want === "object") continue;
|
|
50
|
+
else if (String(have).toLowerCase() !== String(want).toLowerCase()) return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
function memoryEntityRows(e, question2) {
|
|
55
|
+
const limit = Number(question2["limit"] ?? 50);
|
|
56
|
+
const offset = Number(question2["offset"] ?? 0);
|
|
57
|
+
const rows = e.rows.filter((r) => matches(r, question2["where"]));
|
|
58
|
+
const page = rows.slice(offset, offset + limit);
|
|
59
|
+
return {
|
|
60
|
+
rows: page,
|
|
61
|
+
total: rows.length,
|
|
62
|
+
limit,
|
|
63
|
+
offset,
|
|
64
|
+
as_of: null,
|
|
65
|
+
columns: e.columns.map((c) => c.api_name),
|
|
66
|
+
...offset + page.length < rows.length ? { next_offset: offset + page.length } : {}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function memoryEntityAsk(e, question2) {
|
|
70
|
+
const by = (question2["by"] ?? []).map((k) => k.split(":")[0]);
|
|
71
|
+
const shown = question2["show"] ?? ["count"];
|
|
72
|
+
const measures = (shown.length ? shown : ["count"]).map((m) => typeof m === "string" ? m === "count" ? { key: "count", op: "count", of: null } : { key: m, op: m.split("_")[0], of: m.slice(m.indexOf("_") + 1) } : { key: m.op === "count" ? "count" : `${m.op}_${m.of ?? ""}`, op: m.op, of: m.of ?? null });
|
|
73
|
+
const rows = e.rows.filter((r) => matches(r, question2["where"]));
|
|
74
|
+
const measure = (list) => {
|
|
75
|
+
const out2 = {};
|
|
76
|
+
for (const m of measures) {
|
|
77
|
+
if (m.op === "count") {
|
|
78
|
+
out2[m.key] = list.length;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const nums = list.map((r) => r[m.of ?? ""]).filter((v) => typeof v === "number");
|
|
82
|
+
const sum = nums.reduce((a, b) => a + b, 0);
|
|
83
|
+
out2[m.key] = !nums.length ? null : m.op === "sum" ? sum : m.op === "avg" ? sum / nums.length : m.op === "min" ? Math.min(...nums) : m.op === "max" ? Math.max(...nums) : null;
|
|
84
|
+
}
|
|
85
|
+
return out2;
|
|
86
|
+
};
|
|
87
|
+
const row = (kind, groups, list) => ({
|
|
88
|
+
kind,
|
|
89
|
+
groups,
|
|
90
|
+
measures: measure(list),
|
|
91
|
+
row_count: list.length,
|
|
92
|
+
prior_groups: null,
|
|
93
|
+
prior_measures: null,
|
|
94
|
+
prior_row_count: null,
|
|
95
|
+
delta: null,
|
|
96
|
+
compare: null,
|
|
97
|
+
distinct_groups: null,
|
|
98
|
+
labels: {},
|
|
99
|
+
says: null,
|
|
100
|
+
as_of: null
|
|
101
|
+
});
|
|
102
|
+
const out = [];
|
|
103
|
+
if (by.length) {
|
|
104
|
+
const groups = /* @__PURE__ */ new Map();
|
|
105
|
+
for (const r of rows) {
|
|
106
|
+
const g = {};
|
|
107
|
+
for (const k of by) {
|
|
108
|
+
const v = r[k];
|
|
109
|
+
g[k] = v === void 0 || v === "" ? null : v;
|
|
110
|
+
}
|
|
111
|
+
const key = JSON.stringify(g);
|
|
112
|
+
const hit = groups.get(key) ?? { groups: g, rows: [] };
|
|
113
|
+
hit.rows.push(r);
|
|
114
|
+
groups.set(key, hit);
|
|
115
|
+
}
|
|
116
|
+
const first = measures[0].key;
|
|
117
|
+
const answered = [...groups.values()].map((g) => row("group", g.groups, g.rows));
|
|
118
|
+
answered.sort((a, b) => Number(b["measures"][first] ?? 0) - Number(a["measures"][first] ?? 0));
|
|
119
|
+
out.push(...answered.slice(0, Number(question2["limit"] ?? 50)));
|
|
120
|
+
}
|
|
121
|
+
out.push(row("total", {}, rows));
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
function memoryEntityWrite(e, recordId, columns) {
|
|
125
|
+
const row = e.rows.find((r) => r["id"] === recordId);
|
|
126
|
+
if (!row) return refuse(`There is no ${e.label} you can open with that id.`, "02000");
|
|
127
|
+
const next = {};
|
|
128
|
+
for (const [k, v] of Object.entries(columns ?? {})) {
|
|
129
|
+
const c = e.columns.find((x) => x.api_name === k);
|
|
130
|
+
if (!c) return refuse(`This table has no column called "${k}".`);
|
|
131
|
+
if (c.lookup && !c.lookup.replaces) return refuse(`"${c.name}" is shown from another table, so it is changed there. Nothing was written.`);
|
|
132
|
+
if (!c.writable) return refuse(`"${c.name}" is not changed through this door.`, "42501");
|
|
133
|
+
if (c.type === "choice" && v !== null && v !== "") {
|
|
134
|
+
const word = (c.choices ?? []).find((w) => w === v) ?? (c.choices ?? []).find((w) => w.toLowerCase() === String(v).toLowerCase());
|
|
135
|
+
if (!word) return refuse(`"${String(v)}" is not one of the choices of "${c.name}".`, "22023", "The columns call lists its choices.");
|
|
136
|
+
next[k] = word;
|
|
137
|
+
} else next[k] = v === "" ? null : v;
|
|
138
|
+
}
|
|
139
|
+
const changed = Object.entries(next).some(([k, v]) => row[k] !== v);
|
|
140
|
+
Object.assign(row, next);
|
|
141
|
+
return ok({ id: recordId, organization_id: row["organization_id"] ?? null, changed, row });
|
|
142
|
+
}
|
|
143
|
+
function memoryEntityDoors(entities) {
|
|
144
|
+
const of = (args) => {
|
|
145
|
+
const src = args["p_source"];
|
|
146
|
+
return src && src["kind"] === "entity" ? entities.get(String(src["token"])) : void 0;
|
|
147
|
+
};
|
|
148
|
+
return {
|
|
149
|
+
drill_describe: (args) => {
|
|
150
|
+
const e = of(args);
|
|
151
|
+
return e ? ok(memoryEntityDescribe(e)) : null;
|
|
152
|
+
},
|
|
153
|
+
drill_ask: (args) => {
|
|
154
|
+
const e = of(args);
|
|
155
|
+
return e ? ok(memoryEntityAsk(e, args["p_question"] ?? {})) : null;
|
|
156
|
+
},
|
|
157
|
+
drill_rows: (args) => {
|
|
158
|
+
const e = of(args);
|
|
159
|
+
return e ? ok(memoryEntityRows(e, args["p_question"] ?? {})) : null;
|
|
160
|
+
},
|
|
161
|
+
entity_row_write: (args) => {
|
|
162
|
+
const e = entities.get(String(args["p_token"] ?? ""));
|
|
163
|
+
if (!e) return null;
|
|
164
|
+
return memoryEntityWrite(e, String(args["p_record_id"] ?? ""), args["p_columns"] ?? {});
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
1
169
|
// src/templates/payloads.ts
|
|
2
170
|
var ACTOR = "user";
|
|
3
171
|
var COMPUTED = /* @__PURE__ */ new Set(["lookup", "rollup", "formula"]);
|
|
@@ -2226,10 +2394,10 @@ var PREVIEW_REFUSAL = {
|
|
|
2226
2394
|
hint: null
|
|
2227
2395
|
};
|
|
2228
2396
|
var WRITE_DOOR = /(^|_)(write|writes|declare|delete|update|upsert|archive|restore|set|move|save|submit|insert|merge|retype|undo|retire|assign|claim|clear|snooze|unsnooze|publish|invite|revoke|issue|pin|duplicate|designate|bind|unbind|change|start|complete|decide|request|hold|release|expire|forget|begin|finish|rows|take|nudge|import|mute|sign|render|instantiate|ensure)(_|$)/;
|
|
2229
|
-
function
|
|
2397
|
+
function ok2(data) {
|
|
2230
2398
|
return { data, error: null };
|
|
2231
2399
|
}
|
|
2232
|
-
function
|
|
2400
|
+
function refuse2(message, code = "PGRST202") {
|
|
2233
2401
|
return { data: null, error: { code, message, details: null, hint: null } };
|
|
2234
2402
|
}
|
|
2235
2403
|
function stamp(world) {
|
|
@@ -2414,16 +2582,11 @@ function groupValues(doc, stored, key) {
|
|
|
2414
2582
|
const out = list.map((v) => v === void 0 || v === null || v === "" ? null : String(v));
|
|
2415
2583
|
return out.length ? out : [null];
|
|
2416
2584
|
}
|
|
2417
|
-
function
|
|
2418
|
-
const
|
|
2419
|
-
const
|
|
2420
|
-
|
|
2421
|
-
if (
|
|
2422
|
-
if (raw["kind"] === "stuck") return { ...base, rows: [] };
|
|
2423
|
-
const measures = (raw["measures"] ?? [{ op: "count" }]).map((m) => ({ op: String(m["op"] ?? "count"), key: m["key"] }));
|
|
2424
|
-
const groupBy = (raw["group_by"] ?? []).slice();
|
|
2425
|
-
const bucket = raw["bucket"] ?? null;
|
|
2426
|
-
const ids = table.order.filter((id) => admits(world, table, id, raw["filter"]) && admits(world, table, id, canvas));
|
|
2585
|
+
function aggregateRows(world, table, ask) {
|
|
2586
|
+
const { groupBy, measures, bucket } = ask;
|
|
2587
|
+
const search = (ask.search ?? "").trim().toLowerCase();
|
|
2588
|
+
let ids = table.order.filter((id) => ask.filters.every((f) => admits(world, table, id, f)));
|
|
2589
|
+
if (search) ids = ids.filter((id) => JSON.stringify(readDocument(world, table, id)).toLowerCase().includes(search));
|
|
2427
2590
|
const groups = /* @__PURE__ */ new Map();
|
|
2428
2591
|
for (const id of ids) {
|
|
2429
2592
|
const doc = readDocument(world, table, id);
|
|
@@ -2465,8 +2628,25 @@ function runBlock(world, subject, raw, canvas, index) {
|
|
|
2465
2628
|
const k = `${bucket.key}_${bucket.by ?? "month"}`;
|
|
2466
2629
|
rows.sort((a, b) => String(a.groups[k]).localeCompare(String(b.groups[k])));
|
|
2467
2630
|
} else rows.sort((a, b) => (b.measures[primary] ?? 0) - (a.measures[primary] ?? 0));
|
|
2468
|
-
const limit = Number(
|
|
2631
|
+
const limit = Number(ask.limit ?? 0);
|
|
2469
2632
|
if (limit > 0) rows = rows.slice(0, limit);
|
|
2633
|
+
return rows;
|
|
2634
|
+
}
|
|
2635
|
+
function measuresOf(raw) {
|
|
2636
|
+
const list = Array.isArray(raw) ? raw : [];
|
|
2637
|
+
const out = list.map((m) => ({ op: String(m["op"] ?? "count"), key: m["key"] }));
|
|
2638
|
+
return out.length ? out : [{ op: "count" }];
|
|
2639
|
+
}
|
|
2640
|
+
function runBlock(world, subject, raw, canvas, index) {
|
|
2641
|
+
const table = world.tableById.get(String(raw["table_id"] ?? subject));
|
|
2642
|
+
const title = String(raw["title"] ?? `Block ${index + 1}`);
|
|
2643
|
+
const base = { ...raw, title, table_id: table?.id ?? subject, ms: 0 };
|
|
2644
|
+
if (!table) return { ...base, rows: [], refused: "This block's table is not in this template." };
|
|
2645
|
+
if (raw["kind"] === "stuck") return { ...base, rows: [] };
|
|
2646
|
+
const measures = measuresOf(raw["measures"]);
|
|
2647
|
+
const groupBy = (raw["group_by"] ?? []).slice();
|
|
2648
|
+
const bucket = raw["bucket"] ?? null;
|
|
2649
|
+
const rows = aggregateRows(world, table, { groupBy, measures, bucket, filters: [raw["filter"], canvas], limit: Number(raw["limit"] ?? 0) });
|
|
2470
2650
|
return { ...base, measures, group_by: groupBy, rows };
|
|
2471
2651
|
}
|
|
2472
2652
|
function bookingAvailability(world, raw) {
|
|
@@ -2553,55 +2733,55 @@ function memoryDataSource(world) {
|
|
|
2553
2733
|
return typeof v === "string" ? v : v === void 0 || v === null ? null : String(v);
|
|
2554
2734
|
};
|
|
2555
2735
|
const doors = {
|
|
2556
|
-
table_kernel_id: () =>
|
|
2557
|
-
field_kernel_id: () =>
|
|
2558
|
-
person_kernel_id: () =>
|
|
2559
|
-
file_kernel_id: () =>
|
|
2560
|
-
rule_kernel_id: () =>
|
|
2561
|
-
store_is_open: () =>
|
|
2736
|
+
table_kernel_id: () => ok2(MEMORY_KERNEL.table),
|
|
2737
|
+
field_kernel_id: () => ok2(MEMORY_KERNEL.field),
|
|
2738
|
+
person_kernel_id: () => ok2(MEMORY_KERNEL.person),
|
|
2739
|
+
file_kernel_id: () => ok2(MEMORY_KERNEL.file),
|
|
2740
|
+
rule_kernel_id: () => ok2(MEMORY_KERNEL.rule),
|
|
2741
|
+
store_is_open: () => ok2(true),
|
|
2562
2742
|
read_records: (args) => {
|
|
2563
2743
|
const limit = Number(args["p_limit"] ?? 50);
|
|
2564
2744
|
const offset = Number(args["p_offset"] ?? 0);
|
|
2565
|
-
if (args["p_table_id"] === MEMORY_KERNEL.table) return
|
|
2745
|
+
if (args["p_table_id"] === MEMORY_KERNEL.table) return ok2(world.tables.slice(offset, offset + limit).map(tableRow));
|
|
2566
2746
|
const t = tableOf(args);
|
|
2567
|
-
if (!t) return
|
|
2568
|
-
return
|
|
2747
|
+
if (!t) return ok2([]);
|
|
2748
|
+
return ok2(t.order.slice(offset, offset + limit).map((id) => row(t, id)));
|
|
2569
2749
|
},
|
|
2570
2750
|
read_records_by_ids: (args) => {
|
|
2571
2751
|
const ids = args["p_record_ids"] ?? [];
|
|
2572
|
-
if (args["p_table_id"] === MEMORY_KERNEL.table) return
|
|
2752
|
+
if (args["p_table_id"] === MEMORY_KERNEL.table) return ok2(world.tables.filter((t2) => ids.includes(t2.id)).map(tableRow));
|
|
2573
2753
|
const t = tableOf(args);
|
|
2574
|
-
if (!t) return
|
|
2575
|
-
return
|
|
2754
|
+
if (!t) return ok2([]);
|
|
2755
|
+
return ok2(ids.filter((id) => t.rows.has(id)).map((id) => row(t, id)));
|
|
2576
2756
|
},
|
|
2577
2757
|
read_records_matching: (args) => {
|
|
2578
2758
|
const t = tableOf(args);
|
|
2579
|
-
if (!t) return
|
|
2759
|
+
if (!t) return ok2([]);
|
|
2580
2760
|
const limit = Number(args["p_limit"] ?? 50);
|
|
2581
2761
|
const offset = Number(args["p_offset"] ?? 0);
|
|
2582
|
-
return
|
|
2762
|
+
return ok2(matching(world, t, args).slice(offset, offset + limit).map((id) => row(t, id)));
|
|
2583
2763
|
},
|
|
2584
2764
|
read_records_page: (args) => {
|
|
2585
2765
|
const t = tableOf(args);
|
|
2586
2766
|
const limit = Number(args["p_limit"] ?? 50);
|
|
2587
2767
|
const offset = Number(args["p_offset"] ?? 0);
|
|
2588
|
-
if (!t) return
|
|
2768
|
+
if (!t) return ok2({ rows: [], total: 0, limit, offset, sort_ignored: [] });
|
|
2589
2769
|
const ids = matching(world, t, args);
|
|
2590
|
-
return
|
|
2770
|
+
return ok2({ rows: ids.slice(offset, offset + limit).map((id) => row(t, id)), total: ids.length, limit, offset, sort_ignored: [] });
|
|
2591
2771
|
},
|
|
2592
2772
|
read_record: (args) => {
|
|
2593
2773
|
const id = String(args["p_record_id"] ?? "");
|
|
2594
2774
|
const t = world.recordTable.get(id);
|
|
2595
|
-
if (!t) return
|
|
2596
|
-
return
|
|
2775
|
+
if (!t) return refuse2("That record is not in this template.", "P0002");
|
|
2776
|
+
return ok2(readDocument(world, t, id));
|
|
2597
2777
|
},
|
|
2598
|
-
record_headers: (args) =>
|
|
2778
|
+
record_headers: (args) => ok2(
|
|
2599
2779
|
(args["p_ids"] ?? []).filter((id) => world.recordTable.has(id)).map((id) => ({ id, mine: false, version: 1, table_id: world.recordTable.get(id).id, deleted_at: null, ...stamp(world) }))
|
|
2600
2780
|
),
|
|
2601
2781
|
applicable_fields: (args) => {
|
|
2602
2782
|
const t = tableOf(args);
|
|
2603
|
-
if (!t) return
|
|
2604
|
-
return
|
|
2783
|
+
if (!t) return ok2([]);
|
|
2784
|
+
return ok2(
|
|
2605
2785
|
t.fields.map((f) => ({
|
|
2606
2786
|
id: f.id,
|
|
2607
2787
|
data: f.data,
|
|
@@ -2620,9 +2800,9 @@ function memoryDataSource(world) {
|
|
|
2620
2800
|
},
|
|
2621
2801
|
field_options: (args) => {
|
|
2622
2802
|
const hit = fieldById(args["p_field_id"]);
|
|
2623
|
-
if (!hit) return
|
|
2803
|
+
if (!hit) return ok2([]);
|
|
2624
2804
|
const opts = hit.t.options.get(String(hit.f.data["key"])) ?? [];
|
|
2625
|
-
return
|
|
2805
|
+
return ok2(
|
|
2626
2806
|
opts.map((o, i) => ({
|
|
2627
2807
|
id: o.id,
|
|
2628
2808
|
organization_id: world.organization_id,
|
|
@@ -2638,46 +2818,46 @@ function memoryDataSource(world) {
|
|
|
2638
2818
|
}))
|
|
2639
2819
|
);
|
|
2640
2820
|
},
|
|
2641
|
-
my_levels: (args) =>
|
|
2642
|
-
views: (args) =>
|
|
2821
|
+
my_levels: (args) => ok2((args["p_ids"] ?? []).map((id) => ({ id, level: VIEWER }))),
|
|
2822
|
+
views: (args) => ok2(
|
|
2643
2823
|
world.views.filter((v) => !args["p_table_id"] || v.table_id === args["p_table_id"]).map((v) => ({ view_id: v.view_id, name: v.name, table_id: v.table_id, filters: v.filters, definition: v.definition, created_at: `${world.today}T09:00:00Z` }))
|
|
2644
2824
|
),
|
|
2645
2825
|
view_look_read: (args) => {
|
|
2646
2826
|
const out = {};
|
|
2647
2827
|
for (const [key, look] of looks) if (key.startsWith(`${String(args["p_table_id"])}:`)) out[key.split(":")[1]] = look;
|
|
2648
|
-
return
|
|
2828
|
+
return ok2(out);
|
|
2649
2829
|
},
|
|
2650
2830
|
view_look_set: (args) => {
|
|
2651
2831
|
const key = `${String(args["p_table_id"])}:${String(args["p_view_id"])}`;
|
|
2652
2832
|
const look = args["p_look"] ?? null;
|
|
2653
2833
|
if (look) looks.set(key, { look, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
2654
2834
|
else looks.delete(key);
|
|
2655
|
-
return
|
|
2835
|
+
return ok2(look);
|
|
2656
2836
|
},
|
|
2657
|
-
grid_layout: (args) =>
|
|
2837
|
+
grid_layout: (args) => ok2({
|
|
2658
2838
|
layout: { mode: "auto", wrap: false, row_height: "normal", fit_max_columns: 8, freeze_first_column: false },
|
|
2659
2839
|
source: { mode: "platform", wrap: "platform", row_height: "platform", fit_max_columns: "platform", freeze_first_column: "platform" },
|
|
2660
2840
|
refused: [],
|
|
2661
2841
|
view_id: args["p_view_id"] ?? null
|
|
2662
2842
|
}),
|
|
2663
|
-
table_decorations: () =>
|
|
2664
|
-
row_actions: () =>
|
|
2665
|
-
table_stage_field: (args) =>
|
|
2843
|
+
table_decorations: () => ok2({ rows: {}, cells: {}, rules: [], stale: [], colors: ["slate", "green", "amber", "red", "blue", "violet", "teal"], columns: {}, version: 1, rule_ops: [] }),
|
|
2844
|
+
row_actions: () => ok2({ stale: [], actions: [] }),
|
|
2845
|
+
table_stage_field: (args) => ok2(world.stageField.get(String(args["p_table_id"])) ?? null),
|
|
2666
2846
|
pipeline_read: (args) => {
|
|
2667
2847
|
const t = tableOf(args);
|
|
2668
2848
|
const stage = t ? world.stageField.get(t.id) : void 0;
|
|
2669
2849
|
const field = stage ? t.fields.find((f) => f.data["key"] === stage) : void 0;
|
|
2670
|
-
if (!t || !stage || !field) return
|
|
2850
|
+
if (!t || !stage || !field) return ok2({ is_pipeline: false, why: "This table has no stage column." });
|
|
2671
2851
|
const stages = (t.options.get(stage) ?? []).map((o) => ({ key: o.key, label: o.label, retired: false }));
|
|
2672
|
-
return
|
|
2852
|
+
return ok2({ is_pipeline: true, table_id: t.id, stage_field: stage, field_id: field.id, stage_label: field.data["label"], stages, rules: [] });
|
|
2673
2853
|
},
|
|
2674
2854
|
pipeline_board: (args) => {
|
|
2675
2855
|
const t = tableOf(args);
|
|
2676
2856
|
const stage = t ? world.stageField.get(t.id) : void 0;
|
|
2677
|
-
if (!t || !stage) return
|
|
2857
|
+
if (!t || !stage) return ok2([]);
|
|
2678
2858
|
const measure = typeof args["p_measure"] === "string" ? args["p_measure"] : null;
|
|
2679
2859
|
const ids = t.order.filter((id) => admits(world, t, id, args["p_filter"]));
|
|
2680
|
-
return
|
|
2860
|
+
return ok2(
|
|
2681
2861
|
(t.options.get(stage) ?? []).map((o, i) => {
|
|
2682
2862
|
const inIt = ids.filter((id) => t.rows.get(id)[stage] === o.key);
|
|
2683
2863
|
const total = measure ? inIt.reduce((sum, id) => sum + (typeof t.rows.get(id)[measure] === "number" ? t.rows.get(id)[measure] : 0), 0) : null;
|
|
@@ -2685,7 +2865,7 @@ function memoryDataSource(world) {
|
|
|
2685
2865
|
})
|
|
2686
2866
|
);
|
|
2687
2867
|
},
|
|
2688
|
-
relation_words_many: (args) =>
|
|
2868
|
+
relation_words_many: (args) => ok2((args["p_record_ids"] ?? []).map((id) => ({ record_id: id, words: nameOf(id), archived: false }))),
|
|
2689
2869
|
reverse_columns: (args) => {
|
|
2690
2870
|
const target = String(args["p_table_id"] ?? "");
|
|
2691
2871
|
const out = [];
|
|
@@ -2705,11 +2885,11 @@ function memoryDataSource(world) {
|
|
|
2705
2885
|
});
|
|
2706
2886
|
}
|
|
2707
2887
|
}
|
|
2708
|
-
return
|
|
2888
|
+
return ok2(out);
|
|
2709
2889
|
},
|
|
2710
2890
|
reverse_links_many: (args) => {
|
|
2711
2891
|
const hit = fieldById(args["p_field_id"]);
|
|
2712
|
-
return
|
|
2892
|
+
return ok2(
|
|
2713
2893
|
(args["p_record_ids"] ?? []).map((rid) => {
|
|
2714
2894
|
if (!hit) return { record_id: rid, total: 0, links: [] };
|
|
2715
2895
|
const key = String(hit.f.data["key"]);
|
|
@@ -2723,28 +2903,28 @@ function memoryDataSource(world) {
|
|
|
2723
2903
|
},
|
|
2724
2904
|
// A template's own record has no history, comments, checklists or worked-out provenance yet:
|
|
2725
2905
|
// these are the answers an installed template gives on its first day.
|
|
2726
|
-
record_history: () =>
|
|
2727
|
-
field_history: () =>
|
|
2728
|
-
computed_provenance: () =>
|
|
2729
|
-
comment_thread: (args) =>
|
|
2730
|
-
checklist_runs: () =>
|
|
2731
|
-
checklist_templates: () =>
|
|
2732
|
-
doc_templates: () =>
|
|
2733
|
-
doc_renders: () =>
|
|
2734
|
-
doc_signatures: () =>
|
|
2735
|
-
record_row_controls: () =>
|
|
2906
|
+
record_history: () => ok2([]),
|
|
2907
|
+
field_history: () => ok2([]),
|
|
2908
|
+
computed_provenance: () => ok2([]),
|
|
2909
|
+
comment_thread: (args) => ok2({ record_id: args["p_record_id"] ?? null, comments: [], may_comment: false, may_resolve: false }),
|
|
2910
|
+
checklist_runs: () => ok2([]),
|
|
2911
|
+
checklist_templates: () => ok2([]),
|
|
2912
|
+
doc_templates: () => ok2([]),
|
|
2913
|
+
doc_renders: () => ok2([]),
|
|
2914
|
+
doc_signatures: () => ok2([]),
|
|
2915
|
+
record_row_controls: () => ok2({
|
|
2736
2916
|
shown_to: { value: null, effective: "everyone", type_default: null, table_default: null, allowed: ["everyone"], is_child: false, can_change: false },
|
|
2737
2917
|
published_to_web: { available: false, value: false, table_default: null, can_change: false },
|
|
2738
2918
|
indexed: { available: false, value: null, table_default: null, effective: false, can_change: false }
|
|
2739
2919
|
}),
|
|
2740
|
-
enrich_cells: () =>
|
|
2741
|
-
enrichments: () =>
|
|
2742
|
-
pipeline_pending: () =>
|
|
2743
|
-
record_stage_pending: () =>
|
|
2744
|
-
io_imports: () =>
|
|
2745
|
-
relation_words: (args) =>
|
|
2920
|
+
enrich_cells: () => ok2([]),
|
|
2921
|
+
enrichments: () => ok2([]),
|
|
2922
|
+
pipeline_pending: () => ok2([]),
|
|
2923
|
+
record_stage_pending: () => ok2([]),
|
|
2924
|
+
io_imports: () => ok2([]),
|
|
2925
|
+
relation_words: (args) => ok2(nameOf(String(args["p_value"] ?? ""))),
|
|
2746
2926
|
// The read doors a form, a booking page and a dashboard are drawn from (lane CHAIR-GALLERY-3).
|
|
2747
|
-
forms: (args) =>
|
|
2927
|
+
forms: (args) => ok2(
|
|
2748
2928
|
world.forms.filter((f) => !f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2749
2929
|
form_id: f.form_id,
|
|
2750
2930
|
table_id: f.table_id,
|
|
@@ -2767,7 +2947,7 @@ function memoryDataSource(world) {
|
|
|
2767
2947
|
form_preview_asks: (args) => {
|
|
2768
2948
|
const t = tableOf(args);
|
|
2769
2949
|
const values = args["p_values"] ?? {};
|
|
2770
|
-
return
|
|
2950
|
+
return ok2(
|
|
2771
2951
|
(args["p_questions"] ?? []).map((q) => {
|
|
2772
2952
|
const when = q["show_if"] ?? q["showIf"] ?? null;
|
|
2773
2953
|
const asked = !when || !t ? true : rule(t, values, values, when) !== false;
|
|
@@ -2775,7 +2955,7 @@ function memoryDataSource(world) {
|
|
|
2775
2955
|
})
|
|
2776
2956
|
);
|
|
2777
2957
|
},
|
|
2778
|
-
bookings: (args) =>
|
|
2958
|
+
bookings: (args) => ok2(
|
|
2779
2959
|
world.forms.filter((f) => f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2780
2960
|
form_id: f.form_id,
|
|
2781
2961
|
table_id: f.table_id,
|
|
@@ -2797,9 +2977,9 @@ function memoryDataSource(world) {
|
|
|
2797
2977
|
booking_public: (args) => {
|
|
2798
2978
|
const f = world.forms.find((x) => x.form_id === args["p_form_id"] && x.booking);
|
|
2799
2979
|
const t = f ? world.tableById.get(f.table_id) : void 0;
|
|
2800
|
-
if (!f || !t) return
|
|
2980
|
+
if (!f || !t) return refuse2("That booking page is not in this template.", "P0002");
|
|
2801
2981
|
const availability = bookingAvailability(world, f.booking);
|
|
2802
|
-
return
|
|
2982
|
+
return ok2({
|
|
2803
2983
|
form_id: f.form_id,
|
|
2804
2984
|
organization_id: world.organization_id,
|
|
2805
2985
|
table_id: t.id,
|
|
@@ -2813,7 +2993,7 @@ function memoryDataSource(world) {
|
|
|
2813
2993
|
message: null
|
|
2814
2994
|
});
|
|
2815
2995
|
},
|
|
2816
|
-
dashboards: (args) =>
|
|
2996
|
+
dashboards: (args) => ok2(
|
|
2817
2997
|
world.dashboards.filter((d) => !args["p_table_id"] || d.table_id === args["p_table_id"]).map((d) => ({
|
|
2818
2998
|
dashboard_id: d.dashboard_id,
|
|
2819
2999
|
table_id: d.table_id,
|
|
@@ -2828,9 +3008,9 @@ function memoryDataSource(world) {
|
|
|
2828
3008
|
),
|
|
2829
3009
|
dashboard_run: (args) => {
|
|
2830
3010
|
const d = world.dashboards.find((x) => x.dashboard_id === args["p_dashboard_id"]);
|
|
2831
|
-
if (!d) return
|
|
3011
|
+
if (!d) return refuse2("That dashboard is not in this template.", "P0002");
|
|
2832
3012
|
const canvas = args["p_filter"] ?? {};
|
|
2833
|
-
return
|
|
3013
|
+
return ok2({
|
|
2834
3014
|
dashboard_id: d.dashboard_id,
|
|
2835
3015
|
name: d.name,
|
|
2836
3016
|
subject_table_id: d.table_id,
|
|
@@ -2842,16 +3022,34 @@ function memoryDataSource(world) {
|
|
|
2842
3022
|
blocks: d.blocks.map((b, i) => runBlock(world, d.table_id, b, canvas, i))
|
|
2843
3023
|
});
|
|
2844
3024
|
},
|
|
2845
|
-
dashboard_stuck: () =>
|
|
3025
|
+
dashboard_stuck: () => ok2([]),
|
|
3026
|
+
// THE EIGHTH VERB, in memory: the same groups and measures as the live `custom.record_aggregate`
|
|
3027
|
+
// (and its row shape: no comparison asked ⇒ every prior_* null).
|
|
3028
|
+
record_aggregate: (args) => {
|
|
3029
|
+
const t = tableOf(args);
|
|
3030
|
+
if (!t) return refuse2("That table is not in this template.", "P0002");
|
|
3031
|
+
const rows = aggregateRows(world, t, {
|
|
3032
|
+
groupBy: (args["p_group_by"] ?? []).slice(),
|
|
3033
|
+
measures: measuresOf(args["p_measures"]),
|
|
3034
|
+
bucket: args["p_bucket"] ?? null,
|
|
3035
|
+
filters: [args["p_filter"]],
|
|
3036
|
+
...typeof args["p_search"] === "string" ? { search: args["p_search"] } : {},
|
|
3037
|
+
limit: Number(args["p_limit"] ?? 200)
|
|
3038
|
+
});
|
|
3039
|
+
return ok2(rows.map((r) => ({ ...r, prior_groups: null, prior_measures: null, prior_row_count: null, delta: null, compare: null })));
|
|
3040
|
+
}
|
|
2846
3041
|
};
|
|
2847
3042
|
const source = {
|
|
2848
3043
|
world,
|
|
2849
3044
|
rpc(fn, args) {
|
|
2850
|
-
const name = fn.replace(/^custom\./, "");
|
|
3045
|
+
const name = fn.replace(/^custom\./, "").replace(/^platform\./, "");
|
|
3046
|
+
const entityDoor = world.entities ? memoryEntityDoors(world.entities)[name] : void 0;
|
|
3047
|
+
const fromEntity = entityDoor ? entityDoor(args ?? {}) : null;
|
|
3048
|
+
if (fromEntity) return Promise.resolve(fromEntity);
|
|
2851
3049
|
const door = doors[name];
|
|
2852
3050
|
if (door) return Promise.resolve(door(args ?? {}));
|
|
2853
3051
|
if (WRITE_DOOR.test(name)) return Promise.resolve({ data: null, error: PREVIEW_REFUSAL });
|
|
2854
|
-
return Promise.resolve(
|
|
3052
|
+
return Promise.resolve(refuse2(`A template preview does not answer ${name}.`));
|
|
2855
3053
|
},
|
|
2856
3054
|
schema() {
|
|
2857
3055
|
return {
|
|
@@ -2865,6 +3063,12 @@ function memoryDataSource(world) {
|
|
|
2865
3063
|
}
|
|
2866
3064
|
|
|
2867
3065
|
// src/memory/index.ts
|
|
3066
|
+
function withEntities(world, specs) {
|
|
3067
|
+
const entities = new Map(world.entities ?? []);
|
|
3068
|
+
for (const s of specs) entities.set(s.token, { ...s, rows: s.rows.map((r) => ({ ...r })) });
|
|
3069
|
+
world.entities = entities;
|
|
3070
|
+
return world;
|
|
3071
|
+
}
|
|
2868
3072
|
function templatePreview(spec, options = {}) {
|
|
2869
3073
|
const world = templateWorld(spec, options);
|
|
2870
3074
|
const config = {
|
|
@@ -2880,12 +3084,39 @@ function templatePreview(spec, options = {}) {
|
|
|
2880
3084
|
dashboards: world.dashboards.map((d) => ({ id: d.dashboard_id, token: d.token, name: d.name, tableId: d.table_id }))
|
|
2881
3085
|
};
|
|
2882
3086
|
}
|
|
3087
|
+
function entityStore(specs, options = {}) {
|
|
3088
|
+
const world = {
|
|
3089
|
+
organization_id: stableId("entity-store-organization"),
|
|
3090
|
+
user_id: stableId("entity-store-person"),
|
|
3091
|
+
timezone: "UTC",
|
|
3092
|
+
today: options.today ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3093
|
+
businessName: "",
|
|
3094
|
+
tables: [],
|
|
3095
|
+
tableById: /* @__PURE__ */ new Map(),
|
|
3096
|
+
views: [],
|
|
3097
|
+
forms: [],
|
|
3098
|
+
dashboards: [],
|
|
3099
|
+
recordTable: /* @__PURE__ */ new Map(),
|
|
3100
|
+
stageField: /* @__PURE__ */ new Map()
|
|
3101
|
+
};
|
|
3102
|
+
withEntities(world, specs);
|
|
3103
|
+
return {
|
|
3104
|
+
world,
|
|
3105
|
+
config: { dataSource: memoryDataSource(world), actor: { actor: "user", user_id: world.user_id }, organizationId: world.organization_id }
|
|
3106
|
+
};
|
|
3107
|
+
}
|
|
2883
3108
|
export {
|
|
2884
3109
|
MEMORY_KERNEL,
|
|
2885
3110
|
PREVIEW_REFUSAL,
|
|
3111
|
+
entityStore,
|
|
2886
3112
|
memoryDataSource,
|
|
3113
|
+
memoryEntityAsk,
|
|
3114
|
+
memoryEntityDescribe,
|
|
3115
|
+
memoryEntityRows,
|
|
3116
|
+
memoryEntityWrite,
|
|
2887
3117
|
stableId,
|
|
2888
3118
|
templatePreview,
|
|
2889
|
-
templateWorld
|
|
3119
|
+
templateWorld,
|
|
3120
|
+
withEntities
|
|
2890
3121
|
};
|
|
2891
3122
|
//# sourceMappingURL=index.js.map
|