atom.io 0.18.3 → 0.19.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/data/src/join.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/ban-types */
2
2
  import type {
3
3
  MutableAtomFamily,
4
+ MutableAtomFamilyToken,
5
+ MutableAtomToken,
4
6
  Read,
5
7
  ReadonlySelectorFamily,
8
+ ReadonlySelectorToken,
6
9
  RegularAtomFamily,
7
10
  Transactors,
8
11
  Write,
@@ -17,6 +20,8 @@ import {
17
20
  findInStore,
18
21
  getFromStore,
19
22
  getJsonFamily,
23
+ isChildStore,
24
+ newest,
20
25
  setIntoStore,
21
26
  } from "atom.io/internal"
22
27
  import type { Json } from "atom.io/json"
@@ -54,7 +59,7 @@ export interface JoinOptions<
54
59
  readonly cardinality: Cardinality
55
60
  }
56
61
 
57
- export type JoinState<
62
+ export type JoinStateFamilies<
58
63
  ASide extends string,
59
64
  BSide extends string,
60
65
  Cardinality extends Rel8.Cardinality,
@@ -131,7 +136,7 @@ export class Join<
131
136
  private defaultContent: Content | undefined
132
137
  private transactors: Transactors
133
138
  public relations: Junction<ASide, BSide, Content>
134
- public states: JoinState<ASide, BSide, Cardinality, Content>
139
+ public states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
135
140
  public core: {
136
141
  findRelatedKeysState: MutableAtomFamily<
137
142
  SetRTX<string>,
@@ -435,8 +440,8 @@ export class Join<
435
440
  const baseStates = {
436
441
  [stateKeyA]: findSingleRelatedKeyState,
437
442
  [stateKeyB]: findSingleRelatedKeyState,
438
- } as JoinState<ASide, BSide, Cardinality, Content>
439
- let states: JoinState<ASide, BSide, Cardinality, Content>
443
+ } as JoinStateFamilies<ASide, BSide, Cardinality, Content>
444
+ let states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
440
445
  if (defaultContent) {
441
446
  const findSingleRelatedEntryState = createSingleEntryStateFamily()
442
447
  const entriesStateKeyA = `${a}EntryOf${capitalize(b)}` as const
@@ -461,8 +466,8 @@ export class Join<
461
466
  const baseStates = {
462
467
  [stateKeyA]: findSingleRelatedKeyState,
463
468
  [stateKeyB]: findMultipleRelatedKeysState,
464
- } as JoinState<ASide, BSide, Cardinality, Content>
465
- let states: JoinState<ASide, BSide, Cardinality, Content>
469
+ } as JoinStateFamilies<ASide, BSide, Cardinality, Content>
470
+ let states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
466
471
  if (defaultContent) {
467
472
  const findSingleRelatedEntryState = createSingleEntryStateFamily()
468
473
  const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
@@ -487,8 +492,8 @@ export class Join<
487
492
  const baseStates = {
488
493
  [stateKeyA]: findMultipleRelatedKeysState,
489
494
  [stateKeyB]: findMultipleRelatedKeysState,
490
- } as JoinState<ASide, BSide, Cardinality, Content>
491
- let states: JoinState<ASide, BSide, Cardinality, Content>
495
+ } as JoinStateFamilies<ASide, BSide, Cardinality, Content>
496
+ let states: JoinStateFamilies<ASide, BSide, Cardinality, Content>
492
497
  if (defaultContent) {
493
498
  const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
494
499
  const entriesStateKeyA = `${a}EntriesOf${capitalize(b)}` as const
@@ -508,6 +513,20 @@ export class Join<
508
513
  }
509
514
  }
510
515
 
516
+ export type JoinToken<
517
+ ASide extends string,
518
+ BSide extends string,
519
+ Cardinality extends `1:1` | `1:n` | `n:n`,
520
+ Content extends Json.Object | null = null,
521
+ > = {
522
+ key: string
523
+ type: `join`
524
+ cardinality: Cardinality
525
+ a: ASide
526
+ b: BSide
527
+ __content?: Content
528
+ }
529
+
511
530
  export function join<
512
531
  const ASide extends string,
513
532
  const BSide extends string,
@@ -516,22 +535,7 @@ export function join<
516
535
  options: JoinOptions<ASide, BSide, Cardinality, null>,
517
536
  defaultContent?: undefined,
518
537
  store?: Store,
