@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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records
|
|
2
2
|
|
|
3
|
+
## 0.73.5
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/records/v0.73.4..npm/records/v0.73.5 -- apps/shared/records`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
3
9
|
## 0.73.4
|
|
4
10
|
|
|
5
11
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
package/dist/memory/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(memory_exports, {
|
|
|
24
24
|
PREVIEW_REFUSAL: () => PREVIEW_REFUSAL,
|
|
25
25
|
entityStore: () => entityStore,
|
|
26
26
|
memoryDataSource: () => memoryDataSource,
|
|
27
|
+
memoryEntityAsk: () => memoryEntityAsk,
|
|
27
28
|
memoryEntityDescribe: () => memoryEntityDescribe,
|
|
28
29
|
memoryEntityRows: () => memoryEntityRows,
|
|
29
30
|
memoryEntityWrite: () => memoryEntityWrite,
|
|
@@ -102,6 +103,61 @@ function memoryEntityRows(e, question2) {
|
|
|
102
103
|
...offset + page.length < rows.length ? { next_offset: offset + page.length } : {}
|
|
103
104
|
};
|
|
104
105
|
}
|
|
106
|
+
function memoryEntityAsk(e, question2) {
|
|
107
|
+
const by = (question2["by"] ?? []).map((k) => k.split(":")[0]);
|
|
108
|
+
const shown = question2["show"] ?? ["count"];
|
|
109
|
+
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 });
|
|
110
|
+
const rows = e.rows.filter((r) => matches(r, question2["where"]));
|
|
111
|
+
const measure = (list) => {
|
|
112
|
+
const out2 = {};
|
|
113
|
+
for (const m of measures) {
|
|
114
|
+
if (m.op === "count") {
|
|
115
|
+
out2[m.key] = list.length;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const nums = list.map((r) => r[m.of ?? ""]).filter((v) => typeof v === "number");
|
|
119
|
+
const sum = nums.reduce((a, b) => a + b, 0);
|
|
120
|
+
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;
|
|
121
|
+
}
|
|
122
|
+
return out2;
|
|
123
|
+
};
|
|
124
|
+
const row = (kind, groups, list) => ({
|
|
125
|
+
kind,
|
|
126
|
+
groups,
|
|
127
|
+
measures: measure(list),
|
|
128
|
+
row_count: list.length,
|
|
129
|
+
prior_groups: null,
|
|
130
|
+
prior_measures: null,
|
|
131
|
+
prior_row_count: null,
|
|
132
|
+
delta: null,
|
|
133
|
+
compare: null,
|
|
134
|
+
distinct_groups: null,
|
|
135
|
+
labels: {},
|
|
136
|
+
says: null,
|
|
137
|
+
as_of: null
|
|
138
|
+
});
|
|
139
|
+
const out = [];
|
|
140
|
+
if (by.length) {
|
|
141
|
+
const groups = /* @__PURE__ */ new Map();
|
|
142
|
+
for (const r of rows) {
|
|
143
|
+
const g = {};
|
|
144
|
+
for (const k of by) {
|
|
145
|
+
const v = r[k];
|
|
146
|
+
g[k] = v === void 0 || v === "" ? null : v;
|
|
147
|
+
}
|
|
148
|
+
const key = JSON.stringify(g);
|
|
149
|
+
const hit = groups.get(key) ?? { groups: g, rows: [] };
|
|
150
|
+
hit.rows.push(r);
|
|
151
|
+
groups.set(key, hit);
|
|
152
|
+
}
|
|
153
|
+
const first = measures[0].key;
|
|
154
|
+
const answered = [...groups.values()].map((g) => row("group", g.groups, g.rows));
|
|
155
|
+
answered.sort((a, b) => Number(b["measures"][first] ?? 0) - Number(a["measures"][first] ?? 0));
|
|
156
|
+
out.push(...answered.slice(0, Number(question2["limit"] ?? 50)));
|
|
157
|
+
}
|
|
158
|
+
out.push(row("total", {}, rows));
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
105
161
|
function memoryEntityWrite(e, recordId, columns) {
|
|
106
162
|
const row = e.rows.find((r) => r["id"] === recordId);
|
|
107
163
|
if (!row) return refuse(`There is no ${e.label} you can open with that id.`, "02000");
|
|
@@ -131,6 +187,10 @@ function memoryEntityDoors(entities) {
|
|
|
131
187
|
const e = of(args);
|
|
132
188
|
return e ? ok(memoryEntityDescribe(e)) : null;
|
|
133
189
|
},
|
|
190
|
+
drill_ask: (args) => {
|
|
191
|
+
const e = of(args);
|
|
192
|
+
return e ? ok(memoryEntityAsk(e, args["p_question"] ?? {})) : null;
|
|
193
|
+
},
|
|
134
194
|
drill_rows: (args) => {
|
|
135
195
|
const e = of(args);
|
|
136
196
|
return e ? ok(memoryEntityRows(e, args["p_question"] ?? {})) : null;
|
|
@@ -2559,16 +2619,11 @@ function groupValues(doc, stored, key) {
|
|
|
2559
2619
|
const out = list.map((v) => v === void 0 || v === null || v === "" ? null : String(v));
|
|
2560
2620
|
return out.length ? out : [null];
|
|
2561
2621
|
}
|
|
2562
|
-
function
|
|
2563
|
-
const
|
|
2564
|
-
const
|
|
2565
|
-
|
|
2566
|
-
if (
|
|
2567
|
-
if (raw["kind"] === "stuck") return { ...base, rows: [] };
|
|
2568
|
-
const measures = (raw["measures"] ?? [{ op: "count" }]).map((m) => ({ op: String(m["op"] ?? "count"), key: m["key"] }));
|
|
2569
|
-
const groupBy = (raw["group_by"] ?? []).slice();
|
|
2570
|
-
const bucket = raw["bucket"] ?? null;
|
|
2571
|
-
const ids = table.order.filter((id) => admits(world, table, id, raw["filter"]) && admits(world, table, id, canvas));
|
|
2622
|
+
function aggregateRows(world, table, ask) {
|
|
2623
|
+
const { groupBy, measures, bucket } = ask;
|
|
2624
|
+
const search = (ask.search ?? "").trim().toLowerCase();
|
|
2625
|
+
let ids = table.order.filter((id) => ask.filters.every((f) => admits(world, table, id, f)));
|
|
2626
|
+
if (search) ids = ids.filter((id) => JSON.stringify(readDocument(world, table, id)).toLowerCase().includes(search));
|
|
2572
2627
|
const groups = /* @__PURE__ */ new Map();
|
|
2573
2628
|
for (const id of ids) {
|
|
2574
2629
|
const doc = readDocument(world, table, id);
|
|
@@ -2610,8 +2665,25 @@ function runBlock(world, subject, raw, canvas, index) {
|
|
|
2610
2665
|
const k = `${bucket.key}_${bucket.by ?? "month"}`;
|
|
2611
2666
|
rows.sort((a, b) => String(a.groups[k]).localeCompare(String(b.groups[k])));
|
|
2612
2667
|
} else rows.sort((a, b) => (b.measures[primary] ?? 0) - (a.measures[primary] ?? 0));
|
|
2613
|
-
const limit = Number(
|
|
2668
|
+
const limit = Number(ask.limit ?? 0);
|
|
2614
2669
|
if (limit > 0) rows = rows.slice(0, limit);
|
|
2670
|
+
return rows;
|
|
2671
|
+
}
|
|
2672
|
+
function measuresOf(raw) {
|
|
2673
|
+
const list = Array.isArray(raw) ? raw : [];
|
|
2674
|
+
const out = list.map((m) => ({ op: String(m["op"] ?? "count"), key: m["key"] }));
|
|
2675
|
+
return out.length ? out : [{ op: "count" }];
|
|
2676
|
+
}
|
|
2677
|
+
function runBlock(world, subject, raw, canvas, index) {
|
|
2678
|
+
const table = world.tableById.get(String(raw["table_id"] ?? subject));
|
|
2679
|
+
const title = String(raw["title"] ?? `Block ${index + 1}`);
|
|
2680
|
+
const base = { ...raw, title, table_id: table?.id ?? subject, ms: 0 };
|
|
2681
|
+
if (!table) return { ...base, rows: [], refused: "This block's table is not in this template." };
|
|
2682
|
+
if (raw["kind"] === "stuck") return { ...base, rows: [] };
|
|
2683
|
+
const measures = measuresOf(raw["measures"]);
|
|
2684
|
+
const groupBy = (raw["group_by"] ?? []).slice();
|
|
2685
|
+
const bucket = raw["bucket"] ?? null;
|
|
2686
|
+
const rows = aggregateRows(world, table, { groupBy, measures, bucket, filters: [raw["filter"], canvas], limit: Number(raw["limit"] ?? 0) });
|
|
2615
2687
|
return { ...base, measures, group_by: groupBy, rows };
|
|
2616
2688
|
}
|
|
2617
2689
|
function bookingAvailability(world, raw) {
|
|
@@ -2987,7 +3059,22 @@ function memoryDataSource(world) {
|
|
|
2987
3059
|
blocks: d.blocks.map((b, i) => runBlock(world, d.table_id, b, canvas, i))
|
|
2988
3060
|
});
|
|
2989
3061
|
},
|
|
2990
|
-
dashboard_stuck: () => ok2([])
|
|
3062
|
+
dashboard_stuck: () => ok2([]),
|
|
3063
|
+
// THE EIGHTH VERB, in memory: the same groups and measures as the live `custom.record_aggregate`
|
|
3064
|
+
// (and its row shape: no comparison asked ⇒ every prior_* null).
|
|
3065
|
+
record_aggregate: (args) => {
|
|
3066
|
+
const t = tableOf(args);
|
|
3067
|
+
if (!t) return refuse2("That table is not in this template.", "P0002");
|
|
3068
|
+
const rows = aggregateRows(world, t, {
|
|
3069
|
+
groupBy: (args["p_group_by"] ?? []).slice(),
|
|
3070
|
+
measures: measuresOf(args["p_measures"]),
|
|
3071
|
+
bucket: args["p_bucket"] ?? null,
|
|
3072
|
+
filters: [args["p_filter"]],
|
|
3073
|
+
...typeof args["p_search"] === "string" ? { search: args["p_search"] } : {},
|
|
3074
|
+
limit: Number(args["p_limit"] ?? 200)
|
|
3075
|
+
});
|
|
3076
|
+
return ok2(rows.map((r) => ({ ...r, prior_groups: null, prior_measures: null, prior_row_count: null, delta: null, compare: null })));
|
|
3077
|
+
}
|
|
2991
3078
|
};
|
|
2992
3079
|
const source = {
|
|
2993
3080
|
world,
|