import { AggregateBucket } from '../core/index.js'; import { RecordsClient } from '../core/index.js'; import { Field } from '../core/index.js'; import { HiddenFieldNotice, Uuid, RecordsResult } from '../core/index.js'; import { RuleExpression } from '../core/index.js'; import '../relation-B00lR6BX.js'; import '../ports-uIDHLgZN.js'; import '../doors-DZzgZBEf.js'; import '../pickListDoors-DcCN4k-W.js'; import '../portal-CHEQEjS7.js'; import '../table-kind/index.js'; type QuestionOp = "count" | "sum" | "avg" | "min" | "max"; declare const QUESTION_OPS: readonly QuestionOp[]; interface QuestionMeasure { op: QuestionOp; /** The Field measured; absent for `count`. */ key?: string | undefined; } /** What the answer is cut into. */ type QuestionGroup = { kind: "field"; key: string; } | { kind: "bucket"; key: string; by: AggregateBucket; } /** A column of the table a relation points at: `Patient.Referring physician`. */ | { kind: "through"; relation: string; key: string; }; /** A condition on a column of the table a relation points at ("Patient.Referring physician is …"). */ interface ThroughCondition { relation: string; key: string; value: string | number | boolean | null; } type QuestionShow = "table" | "bar" | "column" | "line" | "donut" | "number"; interface QuestionSpec { v: 1; measures: QuestionMeasure[]; /** The grid's condition builder's Rule, on this table's own Fields (by id). */ where: RuleExpression | null; /** Conditions across a relation, ANDed with `where`. */ through: ThroughCondition[]; group: QuestionGroup | null; /** An ISO moment: the table as the store held it then. Null = now. */ asOf: string | null; /** Groups sorted by the FIRST measure (`measure`) or by how many records each holds. Null = the store's default. */ order: { by: "measure" | "count"; direction: "desc" | "asc"; } | null; /** How many groups are shown. */ limit: number; show: QuestionShow; } declare const QUESTION_LIMIT_DEFAULT = 25; /** How many groups the store is asked for when it must be asked for all of them. */ declare const QUESTION_GROUP_CEILING = 200; /** A grouping across a relation asks the store once per related value; past this it refuses. */ declare const QUESTION_THROUGH_GROUP_CAP = 60; declare function newQuestion(): QuestionSpec; /** A kept definition read back: anything malformed becomes the empty question, never a throw. */ declare function questionFromDefinition(definition: unknown): QuestionSpec; interface QuestionRow { /** The group's stored value (a relation's record id, a period's local moment, a word), or null. */ group: string | null; /** By measure key (`count`, `sum_copay`). Null = no value (never 0 passed off as one). */ values: Record; /** A measure over a column this reader may not read: the store's own notice, by measure key. */ withheld: Record; /** How many records the group was measured over. */ n: number; } interface QuestionAnswer { rows: QuestionRow[]; /** The measure keys, in the order asked. */ measures: string[]; /** The key the group values are under (a bucket's is `_`), or null. */ groupKey: string | null; /** How many groups exist; `groupsExact` false when it is "at least". */ groupsTotal: number | null; groupsExact: boolean; truncated: boolean; asOf: string | null; } /** * The Rule as a FLAT map (Field key → value) when it is only "is" conditions joined by ALL — the * one shape the as-of door and a condition across a relation can carry. Null when it is more. */ declare function flatWhere(where: RuleExpression | null, fields: readonly Field[]): Record | null; /** * ASK THE STORE. `fields` are this table's Fields (the condition builder writes Fields by id, and a * formula column cannot be asked "as of"). Every number in the answer is a door's. */ declare function askQuestion(client: RecordsClient, tableId: Uuid, spec: QuestionSpec, fields: readonly Field[]): Promise>; /** * THE COLUMNS THIS READER MAY NOT READ, asked of the store: one aggregate measuring how many * records fill each column that carries a sensitivity, and every measure the store WITHHOLDS is a * column never offered. Nothing is guessed from levels here; the store decides, as it does for the * grid's cells. */ declare function unreadableKeys(client: RecordsClient, tableId: Uuid, fields: readonly Field[]): Promise>; /** The columns a measure other than count may read: numbers (formula arithmetic included); min/max also dates. */ declare function measurableFields(fields: readonly Field[], op: QuestionOp): Field[]; /** The saved-view surface a Question is kept under, beside the table's views (`custom/records`). */ declare const QUESTION_SURFACE = "custom/records/question"; interface SavedQuestion { id: Uuid; name: string; spec: QuestionSpec; /** Shared with the organization (`internal`) or kept for its maker (`personal`). */ shared: boolean; version: number; createdBy: Uuid | null; } /** The table's Questions this person may read (the row's own access decides). */ declare function questionsOf(client: RecordsClient, tableId: Uuid): Promise>; /** Keep a Question (new when `id` is absent). `null` data = somebody changed it first. */ declare function questionSave(client: RecordsClient, args: { id?: Uuid | null; tableId: Uuid; name: string; spec: QuestionSpec; shared: boolean; expectedVersion?: number; }): Promise>; /** Archive a Question (its maker, or an admin of it). */ declare function questionArchive(client: RecordsClient, id: Uuid, version?: number): Promise>; export { QUESTION_GROUP_CEILING, QUESTION_LIMIT_DEFAULT, QUESTION_OPS, QUESTION_SURFACE, QUESTION_THROUGH_GROUP_CAP, askQuestion, flatWhere, measurableFields, newQuestion, questionArchive, questionFromDefinition, questionSave, questionsOf, unreadableKeys }; export type { QuestionAnswer, QuestionGroup, QuestionMeasure, QuestionOp, QuestionRow, QuestionShow, QuestionSpec, SavedQuestion, ThroughCondition };