519
- ): {
520
- readonly relations: Junction<ASide, BSide, null>
521
- readonly states: JoinState<ASide, BSide, Cardinality, null>
522
- readonly in: (store: Store) => Join<ASide, BSide, Cardinality>
523
- readonly transact: (
524
- transactors: Transactors,
525
- run: (join: Join<ASide, BSide, Cardinality, null>) => void,
526
- ) => void
527
- readonly core: {
528
- readonly findRelatedKeysState: MutableAtomFamily<
529
- SetRTX<string>,
530
- SetRTXJson<string>,
531
- string
532
- >
533
- }
534
- }
538
+ ): JoinToken<ASide, BSide, Cardinality, null>
535
539
  export function join<
536
540
  const ASide extends string,
537
541
  const BSide extends string,
@@ -541,22 +545,7 @@ export function join<
541
545
  options: JoinOptions<ASide, BSide, Cardinality, Content>,
542
546
  defaultContent: Content,
543
547
  store?: Store,
544
- ): {
545
- readonly relations: Junction<ASide, BSide, Content>
546
- readonly states: JoinState<ASide, BSide, Cardinality, Content>
547
- readonly in: (store: Store) => Join<ASide, BSide, Cardinality, Content>
548
- readonly transact: (
549
- transactors: Transactors,
550
- run: (join: Join<ASide, BSide, Cardinality, Content>) => void,
551
- ) => void
552
- readonly core: {
553
- readonly findRelatedKeysState: MutableAtomFamily<
554
- SetRTX<string>,
555
- SetRTXJson<string>,
556
- string
557
- >
558
- }
559
- }
548
+ ): JoinToken<ASide, BSide, Cardinality, Content>
560
549
  export function join<
561
550
  ASide extends string,
562
551
  BSide extends string,
@@ -566,6 +555,285 @@ export function join<
566
555
  options: JoinOptions<ASide, BSide, Cardinality, Content>,
567
556
  defaultContent: Content | undefined,
568
557
  store: Store = IMPLICIT.STORE,
