@ai-matrx/records 0.47.0 → 0.49.0

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.
@@ -94,6 +94,7 @@ __export(react_exports, {
94
94
  publicFormPath: () => publicFormPath,
95
95
  rememberedOpCount: () => rememberedOpCount,
96
96
  scopeChip: () => scopeChip,
97
+ stableFilterKey: () => stableFilterKey,
97
98
  tableShapeChanged: () => tableShapeChanged,
98
99
  useEntityFieldMutation: () => useEntityFieldMutation,
99
100
  useEntityFieldRights: () => useEntityFieldRights,
@@ -640,6 +641,7 @@ var STORE_DOORS = [
640
641
  { name: "read_record", args: "p_organization_id uuid, p_record_id uuid, p_by_id boolean DEFAULT false", returns: "jsonb", security: "definer" },
641
642
  { name: "read_records", args: "p_organization_id uuid, p_table_id uuid, p_by_id boolean DEFAULT false, p_limit integer DEFAULT 200, p_offset integer DEFAULT 0", returns: "TABLE(id uuid, document jsonb, level permission_level)", security: "definer" },
642
643
  { name: "read_records_by_ids", args: "p_organization_id uuid, p_table_id uuid, p_record_ids uuid[], p_by_id boolean DEFAULT false", returns: "TABLE(id uuid, document jsonb, level permission_level)", security: "definer" },
644
+ { name: "read_records_matching", args: "p_organization_id uuid, p_table_id uuid, p_filter jsonb DEFAULT '{}'::jsonb, p_by_id boolean DEFAULT false, p_limit integer DEFAULT 200, p_offset integer DEFAULT 0", returns: "TABLE(id uuid, document jsonb, level permission_level)", security: "definer" },
643
645
  { name: "realtime_topic_admits", args: "p_topic text", returns: "boolean", security: "definer" },
644
646
  { name: "record_aggregate", args: "p_organization_id uuid, p_table_id uuid, p_group_by jsonb DEFAULT '[]'::jsonb, p_measures jsonb DEFAULT '[]'::jsonb, p_bucket jsonb DEFAULT NULL::jsonb, p_filter jsonb DEFAULT '{}'::jsonb, p_limit integer DEFAULT 200, p_required text DEFAULT 'viewer'::text", returns: "TABLE(groups jsonb, measures jsonb, row_count bigint)", security: "definer" },
645
647
  { name: "record_applicability", args: "p_organization_id uuid, p_record_id uuid", returns: "TABLE(rule_id uuid, rule_name text, rule_version integer, applies boolean, answer jsonb)", security: "invoker" },
@@ -1969,6 +1971,15 @@ var DOORS = {
1969
1971
  // live Postgres function makes every existing call ambiguous — `is not unique`. Same
1970
1972
  // ladder, same level, same masking, same page ceiling.
1971
1973
  readRecordsByIds: "read_records_by_ids",
1974
+ // THE SAME READ DOOR, ADDRESSED BY A QUESTION. `custom.read_records_matching`
1975
+ // takes the store's one filter shape (`RecordFilter` — the object
1976
+ // `platform.saved_view` carries as `filters` and `custom.record_aggregate`
1977
+ // takes as `p_filter`) and narrows the page INSIDE its own query, in the same
1978
+ // WHERE as Visibility. A separate NAME for the same reason as above. It is
1979
+ // what makes a number on a dashboard walkable: the filter is evaluated by
1980
+ // `custom.record_filter_sql`, the one body `custom.agg_sql` also calls, so the
1981
+ // rows it opens are the rows the number counted.
1982
+ readRecordsMatching: "read_records_matching",
1972
1983
  // DOOR-8, the two clocks. `p_recorded_at` is what the store SAID then;
1973
1984
  // `p_world_on` is what was TRUE of the world on that date, read out of dated
1974
1985
  // values. A client that answered either one itself would be guessing.
@@ -2660,12 +2671,13 @@ function createRecordsClient(config) {
2660
2671
  })
2661
2672
  );
2662
2673
  },
2663
- async list({ table_id, limit = 50, offset = 0 }) {
2674
+ async list({ table_id, filter, limit = 50, offset = 0 }) {
2664
2675
  const door = await callDoor(
2665
- DOORS.readRecords,
2676
+ DOORS.readRecordsMatching,
2666
2677
  {
2667
2678
  p_organization_id: org,
2668
2679
  p_table_id: table_id,
2680
+ p_filter: filter ?? {},
2669
2681
  p_limit: limit,
2670
2682
  p_offset: offset
2671
2683
  },
@@ -4374,6 +4386,27 @@ function useRecordsActor() {
4374
4386
 
4375
4387
  // src/react/hooks.ts
4376
4388
  var import_react2 = require("react");
4389
+
4390
+ // src/aggregate.ts
4391
+ function measureKey(measure) {
4392
+ return measure.op === "count" ? "count" : `${measure.op}_${measure.key ?? ""}`;
4393
+ }
4394
+ function stableFilterKey(filter) {
4395
+ if (!filter) return "{}";
4396
+ const keys = Object.keys(filter).sort();
4397
+ if (keys.length === 0) return "{}";
4398
+ const parts = keys.map((key) => {
4399
+ const value = filter[key];
4400
+ if (value !== null && typeof value === "object") {
4401
+ const window2 = value;
4402
+ return `${JSON.stringify(key)}:{"from":${JSON.stringify(window2.from ?? null)},"to":${JSON.stringify(window2.to ?? null)}}`;
4403
+ }
4404
+ return `${JSON.stringify(key)}:${JSON.stringify(value ?? null)}`;
4405
+ });
4406
+ return `{${parts.join(",")}}`;
4407
+ }
4408
+
4409
+ // src/react/hooks.ts
4377
4410
  function useAsync(run, deps) {
4378
4411
  const client = useRecordsClient();
4379
4412
  const [state, setState] = (0, import_react2.useState)(
@@ -4482,16 +4515,21 @@ function useRecords(tableId, options = {}) {
4482
4515
  const client = useRecordsClient();
4483
4516
  const pageSize = options.pageSize ?? 50;
4484
4517
  const page = options.page ?? 0;
4518
+ const filterKey = stableFilterKey(options.filter);
4485
4519
  const base = useAsync(
4486
4520
  async (c) => {
4487
4521
  if (!tableId) return { ok: true, data: { rows: [], total: null } };
4488
4522
  return c.list({
4489
4523
  table_id: tableId,
4524
+ ...filterKey === "{}" ? {} : { filter: options.filter },
4490
4525
  limit: pageSize,
4491
4526
  offset: page * pageSize
4492
4527
  });
4493
4528
  },
4494
- [tableId, pageSize, page]
4529
+ // The QUESTION, not the object: a parent that rebuilds `{status: "Cancelled"}`
4530
+ // on every render must not re-read the page on every render, and a parent
4531
+ // that changes the question must re-read on the first one.
4532
+ [tableId, pageSize, page, filterKey]
4495
4533
  );
4496
4534
  const realtime = client.config.realtime;
4497
4535
  const { reload, setData } = base;
@@ -5081,11 +5119,6 @@ function portalPath(slug) {
5081
5119
  return `/portal/c/${slug}`;
5082
5120
  }
5083
5121
 
5084
- // src/aggregate.ts
5085
- function measureKey(measure) {
5086
- return measure.op === "count" ? "count" : `${measure.op}_${measure.key ?? ""}`;
5087
- }
5088
-
5089
5122
  // src/capture-queue.ts
5090
5123
  var DB_NAME = "matrx-capture";
5091
5124
  var DB_VERSION = 1;