@ai-matrx/records 0.73.4 → 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 +6 -0
- package/dist/memory/index.cjs +99 -12
- package/dist/memory/index.cjs.map +1 -1
- package/dist/memory/index.d.cts +7 -1
- package/dist/memory/index.d.ts +7 -1
- package/dist/memory/index.js +99 -12
- package/dist/memory/index.js.map +1 -1
- package/package.json +1 -1
package/dist/memory/index.d.cts
CHANGED
|
@@ -46,6 +46,12 @@ type Answer = {
|
|
|
46
46
|
declare function memoryEntityDescribe(e: MemoryEntity): Json$1;
|
|
47
47
|
/** What `drill_rows` answers: one page, rows in words. */
|
|
48
48
|
declare function memoryEntityRows(e: MemoryEntity, question: Json$1): Json$1;
|
|
49
|
+
/**
|
|
50
|
+
* What `drill_ask` answers for a memory entity: one row per group of the asked Dimensions (a choice
|
|
51
|
+
* or a lookup, both already words here), then the `total` row; `count`, `sum_<col>` and ad hoc
|
|
52
|
+
* `{op, of}` measures keyed `<op>_<of>` exactly as the live door keys them; `where` narrows first.
|
|
53
|
+
*/
|
|
54
|
+
declare function memoryEntityAsk(e: MemoryEntity, question: Json$1): Json$1[];
|
|
49
55
|
/** What `entity_row_write` does: a choice by its word (any case), refused in the door's words otherwise. */
|
|
50
56
|
declare function memoryEntityWrite(e: MemoryEntity, recordId: string, columns: Json$1): Answer;
|
|
51
57
|
|
|
@@ -181,4 +187,4 @@ declare function entityStore(specs: MemoryEntitySpec[], options?: {
|
|
|
181
187
|
world: MemoryWorld;
|
|
182
188
|
};
|
|
183
189
|
|
|
184
|
-
export { MEMORY_KERNEL, type MemoryDashboard, type MemoryEntity, type MemoryEntityColumn, type MemoryEntitySpec, type MemoryField, type MemoryForm, type MemoryOption, type MemoryTable, type MemoryView, type MemoryWorld, PREVIEW_REFUSAL, type TemplatePreview, type TemplateWorldOptions, entityStore, memoryDataSource, memoryEntityDescribe, memoryEntityRows, memoryEntityWrite, stableId, templatePreview, templateWorld, withEntities };
|
|
190
|
+
export { MEMORY_KERNEL, type MemoryDashboard, type MemoryEntity, type MemoryEntityColumn, type MemoryEntitySpec, type MemoryField, type MemoryForm, type MemoryOption, type MemoryTable, type MemoryView, type MemoryWorld, PREVIEW_REFUSAL, type TemplatePreview, type TemplateWorldOptions, entityStore, memoryDataSource, memoryEntityAsk, memoryEntityDescribe, memoryEntityRows, memoryEntityWrite, stableId, templatePreview, templateWorld, withEntities };
|
package/dist/memory/index.d.ts
CHANGED
|
@@ -46,6 +46,12 @@ type Answer = {
|
|
|
46
46
|
declare function memoryEntityDescribe(e: MemoryEntity): Json$1;
|
|
47
47
|
/** What `drill_rows` answers: one page, rows in words. */
|
|
48
48
|
declare function memoryEntityRows(e: MemoryEntity, question: Json$1): Json$1;
|
|
49
|
+
/**
|
|
50
|
+
* What `drill_ask` answers for a memory entity: one row per group of the asked Dimensions (a choice
|
|
51
|
+
* or a lookup, both already words here), then the `total` row; `count`, `sum_<col>` and ad hoc
|
|
52
|
+
* `{op, of}` measures keyed `<op>_<of>` exactly as the live door keys them; `where` narrows first.
|
|
53
|
+
*/
|
|
54
|
+
declare function memoryEntityAsk(e: MemoryEntity, question: Json$1): Json$1[];
|
|
49
55
|
/** What `entity_row_write` does: a choice by its word (any case), refused in the door's words otherwise. */
|
|
50
56
|
declare function memoryEntityWrite(e: MemoryEntity, recordId: string, columns: Json$1): Answer;
|
|
51
57
|
|
|
@@ -181,4 +187,4 @@ declare function entityStore(specs: MemoryEntitySpec[], options?: {
|
|
|
181
187
|
world: MemoryWorld;
|
|
182
188
|
};
|
|
183
189
|
|
|
184
|
-
export { MEMORY_KERNEL, type MemoryDashboard, type MemoryEntity, type MemoryEntityColumn, type MemoryEntitySpec, type MemoryField, type MemoryForm, type MemoryOption, type MemoryTable, type MemoryView, type MemoryWorld, PREVIEW_REFUSAL, type TemplatePreview, type TemplateWorldOptions, entityStore, memoryDataSource, memoryEntityDescribe, memoryEntityRows, memoryEntityWrite, stableId, templatePreview, templateWorld, withEntities };
|
|
190
|
+
export { MEMORY_KERNEL, type MemoryDashboard, type MemoryEntity, type MemoryEntityColumn, type MemoryEntitySpec, type MemoryField, type MemoryForm, type MemoryOption, type MemoryTable, type MemoryView, type MemoryWorld, PREVIEW_REFUSAL, type TemplatePreview, type TemplateWorldOptions, entityStore, memoryDataSource, memoryEntityAsk, memoryEntityDescribe, memoryEntityRows, memoryEntityWrite, stableId, templatePreview, templateWorld, withEntities };
|
package/dist/memory/index.js
CHANGED
|
@@ -66,6 +66,61 @@ function memoryEntityRows(e, question2) {
|
|
|
66
66
|
...offset + page.length < rows.length ? { next_offset: offset + page.length } : {}
|
|
67
67
|
};
|
|
68
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
|
+
}
|
|
69
124
|
function memoryEntityWrite(e, recordId, columns) {
|
|
70
125
|
const row = e.rows.find((r) => r["id"] === recordId);
|
|
71
126
|
if (!row) return refuse(`There is no ${e.label} you can open with that id.`, "02000");
|
|
@@ -95,6 +150,10 @@ function memoryEntityDoors(entities) {
|
|
|
95
150
|
const e = of(args);
|
|
96
151
|
return e ? ok(memoryEntityDescribe(e)) : null;
|
|
97
152
|
},
|
|
153
|
+
drill_ask: (args) => {
|
|
154
|
+
const e = of(args);
|
|
155
|
+
return e ? ok(memoryEntityAsk(e, args["p_question"] ?? {})) : null;
|
|
156
|
+
},
|
|
98
157
|
drill_rows: (args) => {
|
|
99
158
|
const e = of(args);
|
|
100
159
|
return e ? ok(memoryEntityRows(e, args["p_question"] ?? {})) : null;
|
|
@@ -2523,16 +2582,11 @@ function groupValues(doc, stored, key) {
|
|
|
2523
2582
|
const out = list.map((v) => v === void 0 || v === null || v === "" ? null : String(v));
|
|
2524
2583
|
return out.length ? out : [null];
|
|
2525
2584
|
}
|
|
2526
|
-
function
|
|
2527
|
-
const
|
|
2528
|
-
const
|
|
2529
|
-
|
|
2530
|
-
if (
|
|
2531
|
-
if (raw["kind"] === "stuck") return { ...base, rows: [] };
|
|
2532
|
-
const measures = (raw["measures"] ?? [{ op: "count" }]).map((m) => ({ op: String(m["op"] ?? "count"), key: m["key"] }));
|
|
2533
|
-
const groupBy = (raw["group_by"] ?? []).slice();
|
|
2534
|
-
const bucket = raw["bucket"] ?? null;
|
|
2535
|
-
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));
|
|
2536
2590
|
const groups = /* @__PURE__ */ new Map();
|
|
2537
2591
|
for (const id of ids) {
|
|
2538
2592
|
const doc = readDocument(world, table, id);
|
|
@@ -2574,8 +2628,25 @@ function runBlock(world, subject, raw, canvas, index) {
|
|
|
2574
2628
|
const k = `${bucket.key}_${bucket.by ?? "month"}`;
|
|
2575
2629
|
rows.sort((a, b) => String(a.groups[k]).localeCompare(String(b.groups[k])));
|
|
2576
2630
|
} else rows.sort((a, b) => (b.measures[primary] ?? 0) - (a.measures[primary] ?? 0));
|
|
2577
|
-
const limit = Number(
|
|
2631
|
+
const limit = Number(ask.limit ?? 0);
|
|
2578
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) });
|
|
2579
2650
|
return { ...base, measures, group_by: groupBy, rows };
|
|
2580
2651
|
}
|
|
2581
2652
|
function bookingAvailability(world, raw) {
|
|
@@ -2951,7 +3022,22 @@ function memoryDataSource(world) {
|
|
|
2951
3022
|
blocks: d.blocks.map((b, i) => runBlock(world, d.table_id, b, canvas, i))
|
|
2952
3023
|
});
|
|
2953
3024
|
},
|
|
2954
|
-
dashboard_stuck: () => ok2([])
|
|
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
|
+
}
|
|
2955
3041
|
};
|
|
2956
3042
|
const source = {
|
|
2957
3043
|
world,
|
|
@@ -3024,6 +3110,7 @@ export {
|
|
|
3024
3110
|
PREVIEW_REFUSAL,
|
|
3025
3111
|
entityStore,
|
|
3026
3112
|
memoryDataSource,
|
|
3113
|
+
memoryEntityAsk,
|
|
3027
3114
|
memoryEntityDescribe,
|
|
3028
3115
|
memoryEntityRows,
|
|
3029
3116
|
memoryEntityWrite,
|