atom.io 0.30.0 → 0.30.2

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/data/src/join.ts CHANGED
@@ -19,10 +19,9 @@ import type { seekState } from "atom.io/immortal"
19
19
  import type {
20
20
  BaseExternalStoreConfiguration,
21
21
  ExternalStoreConfiguration,
22
- JunctionEntries,
23
- JunctionSchema,
22
+ JunctionEntriesBase,
23
+ JunctionSchemaBase,
24
24
  Molecule,
25
- // RelationCardinality,
26
25
  Store,
27
26
  } from "atom.io/internal"
28
27
  import {
@@ -46,7 +45,9 @@ import {
46
45
  setIntoStore,
47
46
  withdraw,
48
47
  } from "atom.io/internal"
49
- import { type Json, stringifyJson } from "atom.io/json"
48
+ import type { Refinement } from "atom.io/introspection"
49
+ import type { Json } from "atom.io/json"
50
+ import { stringifyJson } from "atom.io/json"
50
51
  import type { SetRTXJson } from "atom.io/transceivers/set-rtx"
51
52
  import { SetRTX } from "atom.io/transceivers/set-rtx"
52
53
 
@@ -56,96 +57,122 @@ function capitalize<S extends string>(string: S): Capitalize<S> {
56
57
 
57
58
  export interface JoinOptions<
58
59
  ASide extends string,
60
+ AType extends string,
59
61
  BSide extends string,
62
+ BType extends string,
60
63
  Cardinality extends `1:1` | `1:n` | `n:n`,
61
64
  Content extends Json.Object | null,
62
- > extends Json.Object,
63
- JunctionSchema<ASide, BSide>,
64
- Partial<JunctionEntries<Content>> {
65
+ > extends JunctionSchemaBase<ASide, BSide>,
66
+ Partial<JunctionEntriesBase<AType, BType, Content>> {
65
67
  readonly key: string
66
68
  readonly cardinality: Cardinality
69
+ readonly isAType: Refinement<string, AType>
70
+ readonly isBType: Refinement<string, BType>
67
71
  }
68
72
 
69
73
  export type JoinStateFamilies<
70
74
  ASide extends string,
75
+ AType extends string,
71
76
  BSide extends string,
77
+ BType extends string,
72
78
  Cardinality extends `1:1` | `1:n` | `n:n`,
73
79
  Content extends Json.Object | null,
74
80
  > = Cardinality extends `1:1`
75
81
  ? (Content extends Json.Object
76
82
  ? {
77
- readonly [AB in ASide | BSide as AB extends ASide
78
- ? `${AB}EntryOf${Capitalize<BSide>}`
79
- : `${AB}EntryOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
80
- [string, Content] | null,
81
- string
83
+ readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
84
+ [AType, Content] | null,
85
+ BType
86
+ >
87
+ } & {
88
+ readonly [B in BSide as `${B}EntryOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
89
+ [BType, Content] | null,
90
+ AType
82
91
  >
83
92
  }
84
93
  : {}) & {
85
- readonly [AB in ASide | BSide as AB extends ASide
86
- ? `${AB}KeyOf${Capitalize<BSide>}`
87
- : `${AB}KeyOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
88
- string | null,
89
- string
94
+ readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
95
+ AType | null,
96
+ BType
97
+ >
98
+ } & {
99
+ readonly [B in BSide as `${B}KeyOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
100
+ BType | null,
101
+ AType
90
102
  >
91
103
  }
92
104
  : Cardinality extends `1:n`
93
105
  ? (Content extends Json.Object
94
106
  ? {
95
107
  readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
96
- [string, Content] | null,
97
- string
108
+ [AType, Content] | null,
109
+ BType
98
110
  >
99
111
  } & {
100
112
  readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
101
- [string, Content][],
102
- string
113
+ [BType, Content][],
114
+ AType
103
115
  >
104
116
  }
105
117
  : {}) & {
106
118
  readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
107
- string | null,
108
- string
119
+ AType | null,
120
+ BType
109
121
  >
110
122
  } & {
111
123
  readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
112
- string[],
113
- string
124
+ BType[],
125
+ AType
114
126
  >
115
127
  }
116
128
  : Cardinality extends `n:n`
117
129
  ? (Content extends Json.Object
118
130
  ? {
119
- readonly [AB in ASide | BSide as AB extends ASide
120
- ? `${AB}EntriesOf${Capitalize<BSide>}`
121
- : `${AB}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
122
- [string, Content][],
123
- string
131
+ readonly [A in ASide as `${A}EntriesOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
132
+ [AType, Content][],
133
+ BType
134
+ >
135
+ } & {
136
+ readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
137
+ [BType, Content][],
138
+ AType
124
139
  >
125
140
  }
126
141
  : {}) & {
127
- readonly [AB in ASide | BSide as AB extends ASide
128
- ? `${AB}KeysOf${Capitalize<BSide>}`
129
- : `${AB}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
130
- string[],
131
- string
142
+ readonly [A in ASide as `${A}KeysOf${Capitalize<BSide>}`]: ReadonlySelectorFamilyToken<
143
+ AType[],
144
+ BType
145
+ >
146
+ } & {
147
+ readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorFamilyToken<
148
+ BType[],
149
+ AType
132
150
  >
133
151
  }
134
152
  : never
135
153
 
136
154
  export class Join<
137
155
  const ASide extends string,
156
+ const AType extends string,
138
157
  const BSide extends string,
158
+ const BType extends string,
139
159
  const Cardinality extends `1:1` | `1:n` | `n:n`,
140
160
  const Content extends Json.Object | null = null,
141
161
  > {
142
- private options: JoinOptions<ASide, BSide, Cardinality, Content>
162
+ private options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>
143
163
  private defaultContent: Content | undefined
144
164
  private toolkit: SetterToolkit & { dispose: typeof disposeState }
145
165
  public retrieve: typeof findState
146
166
  public molecules: Map<string, Molecule<any>> = new Map()
147
- public relations: Junction<ASide, BSide, Content>
148
- public states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
167
+ public relations: Junction<ASide, AType, BSide, BType, Content>
168
+ public states: JoinStateFamilies<
169
+ ASide,
170
+ AType,
171
+ BSide,
172
+ BType,
173
+ Cardinality,
174
+ Content
175
+ >
149
176
  public core: {
150
177
  findRelatedKeysState: MutableAtomFamilyToken<
151
178
  SetRTX<string>,
@@ -155,7 +182,7 @@ export class Join<
155
182
  }
156
183
  public transact(
157
184
  toolkit: SetterToolkit & { dispose: typeof disposeState },
158
- run: (join: Join<ASide, BSide, Cardinality, Content>) => void,
185
+ run: (join: Join<ASide, AType, BSide, BType, Cardinality, Content>) => void,
159
186
  ): void {
160
187
  const originalToolkit = this.toolkit
161
188
  this.toolkit = toolkit
@@ -164,12 +191,17 @@ export class Join<
164
191
  }
165
192
 
166
193
  public store: Store
167
- public alternates: Map<string, Join<ASide, BSide, Cardinality, Content>>
194
+ public alternates: Map<
195
+ string,
196
+ Join<ASide, AType, BSide, BType, Cardinality, Content>
197
+ >
168
198
  public [Symbol.dispose](): void {
169
199
  this.alternates.delete(this.store.config.name)
170
200
  }
171
201
 
172
- public in(store: Store): Join<ASide, BSide, Cardinality, Content> {
202
+ public in(
203
+ store: Store,
204
+ ): Join<ASide, AType, BSide, BType, Cardinality, Content> {
173
205
  const key = store.config.name
174
206
  const alternate = this.alternates.get(key)
175
207
  if (alternate) {
@@ -182,10 +214,12 @@ export class Join<
182
214
  }
183
215
 
184
216
  public constructor(
185
- options: JoinOptions<ASide, BSide, Cardinality, Content>,
217
+ options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>,
186
218
  defaultContent: Content | undefined,
187
219
  store: Store = IMPLICIT.STORE,
188
220
  ) {
221
+ type AnyKey = AType & BType
222
+
189
223
  this.store = store
190
224
  this.options = options
191
225
  this.defaultContent = defaultContent
@@ -202,7 +236,7 @@ export class Join<
202
236
  if (maybeToken) {
203
237
  return maybeToken
204
238
  }
205
- const molecule = this.molecules.get(stringifyJson(key))
239
+ const molecule = this.store.molecules.get(stringifyJson(key))
206
240
  if (molecule) {
207
241
  const family = withdraw(token, store)
208
242
  return growMoleculeInStore(molecule, family, store)
@@ -245,10 +279,9 @@ export class Join<
245
279
  [`join`, `relations`],
246
280
  )
247
281
  this.core = { findRelatedKeysState: relatedKeysAtoms }
248
- const getRelatedKeys: Read<(key: string) => SetRTX<string>> = (
249
- { get },
250
- key,
251
- ) => get(this.retrieve(relatedKeysAtoms, key))
282
+ const getRelatedKeys: Read<
283
+ (key: string) => SetRTX<AType> | SetRTX<BType>
284
+ > = ({ get }, key) => get(this.retrieve(relatedKeysAtoms, key) as any)
252
285
  const addRelation: Write<(a: string, b: string) => void> = (
253
286
  toolkit,
254
287
  a,
@@ -310,7 +343,7 @@ export class Join<
310
343
  nextRelationsOfA.clear()
311
344
  for (const newRelationB of newRelationsOfA) {
312
345
  const relationsOfB = getRelatedKeys(toolkit, newRelationB)
313
- const newRelationBIsAlreadyRelated = relationsOfB.has(a)
346
+ const newRelationBIsAlreadyRelated = relationsOfB.has(a as AnyKey)
314
347
  if (this.relations.cardinality === `1:n`) {
315
348
  const previousOwnersToDispose: string[] = []
316
349
  for (const previousOwner of relationsOfB) {
@@ -321,7 +354,7 @@ export class Join<
321
354
  toolkit,
322
355
  previousOwner,
323
356
  )
324
- previousOwnerRelations.delete(newRelationB)
357
+ previousOwnerRelations.delete(newRelationB as AnyKey)
325
358
  if (previousOwnerRelations.size === 0) {
326
359
  previousOwnersToDispose.push(previousOwner)
327
360
  }
@@ -336,7 +369,7 @@ export class Join<
336
369
  }
337
370
  }
338
371
  if (!newRelationBIsAlreadyRelated) {
339
- relationsOfB.add(a)
372
+ relationsOfB.add(a as AnyKey)
340
373
  }
341
374
  nextRelationsOfA.add(newRelationB)
342
375
  }
@@ -370,7 +403,7 @@ export class Join<
370
403
  }
371
404
  const has: Read<(a: string, b?: string) => boolean> = (toolkit, a, b) => {
372
405
  const aKeys = getRelatedKeys(toolkit, a)
373
- return b ? aKeys.has(b) : aKeys.size > 0
406
+ return b ? aKeys.has(b as AnyKey) : aKeys.size > 0
374
407
  }
375
408
  const baseExternalStoreConfiguration: BaseExternalStoreConfiguration = {
376
409
  getRelatedKeys: (key) => getRelatedKeys(this.toolkit, key),
@@ -404,13 +437,6 @@ export class Join<
404
437
  },
405
438
  [`join`, `content`],
406
439
  )
407
- const joinToken = {
408
- key: options.key,
409
- type: `join`,
410
- a: options.between[0],
411
- b: options.between[1],
412
- cardinality: options.cardinality,
413
- } as const satisfies JoinToken<ASide, BSide, Cardinality, Content>
414
440
  contentMolecules = createMoleculeFamily(store, {
415
441
  key: `${options.key}/content-molecules`,
416
442
  new: class ContentMolecule {
@@ -459,30 +485,35 @@ export class Join<
459
485
  externalStore =
460
486
  baseExternalStoreConfiguration as ExternalStoreConfiguration<Content>
461
487
  }
462
- const relations = new Junction<ASide, BSide, Content>(options, {
463
- externalStore,
464
- makeContentKey: (...args) => {
465
- const sorted = args.sort()
466
- const compositeKey = `${sorted[0]}:${sorted[1]}`
467
- const [m0, m1] = sorted.map((key) =>
468
- this.molecules.get(stringifyJson(key)),
469
- )
470
- if (store.config.lifespan === `immortal` && m0 && m1) {
471
- const target = newest(store)
472
- const moleculeToken = makeMoleculeInStore(
473
- target,
474
- [m0, m1],
475
- contentMolecules,
476
- compositeKey,
477
- )
478
- this.molecules.set(
479
- `"${compositeKey}"`,
480
- withdraw(moleculeToken, target),
488
+ const relations = new Junction<ASide, AType, BSide, BType, Content>(
489
+ options as any,
490
+ {
491
+ externalStore,
492
+ isAType: options.isAType,
493
+ isBType: options.isBType,
494
+ makeContentKey: (...args) => {
495
+ const sorted = args.sort()
496
+ const compositeKey = `${sorted[0]}:${sorted[1]}`
497
+ const [m0, m1] = sorted.map((key) =>
498
+ this.molecules.get(stringifyJson(key)),
481
499
  )
482
- }
483
- return compositeKey
500
+ if (store.config.lifespan === `immortal` && m0 && m1) {
501
+ const target = newest(store)
502
+ const moleculeToken = makeMoleculeInStore(
503
+ target,
504
+ [m0, m1],
505
+ contentMolecules,
506
+ compositeKey,
507
+ )
508
+ this.molecules.set(
509
+ `"${compositeKey}"`,
510
+ withdraw(moleculeToken, target),
511
+ )
512
+ }
513
+ return compositeKey
514
+ },
484
515
  },
485
- })
516
+ )
486
517
 
487
518
  const createSingleKeyStateFamily = () =>
488
519
  createReadonlySelectorFamily<string | null, string>(
@@ -525,15 +556,19 @@ export class Join<
525
556
  {
526
557
  key: `${options.key}/singleRelatedEntry`,
527
558
  get:
528
- (key) =>
559
+ (x) =>
529
560
  ({ get }) => {
530
- const relatedKeysState = this.retrieve(relatedKeysAtoms, key)
561
+ const relatedKeysState = this.retrieve(relatedKeysAtoms, x)
531
562
  const relatedKeys = get(relatedKeysState)
532
- for (const relatedKey of relatedKeys) {
533
- const contentKey = relations.makeContentKey(key, relatedKey)
563
+ for (const y of relatedKeys) {
564
+ let a = relations.isAType?.(x) ? x : undefined
565
+ let b = a === undefined ? (x as BType) : undefined
566
+ a ??= y as AType
567
+ b ??= y as BType
568
+ const contentKey = relations.makeContentKey(a, b)
534
569
  const contentState = this.retrieve(contentAtoms, contentKey)
535
570
  const content = get(contentState)
536
- return [relatedKey, content]
571
+ return [y, content]
537
572
  }
538
573
  return null
539
574
  },
@@ -546,16 +581,20 @@ export class Join<
546
581
  {
547
582
  key: `${options.key}/multipleRelatedEntries`,
548
583
  get:
549
- (key) =>
584
+ (x) =>
550
585
  ({ get }) => {
551
586
  const jsonFamily = getJsonFamily(relatedKeysAtoms, store)
552
- const jsonState = this.retrieve(jsonFamily, key)
587
+ const jsonState = this.retrieve(jsonFamily, x)
553
588
  const json = get(jsonState)
554
- return json.members.map((relatedKey) => {
555
- const contentKey = relations.makeContentKey(key, relatedKey)
589
+ return json.members.map((y) => {
590
+ let a = relations.isAType?.(x) ? x : undefined
591
+ let b = a === undefined ? (x as BType) : undefined
592
+ a ??= y as AType
593
+ b ??= y as BType
594
+ const contentKey = relations.makeContentKey(a, b)
556
595
  const contentState = this.retrieve(contentAtoms, contentKey)
557
596
  const content = get(contentState)
558
- return [relatedKey, content]
597
+ return [y, content]
559
598
  })
560
599
  },
561
600
  },
@@ -570,8 +609,15 @@ export class Join<
570
609
  const baseStates = {
571
610
  [stateKeyA]: findSingleRelatedKeyState,
572
611
  [stateKeyB]: findSingleRelatedKeyState,
573
- } as JoinStateFamilies<ASide, BSide, Cardinality, Content>
574
- let states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
612
+ } as JoinStateFamilies<ASide, AType, BSide, BType, Cardinality, Content>
613
+ let states: JoinStateFamilies<
614
+ ASide,
615
+ AType,
616
+ BSide,
617
+ BType,
618
+ Cardinality,
619
+ Content
620
+ >
575
621
  if (defaultContent) {
576
622
  const findSingleRelatedEntryState = createSingleEntryStateFamily()
577
623
  const entriesStateKeyA = `${aSide}EntryOf${capitalize(bSide)}` as const
@@ -596,8 +642,15 @@ export class Join<
596
642
  const baseStates = {
597
643
  [stateKeyA]: findSingleRelatedKeyState,
598
644
  [stateKeyB]: findMultipleRelatedKeysState,
599
- } as JoinStateFamilies<ASide, BSide, Cardinality, Content>
600
- let states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
645
+ } as JoinStateFamilies<ASide, AType, BSide, BType, Cardinality, Content>
646
+ let states: JoinStateFamilies<
647
+ ASide,
648
+ AType,
649
+ BSide,
650
+ BType,
651
+ Cardinality,
652
+ Content
653
+ >
601
654
  if (defaultContent) {
602
655
  const findSingleRelatedEntryState = createSingleEntryStateFamily()
603
656
  const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
@@ -624,8 +677,15 @@ export class Join<
624
677
  const baseStates = {
625
678
  [stateKeyA]: findMultipleRelatedKeysState,
626
679
  [stateKeyB]: findMultipleRelatedKeysState,
627
- } as JoinStateFamilies<ASide, BSide, Cardinality, Content>
628
- let states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
680
+ } as JoinStateFamilies<ASide, AType, BSide, BType, Cardinality, Content>
681
+ let states: JoinStateFamilies<
682
+ ASide,
683
+ AType,
684
+ BSide,
685
+ BType,
686
+ Cardinality,
687
+ Content
688
+ >
629
689
  if (defaultContent) {
630
690
  const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
631
691
  const entriesStateKeyA = `${aSide}EntriesOf${capitalize(
@@ -651,7 +711,9 @@ export class Join<
651
711
 
652
712
  export type JoinToken<
653
713
  ASide extends string,
714
+ AType extends string,
654
715
  BSide extends string,
716
+ BType extends string,
655
717
  Cardinality extends `1:1` | `1:n` | `n:n`,
656
718
  Content extends Json.Object | null = null,
657
719
  > = {
@@ -660,41 +722,49 @@ export type JoinToken<
660
722
  cardinality: Cardinality
661
723
  a: ASide
662
724
  b: BSide
725
+ __aType?: AType
726
+ __bType?: BType
663
727
  __content?: Content
664
728
  }
665
729
 
666
730
  export function join<
667
731
  const ASide extends string,
732
+ const AType extends string,
668
733
  const BSide extends string,
734
+ const BType extends string,
669
735
  const Cardinality extends `1:1` | `1:n` | `n:n`,
670
736
  >(
671
- options: JoinOptions<ASide, BSide, Cardinality, null>,
737
+ options: JoinOptions<ASide, AType, BSide, BType, Cardinality, null>,
672
738
  defaultContent?: undefined,
673
739
  store?: Store,
674
- ): JoinToken<ASide, BSide, Cardinality, null>
740
+ ): JoinToken<ASide, AType, BSide, BType, Cardinality, null>
675
741
  export function join<
676
742
  const ASide extends string,
743
+ const AType extends string,
677
744
  const BSide extends string,
745
+ const BType extends string,
678
746
  const Cardinality extends `1:1` | `1:n` | `n:n`,
679
747
  const Content extends Json.Object,
680
748
  >(
681
- options: JoinOptions<ASide, BSide, Cardinality, Content>,
749
+ options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>,
682
750
  defaultContent: Content,
683
751
  store?: Store,
684
- ): JoinToken<ASide, BSide, Cardinality, Content>
752
+ ): JoinToken<ASide, AType, BSide, BType, Cardinality, Content>
685
753
  export function join<
686
754
  ASide extends string,
755
+ AType extends string,
687
756
  BSide extends string,
757
+ BType extends string,
688
758
  Cardinality extends `1:1` | `1:n` | `n:n`,
689
759
  Content extends Json.Object,
690
760
  >(
691
- options: JoinOptions<ASide, BSide, Cardinality, Content>,
761
+ options: JoinOptions<ASide, AType, BSide, BType, Cardinality, Content>,
692
762
  defaultContent: Content | undefined,
693
763
  store: Store = IMPLICIT.STORE,
694
- ): JoinToken<ASide, BSide, Cardinality, Content> {
764
+ ): JoinToken<ASide, AType, BSide, BType, Cardinality, Content> {
695
765
  const joins = getJoinMap(store)
696
766
  joins.set(options.key, new Join(options, defaultContent, store))
697
- const token: JoinToken<ASide, BSide, Cardinality, Content> = {
767
+ const token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content> = {
698
768
  key: options.key,
699
769
  type: `join`,
700
770
  a: options.between[0],
@@ -705,24 +775,26 @@ export function join<
705
775
  }
706
776
 
707
777
  export function getJoinMap(
708
- store: Store & { joins?: Map<string, Join<any, any, any, any>> },
709
- ): Map<string, Join<any, any, any, any>> {
778
+ store: Store & { joins?: Map<string, Join<any, any, any, any, any, any>> },
779
+ ): Map<string, Join<any, any, any, any, any, any>> {
710
780
  if (`joins` in store && store.joins instanceof Map) {
711
781
  return store.joins
712
782
  }
713
- const joins = new Map<string, Join<any, any, any, any>>()
783
+ const joins = new Map<string, Join<any, any, any, any, any, any>>()
714
784
  store.joins = joins
715
785
  return joins
716
786
  }
717
787
  export function getJoin<
718
788
  ASide extends string,
789
+ AType extends string,
719
790
  BSide extends string,
791
+ BType extends string,
720
792
  Cardinality extends `1:1` | `1:n` | `n:n`,
721
793
  Content extends Json.Object | null,
722
794
  >(
723
- token: JoinToken<ASide, BSide, Cardinality, Content>,
795
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
724
796
  store: Store,
725
- ): Join<ASide, BSide, Cardinality, Content> {
797
+ ): Join<ASide, AType, BSide, BType, Cardinality, Content> {
726
798
  const joinMap = getJoinMap(store)
727
799
  let myJoin = joinMap.get(token.key)
728
800
  if (myJoin === undefined) {
@@ -740,71 +812,99 @@ export function getJoin<
740
812
 
741
813
  export type JoinStates<
742
814
  ASide extends string,
815
+ AType extends string,
743
816
  BSide extends string,
817
+ BType extends string,
744
818
  Cardinality extends `1:1` | `1:n` | `n:n`,
745
819
  Content extends Json.Object | null,
746
820
  > = Cardinality extends `1:1`
747
821
  ? (Content extends Json.Object
748
822
  ? {
749
- readonly [AB in ASide | BSide as AB extends ASide
750
- ? `${AB}EntryOf${Capitalize<BSide>}`
751
- : `${AB}EntryOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
752
- [string, Content] | null
823
+ readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
824
+ [AType, Content] | null,
825
+ BType
826
+ >
827
+ } & {
828
+ readonly [B in BSide as `${B}EntryOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
829
+ [BType, Content] | null,
830
+ AType
753
831
  >
754
832
  }
755
833
  : {}) & {
756
- readonly [AB in ASide | BSide as AB extends ASide
757
- ? `${AB}KeyOf${Capitalize<BSide>}`
758
- : `${AB}KeyOf${Capitalize<ASide>}`]: ReadonlySelectorToken<string | null>
834
+ readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
835
+ AType | null,
836
+ BType
837
+ >
838
+ } & {
839
+ readonly [B in BSide as `${B}KeyOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
840
+ BType | null,
841
+ AType
842
+ >
759
843
  }
760
844
  : Cardinality extends `1:n`
761
845
  ? (Content extends Json.Object
762
846
  ? {
763
847
  readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
764
- [string, Content] | null
848
+ [AType, Content] | null,
849
+ BType
765
850
  >
766
851
  } & {
767
852
  readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
768
- [string, Content][]
853
+ [BType, Content][],
854
+ AType
769
855
  >
770
856
  }
771
857
  : {}) & {
772
858
  readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
773
- string | null
859
+ AType | null,
860
+ BType
774
861
  >
775
862
  } & {
776
863
  readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
777
- string[]
864
+ BType[],
865
+ AType
778
866
  >
779
867
  }
780
868
  : Cardinality extends `n:n`
781
869
  ? (Content extends Json.Object
782
870
  ? {
783
- readonly [AB in ASide | BSide as AB extends ASide
784
- ? `${AB}EntriesOf${Capitalize<BSide>}`
785
- : `${AB}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
786
- [string, Content][]
871
+ readonly [A in ASide as `${A}EntriesOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
872
+ [AType, Content][],
873
+ BType
874
+ >
875
+ } & {
876
+ readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
877
+ [BType, Content][],
878
+ AType
787
879
  >
788
880
  }
789
881
  : {}) & {
790
- readonly [AB in ASide | BSide as AB extends ASide
791
- ? `${AB}KeysOf${Capitalize<BSide>}`
792
- : `${AB}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorToken<string[]>
882
+ readonly [A in ASide as `${A}KeysOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
883
+ AType[],
884
+ BType
885
+ >
886
+ } & {
887
+ readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
888
+ BType[],
889
+ AType
890
+ >
793
891
  }
794
892
  : never
795
893
 
796
894
  export function findRelationsInStore<
797
895
  ASide extends string,
896
+ AType extends string,
798
897
  BSide extends string,
898
+ BType extends string,
799
899
  Cardinality extends `1:1` | `1:n` | `n:n`,
800
900
  Content extends Json.Object | null,
801
901
  >(
802
- token: JoinToken<ASide, BSide, Cardinality, Content>,
803
- key: string,
902
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
903
+ key: AType | BType,
804
904
  store: Store,
805
- ): JoinStates<ASide, BSide, Cardinality, Content> {
905
+ ): JoinStates<ASide, AType, BSide, BType, Cardinality, Content> {
806
906
  const myJoin = getJoin(token, store)
807
- let relations: JoinStates<ASide, BSide, Cardinality, Content>
907
+ let relations: JoinStates<ASide, AType, BSide, BType, Cardinality, Content>
808
908
  switch (token.cardinality satisfies `1:1` | `1:n` | `n:n`) {
809
909
  case `1:1`: {
810
910
  const keyAB = `${token.a}KeyOf${capitalize(token.b)}`
@@ -820,7 +920,7 @@ export function findRelationsInStore<
820
920
  const state = myJoin.retrieve(familyBA, key)
821
921
  return state
822
922
  },
823
- } as JoinStates<ASide, BSide, Cardinality, Content>
923
+ } as JoinStates<ASide, AType, BSide, BType, Cardinality, Content>
824
924
  const entryAB = `${token.a}EntryOf${capitalize(token.b)}`
825
925
  if (entryAB in myJoin.states) {
826
926
  const entryBA = `${token.b}EntryOf${capitalize(token.a)}`
@@ -853,7 +953,7 @@ export function findRelationsInStore<
853
953
  const state = myJoin.retrieve(familyBA, key)
854
954
  return state
855
955
  },
856
- } as JoinStates<ASide, BSide, Cardinality, Content>
956
+ } as JoinStates<ASide, AType, BSide, BType, Cardinality, Content>
857
957
  const entryAB = `${token.a}EntryOf${capitalize(token.b)}`
858
958
  if (entryAB in myJoin.states) {
859
959
  const entriesBA = `${token.b}EntriesOf${capitalize(token.a)}`
@@ -886,7 +986,7 @@ export function findRelationsInStore<
886
986
  const state = myJoin.retrieve(familyBA, key)
887
987
  return state
888
988
  },
889
- } as JoinStates<ASide, BSide, Cardinality, Content>
989
+ } as JoinStates<ASide, AType, BSide, BType, Cardinality, Content>
890
990
  const entriesAB = `${token.a}EntriesOf${capitalize(token.b)}`
891
991
  if (entriesAB in myJoin.states) {
892
992
  const entriesBA = `${token.b}EntriesOf${capitalize(token.a)}`
@@ -910,24 +1010,28 @@ export function findRelationsInStore<
910
1010
 
911
1011
  export function findRelations<
912
1012
  ASide extends string,
1013
+ AType extends string,
913
1014
  BSide extends string,
1015
+ BType extends string,
914
1016
  Cardinality extends `1:1` | `1:n` | `n:n`,
915
1017
  Content extends Json.Object | null,
916
1018
  >(
917
- token: JoinToken<ASide, BSide, Cardinality, Content>,
918
- key: string,
919
- ): JoinStates<ASide, BSide, Cardinality, Content> {
1019
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
1020
+ key: AType | BType,
1021
+ ): JoinStates<ASide, AType, BSide, BType, Cardinality, Content> {
920
1022
  return findRelationsInStore(token, key, IMPLICIT.STORE)
921
1023
  }
922
1024
 
923
1025
  export function editRelationsInStore<
924
1026
  ASide extends string,
1027
+ AType extends string,
925
1028
  BSide extends string,
1029
+ BType extends string,
926
1030
  Cardinality extends `1:1` | `1:n` | `n:n`,
927
1031
  Content extends Json.Object | null,
928
1032
  >(
929
- token: JoinToken<ASide, BSide, Cardinality, Content>,
930
- change: (relations: Junction<ASide, BSide, Content>) => void,
1033
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
1034
+ change: (relations: Junction<ASide, AType, BSide, BType, Content>) => void,
931
1035
  store: Store,
932
1036
  ): void {
933
1037
  const myJoin = getJoin(token, store)
@@ -944,18 +1048,20 @@ export function editRelationsInStore<
944
1048
 
945
1049
  export function editRelations<
946
1050
  ASide extends string,
1051
+ AType extends string,
947
1052
  BSide extends string,
1053
+ BType extends string,
948
1054
  Cardinality extends `1:1` | `1:n` | `n:n`,
949
1055
  Content extends Json.Object | null,
950
1056
  >(
951
- token: JoinToken<ASide, BSide, Cardinality, Content>,
952
- change: (relations: Junction<ASide, BSide, Content>) => void,
1057
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
1058
+ change: (relations: Junction<ASide, AType, BSide, BType, Content>) => void,
953
1059
  ): void {
954
1060
  editRelationsInStore(token, change, IMPLICIT.STORE)
955
1061
  }
956
1062
 
957
1063
  export function getInternalRelationsFromStore(
958
- token: JoinToken<any, any, any, any>,
1064
+ token: JoinToken<any, any, any, any, any, any>,
959
1065
  store: Store,
960
1066
  ): MutableAtomFamilyToken<SetRTX<string>, SetRTXJson<string>, string> {
961
1067
  const myJoin = getJoin(token, store)
@@ -965,11 +1071,13 @@ export function getInternalRelationsFromStore(
965
1071
 
966
1072
  export function getInternalRelations<
967
1073
  ASide extends string,
1074
+ AType extends string,
968
1075
  BSide extends string,
1076
+ BType extends string,
969
1077
  Cardinality extends `1:1` | `1:n` | `n:n`,
970
1078
  Content extends Json.Object | null,
971
1079
  >(
972
- token: JoinToken<ASide, BSide, Cardinality, Content>,
1080
+ token: JoinToken<ASide, AType, BSide, BType, Cardinality, Content>,
973
1081
  ): MutableAtomFamilyToken<SetRTX<string>, SetRTXJson<string>, string> {
974
1082
  return getInternalRelationsFromStore(token, IMPLICIT.STORE)
975
1083
  }