@query-graph/core 1.0.0 → 1.1.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.
package/dsl.d.ts CHANGED
@@ -32,6 +32,44 @@ export type SemanticFunctionName = 'lower' | 'upper' | 'coalesce' | 'concat'
32
32
  export type AggregateFunctionName = 'count' | 'countDistinct' | 'sum' | 'average' | 'minimum' | 'maximum'
33
33
  export type ProjectionFieldRole = 'value' | 'dimension' | 'measure'
34
34
 
35
+ type BooleanOr<Value extends boolean> = true extends Value ? true : false
36
+
37
+ export interface SourceFieldNullability<Source extends string = string, FieldNullable extends boolean = boolean> {
38
+ kind: 'sourceField'
39
+ source: Source
40
+ fieldNullable: FieldNullable
41
+ }
42
+
43
+ export interface AnyNullability<Values = unknown> {
44
+ kind: 'any'
45
+ values: Values
46
+ }
47
+
48
+ export interface AllNullability<Values = unknown> {
49
+ kind: 'all'
50
+ values: Values
51
+ }
52
+
53
+ export type NullabilityExpression = boolean | SourceFieldNullability | AnyNullability | AllNullability
54
+
55
+ declare const expressionTypeMetadata: unique symbol
56
+
57
+ export interface ExpressionTypeMetadata<
58
+ Type extends ScalarType | null = ScalarType,
59
+ Nullability extends NullabilityExpression = NullabilityExpression,
60
+ > {
61
+ readonly [expressionTypeMetadata]: {
62
+ scalarType: Type
63
+ nullability: Nullability
64
+ }
65
+ }
66
+
67
+ export type TypedExpression<
68
+ Definition extends Expression = Expression,
69
+ Type extends ScalarType | null = ScalarType,
70
+ Nullability extends NullabilityExpression = NullabilityExpression,
71
+ > = Definition & ExpressionTypeMetadata<Type, Nullability>
72
+
35
73
  export interface FieldDefinition {
36
74
  name: string
37
75
  scalarType: ScalarType
@@ -149,12 +187,18 @@ export type Expression =
149
187
  | FunctionExpression
150
188
  | AggregateExpression
151
189
 
152
- export interface RelationDefinition {
153
- name: string
154
- from: string
155
- to: string
156
- cardinality?: RelationCardinality
157
- required?: boolean
190
+ export interface RelationDefinition<
191
+ Name extends string = string,
192
+ From extends string = string,
193
+ To extends string = string,
194
+ Required extends boolean = boolean,
195
+ Cardinality extends RelationCardinality = RelationCardinality,
196
+ > {
197
+ name: Name
198
+ from: From
199
+ to: To
200
+ cardinality?: Cardinality
201
+ required?: Required
158
202
  selection?: RelationSelection
159
203
  on: Expression
160
204
  }
@@ -177,34 +221,108 @@ export type JoinProjectionPath<Segments extends readonly string[]> = number exte
177
221
  : string
178
222
 
179
223
  declare const projectionPathType: unique symbol
224
+ declare const projectionScalarType: unique symbol
225
+ declare const projectionNullabilityType: unique symbol
226
+ declare const projectionDefaultType: unique symbol
180
227
  declare const summaryFieldType: unique symbol
228
+ declare const typedProjectionPathType: unique symbol
229
+ declare const typedProjectionScalarType: unique symbol
230
+ declare const typedProjectionNullabilityType: unique symbol
231
+ declare const typedProjectionDefaultType: unique symbol
232
+
233
+ export interface ProjectionTypeMetadata<
234
+ Path extends string = string,
235
+ Type extends ScalarType = ScalarType,
236
+ Nullability extends NullabilityExpression = NullabilityExpression,
237
+ SelectedByDefault extends boolean = boolean,
238
+ > {
239
+ readonly [typedProjectionPathType]: Path
240
+ readonly [typedProjectionScalarType]: Type
241
+ readonly [typedProjectionNullabilityType]: Nullability
242
+ readonly [typedProjectionDefaultType]: SelectedByDefault
243
+ }
244
+
245
+ export type TypedProjectionField<
246
+ Path extends string = string,
247
+ Type extends ScalarType = ScalarType,
248
+ Nullability extends NullabilityExpression = NullabilityExpression,
249
+ SelectedByDefault extends boolean = boolean,
250
+ > = ProjectionFieldDefinition<Path, Type, Nullability, SelectedByDefault> &
251
+ ProjectionTypeMetadata<Path, Type, Nullability, SelectedByDefault>
252
+
253
+ export type TypedDimensionDefinition<
254
+ Path extends string = string,
255
+ Type extends ScalarType = ScalarType,
256
+ Nullability extends NullabilityExpression = NullabilityExpression,
257
+ SelectedByDefault extends boolean = boolean,
258
+ > = DimensionDefinition<Path, Type, Nullability, SelectedByDefault> &
259
+ ProjectionTypeMetadata<Path, Type, Nullability, SelectedByDefault>
260
+
261
+ export type TypedMeasureDefinition<
262
+ Path extends string = string,
263
+ Type extends ScalarType = ScalarType,
264
+ Nullability extends NullabilityExpression = NullabilityExpression,
265
+ SelectedByDefault extends boolean = boolean,
266
+ > = MeasureDefinition<Path, Type, Nullability, SelectedByDefault> &
267
+ ProjectionTypeMetadata<Path, Type, Nullability, SelectedByDefault>
181
268
 
182
- export interface ProjectionFieldDefinition<Path extends string = string> {
269
+ export interface ProjectionFieldDefinition<
270
+ Path extends string = string,
271
+ Type extends ScalarType = ScalarType,
272
+ Nullability extends NullabilityExpression = NullabilityExpression,
273
+ SelectedByDefault extends boolean = boolean,
274
+ > {
183
275
  path: string[]
184
276
  readonly [projectionPathType]?: Path
277
+ readonly [projectionScalarType]?: Type
278
+ readonly [projectionNullabilityType]?: Nullability
279
+ readonly [projectionDefaultType]?: SelectedByDefault
185
280
  expression: Expression
186
281
  role?: ProjectionFieldRole
187
282
  selectedByDefault?: boolean
188
283
  }
189
284
 
190
- export interface DimensionDefinition<Path extends string = string> extends ProjectionFieldDefinition<Path> {
285
+ export interface DimensionDefinition<
286
+ Path extends string = string,
287
+ Type extends ScalarType = ScalarType,
288
+ Nullability extends NullabilityExpression = NullabilityExpression,
289
+ SelectedByDefault extends boolean = boolean,
290
+ > extends ProjectionFieldDefinition<Path, Type, Nullability, SelectedByDefault> {
191
291
  readonly [summaryFieldType]: 'dimension'
192
292
  role: 'dimension'
193
293
  }
194
294
 
195
- export interface MeasureDefinition<Path extends string = string> extends ProjectionFieldDefinition<Path> {
295
+ export interface MeasureDefinition<
296
+ Path extends string = string,
297
+ Type extends ScalarType = ScalarType,
298
+ Nullability extends NullabilityExpression = NullabilityExpression,
299
+ SelectedByDefault extends boolean = boolean,
300
+ > extends ProjectionFieldDefinition<Path, Type, Nullability, SelectedByDefault> {
196
301
  readonly [summaryFieldType]: 'measure'
197
302
  role: 'measure'
198
303
  }
199
304
 
200
- export type SummaryFieldDefinition<Path extends string = string> = DimensionDefinition<Path> | MeasureDefinition<Path>
201
-
202
- export interface ProjectionDefinition<Path extends string = string> {
203
- fields: ProjectionFieldDefinition<Path>[]
305
+ export type SummaryFieldDefinition<
306
+ Path extends string = string,
307
+ Type extends ScalarType = ScalarType,
308
+ Nullability extends NullabilityExpression = NullabilityExpression,
309
+ SelectedByDefault extends boolean = boolean,
310
+ > =
311
+ | DimensionDefinition<Path, Type, Nullability, SelectedByDefault>
312
+ | MeasureDefinition<Path, Type, Nullability, SelectedByDefault>
313
+
314
+ export interface ProjectionDefinition<
315
+ Path extends string = string,
316
+ Field extends ProjectionFieldDefinition = ProjectionFieldDefinition<Path>,
317
+ > {
318
+ fields: Field[]
204
319
  }
205
320
 
206
- export interface ProjectionDefinitionInput<Path extends string = string> {
207
- fields?: ProjectionFieldDefinition<Path>[]
321
+ export interface ProjectionDefinitionInput<
322
+ Path extends string = string,
323
+ Field extends ProjectionFieldDefinition = ProjectionFieldDefinition<Path>,
324
+ > {
325
+ fields?: Field[]
208
326
  }
209
327
 
210
328
  export interface OrderByDefinition {
@@ -242,11 +360,15 @@ export interface GraphDefinition<
242
360
  Parameter extends ParameterDefinition = ParameterDefinition,
243
361
  ProjectionPath extends string = string,
244
362
  OrderingName extends string = string,
363
+ ProjectionField extends ProjectionFieldDefinition = ProjectionFieldDefinition<ProjectionPath>,
364
+ Relation extends RelationDefinition = RelationDefinition,
365
+ Root extends string = string,
245
366
  > extends GraphDefinitionInput {
367
+ root: Root
246
368
  parameters: Parameter[]
247
- relations: RelationDefinition[]
369
+ relations: Relation[]
248
370
  constraints: ConstraintDefinition[]
249
- projection: ProjectionDefinition<ProjectionPath>
371
+ projection: ProjectionDefinition<ProjectionPath, ProjectionField>
250
372
  orderings: OrderingDefinition<OrderingName>[]
251
373
  }
252
374
 
@@ -278,24 +400,53 @@ export interface QueryOperationBase<SelectPath extends string = string, Ordering
278
400
  }
279
401
 
280
402
  export type DefinitionParameter<Definition extends GraphDefinitionInput> =
281
- Definition extends GraphDefinition<infer Parameter, infer _ProjectionPath, infer _OrderingName>
403
+ Definition extends GraphDefinition<
404
+ infer Parameter,
405
+ infer _ProjectionPath,
406
+ infer _OrderingName,
407
+ infer _ProjectionField,
408
+ infer _Relation,
409
+ infer _Root
410
+ >
282
411
  ? Parameter
283
412
  : NonNullable<Definition['parameters']>[number]
284
413
 
285
414
  export type DefinitionProjectionPath<Definition extends GraphDefinitionInput> =
286
- Definition extends GraphDefinition<infer _Parameter, infer ProjectionPath, infer _OrderingName>
415
+ Definition extends GraphDefinition<
416
+ infer _Parameter,
417
+ infer ProjectionPath,
418
+ infer _OrderingName,
419
+ infer _ProjectionField,
420
+ infer _Relation,
421
+ infer _Root
422
+ >
287
423
  ? ProjectionPath
288
424
  : Definition['projection'] extends ProjectionDefinitionInput<infer ProjectionPath>
289
425
  ? ProjectionPath
290
426
  : string
291
427
 
292
428
  export type DefinitionOrderingName<Definition extends GraphDefinitionInput> =
293
- Definition extends GraphDefinition<infer _Parameter, infer _ProjectionPath, infer OrderingName>
429
+ Definition extends GraphDefinition<
430
+ infer _Parameter,
431
+ infer _ProjectionPath,
432
+ infer OrderingName,
433
+ infer _ProjectionField,
434
+ infer _Relation,
435
+ infer _Root
436
+ >
294
437
  ? OrderingName
295
438
  : NonNullable<Definition['orderings']>[number] extends OrderingDefinition<infer OrderingName>
296
439
  ? OrderingName
297
440
  : never
298
441
 
442
+ export type DefinitionProjectionField<Definition extends GraphDefinitionInput> = NonNullable<
443
+ NonNullable<Definition['projection']>['fields']
444
+ >[number]
445
+
446
+ export type DefinitionRelation<Definition extends GraphDefinitionInput> = NonNullable<Definition['relations']>[number]
447
+
448
+ export type DefinitionRoot<Definition extends GraphDefinitionInput> = Definition['root']
449
+
299
450
  export type ParameterValue<Parameter extends ParameterDefinition> = Parameter extends { shape: 'list' }
300
451
  ? readonly ScalarParameterValue<Parameter['scalarType']>[]
301
452
  : ScalarParameterValue<Parameter['scalarType']>
@@ -332,7 +483,10 @@ export type QueryOperation<Definition extends GraphDefinitionInput = GraphDefini
332
483
  > &
333
484
  OperationParameterInput<Definition>
334
485
 
486
+ declare const graphDefinitionType: unique symbol
487
+
335
488
  export interface QueryGraph<Definition extends GraphDefinitionInput = GraphDefinitionInput> {
489
+ readonly [graphDefinitionType]?: Definition
336
490
  readonly name: string
337
491
  readonly root: string
338
492
  readonly sourceCount: number
@@ -346,6 +500,7 @@ export interface QueryGraph<Definition extends GraphDefinitionInput = GraphDefin
346
500
  }
347
501
 
348
502
  export interface RelationalQueryGraph<Definition extends GraphDefinitionInput = GraphDefinitionInput> {
503
+ readonly [graphDefinitionType]?: Definition
349
504
  readonly name: string
350
505
  compileSqlServer(
351
506
  operation: QueryOperation<Definition>,
@@ -357,6 +512,255 @@ export interface RelationalQueryGraph<Definition extends GraphDefinitionInput =
357
512
  ): import('./index.js').CompiledSqlStatement
358
513
  }
359
514
 
515
+ export interface ScalarOutputTypeMap {
516
+ boolean: unknown
517
+ int32: unknown
518
+ int64: unknown
519
+ float64: unknown
520
+ decimal: unknown
521
+ string: unknown
522
+ date: unknown
523
+ dateTime: unknown
524
+ binary: unknown
525
+ json: unknown
526
+ }
527
+
528
+ export interface DefaultScalarOutputTypeMap extends ScalarOutputTypeMap {
529
+ boolean: boolean
530
+ int32: number
531
+ int64: number | string
532
+ float64: number
533
+ decimal: number | string
534
+ string: string
535
+ date: string
536
+ dateTime: string
537
+ binary: string
538
+ json: JsonValue
539
+ }
540
+
541
+ export type DefinitionOf<Subject extends GraphDefinitionInput | QueryGraph | RelationalQueryGraph> =
542
+ Subject extends GraphDefinitionInput
543
+ ? Subject
544
+ : Subject extends QueryGraph<infer Definition>
545
+ ? Definition
546
+ : Subject extends RelationalQueryGraph<infer Definition>
547
+ ? Definition
548
+ : never
549
+
550
+ type IncomingRelation<Definition extends GraphDefinitionInput, Source extends string> =
551
+ DefinitionRelation<Definition> extends infer Candidate
552
+ ? Candidate extends RelationDefinition<infer _Name, infer _From, infer To, infer _Required, infer _Cardinality>
553
+ ? Source extends To
554
+ ? Candidate
555
+ : never
556
+ : never
557
+ : never
558
+
559
+ type RelationPathNullability<
560
+ Definition extends GraphDefinitionInput,
561
+ Relation,
562
+ Visited extends string,
563
+ Depth extends readonly unknown[],
564
+ > =
565
+ Relation extends RelationDefinition<infer _Name, infer From, infer _To, infer Required, infer _Cardinality>
566
+ ? BooleanOr<
567
+ | (Required extends true ? false : true)
568
+ | SourceOuterNullable<Definition, From, Visited, readonly [...Depth, unknown]>
569
+ >
570
+ : boolean
571
+
572
+ type SourceOuterNullable<
573
+ Definition extends GraphDefinitionInput,
574
+ Source extends string,
575
+ Visited extends string = never,
576
+ Depth extends readonly unknown[] = readonly [],
577
+ > = Depth['length'] extends 12
578
+ ? boolean
579
+ : string extends Source
580
+ ? boolean
581
+ : string extends DefinitionRoot<Definition>
582
+ ? boolean
583
+ : Source extends DefinitionRoot<Definition>
584
+ ? false
585
+ : Source extends Visited
586
+ ? boolean
587
+ : [IncomingRelation<Definition, Source>] extends [never]
588
+ ? boolean
589
+ : BooleanOr<
590
+ RelationPathNullability<Definition, IncomingRelation<Definition, Source>, Visited | Source, Depth>
591
+ >
592
+
593
+ type CombineAllNullability<Left extends boolean, Right extends boolean> = [Left] extends [false]
594
+ ? false
595
+ : [Right] extends [false]
596
+ ? false
597
+ : [Left] extends [true]
598
+ ? Right
599
+ : [Right] extends [true]
600
+ ? Left
601
+ : boolean
602
+
603
+ type EvaluateAnyNullability<
604
+ Definition extends GraphDefinitionInput,
605
+ Values,
606
+ Depth extends readonly unknown[],
607
+ > = Values extends readonly []
608
+ ? false
609
+ : Values extends readonly [
610
+ infer First extends NullabilityExpression,
611
+ ...infer Rest extends readonly NullabilityExpression[],
612
+ ]
613
+ ? BooleanOr<
614
+ | EvaluateNullability<Definition, First, readonly [...Depth, unknown]>
615
+ | EvaluateAnyNullability<Definition, Rest, readonly [...Depth, unknown]>
616
+ >
617
+ : Values extends readonly (infer Value extends NullabilityExpression)[]
618
+ ? BooleanOr<EvaluateNullability<Definition, Value, readonly [...Depth, unknown]>>
619
+ : boolean
620
+
621
+ type EvaluateAllNullability<
622
+ Definition extends GraphDefinitionInput,
623
+ Values,
624
+ Depth extends readonly unknown[],
625
+ > = Values extends readonly []
626
+ ? true
627
+ : Values extends readonly [
628
+ infer First extends NullabilityExpression,
629
+ ...infer Rest extends readonly NullabilityExpression[],
630
+ ]
631
+ ? CombineAllNullability<
632
+ EvaluateNullability<Definition, First, readonly [...Depth, unknown]>,
633
+ EvaluateAllNullability<Definition, Rest, readonly [...Depth, unknown]>
634
+ >
635
+ : boolean
636
+
637
+ type EvaluateNullability<
638
+ Definition extends GraphDefinitionInput,
639
+ Formula extends NullabilityExpression,
640
+ Depth extends readonly unknown[] = readonly [],
641
+ > = Depth['length'] extends 16
642
+ ? boolean
643
+ : NullabilityExpression extends Formula
644
+ ? boolean
645
+ : Formula extends boolean
646
+ ? Formula
647
+ : Formula extends SourceFieldNullability<infer Source, infer FieldNullable>
648
+ ? BooleanOr<FieldNullable | SourceOuterNullable<Definition, Source, never, Depth>>
649
+ : Formula extends AnyNullability<infer Values>
650
+ ? EvaluateAnyNullability<Definition, Values, Depth>
651
+ : Formula extends AllNullability<infer Values>
652
+ ? EvaluateAllNullability<Definition, Values, Depth>
653
+ : boolean
654
+
655
+ type ProjectionFieldPath<Field> =
656
+ Field extends ProjectionTypeMetadata<infer Path, infer _Type, infer _Nullability, infer _SelectedByDefault>
657
+ ? Path
658
+ : Field extends ProjectionFieldDefinition<infer Path>
659
+ ? Path
660
+ : never
661
+
662
+ type ProjectionFieldValue<Definition extends GraphDefinitionInput, Field, TypeMap extends ScalarOutputTypeMap> =
663
+ Field extends ProjectionTypeMetadata<infer _Path, infer Type, infer Nullability, infer _SelectedByDefault>
664
+ ? true extends EvaluateNullability<Definition, Nullability>
665
+ ? TypeMap[Type] | null
666
+ : TypeMap[Type]
667
+ : Field extends ProjectionFieldDefinition<infer _Path, infer Type, infer Nullability, infer _SelectedByDefault>
668
+ ? true extends EvaluateNullability<Definition, Nullability>
669
+ ? TypeMap[Type] | null
670
+ : TypeMap[Type]
671
+ : never
672
+
673
+ type ProjectionFieldByPath<Field, Path extends string> = Field extends ProjectionFieldDefinition
674
+ ? ProjectionFieldPath<Field> extends Path
675
+ ? Field
676
+ : never
677
+ : never
678
+
679
+ type ProjectionDefaultAtPath<Field, Path extends string> =
680
+ Field extends ProjectionTypeMetadata<infer FieldPath, infer _Type, infer _Nullability, infer SelectedByDefault>
681
+ ? FieldPath extends Path
682
+ ? SelectedByDefault
683
+ : never
684
+ : Field extends ProjectionFieldDefinition
685
+ ? ProjectionFieldPath<Field> extends Path
686
+ ? Field extends { selectedByDefault: true }
687
+ ? true
688
+ : false
689
+ : never
690
+ : never
691
+
692
+ type DefaultProjectionPath<Field, Path extends string = ProjectionFieldPath<Field>> = Path extends unknown
693
+ ? [ProjectionDefaultAtPath<Field, Path>] extends [never]
694
+ ? never
695
+ : ProjectionDefaultAtPath<Field, Path> extends true
696
+ ? Path
697
+ : never
698
+ : never
699
+
700
+ type DefaultProjectionField<Field> = ProjectionFieldByPath<Field, DefaultProjectionPath<Field>>
701
+
702
+ type SelectedProjectionField<Definition extends GraphDefinitionInput, Operation> = [Operation] extends [undefined]
703
+ ? DefaultProjectionField<DefinitionProjectionField<Definition>>
704
+ : Operation extends { select: readonly (infer Path extends string)[] }
705
+ ? ProjectionFieldByPath<DefinitionProjectionField<Definition>, Path>
706
+ : DefaultProjectionField<DefinitionProjectionField<Definition>>
707
+
708
+ type ProjectionEntry<
709
+ Definition extends GraphDefinitionInput,
710
+ Field,
711
+ TypeMap extends ScalarOutputTypeMap,
712
+ > = Field extends ProjectionFieldDefinition
713
+ ? {
714
+ path: ProjectionFieldPath<Field>
715
+ value: ProjectionFieldValue<Definition, Field, TypeMap>
716
+ }
717
+ : never
718
+
719
+ type ProjectionEntryHead<Entry> = Entry extends { path: infer Path extends string }
720
+ ? Path extends `${infer Head}.${string}`
721
+ ? Head
722
+ : Path
723
+ : never
724
+
725
+ type DirectProjectionEntryValue<Entry, Key extends string> = Entry extends {
726
+ path: infer Path extends string
727
+ value: infer Value
728
+ }
729
+ ? Path extends Key
730
+ ? Value
731
+ : never
732
+ : never
733
+
734
+ type NestedProjectionEntry<Entry, Key extends string> = Entry extends {
735
+ path: infer Path extends string
736
+ value: infer Value
737
+ }
738
+ ? Path extends `${Key}.${infer Rest}`
739
+ ? { path: Rest; value: Value }
740
+ : never
741
+ : never
742
+
743
+ type ProjectionValueAtKey<Entry, Key extends string> = [NestedProjectionEntry<Entry, Key>] extends [never]
744
+ ? DirectProjectionEntryValue<Entry, Key>
745
+ : [DirectProjectionEntryValue<Entry, Key>] extends [never]
746
+ ? BuildProjectionResult<NestedProjectionEntry<Entry, Key>>
747
+ : DirectProjectionEntryValue<Entry, Key> | BuildProjectionResult<NestedProjectionEntry<Entry, Key>>
748
+
749
+ type BuildProjectionResult<Entry> = [Entry] extends [never]
750
+ ? Record<never, never>
751
+ : {
752
+ [Key in ProjectionEntryHead<Entry>]: ProjectionValueAtKey<Entry, Key>
753
+ }
754
+
755
+ export type ResultOf<
756
+ Subject extends GraphDefinitionInput | QueryGraph | RelationalQueryGraph,
757
+ Operation = undefined,
758
+ TypeMap extends ScalarOutputTypeMap = DefaultScalarOutputTypeMap,
759
+ > =
760
+ DefinitionOf<Subject> extends infer Definition extends GraphDefinitionInput
761
+ ? BuildProjectionResult<ProjectionEntry<Definition, SelectedProjectionField<Definition, Operation>, TypeMap>>
762
+ : never
763
+
360
764
  export type SqlServerVersion = '2008' | '2012' | '2016' | '2019' | '2022'
361
765
  export type OracleVersion = '11g' | '12c' | '19c' | '21c' | '23ai'
362
766
 
@@ -383,19 +787,47 @@ export interface QueryGraphError extends Error {
383
787
  readonly issues: readonly QueryGraphDiagnostic[]
384
788
  }
385
789
 
386
- export interface FieldSpecDefinition {
387
- scalarType: ScalarType
388
- nullable?: boolean
389
- selectable?: boolean
790
+ export interface FieldSpecDefinition<
791
+ Type extends ScalarType = ScalarType,
792
+ Nullable extends boolean = boolean,
793
+ Selectable extends boolean = boolean,
794
+ > {
795
+ scalarType: Type
796
+ nullable?: Nullable
797
+ selectable?: Selectable
390
798
  }
391
799
 
392
800
  export type FieldSpec = ScalarType | FieldSpecDefinition
393
801
  export type FieldSpecMap = Record<string, FieldSpec>
394
802
 
803
+ export type FieldSpecScalarType<Specification extends FieldSpec> = Specification extends ScalarType
804
+ ? Specification
805
+ : Specification extends FieldSpecDefinition<infer Type, infer _Nullable, infer _Selectable>
806
+ ? Type
807
+ : never
808
+
809
+ export type FieldSpecIsNullable<Specification extends FieldSpec> = Specification extends ScalarType
810
+ ? false
811
+ : Specification extends FieldSpecDefinition<infer _Type, infer Nullable, infer _Selectable>
812
+ ? Nullable
813
+ : boolean
814
+
815
+ export type FieldSpecIsSelectable<Specification extends FieldSpec> = Specification extends ScalarType
816
+ ? true
817
+ : Specification extends FieldSpecDefinition<infer _Type, infer _Nullable, infer Selectable>
818
+ ? Selectable
819
+ : boolean
820
+
395
821
  export interface SourceRef<Key extends string = string, Fields extends FieldSpecMap = FieldSpecMap>
396
822
  extends SourceDefinition {
397
823
  key: Key
398
- field<Name extends Extract<keyof Fields, string>>(name: Name): FieldExpression<Key, Name>
824
+ field<Name extends Extract<keyof Fields, string>>(
825
+ name: Name,
826
+ ): TypedExpression<
827
+ FieldExpression<Key, Name>,
828
+ FieldSpecScalarType<Fields[Name]>,
829
+ SourceFieldNullability<Key, FieldSpecIsNullable<Fields[Name]>>
830
+ >
399
831
  }
400
832
 
401
833
  export interface ScalarParameterRef<
@@ -426,21 +858,95 @@ export type ParameterRef<
426
858
  Required extends boolean = boolean,
427
859
  > = ScalarParameterRef<Name, Type, Required> | ListParameterRef<Name, Type, Required>
428
860
 
429
- export interface RelationRef<Name extends string = string> extends RelationDefinition {
430
- name: Name
431
- }
861
+ export type RelationRef<
862
+ Name extends string = string,
863
+ From extends string = string,
864
+ To extends string = string,
865
+ Required extends boolean = boolean,
866
+ Cardinality extends RelationCardinality = RelationCardinality,
867
+ > = RelationDefinition<Name, From, To, Required, Cardinality>
432
868
 
433
869
  export type LiteralInput = null | boolean | string | number
434
870
  export type ExpressionInput = Expression | LiteralInput | SummaryFieldDefinition
435
871
 
872
+ type NumberLiteralScalarType<Value extends number> = number extends Value
873
+ ? 'int64' | 'decimal'
874
+ : `${Value}` extends `${bigint}`
875
+ ? 'int64'
876
+ : 'decimal'
877
+
878
+ type InputScalarType<Input extends ExpressionInput> =
879
+ Input extends ExpressionTypeMetadata<infer Type, infer _Nullability>
880
+ ? Type
881
+ : Input extends ProjectionFieldDefinition<infer _Path, infer Type, infer _Nullability, infer _SelectedByDefault>
882
+ ? Type
883
+ : Input extends null
884
+ ? null
885
+ : Input extends boolean
886
+ ? 'boolean'
887
+ : Input extends string
888
+ ? 'string'
889
+ : Input extends number
890
+ ? NumberLiteralScalarType<Input>
891
+ : ScalarType
892
+
893
+ type InputNullability<Input extends ExpressionInput> =
894
+ Input extends ExpressionTypeMetadata<infer _Type, infer Nullability>
895
+ ? Nullability
896
+ : Input extends ProjectionFieldDefinition<infer _Path, infer _Type, infer Nullability, infer _SelectedByDefault>
897
+ ? Nullability
898
+ : Input extends null
899
+ ? true
900
+ : Input extends Expression
901
+ ? boolean
902
+ : false
903
+
904
+ export type ExpressionScalarType<Input extends ExpressionInput> = InputScalarType<Input>
905
+ export type ExpressionNullability<Input extends ExpressionInput> = InputNullability<Input>
906
+
907
+ type PromoteScalarType<Type extends ScalarType | null> = 'float64' extends Type
908
+ ? 'float64'
909
+ : 'decimal' extends Type
910
+ ? 'decimal'
911
+ : 'int64' extends Type
912
+ ? 'int64'
913
+ : 'int32' extends Type
914
+ ? 'int32'
915
+ : 'dateTime' extends Type
916
+ ? 'dateTime'
917
+ : Exclude<Type, null>
918
+
919
+ type AverageScalarType<Type extends ScalarType | null> = Type extends 'float64'
920
+ ? 'float64'
921
+ : Type extends 'int32' | 'int64' | 'decimal'
922
+ ? 'decimal'
923
+ : Exclude<Type, null>
924
+
925
+ type InputNullabilities<Inputs extends readonly ExpressionInput[]> = {
926
+ [Index in keyof Inputs]: InputNullability<Inputs[Index]>
927
+ }
928
+
929
+ type AnyInputNullability<Inputs extends readonly ExpressionInput[]> = AnyNullability<InputNullabilities<Inputs>>
930
+ type AllInputNullability<Inputs extends readonly ExpressionInput[]> = AllNullability<InputNullabilities<Inputs>>
931
+
436
932
  export interface FieldTypeOptions {
437
933
  nullable?: boolean
438
934
  selectable?: boolean
439
935
  }
440
936
 
441
- export function fieldType(scalarType: ScalarType, options?: FieldTypeOptions): FieldSpecDefinition
442
- export function nullable(specification: FieldSpec): FieldSpecDefinition
443
- export function hidden(specification: FieldSpec): FieldSpecDefinition
937
+ type OptionNullable<Options extends FieldTypeOptions> = Options extends { nullable: true } ? true : false
938
+ type OptionSelectable<Options extends FieldTypeOptions> = Options extends { selectable: false } ? false : true
939
+
940
+ export function fieldType<const Type extends ScalarType, const Options extends FieldTypeOptions = Record<never, never>>(
941
+ scalarType: Type,
942
+ options?: Options,
943
+ ): FieldSpecDefinition<Type, OptionNullable<Options>, OptionSelectable<Options>>
944
+ export function nullable<const Specification extends FieldSpec>(
945
+ specification: Specification,
946
+ ): FieldSpecDefinition<FieldSpecScalarType<Specification>, true, FieldSpecIsSelectable<Specification>>
947
+ export function hidden<const Specification extends FieldSpec>(
948
+ specification: Specification,
949
+ ): FieldSpecDefinition<FieldSpecScalarType<Specification>, FieldSpecIsNullable<Specification>, false>
444
950
 
445
951
  export function source<const Key extends string, const Fields extends FieldSpecMap>(
446
952
  key: Key,
@@ -465,33 +971,75 @@ export function optionalListParameter<const Name extends string, const Type exte
465
971
  ): ListParameterRef<Name, Type, false>
466
972
  export function param<const Name extends string, const Type extends ScalarType>(
467
973
  parameter: ScalarParameterRef<Name, Type>,
468
- ): ParameterExpression<Name>
469
-
470
- export function literal(value: LiteralInput): LiteralExpression
471
- export function integer(value: number): LiteralExpression
472
- export function decimal(value: string | number): LiteralExpression
473
-
474
- export function eq(left: ExpressionInput, right: ExpressionInput): BinaryExpression
475
- export function neq(left: ExpressionInput, right: ExpressionInput): BinaryExpression
476
- export function lt(left: ExpressionInput, right: ExpressionInput): BinaryExpression
477
- export function lte(left: ExpressionInput, right: ExpressionInput): BinaryExpression
478
- export function gt(left: ExpressionInput, right: ExpressionInput): BinaryExpression
479
- export function gte(left: ExpressionInput, right: ExpressionInput): BinaryExpression
480
- export function like(expression: ExpressionInput, pattern: ExpressionInput): LikeExpression
481
- export function inList(expression: ExpressionInput, values: readonly ExpressionInput[]): InExpression
482
- export function and(...expressions: readonly ExpressionInput[]): ExpressionGroup
483
- export function inParameter<const Name extends string, const Type extends ScalarType>(
484
- expression: ExpressionInput,
974
+ ): TypedExpression<ParameterExpression<Name>, Type, false>
975
+
976
+ export function literal<const Value extends LiteralInput>(
977
+ value: Value,
978
+ ): TypedExpression<LiteralExpression, InputScalarType<Value>, InputNullability<Value>>
979
+ export function integer(value: number): TypedExpression<LiteralExpression, 'int64', false>
980
+ export function decimal(value: string | number): TypedExpression<LiteralExpression, 'decimal', false>
981
+
982
+ type EqualityNullability<Left extends ExpressionInput, Right extends ExpressionInput> = null extends
983
+ | InputScalarType<Left>
984
+ | InputScalarType<Right>
985
+ ? false
986
+ : AnyInputNullability<readonly [Left, Right]>
987
+
988
+ export function eq<const Left extends ExpressionInput, const Right extends ExpressionInput>(
989
+ left: Left,
990
+ right: Right,
991
+ ): TypedExpression<BinaryExpression, 'boolean', EqualityNullability<Left, Right>>
992
+ export function neq<const Left extends ExpressionInput, const Right extends ExpressionInput>(
993
+ left: Left,
994
+ right: Right,
995
+ ): TypedExpression<BinaryExpression, 'boolean', EqualityNullability<Left, Right>>
996
+ export function lt<const Left extends ExpressionInput, const Right extends ExpressionInput>(
997
+ left: Left,
998
+ right: Right,
999
+ ): TypedExpression<BinaryExpression, 'boolean', AnyInputNullability<readonly [Left, Right]>>
1000
+ export function lte<const Left extends ExpressionInput, const Right extends ExpressionInput>(
1001
+ left: Left,
1002
+ right: Right,
1003
+ ): TypedExpression<BinaryExpression, 'boolean', AnyInputNullability<readonly [Left, Right]>>
1004
+ export function gt<const Left extends ExpressionInput, const Right extends ExpressionInput>(
1005
+ left: Left,
1006
+ right: Right,
1007
+ ): TypedExpression<BinaryExpression, 'boolean', AnyInputNullability<readonly [Left, Right]>>
1008
+ export function gte<const Left extends ExpressionInput, const Right extends ExpressionInput>(
1009
+ left: Left,
1010
+ right: Right,
1011
+ ): TypedExpression<BinaryExpression, 'boolean', AnyInputNullability<readonly [Left, Right]>>
1012
+ export function like<const Value extends ExpressionInput, const Pattern extends ExpressionInput>(
1013
+ expression: Value,
1014
+ pattern: Pattern,
1015
+ ): TypedExpression<LikeExpression, 'boolean', AnyInputNullability<readonly [Value, Pattern]>>
1016
+ export function inList<const Value extends ExpressionInput, const Values extends readonly ExpressionInput[]>(
1017
+ expression: Value,
1018
+ values: Values,
1019
+ ): TypedExpression<InExpression, 'boolean', AnyInputNullability<readonly [Value, ...Values]>>
1020
+ export function and<const Expressions extends readonly ExpressionInput[]>(
1021
+ ...expressions: Expressions
1022
+ ): TypedExpression<ExpressionGroup, 'boolean', AnyInputNullability<Expressions>>
1023
+ export function inParameter<
1024
+ const Value extends ExpressionInput,
1025
+ const Name extends string,
1026
+ const Type extends ScalarType,
1027
+ >(
1028
+ expression: Value,
485
1029
  parameter: ListParameterRef<Name, Type>,
486
- ): InParameterExpression<Name>
487
- export function or(...expressions: readonly ExpressionInput[]): ExpressionGroup
488
- export function not(expression: ExpressionInput): UnaryExpression
489
- export function isNull(expression: ExpressionInput): UnaryExpression
490
- export function isNotNull(expression: ExpressionInput): UnaryExpression
1030
+ ): TypedExpression<InParameterExpression<Name>, 'boolean', InputNullability<Value>>
1031
+ export function or<const Expressions extends readonly ExpressionInput[]>(
1032
+ ...expressions: Expressions
1033
+ ): TypedExpression<ExpressionGroup, 'boolean', AnyInputNullability<Expressions>>
1034
+ export function not<const Value extends ExpressionInput>(
1035
+ expression: Value,
1036
+ ): TypedExpression<UnaryExpression, 'boolean', InputNullability<Value>>
1037
+ export function isNull(expression: ExpressionInput): TypedExpression<UnaryExpression, 'boolean', false>
1038
+ export function isNotNull(expression: ExpressionInput): TypedExpression<UnaryExpression, 'boolean', false>
491
1039
  export function exists<const Source extends string>(
492
1040
  source: Source | SourceRef<Source>,
493
1041
  predicate?: ExpressionInput,
494
- ): ExistsExpression<Source, never>
1042
+ ): TypedExpression<ExistsExpression<Source, never>, 'boolean', false>
495
1043
  export interface ExistsConfiguration<From extends string = string> {
496
1044
  from: From | SourceRef<From>
497
1045
  }
@@ -499,35 +1047,75 @@ export function exists<const Source extends string, const From extends string>(
499
1047
  source: Source | SourceRef<Source>,
500
1048
  predicate: ExpressionInput | undefined,
501
1049
  configuration: ExistsConfiguration<From>,
502
- ): ExistsExpression<Source, From>
503
-
504
- export function lower(expression: ExpressionInput): FunctionExpression
505
- export function upper(expression: ExpressionInput): FunctionExpression
506
- export function coalesce(
507
- first: ExpressionInput,
508
- second: ExpressionInput,
509
- ...rest: readonly ExpressionInput[]
510
- ): FunctionExpression
511
- export function concat(first: ExpressionInput, ...rest: readonly ExpressionInput[]): FunctionExpression
512
-
513
- export function count(expression?: ExpressionInput): AggregateExpression
514
- export function countDistinct(expression: ExpressionInput): AggregateExpression
515
- export function sum(expression: ExpressionInput): AggregateExpression
516
- export function average(expression: ExpressionInput): AggregateExpression
517
- export function minimum(expression: ExpressionInput): AggregateExpression
518
- export function maximum(expression: ExpressionInput): AggregateExpression
519
-
520
- export interface RelationConfiguration<Name extends string = string> {
1050
+ ): TypedExpression<ExistsExpression<Source, From>, 'boolean', false>
1051
+
1052
+ export function lower<const Value extends ExpressionInput>(
1053
+ expression: Value,
1054
+ ): TypedExpression<FunctionExpression, 'string', InputNullability<Value>>
1055
+ export function upper<const Value extends ExpressionInput>(
1056
+ expression: Value,
1057
+ ): TypedExpression<FunctionExpression, 'string', InputNullability<Value>>
1058
+ export function coalesce<
1059
+ const First extends ExpressionInput,
1060
+ const Second extends ExpressionInput,
1061
+ const Rest extends readonly ExpressionInput[],
1062
+ >(
1063
+ first: First,
1064
+ second: Second,
1065
+ ...rest: Rest
1066
+ ): TypedExpression<
1067
+ FunctionExpression,
1068
+ PromoteScalarType<InputScalarType<First | Second | Rest[number]>>,
1069
+ AllInputNullability<readonly [First, Second, ...Rest]>
1070
+ >
1071
+ export function concat<const First extends ExpressionInput, const Rest extends readonly ExpressionInput[]>(
1072
+ first: First,
1073
+ ...rest: Rest
1074
+ ): TypedExpression<FunctionExpression, 'string', AllInputNullability<readonly [First, ...Rest]>>
1075
+
1076
+ export function count(expression?: ExpressionInput): TypedExpression<AggregateExpression, 'int64', false>
1077
+ export function countDistinct(expression: ExpressionInput): TypedExpression<AggregateExpression, 'int64', false>
1078
+ export function sum<const Value extends ExpressionInput>(
1079
+ expression: Value,
1080
+ ): TypedExpression<AggregateExpression, Exclude<InputScalarType<Value>, null>, true>
1081
+ export function average<const Value extends ExpressionInput>(
1082
+ expression: Value,
1083
+ ): TypedExpression<AggregateExpression, AverageScalarType<InputScalarType<Value>>, true>
1084
+ export function minimum<const Value extends ExpressionInput>(
1085
+ expression: Value,
1086
+ ): TypedExpression<AggregateExpression, Exclude<InputScalarType<Value>, null>, true>
1087
+ export function maximum<const Value extends ExpressionInput>(
1088
+ expression: Value,
1089
+ ): TypedExpression<AggregateExpression, Exclude<InputScalarType<Value>, null>, true>
1090
+
1091
+ export type SourceReferenceKey<Reference extends string | SourceRef> =
1092
+ Reference extends SourceRef<infer Key, infer _Fields> ? Key : Reference extends string ? Reference : string
1093
+
1094
+ export interface RelationConfiguration<
1095
+ Name extends string = string,
1096
+ From extends string | SourceRef = string | SourceRef,
1097
+ To extends string | SourceRef = string | SourceRef,
1098
+ Required extends boolean = boolean,
1099
+ Cardinality extends RelationCardinality = RelationCardinality,
1100
+ > {
521
1101
  name: Name
522
- from: string | SourceRef
523
- to: string | SourceRef
1102
+ from: From
1103
+ to: To
524
1104
  on: Expression
525
- required?: boolean
526
- cardinality?: RelationCardinality
1105
+ required?: Required
1106
+ cardinality?: Cardinality
527
1107
  selection?: RelationSelection
528
1108
  }
529
1109
 
530
- export function relation<const Name extends string>(configuration: RelationConfiguration<Name>): RelationRef<Name>
1110
+ export function relation<
1111
+ const Name extends string,
1112
+ const From extends string | SourceRef,
1113
+ const To extends string | SourceRef,
1114
+ const Required extends boolean = false,
1115
+ const Cardinality extends RelationCardinality = 'one',
1116
+ >(
1117
+ configuration: RelationConfiguration<Name, From, To, Required, Cardinality>,
1118
+ ): RelationRef<Name, SourceReferenceKey<From>, SourceReferenceKey<To>, Required, Cardinality>
531
1119
 
532
1120
  export interface ConstraintConfiguration {
533
1121
  predicate: Expression
@@ -536,10 +1124,14 @@ export interface ConstraintConfiguration {
536
1124
 
537
1125
  export function constraint(configuration: ConstraintConfiguration): ConstraintDefinition
538
1126
 
539
- export interface ProjectionConfiguration<Path extends string | readonly string[] = string | readonly string[]> {
1127
+ export interface ProjectionConfiguration<
1128
+ Path extends string | readonly string[] = string | readonly string[],
1129
+ Value extends ExpressionInput = ExpressionInput,
1130
+ SelectedByDefault extends boolean = boolean,
1131
+ > {
540
1132
  path: Path
541
- expression: ExpressionInput
542
- default?: boolean
1133
+ expression: Value
1134
+ default?: SelectedByDefault
543
1135
  }
544
1136
 
545
1137
  type ConfigurationPath<Path extends string | readonly string[]> = Path extends string
@@ -548,17 +1140,44 @@ type ConfigurationPath<Path extends string | readonly string[]> = Path extends s
548
1140
  ? JoinProjectionPath<Path>
549
1141
  : never
550
1142
 
551
- export function project<const Path extends string | readonly string[]>(
552
- configuration: ProjectionConfiguration<Path>,
553
- ): ProjectionFieldDefinition<ConfigurationPath<Path>>
1143
+ export function project<
1144
+ const Path extends string | readonly string[],
1145
+ const Value extends ExpressionInput,
1146
+ const SelectedByDefault extends boolean = false,
1147
+ >(
1148
+ configuration: ProjectionConfiguration<Path, Value, SelectedByDefault>,
1149
+ ): TypedProjectionField<
1150
+ ConfigurationPath<Path>,
1151
+ Extract<InputScalarType<Value>, ScalarType>,
1152
+ InputNullability<Value>,
1153
+ SelectedByDefault
1154
+ >
554
1155
 
555
- export function dimension<const Path extends string | readonly string[]>(
556
- configuration: ProjectionConfiguration<Path>,
557
- ): DimensionDefinition<ConfigurationPath<Path>>
1156
+ export function dimension<
1157
+ const Path extends string | readonly string[],
1158
+ const Value extends ExpressionInput,
1159
+ const SelectedByDefault extends boolean = false,
1160
+ >(
1161
+ configuration: ProjectionConfiguration<Path, Value, SelectedByDefault>,
1162
+ ): TypedDimensionDefinition<
1163
+ ConfigurationPath<Path>,
1164
+ Extract<InputScalarType<Value>, ScalarType>,
1165
+ InputNullability<Value>,
1166
+ SelectedByDefault
1167
+ >
558
1168
 
559
- export function measure<const Path extends string | readonly string[]>(
560
- configuration: ProjectionConfiguration<Path>,
561
- ): MeasureDefinition<ConfigurationPath<Path>>
1169
+ export function measure<
1170
+ const Path extends string | readonly string[],
1171
+ const Value extends ExpressionInput,
1172
+ const SelectedByDefault extends boolean = false,
1173
+ >(
1174
+ configuration: ProjectionConfiguration<Path, Value, SelectedByDefault>,
1175
+ ): TypedMeasureDefinition<
1176
+ ConfigurationPath<Path>,
1177
+ Extract<InputScalarType<Value>, ScalarType>,
1178
+ InputNullability<Value>,
1179
+ SelectedByDefault
1180
+ >
562
1181
 
563
1182
  export interface OrderByOptions {
564
1183
  nulls?: NullsOrder
@@ -597,13 +1216,59 @@ type ConfigurationElement<Configuration, Key extends PropertyKey> = Key extends
597
1216
  : never
598
1217
 
599
1218
  type ModuleParameter<Module> =
600
- Module extends GraphModule<infer Parameter, infer _ProjectionPath, infer _OrderingName> ? Parameter : never
1219
+ Module extends GraphModule<
1220
+ infer Parameter,
1221
+ infer _ProjectionPath,
1222
+ infer _OrderingName,
1223
+ infer _ProjectionField,
1224
+ infer _Relation
1225
+ >
1226
+ ? Parameter
1227
+ : never
601
1228
 
602
1229
  type ModuleProjectionPath<Module> =
603
- Module extends GraphModule<infer _Parameter, infer ProjectionPath, infer _OrderingName> ? ProjectionPath : never
1230
+ Module extends GraphModule<
1231
+ infer _Parameter,
1232
+ infer ProjectionPath,
1233
+ infer _OrderingName,
1234
+ infer _ProjectionField,
1235
+ infer _Relation
1236
+ >
1237
+ ? ProjectionPath
1238
+ : never
604
1239
 
605
1240
  type ModuleOrderingName<Module> =
606
- Module extends GraphModule<infer _Parameter, infer _ProjectionPath, infer OrderingName> ? OrderingName : never
1241
+ Module extends GraphModule<
1242
+ infer _Parameter,
1243
+ infer _ProjectionPath,
1244
+ infer OrderingName,
1245
+ infer _ProjectionField,
1246
+ infer _Relation
1247
+ >
1248
+ ? OrderingName
1249
+ : never
1250
+
1251
+ type ModuleProjectionField<Module> =
1252
+ Module extends GraphModule<
1253
+ infer _Parameter,
1254
+ infer _ProjectionPath,
1255
+ infer _OrderingName,
1256
+ infer ProjectionField,
1257
+ infer _Relation
1258
+ >
1259
+ ? ProjectionField
1260
+ : never
1261
+
1262
+ type ModuleRelation<Module> =
1263
+ Module extends GraphModule<
1264
+ infer _Parameter,
1265
+ infer _ProjectionPath,
1266
+ infer _OrderingName,
1267
+ infer _ProjectionField,
1268
+ infer Relation
1269
+ >
1270
+ ? Relation
1271
+ : never
607
1272
 
608
1273
  type ProjectionPathOf<Field> = Field extends ProjectionFieldDefinition<infer Path> ? Path : never
609
1274
 
@@ -619,21 +1284,39 @@ type ConfigurationProjectionPath<Configuration> =
619
1284
  | ProjectionPathOf<ConfigurationElement<Configuration, 'measures'>>
620
1285
  | ModuleProjectionPath<ConfigurationElement<Configuration, 'modules'>>
621
1286
 
1287
+ type ConfigurationProjectionField<Configuration> =
1288
+ | Extract<ConfigurationElement<Configuration, 'projection'>, ProjectionFieldDefinition>
1289
+ | Extract<ConfigurationElement<Configuration, 'dimensions'>, ProjectionFieldDefinition>
1290
+ | Extract<ConfigurationElement<Configuration, 'measures'>, ProjectionFieldDefinition>
1291
+ | ModuleProjectionField<ConfigurationElement<Configuration, 'modules'>>
1292
+
622
1293
  type ConfigurationOrderingName<Configuration> =
623
1294
  | OrderingNameOf<ConfigurationElement<Configuration, 'orderings'>>
624
1295
  | ModuleOrderingName<ConfigurationElement<Configuration, 'modules'>>
625
1296
 
1297
+ type ConfigurationRelation<Configuration> =
1298
+ | Extract<ConfigurationElement<Configuration, 'relations'>, RelationDefinition>
1299
+ | ModuleRelation<ConfigurationElement<Configuration, 'modules'>>
1300
+
1301
+ type ConfigurationRoot<Configuration> = Configuration extends {
1302
+ root: infer Root extends string | SourceRef
1303
+ }
1304
+ ? SourceReferenceKey<Root>
1305
+ : string
1306
+
626
1307
  export interface GraphModule<
627
1308
  Parameter extends ParameterDefinition = ParameterDefinition,
628
1309
  ProjectionPath extends string = string,
629
1310
  OrderingName extends string = string,
1311
+ ProjectionField extends ProjectionFieldDefinition = ProjectionFieldDefinition<ProjectionPath>,
1312
+ Relation extends RelationDefinition = RelationDefinition,
630
1313
  > {
631
1314
  readonly name: string
632
1315
  readonly sources: readonly SourceRef[]
633
1316
  readonly parameters: readonly Parameter[]
634
- readonly relations: readonly RelationDefinition[]
1317
+ readonly relations: readonly Relation[]
635
1318
  readonly constraints: readonly ConstraintDefinition[]
636
- readonly projection: readonly ProjectionFieldDefinition<ProjectionPath>[]
1319
+ readonly projection: readonly ProjectionField[]
637
1320
  readonly orderings: readonly OrderingDefinition<OrderingName>[]
638
1321
  }
639
1322
 
@@ -642,7 +1325,9 @@ export function defineGraphModule<const Configuration extends GraphModuleConfigu
642
1325
  ): GraphModule<
643
1326
  ConfigurationParameter<Configuration>,
644
1327
  ConfigurationProjectionPath<Configuration>,
645
- ConfigurationOrderingName<Configuration>
1328
+ ConfigurationOrderingName<Configuration>,
1329
+ ConfigurationProjectionField<Configuration>,
1330
+ ConfigurationRelation<Configuration>
646
1331
  >
647
1332
 
648
1333
  export interface GraphConfiguration {
@@ -662,7 +1347,10 @@ export function defineGraph<const Configuration extends GraphConfiguration>(
662
1347
  ): GraphDefinition<
663
1348
  ConfigurationParameter<Configuration>,
664
1349
  ConfigurationProjectionPath<Configuration>,
665
- ConfigurationOrderingName<Configuration>
1350
+ ConfigurationOrderingName<Configuration>,
1351
+ ConfigurationProjectionField<Configuration>,
1352
+ ConfigurationRelation<Configuration>,
1353
+ ConfigurationRoot<Configuration>
666
1354
  >
667
1355
 
668
1356
  export interface SummaryGraphConfiguration {
@@ -683,5 +1371,8 @@ export function defineSummaryGraph<const Configuration extends SummaryGraphConfi
683
1371
  ): GraphDefinition<
684
1372
  ConfigurationParameter<Configuration>,
685
1373
  ConfigurationProjectionPath<Configuration>,
686
- ConfigurationOrderingName<Configuration>
1374
+ ConfigurationOrderingName<Configuration>,
1375
+ ConfigurationProjectionField<Configuration>,
1376
+ ConfigurationRelation<Configuration>,
1377
+ ConfigurationRoot<Configuration>
687
1378
  >