@segmentstream-cloud/ontology 0.15.0 → 0.17.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.
@@ -12,9 +12,10 @@ import { type SignInOptions, type SignInPolicy } from "./sign-in.js";
12
12
  * relationships target warehouse-backed entities and warehouse-backed properties declare `unique`:
13
13
  * a relationship with a warehouse-backed end carries `on` and omits `optional` and `onDelete`.
14
14
  * Version 6 adds the `countDistinct` measure operator and lets stored entities declare `measures`,
15
- * whose columns name the stored properties' replication view columns.
15
+ * whose columns name the stored properties' replication view columns. Version 7 adds the avg, min,
16
+ * max and filtered measure operators and balanceOver on measures.
16
17
  */
17
- export declare const MANIFEST_VERSION = 6;
18
+ export declare const MANIFEST_VERSION = 7;
18
19
  /** The phrase used for a direction the author did not phrase. */
19
20
  export declare const DEFAULT_PHRASE = "has";
20
21
  export declare const SelectOptionManifest: Schema.Struct<{
@@ -129,6 +130,21 @@ export declare const EntityPermissionsManifest: Schema.Struct<{
129
130
  readonly unlink: Schema.optionalKey<Schema.String>;
130
131
  }>;
131
132
  export type EntityPermissionsManifest = typeof EntityPermissionsManifest.Type;
133
+ /** A measure of an entity: its metadata and the expression the platform computes. */
134
+ export declare const MeasureManifest: Schema.Struct<{
135
+ readonly name: Schema.String;
136
+ readonly label: Schema.String;
137
+ readonly description: Schema.String;
138
+ readonly unit: Schema.Literals<readonly ["number", "currency", "ratio", "percent"]>;
139
+ readonly format: Schema.Literals<readonly ["decimal", "currency", "percent"]>;
140
+ readonly expression: Schema.Codec<Schema.Json, Schema.Json, never, never>;
141
+ /**
142
+ * The column of the date or timestamp property a balance measure snapshots over; absent for
143
+ * additive measures and in manifests before version 7. `balance_over` on the wire.
144
+ */
145
+ readonly balanceOver: Schema.optionalKey<Schema.String>;
146
+ }>;
147
+ export type MeasureManifest = typeof MeasureManifest.Type;
132
148
  export declare const EntityManifest: Schema.Struct<{
133
149
  readonly source: Schema.optionalKey<Schema.Struct<{
134
150
  readonly asset: Schema.String;
@@ -142,6 +158,11 @@ export declare const EntityManifest: Schema.Struct<{
142
158
  readonly unit: Schema.Literals<readonly ["number", "currency", "ratio", "percent"]>;
143
159
  readonly format: Schema.Literals<readonly ["decimal", "currency", "percent"]>;
144
160
  readonly expression: Schema.Codec<Schema.Json, Schema.Json, never, never>;
161
+ /**
162
+ * The column of the date or timestamp property a balance measure snapshots over; absent for
163
+ * additive measures and in manifests before version 7. `balance_over` on the wire.
164
+ */
165
+ readonly balanceOver: Schema.optionalKey<Schema.String>;
145
166
  }>>>;
146
167
  readonly id: Schema.String;
147
168
  readonly name: Schema.String;
@@ -270,6 +291,21 @@ export type SignInManifest = typeof SignInManifest.Type;
270
291
  /** The JSON contract written since version 4; decoded SDK models remain camelCase. */
271
292
  export declare const OntologyManifestWire: Schema.encodeKeys<Schema.Struct<{
272
293
  readonly entities: Schema.$Array<Schema.encodeKeys<Schema.Struct<{
294
+ readonly measures: Schema.optionalKey<Schema.$Array<Schema.encodeKeys<Schema.Struct<{
295
+ readonly name: Schema.String;
296
+ readonly label: Schema.String;
297
+ readonly description: Schema.String;
298
+ readonly unit: Schema.Literals<readonly ["number", "currency", "ratio", "percent"]>;
299
+ readonly format: Schema.Literals<readonly ["decimal", "currency", "percent"]>;
300
+ readonly expression: Schema.Codec<Schema.Json, Schema.Json, never, never>;
301
+ /**
302
+ * The column of the date or timestamp property a balance measure snapshots over; absent for
303
+ * additive measures and in manifests before version 7. `balance_over` on the wire.
304
+ */
305
+ readonly balanceOver: Schema.optionalKey<Schema.String>;
306
+ }>, {
307
+ readonly balanceOver: "balance_over";
308
+ }>>>;
273
309
  readonly properties: Schema.$Array<Schema.encodeKeys<Schema.Struct<{
274
310
  readonly column: Schema.optionalKey<Schema.String>;
275
311
  readonly scope: Schema.optionalKey<Schema.$Array<Schema.String>>;
@@ -325,14 +361,6 @@ export declare const OntologyManifestWire: Schema.encodeKeys<Schema.Struct<{
325
361
  readonly key: Schema.$Array<Schema.String>;
326
362
  readonly currency: Schema.optionalKey<Schema.String>;
327
363
  }>>;
328
- readonly measures: Schema.optionalKey<Schema.$Array<Schema.Struct<{
329
- readonly name: Schema.String;
330
- readonly label: Schema.String;
331
- readonly description: Schema.String;
332
- readonly unit: Schema.Literals<readonly ["number", "currency", "ratio", "percent"]>;
333
- readonly format: Schema.Literals<readonly ["decimal", "currency", "percent"]>;
334
- readonly expression: Schema.Codec<Schema.Json, Schema.Json, never, never>;
335
- }>>>;
336
364
  readonly id: Schema.String;
337
365
  readonly name: Schema.String;
338
366
  readonly label: Schema.String;
@@ -413,6 +441,21 @@ export declare const OntologyManifestWire: Schema.encodeKeys<Schema.Struct<{
413
441
  /** Historical readers accept either metadata spelling and any manifest version. */
414
442
  export declare const OntologyManifest: Schema.Union<readonly [Schema.encodeKeys<Schema.Struct<{
415
443
  readonly entities: Schema.$Array<Schema.encodeKeys<Schema.Struct<{
444
+ readonly measures: Schema.optionalKey<Schema.$Array<Schema.encodeKeys<Schema.Struct<{
445
+ readonly name: Schema.String;
446
+ readonly label: Schema.String;
447
+ readonly description: Schema.String;
448
+ readonly unit: Schema.Literals<readonly ["number", "currency", "ratio", "percent"]>;
449
+ readonly format: Schema.Literals<readonly ["decimal", "currency", "percent"]>;
450
+ readonly expression: Schema.Codec<Schema.Json, Schema.Json, never, never>;
451
+ /**
452
+ * The column of the date or timestamp property a balance measure snapshots over; absent for
453
+ * additive measures and in manifests before version 7. `balance_over` on the wire.
454
+ */
455
+ readonly balanceOver: Schema.optionalKey<Schema.String>;
456
+ }>, {
457
+ readonly balanceOver: "balance_over";
458
+ }>>>;
416
459
  readonly properties: Schema.$Array<Schema.encodeKeys<Schema.Struct<{
417
460
  readonly column: Schema.optionalKey<Schema.String>;
418
461
  readonly scope: Schema.optionalKey<Schema.$Array<Schema.String>>;
@@ -468,14 +511,6 @@ export declare const OntologyManifest: Schema.Union<readonly [Schema.encodeKeys<
468
511
  readonly key: Schema.$Array<Schema.String>;
469
512
  readonly currency: Schema.optionalKey<Schema.String>;
470
513
  }>>;
471
- readonly measures: Schema.optionalKey<Schema.$Array<Schema.Struct<{
472
- readonly name: Schema.String;
473
- readonly label: Schema.String;
474
- readonly description: Schema.String;
475
- readonly unit: Schema.Literals<readonly ["number", "currency", "ratio", "percent"]>;
476
- readonly format: Schema.Literals<readonly ["decimal", "currency", "percent"]>;
477
- readonly expression: Schema.Codec<Schema.Json, Schema.Json, never, never>;
478
- }>>>;
479
514
  readonly id: Schema.String;
480
515
  readonly name: Schema.String;
481
516
  readonly label: Schema.String;
@@ -569,6 +604,11 @@ export declare const OntologyManifest: Schema.Union<readonly [Schema.encodeKeys<
569
604
  readonly unit: Schema.Literals<readonly ["number", "currency", "ratio", "percent"]>;
570
605
  readonly format: Schema.Literals<readonly ["decimal", "currency", "percent"]>;
571
606
  readonly expression: Schema.Codec<Schema.Json, Schema.Json, never, never>;
607
+ /**
608
+ * The column of the date or timestamp property a balance measure snapshots over; absent for
609
+ * additive measures and in manifests before version 7. `balance_over` on the wire.
610
+ */
611
+ readonly balanceOver: Schema.optionalKey<Schema.String>;
572
612
  }>>>;
573
613
  readonly id: Schema.String;
574
614
  readonly name: Schema.String;
@@ -696,31 +736,18 @@ export declare const decodeManifestDocument: (value: unknown) => Effect.Effect<{
696
736
  readonly description: string;
697
737
  readonly label: string;
698
738
  readonly title: string;
699
- readonly actions: readonly {
700
- readonly name: string;
701
- readonly description: string;
702
- readonly input: {
703
- readonly [x: string]: Schema.Json;
704
- };
705
- readonly permission?: string | undefined;
706
- readonly connections?: readonly string[] | undefined;
707
- readonly hints?: {
708
- readonly destructive?: boolean | undefined;
709
- readonly idempotent?: boolean | undefined;
710
- } | undefined;
711
- }[];
712
739
  readonly properties: readonly {
713
740
  readonly optional: boolean;
714
741
  readonly name: string;
715
742
  readonly label: string;
716
- readonly type: "number" | "boolean" | "text" | "email" | "url" | "integer" | "date" | "timestamp" | "select" | "json" | "blob";
743
+ readonly type: "number" | "boolean" | "date" | "timestamp" | "text" | "email" | "url" | "select" | "integer" | "json" | "blob";
717
744
  readonly unique: boolean;
718
745
  readonly managed: boolean;
746
+ readonly min?: number | undefined;
747
+ readonly max?: number | undefined;
719
748
  readonly column?: string | undefined;
720
749
  readonly description?: string | undefined;
721
750
  readonly maxLength?: number | undefined;
722
- readonly min?: number | undefined;
723
- readonly max?: number | undefined;
724
751
  readonly options?: readonly {
725
752
  readonly value: string;
726
753
  readonly label: string;
@@ -735,23 +762,36 @@ export declare const decodeManifestDocument: (value: unknown) => Effect.Effect<{
735
762
  }[];
736
763
  readonly relationships: readonly {
737
764
  readonly name: string;
765
+ readonly to: string;
738
766
  readonly description: string;
739
- readonly phrase: readonly [string, string];
740
767
  readonly cardinality: "one" | "many";
741
- readonly to: string;
768
+ readonly phrase: readonly [string, string];
742
769
  readonly inverse: string;
743
770
  readonly optional?: boolean | undefined;
744
- readonly onDelete?: "setNull" | "cascade" | "restrict" | undefined;
745
771
  readonly on?: {
746
772
  readonly property: string;
747
773
  readonly targetProperty: string;
748
774
  } | undefined;
775
+ readonly onDelete?: "setNull" | "cascade" | "restrict" | undefined;
749
776
  readonly ordered?: boolean | undefined;
750
777
  }[];
751
778
  readonly indexes: readonly {
752
779
  readonly properties: readonly string[];
753
780
  readonly unique: boolean;
754
781
  }[];
782
+ readonly actions: readonly {
783
+ readonly name: string;
784
+ readonly description: string;
785
+ readonly input: {
786
+ readonly [x: string]: Schema.Json;
787
+ };
788
+ readonly permission?: string | undefined;
789
+ readonly connections?: readonly string[] | undefined;
790
+ readonly hints?: {
791
+ readonly destructive?: boolean | undefined;
792
+ readonly idempotent?: boolean | undefined;
793
+ } | undefined;
794
+ }[];
755
795
  readonly plural: string;
756
796
  readonly builtIn: boolean;
757
797
  readonly renamedFrom?: string | undefined;
@@ -762,11 +802,12 @@ export declare const decodeManifestDocument: (value: unknown) => Effect.Effect<{
762
802
  } | undefined;
763
803
  readonly measures?: readonly {
764
804
  readonly name: string;
765
- readonly label: string;
766
805
  readonly description: string;
806
+ readonly label: string;
767
807
  readonly unit: "number" | "currency" | "ratio" | "percent";
768
- readonly format: "currency" | "percent" | "decimal";
808
+ readonly format: "decimal" | "currency" | "percent";
769
809
  readonly expression: Schema.Json;
810
+ readonly balanceOver?: string | undefined;
770
811
  }[] | undefined;
771
812
  readonly guide?: string | undefined;
772
813
  readonly permissions?: {
@@ -800,31 +841,18 @@ export declare const decodeManifestDocument: (value: unknown) => Effect.Effect<{
800
841
  readonly description: string;
801
842
  readonly label: string;
802
843
  readonly title: string;
803
- readonly actions: readonly {
804
- readonly name: string;
805
- readonly description: string;
806
- readonly input: {
807
- readonly [x: string]: Schema.Json;
808
- };
809
- readonly permission?: string | undefined;
810
- readonly connections?: readonly string[] | undefined;
811
- readonly hints?: {
812
- readonly destructive?: boolean | undefined;
813
- readonly idempotent?: boolean | undefined;
814
- } | undefined;
815
- }[];
816
844
  readonly properties: readonly {
817
845
  readonly optional: boolean;
818
846
  readonly name: string;
819
847
  readonly label: string;
820
- readonly type: "number" | "boolean" | "text" | "email" | "url" | "integer" | "date" | "timestamp" | "select" | "json" | "blob";
848
+ readonly type: "number" | "boolean" | "date" | "timestamp" | "text" | "email" | "url" | "select" | "integer" | "json" | "blob";
821
849
  readonly unique: boolean;
822
850
  readonly managed: boolean;
851
+ readonly min?: number | undefined;
852
+ readonly max?: number | undefined;
823
853
  readonly column?: string | undefined;
824
854
  readonly description?: string | undefined;
825
855
  readonly maxLength?: number | undefined;
826
- readonly min?: number | undefined;
827
- readonly max?: number | undefined;
828
856
  readonly options?: readonly {
829
857
  readonly value: string;
830
858
  readonly label: string;
@@ -839,23 +867,36 @@ export declare const decodeManifestDocument: (value: unknown) => Effect.Effect<{
839
867
  }[];
840
868
  readonly relationships: readonly {
841
869
  readonly name: string;
870
+ readonly to: string;
842
871
  readonly description: string;
843
- readonly phrase: readonly [string, string];
844
872
  readonly cardinality: "one" | "many";
845
- readonly to: string;
873
+ readonly phrase: readonly [string, string];
846
874
  readonly inverse: string;
847
875
  readonly optional?: boolean | undefined;
848
- readonly onDelete?: "setNull" | "cascade" | "restrict" | undefined;
849
876
  readonly on?: {
850
877
  readonly property: string;
851
878
  readonly targetProperty: string;
852
879
  } | undefined;
880
+ readonly onDelete?: "setNull" | "cascade" | "restrict" | undefined;
853
881
  readonly ordered?: boolean | undefined;
854
882
  }[];
855
883
  readonly indexes: readonly {
856
884
  readonly properties: readonly string[];
857
885
  readonly unique: boolean;
858
886
  }[];
887
+ readonly actions: readonly {
888
+ readonly name: string;
889
+ readonly description: string;
890
+ readonly input: {
891
+ readonly [x: string]: Schema.Json;
892
+ };
893
+ readonly permission?: string | undefined;
894
+ readonly connections?: readonly string[] | undefined;
895
+ readonly hints?: {
896
+ readonly destructive?: boolean | undefined;
897
+ readonly idempotent?: boolean | undefined;
898
+ } | undefined;
899
+ }[];
859
900
  readonly plural: string;
860
901
  readonly builtIn: boolean;
861
902
  readonly renamedFrom?: string | undefined;
@@ -866,11 +907,12 @@ export declare const decodeManifestDocument: (value: unknown) => Effect.Effect<{
866
907
  } | undefined;
867
908
  readonly measures?: readonly {
868
909
  readonly name: string;
869
- readonly label: string;
870
910
  readonly description: string;
911
+ readonly label: string;
871
912
  readonly unit: "number" | "currency" | "ratio" | "percent";
872
- readonly format: "currency" | "percent" | "decimal";
913
+ readonly format: "decimal" | "currency" | "percent";
873
914
  readonly expression: Schema.Json;
915
+ readonly balanceOver?: string | undefined;
874
916
  }[] | undefined;
875
917
  readonly guide?: string | undefined;
876
918
  readonly permissions?: {
@@ -911,6 +953,13 @@ export declare function canonicalJson(value: unknown): string;
911
953
  export declare function formatManifest(manifest: OntologyManifest): string;
912
954
  /** The hash of a manifest, computed over its canonical JSON without the `hash` field. */
913
955
  export declare function manifestHash(manifest: Readonly<Record<string, unknown>>): string;
956
+ /**
957
+ * The measures of an entity, of one that passed `check`. A warehouse-backed property's column is its
958
+ * `column`; a stored property has none, and its column in the replication view is its wire name.
959
+ * Conditions name columns too, and so does `balanceOver`, which comes from the measure's own
960
+ * aggregates, top-level or inside arithmetic: `check` lets them name one property at most.
961
+ */
962
+ export declare function measuresManifest(resolved: ResolvedEntity): ReadonlyArray<MeasureManifest>;
914
963
  /** Builds the manifest of a resolved ontology that passed `check`. */
915
964
  export declare function buildManifest(input: {
916
965
  readonly entities: ReadonlyArray<ResolvedEntity>;
package/dist/manifest.js CHANGED
@@ -1,4 +1,4 @@
1
- import { measureExpression } from "./measure.js";
1
+ import { balancesOf, measureExpression } from "./measure.js";
2
2
  import { createHash } from "node:crypto";
3
3
  import { Effect, Schema, SchemaTransformation } from "effect";
4
4
  import { humanize, MEMBER_ROLE } from "./names.js";
@@ -15,9 +15,10 @@ import { DEFAULT_SIGN_IN_POLICY, isSignInPolicy, } from "./sign-in.js";
15
15
  * relationships target warehouse-backed entities and warehouse-backed properties declare `unique`:
16
16
  * a relationship with a warehouse-backed end carries `on` and omits `optional` and `onDelete`.
17
17
  * Version 6 adds the `countDistinct` measure operator and lets stored entities declare `measures`,
18
- * whose columns name the stored properties' replication view columns.
18
+ * whose columns name the stored properties' replication view columns. Version 7 adds the avg, min,
19
+ * max and filtered measure operators and balanceOver on measures.
19
20
  */
20
- export const MANIFEST_VERSION = 6;
21
+ export const MANIFEST_VERSION = 7;
21
22
  /** The first version whose documents use snake_case names on the wire. */
22
23
  const WIRE_MANIFEST_VERSION = 4;
23
24
  /** The phrase used for a direction the author did not phrase. */
@@ -123,20 +124,27 @@ export const EntityPermissionsManifest = Schema.Struct({
123
124
  link: Schema.optionalKey(Schema.String),
124
125
  unlink: Schema.optionalKey(Schema.String),
125
126
  });
127
+ /** A measure of an entity: its metadata and the expression the platform computes. */
128
+ export const MeasureManifest = Schema.Struct({
129
+ name: Schema.String,
130
+ label: Schema.String,
131
+ description: Schema.String,
132
+ unit: Schema.Literals(["number", "currency", "ratio", "percent"]),
133
+ format: Schema.Literals(["decimal", "currency", "percent"]),
134
+ expression: Schema.Json,
135
+ /**
136
+ * The column of the date or timestamp property a balance measure snapshots over; absent for
137
+ * additive measures and in manifests before version 7. `balance_over` on the wire.
138
+ */
139
+ balanceOver: Schema.optionalKey(Schema.String),
140
+ });
126
141
  export const EntityManifest = Schema.Struct({
127
142
  source: Schema.optionalKey(Schema.Struct({
128
143
  asset: Schema.String,
129
144
  key: Schema.Array(Schema.String),
130
145
  currency: Schema.optionalKey(Schema.String),
131
146
  })),
132
- measures: Schema.optionalKey(Schema.Array(Schema.Struct({
133
- name: Schema.String,
134
- label: Schema.String,
135
- description: Schema.String,
136
- unit: Schema.Literals(["number", "currency", "ratio", "percent"]),
137
- format: Schema.Literals(["decimal", "currency", "percent"]),
138
- expression: Schema.Json,
139
- }))),
147
+ measures: Schema.optionalKey(Schema.Array(MeasureManifest)),
140
148
  id: Schema.String,
141
149
  name: Schema.String,
142
150
  label: Schema.String,
@@ -206,8 +214,10 @@ const RelationshipManifestWire = Schema.Struct({
206
214
  on: Schema.optionalKey(Schema.Struct({ property: Schema.String, targetProperty: Schema.String }).pipe(Schema.encodeKeys({ targetProperty: "target_property" }))),
207
215
  onDelete: Schema.optionalKey(OnDeleteWire),
208
216
  }).pipe(Schema.encodeKeys({ onDelete: "on_delete" }));
217
+ const MeasureManifestWire = MeasureManifest.pipe(Schema.encodeKeys({ balanceOver: "balance_over" }));
209
218
  const EntityManifestWire = Schema.Struct({
210
219
  ...EntityManifest.fields,
220
+ measures: Schema.optionalKey(Schema.Array(MeasureManifestWire)),
211
221
  properties: Schema.Array(PropertyManifestWire),
212
222
  relationships: Schema.Array(RelationshipManifestWire),
213
223
  }).pipe(Schema.encodeKeys({ builtIn: "built_in", renamedFrom: "renamed_from" }));
@@ -348,27 +358,33 @@ function relationshipManifest(input) {
348
358
  };
349
359
  }
350
360
  /**
351
- * The measures of an entity. A warehouse-backed property's column is its `column`; a stored property
352
- * has none, and its column in the replication view is its wire name.
361
+ * The measures of an entity, of one that passed `check`. A warehouse-backed property's column is its
362
+ * `column`; a stored property has none, and its column in the replication view is its wire name.
363
+ * Conditions name columns too, and so does `balanceOver`, which comes from the measure's own
364
+ * aggregates, top-level or inside arithmetic: `check` lets them name one property at most.
353
365
  */
354
- function measuresManifest(resolved) {
366
+ export function measuresManifest(resolved) {
355
367
  const columns = new Map(resolved.properties.map((property) => [
356
368
  property.name,
357
369
  property.definition.column ?? property.name,
358
370
  ]));
359
- return Object.entries(resolved.entity.definition.measures ?? {}).map(([name, measure]) => ({
360
- name,
361
- label: measure.label ?? humanize(name),
362
- description: measure.description ?? "",
363
- unit: measure.unit ?? "number",
364
- format: measure.format ??
365
- (measure.unit === "currency"
366
- ? "currency"
367
- : measure.unit === "percent"
368
- ? "percent"
369
- : "decimal"),
370
- expression: measureExpression(measure, columns),
371
- }));
371
+ return Object.entries(resolved.entity.definition.measures ?? {}).map(([name, measure]) => {
372
+ const [balance] = balancesOf(measure);
373
+ return {
374
+ name,
375
+ label: measure.label ?? humanize(name),
376
+ description: measure.description ?? "",
377
+ unit: measure.unit ?? "number",
378
+ format: measure.format ??
379
+ (measure.unit === "currency"
380
+ ? "currency"
381
+ : measure.unit === "percent"
382
+ ? "percent"
383
+ : "decimal"),
384
+ expression: measureExpression(measure, columns),
385
+ ...(balance === undefined ? {} : { balanceOver: columns.get(balance) ?? balance }),
386
+ };
387
+ });
372
388
  }
373
389
  /** `warehouseBacked` names the ontology's warehouse-backed entities, which relationships may target. */
374
390
  function entityManifest(input) {
package/dist/measure.d.ts CHANGED
@@ -1,3 +1,26 @@
1
+ import type { AggregateValue, MeasureConditionOperator } from "./aggregate-filters.js";
2
+ /**
3
+ * A condition on the rows an aggregate reads: a property of the measure's own entity, in TypeScript
4
+ * names, and an operator with literal values, as a request filter takes them.
5
+ */
6
+ export interface MeasureCondition {
7
+ readonly property: string;
8
+ readonly operator: MeasureConditionOperator;
9
+ readonly value?: AggregateValue;
10
+ readonly values?: ReadonlyArray<AggregateValue>;
11
+ }
12
+ /**
13
+ * A condition as a `filtered` expression holds it: like a `column` expression, it names a property
14
+ * until `measureExpression` maps it to the property's column for the manifest.
15
+ */
16
+ export interface MeasureColumnCondition {
17
+ readonly column: string;
18
+ readonly operator: MeasureConditionOperator;
19
+ readonly value?: AggregateValue;
20
+ readonly values?: ReadonlyArray<AggregateValue>;
21
+ }
22
+ /** The aggregates a measure expression may contain, `count` included. */
23
+ export declare const MEASURE_AGGREGATES: readonly ["count", "sum", "countDistinct", "avg", "min", "max"];
1
24
  export type MeasureExpression = {
2
25
  readonly op: "count";
3
26
  } | {
@@ -7,8 +30,17 @@ export type MeasureExpression = {
7
30
  readonly op: "literal";
8
31
  readonly value: string;
9
32
  } | {
10
- readonly op: "sum" | "countDistinct" | "add" | "subtract" | "multiply" | "divide";
33
+ readonly op: "sum" | "countDistinct" | "avg" | "min" | "max" | "add" | "subtract" | "multiply" | "divide";
34
+ readonly args: ReadonlyArray<MeasureExpression>;
35
+ }
36
+ /**
37
+ * One aggregate over the rows that meet every condition. The condition wraps the aggregate, so a
38
+ * platform that does not know `filtered` cannot compute the aggregate unfiltered.
39
+ */
40
+ | {
41
+ readonly op: "filtered";
11
42
  readonly args: ReadonlyArray<MeasureExpression>;
43
+ readonly where: ReadonlyArray<MeasureColumnCondition>;
12
44
  };
13
45
  export interface MeasureOptions {
14
46
  readonly description: string;
@@ -16,17 +48,51 @@ export interface MeasureOptions {
16
48
  readonly unit?: "number" | "currency" | "ratio" | "percent";
17
49
  readonly format?: "decimal" | "currency" | "percent";
18
50
  }
19
- export type Measure = MeasureExpression & Partial<MeasureOptions>;
51
+ /** What an aggregate declares about the rows it reads, beside a measure's options. */
52
+ export interface AggregateDeclarations {
53
+ /** 1–10 conditions on properties of the entity, all of which the rows read must meet. */
54
+ readonly where?: ReadonlyArray<MeasureCondition>;
55
+ /**
56
+ * The date or timestamp property the entity's rows are snapshots over, such as a daily stock
57
+ * table's date. Summing snapshots over days would overstate the balance, so a request must group
58
+ * by the property or filter it to one day. Arithmetic and references over the aggregate inherit
59
+ * it.
60
+ */
61
+ readonly balanceOver?: string;
62
+ }
63
+ /**
64
+ * The options of `count`, `sum`, `countDistinct`, `avg`, `min` and `max`: a measure's options with
65
+ * the aggregate's declarations, or the declarations alone for an aggregate that is an argument of
66
+ * arithmetic.
67
+ */
68
+ export type AggregateOptions = (MeasureOptions & AggregateDeclarations) | AggregateDeclarations;
69
+ export type Measure = MeasureExpression & Partial<MeasureOptions> & {
70
+ /** An aggregate's conditions, as its builder's `where` option declares them. */
71
+ readonly where?: ReadonlyArray<MeasureCondition | MeasureColumnCondition>;
72
+ /** An aggregate's balance property, as its builder's `balanceOver` option declares it. */
73
+ readonly balanceOver?: string;
74
+ };
20
75
  export type Measures = Readonly<Record<string, Measure>>;
21
- /** Arithmetic combines aggregates; references name another measure of the same entity. */
76
+ /**
77
+ * Arithmetic combines aggregates; references name another measure of the same entity. Every
78
+ * aggregate takes `where`, conditions on properties of the entity that the rows it reads must meet,
79
+ * and `balanceOver`, the date its rows are snapshots over.
80
+ */
22
81
  export declare const m: {
23
- readonly count: (options?: MeasureOptions) => Measure;
24
- readonly sum: (property: string, options?: MeasureOptions) => Measure;
82
+ readonly count: (options?: AggregateOptions) => Measure;
83
+ /** The sum of an integer or number property. */
84
+ readonly sum: (property: string, options?: AggregateOptions) => Measure;
25
85
  /**
26
86
  * The number of distinct non-null values of a text, email, url, select, integer, date or timestamp
27
87
  * property. Distinct counts do not add up across groups.
28
88
  */
29
- readonly countDistinct: (property: string, options?: MeasureOptions) => Measure;
89
+ readonly countDistinct: (property: string, options?: AggregateOptions) => Measure;
90
+ /** The average of an integer or number property, ignoring nulls. Averages do not add up. */
91
+ readonly avg: (property: string, options?: AggregateOptions) => Measure;
92
+ /** The least value of an integer or number property. Minimums do not add up. */
93
+ readonly min: (property: string, options?: AggregateOptions) => Measure;
94
+ /** The greatest value of an integer or number property. Maximums do not add up. */
95
+ readonly max: (property: string, options?: AggregateOptions) => Measure;
30
96
  readonly ref: (name: string, options?: MeasureOptions) => Measure;
31
97
  readonly literal: (value: number | string, options?: MeasureOptions) => Measure;
32
98
  readonly add: (left: MeasureExpression, right: MeasureExpression, options?: MeasureOptions) => Measure;
@@ -34,9 +100,22 @@ export declare const m: {
34
100
  readonly multiply: (left: MeasureExpression, right: MeasureExpression, options?: MeasureOptions) => Measure;
35
101
  readonly divide: (left: MeasureExpression, right: MeasureExpression, options?: MeasureOptions) => Measure;
36
102
  };
103
+ /** The conditions an expression declares: an aggregate's `where` option, or a `filtered` node's. */
104
+ export declare function conditionsOf(value: Measure | MeasureExpression): ReadonlyArray<MeasureCondition | MeasureColumnCondition> | undefined;
105
+ /** The balance property an expression node declares: an aggregate's `balanceOver` option. */
106
+ export declare function balanceOf(value: Measure | MeasureExpression): unknown;
107
+ /**
108
+ * The balance properties a measure's own aggregates declare, top-level or inside arithmetic and
109
+ * `filtered` expressions, without duplicates. References are not followed: the platform inherits a
110
+ * referenced measure's balance itself.
111
+ */
112
+ export declare function balancesOf(value: Measure | MeasureExpression): ReadonlyArray<string>;
113
+ /** The property a condition names: `property` as authored, `column` in a `filtered` expression. */
114
+ export declare function conditionProperty(condition: object): unknown;
37
115
  /**
38
116
  * Strip authoring options and resolve logical properties to physical columns for the manifest: a
39
117
  * warehouse-backed property's `column`, or a stored property's replication view column, which is its
40
- * wire name.
118
+ * wire name. An aggregate's `where` becomes the `filtered` expression that wraps it, its conditions
119
+ * naming columns too.
41
120
  */
42
121
  export declare function measureExpression(value: MeasureExpression, columns: ReadonlyMap<string, string>): MeasureExpression;