558
+ ): JoinToken<ASide, BSide, Cardinality, Content> {
559
+ const joins = getJoinMap(store)
560
+ joins.set(options.key, new Join(options, defaultContent, store))
561
+ const token: JoinToken<ASide, BSide, Cardinality, Content> = {
562
+ key: options.key,
563
+ type: `join`,
564
+ a: options.between[0],
565
+ b: options.between[1],
566
+ cardinality: options.cardinality,
567
+ }
568
+ return token
569
+ }
570
+
571
+ export function getJoinMap(
572
+ store: Store & { joins?: Map<string, Join<any, any, any, any>> },
573
+ ): Map<string, Join<any, any, any, any>> {
574
+ if (`joins` in store && store.joins instanceof Map) {
575
+ return store.joins
576
+ }
577
+ const joins = new Map<string, Join<any, any, any, any>>()
578
+ store.joins = joins
579
+ return joins
580
+ }
581
+ export function getJoin<
582
+ ASide extends string,
583
+ BSide extends string,
584
+ Cardinality extends `1:1` | `1:n` | `n:n`,
585
+ Content extends Json.Object | null,
586
+ >(
587
+ token: JoinToken<ASide, BSide, Cardinality, Content>,
588
+ store: Store,
569
589
  ): Join<ASide, BSide, Cardinality, Content> {
570
- return new Join(options, defaultContent, store)
590
+ const joinMap = getJoinMap(store)
591
+ let join = joinMap.get(token.key)
592
+ if (join === undefined) {
593
+ const rootJoinMap = getJoinMap(IMPLICIT.STORE)
594
+ join = rootJoinMap.get(token.key)?.in(store)
595
+ if (join === undefined) {
596
+ throw new Error(
597
+ `Join "${token.key}" not found in store "${store.config.name}"`,
598
+ )
599
+ }
600
+ joinMap.set(token.key, join)
601
+ }
602
+ return join
603
+ }
604
+
605
+ export type JoinStates<
606
+ ASide extends string,
607
+ BSide extends string,
608
+ Cardinality extends Rel8.Cardinality,
609
+ Content extends Json.Object | null,
610
+ > = Cardinality extends `1:1`
611
+ ? (Content extends Json.Object
612
+ ? {
613
+ readonly [AB in ASide | BSide as AB extends ASide
614
+ ? `${AB}EntryOf${Capitalize<BSide>}`
615
+ : `${AB}EntryOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
616
+ [string, Content] | null
617
+ >
618
+ }
619
+ : {}) & {
620
+ readonly [AB in ASide | BSide as AB extends ASide
621
+ ? `${AB}KeyOf${Capitalize<BSide>}`
622
+ : `${AB}KeyOf${Capitalize<ASide>}`]: ReadonlySelectorToken<string | null>
623
+ }
624
+ : Cardinality extends `1:n`
625
+ ? (Content extends Json.Object
626
+ ? {
627
+ readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
628
+ [string, Content] | null
629
+ >
630
+ } & {
631
+ readonly [B in BSide as `${B}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
632
+ [string, Content][]
633
+ >
634
+ }
635
+ : {}) & {
636
+ readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: ReadonlySelectorToken<
637
+ string | null
638
+ >
639
+ } & {
640
+ readonly [B in BSide as `${B}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
641
+ string[]
642
+ >
643
+ }
644
+ : Cardinality extends `n:n`
645
+ ? (Content extends Json.Object
646
+ ? {
647
+ readonly [AB in ASide | BSide as AB extends ASide
648
+ ? `${AB}EntriesOf${Capitalize<BSide>}`
649
+ : `${AB}EntriesOf${Capitalize<ASide>}`]: ReadonlySelectorToken<
650
+ [string, Content][]
651
+ >
652
+ }
653
+ : {}) & {
654
+ readonly [AB in ASide | BSide as AB extends ASide
655
+ ? `${AB}KeysOf${Capitalize<BSide>}`
656
+ : `${AB}KeysOf${Capitalize<ASide>}`]: ReadonlySelectorToken<string[]>
657
+ }
658
+ : never
659
+
660
+ export function findRelationsInStore<
661
+ ASide extends string,
662
+ BSide extends string,
663
+ Cardinality extends `1:1` | `1:n` | `n:n`,
664
+ Content extends Json.Object | null,
665
+ >(
666
+ token: JoinToken<ASide, BSide, Cardinality, Content>,
667
+ key: string,
668
+ store: Store,
669
+ ): JoinStates<ASide, BSide, Cardinality, Content> {
670
+ const join = getJoin(token, store)
671
+ let relations: JoinStates<ASide, BSide, Cardinality, Content>
672
+ switch (token.cardinality satisfies `1:1` | `1:n` | `n:n`) {
673
+ case `1:1`: {
674
+ const keyAB = `${token.a}KeyOf${capitalize(token.b)}`
675
+ const keyBA = `${token.b}KeyOf${capitalize(token.a)}`
676
+ relations = {
677
+ get [keyAB]() {
678
+ const familyAB = join.states[keyAB as any]
679
+ const state = findInStore(familyAB, key, store)
680
+ return state
681
+ },
682
+ get [keyBA]() {
683
+ const familyBA = join.states[keyBA as any]
684
+ const state = findInStore(familyBA, key, store)
685
+ return state
686
+ },
687
+ } as JoinStates<ASide, BSide, Cardinality, Content>
688
+ const entryAB = `${token.a}EntryOf${capitalize(token.b)}`
689
+ if (entryAB in join.states) {
690
+ const entryBA = `${token.b}EntryOf${capitalize(token.a)}`
691
+ Object.assign(relations, {
692
+ get [entryAB]() {
693
+ const familyAB = join.states[entryAB as any]
694
+ const state = findInStore(familyAB, key, store)
695
+ return state
696
+ },
697
+ get [entryBA]() {
698
+ const familyBA = join.states[entryBA as any]
699
+ const state = findInStore(familyBA, key, store)
700
+ return state
701
+ },
702
+ })
703
+ }
704
+ break
705
+ }
706
+ case `1:n`: {
707
+ const keyAB = `${token.a}KeyOf${capitalize(token.b)}`
708
+ const keysBA = `${token.b}KeysOf${capitalize(token.a)}`
709
+ relations = {
710
+ get [keyAB]() {
711
+ const familyAB = join.states[keyAB as any]
712
+ const state = findInStore(familyAB, key, store)
713
+ return state
714
+ },
715
+ get [keysBA]() {
716
+ const familyBA = join.states[keysBA as any]
717
+ const state = findInStore(familyBA, key, store)
718
+ return state
719
+ },
720
+ } as JoinStates<ASide, BSide, Cardinality, Content>
721
+ const entryAB = `${token.a}EntryOf${capitalize(token.b)}`
722
+ if (entryAB in join.states) {
723
+ const entriesBA = `${token.b}EntriesOf${capitalize(token.a)}`
724
+ Object.assign(relations, {
725
+ get [entryAB]() {
726
+ const familyAB = join.states[entryAB as any]
727
+ const state = findInStore(familyAB, key, store)
728
+ return state
729
+ },
730
+ get [entriesBA]() {
731
+ const familyBA = join.states[entriesBA as any]
732
+ const state = findInStore(familyBA, key, store)
733
+ return state
734
+ },
735
+ })
736
+ }
737
+ break
738
+ }
739
+ case `n:n`: {
740
+ const keysAB = `${token.a}KeysOf${capitalize(token.b)}`
741
+ const keysBA = `${token.b}KeysOf${capitalize(token.a)}`
742
+ relations = {
743
+ get [keysAB]() {
744
+ const familyAB = join.states[keysAB as any]
745
+ const state = findInStore(familyAB, key, store)
746
+ return state
747
+ },
748
+ get [keysBA]() {
749
+ const familyBA = join.states[keysBA as any]
750
+ const state = findInStore(familyBA, key, store)
751
+ return state
752
+ },
753
+ } as JoinStates<ASide, BSide, Cardinality, Content>
754
+ const entriesAB = `${token.a}EntriesOf${capitalize(token.b)}`
755
+ if (entriesAB in join.states) {
756
+ const entriesBA = `${token.b}EntriesOf${capitalize(token.a)}`
757
+ Object.assign(relations, {
758
+ get [entriesAB]() {
759
+ const familyAB = join.states[entriesAB as any]
760
+ const state = findInStore(familyAB, key, store)
761
+ return state
762
+ },
763
+ get [entriesBA]() {
764
+ const familyBA = join.states[entriesBA as any]
765
+ const state = findInStore(familyBA, key, store)
766
+ return state
767
+ },
768
+ })
769
+ }
770
+ }
771
+ }
772
+ return relations
773
+ }
774
+
775
+ export function findRelations<
776
+ ASide extends string,
777
+ BSide extends string,
778
+ Cardinality extends `1:1` | `1:n` | `n:n`,
779
+ Content extends Json.Object | null,
780
+ >(
781
+ token: JoinToken<ASide, BSide, Cardinality, Content>,
782
+ key: string,
783
+ ): JoinStates<ASide, BSide, Cardinality, Content> {
784
+ return findRelationsInStore(token, key, IMPLICIT.STORE)
785
+ }
786
+
787
+ export function editRelationsInStore<
788
+ ASide extends string,
789
+ BSide extends string,
790
+ Cardinality extends `1:1` | `1:n` | `n:n`,
791
+ Content extends Json.Object | null,
792
+ >(
793
+ token: JoinToken<ASide, BSide, Cardinality, Content>,
794
+ change: (relations: Junction<ASide, BSide, Content>) => void,
795
+ store: Store,
796
+ ): void {
797
+ const join = getJoin(token, store)
798
+ const target = newest(store)
799
+ if (isChildStore(target)) {
800
+ const { transactors } = target.transactionMeta
801
+ join.transact(transactors, ({ relations }) => {
802
+ change(relations)
803
+ })
804
+ } else {
805
+ change(join.relations)
806
+ }
807
+ }
808
+
809
+ export function editRelations<
810
+ ASide extends string,
811
+ BSide extends string,
812
+ Cardinality extends `1:1` | `1:n` | `n:n`,
813
+ Content extends Json.Object | null,
814
+ >(
815
+ token: JoinToken<ASide, BSide, Cardinality, Content>,
816
+ change: (relations: Junction<ASide, BSide, Content>) => void,
817
+ ): void {
818
+ editRelationsInStore(token, change, IMPLICIT.STORE)
819
+ }
820
+
821
+ export function getInternalRelationsFromStore(
822
+ token: JoinToken<any, any, any, any>,
823
+ store: Store,
824
+ ): MutableAtomFamilyToken<SetRTX<string>, SetRTXJson<string>, string> {
825
+ const join = getJoin(token, store)
826
+ const family = join.core.findRelatedKeysState
827
+ return family
828
+ }
829
+
830
+ export function getInternalRelations<
831
+ ASide extends string,
832
+ BSide extends string,
833
+ Cardinality extends `1:1` | `1:n` | `n:n`,
834
+ Content extends Json.Object | null,
835
+ >(
836
+ token: JoinToken<ASide, BSide, Cardinality, Content>,
837
+ ): MutableAtomFamilyToken<SetRTX<string>, SetRTXJson<string>, string> {
838
+ return getInternalRelationsFromStore(token, IMPLICIT.STORE)
571
839
  }