1
10
11import type { FilterNode, SortSpec, GroupSpec, RecordQuery } from "@factory/shared/dto";
12
13import type { RecordRow, PropertyInfo, PropertyValue } from "../values/types.js";
14import { applyFilter, propertiesMap } from "../filter/index.js";
15import { sortRecords, type SortKey } from "./sort.js";
16import { groupRecords, type GroupMeta } from "./group.js";
17import { paginateRows, type Paged } from "./paginate.js";
18
19export interface QueryInput {
20 records: RecordRow[];
21 properties: PropertyInfo[];
22 filter?: FilterNode | null;
23 sort?: SortSpec[];
24 group?: GroupSpec[];
25 includeArchived?: boolean;
26 visiblePropertyIds?: string[];
27 cursor?: string | null;
28 pageSize?: number;
29 now?: number;
30 actorUserId?: string;
31 userTimezone?: string;
32}
33
34export interface QueryResult {
35 records: RecordRow[];
36 groups: GroupMeta[] | null;
37 cursor: string | null;
38 total: number;
39}
40
41export function runRecordQuery(input: QueryInput): QueryResult {
42 const props = propertiesMap(input.properties);
43 const now = input.now ?? Date.now();
44 const ctx = { now, actorUserId: input.actorUserId, userTimezone: input.userTimezone ?? "UTC" };
45
46
47 let rows = input.records;
48 if (!input.includeArchived) rows = rows.filter((r) => !r.archivedAt);
49
50
51 rows = applyFilter(rows, input.filter ?? null, props, ctx);
52
53
54 const sort: readonly SortKey[] =
55 input.sort && input.sort.length > 0 ? (input.sort as SortKey[]) : [];
56 rows = sortRecords(rows, sort, props, true);
57
58
59 if (input.visiblePropertyIds && input.visiblePropertyIds.length > 0) {
60 const visible = new Set(input.visiblePropertyIds);
61 rows = rows.map((r) => {
62 const values: Record<string, PropertyValue | undefined> = {};
63 for (const [k, v] of Object.entries(r.values)) if (visible.has(k)) values[k] = v;
64 const masked: RecordRow = { ...r, values };
65 return masked;
66 });
67 }
68
69
70 if (input.group && input.group.length > 0) {
71 const groups = groupRecords(rows, input.group, props);
72 return { records: rows, groups, cursor: null, total: rows.length };
73 }
74
75
76 const paged: Paged<RecordRow> = paginateRows(
77 rows,
78 input.cursor ?? undefined,
79 input.pageSize ?? 50,
80 );
81 return { records: paged.items, groups: null, cursor: paged.cursor, total: paged.total };
82}
83
84export * from "./sort.js";
85export * from "./group.js";
86export * from "./paginate.js";
87export * from "./pivot.js";
88