atom.io 0.14.8 → 0.15.1

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.
Files changed (100) hide show
  1. package/README.md +5 -0
  2. package/data/dist/index.cjs +216 -218
  3. package/data/dist/index.cjs.map +1 -1
  4. package/data/dist/index.d.ts +30 -11
  5. package/data/dist/index.js +218 -221
  6. package/data/dist/index.js.map +1 -1
  7. package/data/src/join.ts +337 -296
  8. package/data/src/struct-family.ts +2 -2
  9. package/data/src/struct.ts +2 -2
  10. package/dist/chunk-S7R5MU6A.js +137 -0
  11. package/dist/chunk-S7R5MU6A.js.map +1 -0
  12. package/dist/index.cjs +3 -20
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +15 -8
  15. package/dist/index.js +1 -151
  16. package/dist/index.js.map +1 -1
  17. package/internal/dist/index.cjs +278 -201
  18. package/internal/dist/index.cjs.map +1 -1
  19. package/internal/dist/index.d.ts +43 -36
  20. package/internal/dist/index.js +224 -194
  21. package/internal/dist/index.js.map +1 -1
  22. package/internal/src/atom/create-atom.ts +5 -86
  23. package/internal/src/atom/create-regular-atom.ts +92 -0
  24. package/internal/src/atom/index.ts +16 -0
  25. package/internal/src/atom/is-default.ts +0 -5
  26. package/internal/src/caching.ts +14 -16
  27. package/internal/src/families/create-atom-family.ts +20 -46
  28. package/internal/src/families/create-readonly-selector-family.ts +4 -1
  29. package/internal/src/families/create-regular-atom-family.ts +72 -0
  30. package/internal/src/families/create-selector-family.ts +2 -0
  31. package/internal/src/families/index.ts +1 -0
  32. package/internal/src/mutable/create-mutable-atom-family.ts +2 -2
  33. package/internal/src/mutable/create-mutable-atom.ts +8 -3
  34. package/internal/src/mutable/get-update-family.ts +1 -1
  35. package/internal/src/mutable/is-mutable.ts +3 -30
  36. package/internal/src/mutable/tracker-family.ts +2 -2
  37. package/internal/src/mutable/tracker.ts +5 -5
  38. package/internal/src/operation.ts +14 -18
  39. package/internal/src/selector/create-read-write-selector.ts +2 -3
  40. package/internal/src/selector/create-selector.ts +1 -1
  41. package/internal/src/selector/register-selector.ts +9 -14
  42. package/internal/src/set-state/evict-downstream.ts +3 -5
  43. package/internal/src/set-state/set-atom.ts +14 -17
  44. package/internal/src/store/store.ts +23 -19
  45. package/internal/src/store/withdraw.ts +32 -70
  46. package/internal/src/subscribe/subscribe-to-root-atoms.ts +5 -3
  47. package/internal/src/subscribe/subscribe-to-state.ts +5 -3
  48. package/internal/src/transaction/apply-transaction.ts +20 -2
  49. package/internal/src/transaction/build-transaction.ts +19 -11
  50. package/internal/src/transaction/create-transaction.ts +6 -11
  51. package/internal/src/transaction/index.ts +2 -3
  52. package/introspection/dist/index.cjs +6 -6
  53. package/introspection/dist/index.cjs.map +1 -1
  54. package/introspection/dist/index.d.ts +3 -3
  55. package/introspection/dist/index.js +7 -7
  56. package/introspection/dist/index.js.map +1 -1
  57. package/introspection/src/attach-atom-index.ts +7 -2
  58. package/introspection/src/attach-selector-index.ts +7 -2
  59. package/introspection/src/attach-timeline-family.ts +5 -2
  60. package/introspection/src/attach-timeline-index.ts +2 -2
  61. package/introspection/src/attach-transaction-index.ts +2 -2
  62. package/introspection/src/attach-transaction-logs.ts +2 -2
  63. package/package.json +10 -8
  64. package/react-devtools/dist/index.d.ts +17 -11
  65. package/realtime-client/dist/index.cjs +3 -0
  66. package/realtime-client/dist/index.cjs.map +1 -1
  67. package/realtime-client/dist/index.d.ts +3 -3
  68. package/realtime-client/dist/index.js +3 -0
  69. package/realtime-client/dist/index.js.map +1 -1
  70. package/realtime-client/src/index.ts +6 -6
  71. package/realtime-client/src/{use-pull-family-member.ts → pull-family-member.ts} +1 -1
  72. package/realtime-client/src/{use-pull-mutable-family-member.ts → pull-mutable-family-member.ts} +1 -1
  73. package/realtime-client/src/{use-pull-mutable.ts → pull-mutable.ts} +1 -1
  74. package/realtime-client/src/{use-server-action.ts → server-action.ts} +3 -0
  75. package/realtime-react/dist/index.cjs +31 -17
  76. package/realtime-react/dist/index.cjs.map +1 -1
  77. package/realtime-react/dist/index.d.ts +3 -3
  78. package/realtime-react/dist/index.js +31 -17
  79. package/realtime-react/dist/index.js.map +1 -1
  80. package/realtime-react/src/realtime-context.tsx +2 -3
  81. package/realtime-react/src/use-pull-family-member.ts +6 -2
  82. package/realtime-react/src/use-pull-mutable-family-member.ts +5 -4
  83. package/realtime-react/src/use-pull-mutable.ts +6 -2
  84. package/realtime-react/src/use-pull.ts +5 -1
  85. package/realtime-react/src/use-push.ts +5 -4
  86. package/realtime-react/src/use-server-action.ts +5 -4
  87. package/src/atom.ts +8 -17
  88. package/src/selector.ts +3 -1
  89. package/src/set-state.ts +1 -3
  90. package/src/silo.ts +2 -14
  91. package/src/transaction.ts +17 -6
  92. package/transceivers/set-rtx/dist/index.cjs +2 -1
  93. package/transceivers/set-rtx/dist/index.cjs.map +1 -1
  94. package/transceivers/set-rtx/dist/index.js +2 -1
  95. package/transceivers/set-rtx/dist/index.js.map +1 -1
  96. package/transceivers/set-rtx/src/set-rtx.ts +2 -1
  97. package/internal/src/transaction/redo-transaction.ts +0 -27
  98. package/internal/src/transaction/undo-transaction.ts +0 -27
  99. /package/realtime-client/src/{use-pull.ts → pull.ts} +0 -0
  100. /package/realtime-client/src/{use-push.ts → push.ts} +0 -0
package/data/src/join.ts CHANGED
@@ -1,27 +1,28 @@
1
1
  /* eslint-disable @typescript-eslint/ban-types */
2
2
  import type {
3
3
  AtomFamily,
4
+ MutableAtomFamily,
4
5
  Read,
5
6
  SelectorFamily,
6
7
  Transactors,
7
8
  Write,
8
9
  } from "atom.io"
9
- import { getState, setState } from "atom.io"
10
+ import { dispose, getState, setState } from "atom.io"
10
11
  import type { Store } from "atom.io/internal"
11
12
  import {
12
13
  IMPLICIT,
13
- createAtomFamily,
14
14
  createMutableAtomFamily,
15
+ createRegularAtomFamily,
15
16
  createSelectorFamily,
16
17
  getJsonFamily,
17
18
  } from "atom.io/internal"
18
19
  import type { Json } from "atom.io/json"
20
+ import type { SetRTXJson } from "atom.io/transceivers/set-rtx"
19
21
  import { SetRTX } from "atom.io/transceivers/set-rtx"
20
22
 
21
23
  import type {
22
24
  BaseExternalStoreConfiguration,
23
25
  ExternalStoreConfiguration,
24
- ExternalStoreWithContentConfiguration,
25
26
  JunctionEntries,
26
27
  JunctionSchema,
27
28
  } from "~/packages/rel8/junction/src"
@@ -57,7 +58,7 @@ export type JoinState<
57
58
  readonly [AB in ASide | BSide as AB extends ASide
58
59
  ? `${AB}EntryOf${Capitalize<BSide>}`
59
60
  : `${AB}EntryOf${Capitalize<ASide>}`]: SelectorFamily<
60
- [string, Content] | undefined,
61
+ [string, Content] | null,
61
62
  string
62
63
  >
63
64
  }
@@ -65,7 +66,7 @@ export type JoinState<
65
66
  readonly [AB in ASide | BSide as AB extends ASide
66
67
  ? `${AB}KeyOf${Capitalize<BSide>}`
67
68
  : `${AB}KeyOf${Capitalize<ASide>}`]: SelectorFamily<
68
- string | undefined,
69
+ string | null,
69
70
  string
70
71
  >
71
72
  }
@@ -73,7 +74,7 @@ export type JoinState<
73
74
  ? (Content extends Json.Object
74
75
  ? {
75
76
  readonly [A in ASide as `${A}EntryOf${Capitalize<BSide>}`]: SelectorFamily<
76
- [string, Content] | undefined,
77
+ [string, Content] | null,
77
78
  string
78
79
  >
79
80
  } & {
@@ -84,7 +85,7 @@ export type JoinState<
84
85
  }
85
86
  : {}) & {
86
87
  readonly [A in ASide as `${A}KeyOf${Capitalize<BSide>}`]: SelectorFamily<
87
- string | undefined,
88
+ string | null,
88
89
  string
89
90
  >
90
91
  } & {
@@ -113,338 +114,378 @@ export type JoinState<
113
114
  }
114
115
  : never
115
116
 
116
- export function join<
117
+ export class Join<
117
118
  const ASide extends string,
118
119
  const BSide extends string,
119
- const Cardinality extends Rel8.Cardinality,
120
- >(
121
- options: JoinOptions<ASide, BSide, Cardinality, null>,
122
- defaultContent?: undefined,
123
- store?: Store,
124
- ): {
125
- relations: Junction<ASide, BSide>
126
- findState: JoinState<ASide, BSide, Cardinality, null>
127
- }
128
- export function join<
129
- const ASide extends string,
130
120
  const Cardinality extends `1:1` | `1:n` | `n:n`,
131
- const BSide extends string,
132
- const Content extends Json.Object,
133
- >(
134
- options: JoinOptions<ASide, BSide, Cardinality, Content>,
135
- defaultContent: Content,
136
- store?: Store,
137
- ): {
138
- relations: Junction<ASide, BSide, Content>
139
- findState: JoinState<ASide, BSide, Cardinality, Content>
140
- }
141
- export function join<
142
- ASide extends string,
143
- BSide extends string,
144
- Cardinality extends Rel8.Cardinality,
145
- Content extends Json.Object,
146
- >(
147
- options: JoinOptions<ASide, BSide, Cardinality, Content>,
148
- defaultContent: Content | undefined,
149
- store: Store = IMPLICIT.STORE,
150
- ): {
151
- relations: Junction<ASide, BSide, Content>
152
- findState: JoinState<ASide, BSide, Cardinality, Content>
153
- } {
154
- const a: ASide = options.between[0]
155
- const b: BSide = options.between[1]
156
- const findRelatedKeysState = createMutableAtomFamily<
157
- SetRTX<string>,
158
- string[],
159
- string
160
- >(
161
- {
162
- key: `${options.key}/relatedKeys`,
163
- default: () => new SetRTX(),
164
- mutable: true,
165
- fromJson: (json) => new SetRTX(json),
166
- toJson: (set) => [...set],
167
- },
168
- store,
169
- )
170
- const getRelatedKeys: Read<(key: string) => Set<string> | undefined> = (
171
- { get },
172
- key,
173
- ) => get(findRelatedKeysState(key))
174
- const addRelation: Write<(a: string, b: string) => void> = (
175
- transactors,
176
- a,
177
- b,
178
- ) => {
179
- const aKeys = getRelatedKeys(transactors, a)
180
- const bKeys = getRelatedKeys(transactors, b)
181
- if (aKeys) {
121
+ const Content extends Json.Object | null = null,
122
+ > {
123
+ private transactors: Transactors = TRANSACTORS
124
+ public relations: Junction<ASide, BSide, Content>
125
+ public findState: JoinState<ASide, BSide, Cardinality, Content>
126
+ public core: {
127
+ findRelatedKeysState: MutableAtomFamily<
128
+ SetRTX<string>,
129
+ SetRTXJson<string>,
130
+ string
131
+ >
132
+ }
133
+ public transact(
134
+ transactors: Transactors,
135
+ run: (join: Join<ASide, BSide, Cardinality, Content>) => void,
136
+ ): void {
137
+ this.transactors = transactors
138
+ run(this)
139
+ this.transactors = TRANSACTORS
140
+ }
141
+ public constructor(
142
+ options: JoinOptions<ASide, BSide, Cardinality, Content>,
143
+ defaultContent: Content | undefined,
144
+ store: Store = IMPLICIT.STORE,
145
+ ) {
146
+ const a: ASide = options.between[0]
147
+ const b: BSide = options.between[1]
148
+ const findRelatedKeysState = createMutableAtomFamily<
149
+ SetRTX<string>,
150
+ SetRTXJson<string>,
151
+ string
152
+ >(
153
+ {
154
+ key: `${options.key}/relatedKeys`,
155
+ default: () => new SetRTX(),
156
+ mutable: true,
157
+ fromJson: (json) => SetRTX.fromJSON(json),
158
+ toJson: (set) => set.toJSON(),
159
+ },
160
+ store,
161
+ )
162
+ this.core = { findRelatedKeysState }
163
+ const getRelatedKeys: Read<(key: string) => SetRTX<string>> = (
164
+ { get },
165
+ key,
166
+ ) => get(findRelatedKeysState(key))
167
+ const addRelation: Write<(a: string, b: string) => void> = (
168
+ transactors,
169
+ a,
170
+ b,
171
+ ) => {
172
+ const aKeys = getRelatedKeys(transactors, a)
173
+ const bKeys = getRelatedKeys(transactors, b)
182
174
  transactors.set(findRelatedKeysState(a), aKeys.add(b))
183
- } else {
184
- transactors.set(findRelatedKeysState(a), new SetRTX([b]))
185
- }
186
- if (bKeys) {
187
175
  transactors.set(findRelatedKeysState(b), bKeys.add(a))
188
- } else {
189
- transactors.set(findRelatedKeysState(b), new SetRTX([a]))
190
176
  }
191
- }
192
- const deleteRelation: Write<(a: string, b: string) => void> = (
193
- transactors,
194
- a,
195
- b,
196
- ) => {
197
- const aKeys = getRelatedKeys(transactors, a)
198
- if (aKeys) {
177
+ const deleteRelation: Write<(a: string, b: string) => void> = (
178
+ transactors,
179
+ a,
180
+ b,
181
+ ) => {
182
+ const aKeys = getRelatedKeys(transactors, a)
199
183
  aKeys.delete(b)
200
184
  if (aKeys.size === 0) {
201
- transactors.set(findRelatedKeysState(a), undefined)
185
+ dispose(findRelatedKeysState(a))
202
186
  }
203
187
  const bKeys = getRelatedKeys(transactors, b)
204
- if (bKeys) {
205
- bKeys.delete(a)
206
- if (bKeys.size === 0) {
207
- transactors.set(findRelatedKeysState(b), undefined)
208
- }
188
+ bKeys.delete(a)
189
+ if (bKeys.size === 0) {
190
+ dispose(findRelatedKeysState(b))
209
191
  }
210
192
  }
211
- }
212
- const replaceRelationsSafely: Write<(a: string, bs: string[]) => void> = (
213
- transactors,
214
- a,
215
- bs,
216
- ) => {
217
- const aRelations = getRelatedKeys(transactors, a)
218
- if (aRelations) {
193
+ const replaceRelationsSafely: Write<(a: string, bs: string[]) => void> = (
194
+ transactors,
195
+ a,
196
+ bs,
197
+ ) => {
198
+ const aRelations = getRelatedKeys(transactors, a)
219
199
  for (const b of aRelations) {
220
200
  const bKeys = getRelatedKeys(transactors, b)
221
201
  if (bKeys) {
222
202
  bKeys.delete(a)
223
203
  if (bKeys.size === 0) {
224
- transactors.set(findRelatedKeysState(b), undefined)
204
+ dispose(findRelatedKeysState(b))
225
205
  }
226
206
  }
227
207
  }
228
- }
229
- transactors.set(findRelatedKeysState(a), new SetRTX(bs))
230
- for (const b of bs) {
231
- const bKeys = getRelatedKeys(transactors, b)
232
- if (bKeys) {
208
+ transactors.set(findRelatedKeysState(a), new SetRTX(bs))
209
+ for (const b of bs) {
210
+ const bKeys = getRelatedKeys(transactors, b)
233
211
  bKeys.add(a)
234
- } else {
235
- transactors.set(findRelatedKeysState(b), new SetRTX([a]))
236
212
  }
237
213
  }
238
- }
239
- const replaceRelationsUnsafely: Write<(a: string, bs: string[]) => void> = (
240
- transactors,
241
- a,
242
- bs,
243
- ) => {
244
- transactors.set(findRelatedKeysState(a), new SetRTX(bs))
245
- for (const b of bs) {
246
- let bKeys = getRelatedKeys(transactors, b)
247
- if (bKeys) {
214
+ const replaceRelationsUnsafely: Write<(a: string, bs: string[]) => void> = (
215
+ transactors,
216
+ a,
217
+ bs,
218
+ ) => {
219
+ transactors.set(findRelatedKeysState(a), new SetRTX(bs))
220
+ for (const b of bs) {
221
+ const bKeys = getRelatedKeys(transactors, b)
248
222
  bKeys.add(a)
249
- } else {
250
- bKeys = new SetRTX([a])
251
- transactors.set(findRelatedKeysState(b), bKeys)
252
223
  }
253
224
  }
254
- }
255
- const has: Read<(a: string, b?: string) => boolean> = (transactors, a, b) => {
256
- const aKeys = getRelatedKeys(transactors, a)
257
- return b ? aKeys?.has(b) ?? false : (aKeys?.size ?? 0) > 0 ?? false
258
- }
259
- const baseExternalStoreConfiguration: BaseExternalStoreConfiguration = {
260
- getRelatedKeys: (key) => getRelatedKeys(TRANSACTORS, key),
261
- addRelation: (a, b) => addRelation(TRANSACTORS, a, b),
262
- deleteRelation: (a, b) => deleteRelation(TRANSACTORS, a, b),
263
- replaceRelationsSafely: (a, bs) =>
264
- replaceRelationsSafely(TRANSACTORS, a, bs),
265
- replaceRelationsUnsafely: (a, bs) =>
266
- replaceRelationsUnsafely(TRANSACTORS, a, bs),
267
- has: (a, b) => has(TRANSACTORS, a, b),
268
- }
269
- let externalStore: ExternalStoreConfiguration<Content>
270
- let findContentState: AtomFamily<Content, string>
271
- if (defaultContent) {
272
- findContentState = createAtomFamily<Content, string>(
273
- {
274
- key: `${options.key}/content`,
275
- default: defaultContent,
276
- },
277
- store,
278
- )
279
- const getContent: Read<(key: string) => Content | undefined> = (
280
- { get },
281
- key,
282
- ) => get(findContentState(key))
283
- const setContent: Write<(key: string, content: Content) => void> = (
225
+ const has: Read<(a: string, b?: string) => boolean> = (
284
226
  transactors,
285
- key,
286
- content,
287
- ) => transactors.set(findContentState(key), content)
288
- const deleteContent: Write<(key: string) => void> = (transactors, key) =>
289
- transactors.set(findContentState(key), undefined)
290
- const externalStoreWithContentConfiguration: ExternalStoreWithContentConfiguration<Content> =
291
- {
227
+ a,
228
+ b,
229
+ ) => {
230
+ const aKeys = getRelatedKeys(transactors, a)
231
+ return b ? aKeys.has(b) : aKeys.size > 0
232
+ }
233
+ const baseExternalStoreConfiguration: BaseExternalStoreConfiguration = {
234
+ getRelatedKeys: (key) => getRelatedKeys(this.transactors, key),
235
+ addRelation: (a, b) => addRelation(this.transactors, a, b),
236
+ deleteRelation: (a, b) => deleteRelation(this.transactors, a, b),
237
+ replaceRelationsSafely: (a, bs) =>
238
+ replaceRelationsSafely(this.transactors, a, bs),
239
+ replaceRelationsUnsafely: (a, bs) =>
240
+ replaceRelationsUnsafely(this.transactors, a, bs),
241
+ has: (a, b) => has(this.transactors, a, b),
242
+ }
243
+ let externalStore: ExternalStoreConfiguration<Content>
244
+ let findContentState: AtomFamily<Content, string>
245
+ if (defaultContent) {
246
+ findContentState = createRegularAtomFamily<Content, string>(
247
+ {
248
+ key: `${options.key}/content`,
249
+ default: defaultContent,
250
+ },
251
+ store,
252
+ )
253
+ const getContent: Read<(key: string) => Content | null> = ({ get }, key) =>
254
+ get(findContentState(key))
255
+ const setContent: Write<(key: string, content: Content) => void> = (
256
+ transactors,
257
+ key,
258
+ content,
259
+ ) => transactors.set(findContentState(key), content)
260
+ const deleteContent: Write<(key: string) => void> = (_, key) =>
261
+ dispose(findContentState(key))
262
+ const externalStoreWithContentConfiguration = {
292
263
  getContent: (contentKey: string) => {
293
- const content = getContent(TRANSACTORS, contentKey)
264
+ const content = getContent(this.transactors, contentKey)
294
265
  return content
295
266
  },
296
267
  setContent: (contentKey: string, content: Content) => {
297
- setContent(TRANSACTORS, contentKey, content)
268
+ setContent(this.transactors, contentKey, content)
298
269
  },
299
270
  deleteContent: (contentKey: string) => {
300
- deleteContent(TRANSACTORS, contentKey)
271
+ deleteContent(this.transactors, contentKey)
301
272
  },
302
273
  }
303
- externalStore = Object.assign(
304
- baseExternalStoreConfiguration,
305
- externalStoreWithContentConfiguration,
306
- ) as ExternalStoreConfiguration<Content>
307
- } else {
308
- externalStore =
309
- baseExternalStoreConfiguration as ExternalStoreConfiguration<Content>
310
- }
311
- const relations = new Junction<ASide, BSide, Content>(options, {
312
- externalStore,
313
- makeContentKey: (...args) => args.sort().join(`:`),
314
- })
274
+ externalStore = Object.assign(
275
+ baseExternalStoreConfiguration,
276
+ externalStoreWithContentConfiguration,
277
+ ) as ExternalStoreConfiguration<Content>
278
+ } else {
279
+ externalStore =
280
+ baseExternalStoreConfiguration as ExternalStoreConfiguration<Content>
281
+ }
282
+ const relations = new Junction<ASide, BSide, Content>(options, {
283
+ externalStore,
284
+ makeContentKey: (...args) => args.sort().join(`:`),
285
+ })
315
286
 
316
- const createSingleKeyStateFamily = () =>
317
- createSelectorFamily<string | undefined, string>(
318
- {
319
- key: `${options.key}/singleRelatedKey`,
320
- get:
321
- (key) =>
322
- ({ get }) => {
323
- const relatedKeys = get(findRelatedKeysState(key))
324
- for (const relatedKey of relatedKeys) {
325
- return relatedKey
326
- }
327
- },
328
- },
329
- store,
330
- )
331
- const getMultipleKeyStateFamily = () =>
332
- getJsonFamily(findRelatedKeysState, store)
333
- const createSingleEntryStateFamily = () =>
334
- createSelectorFamily<[string, Content] | undefined, string>(
335
- {
336
- key: `${options.key}/singleRelatedEntry`,
337
- get:
338
- (key) =>
339
- ({ get }) => {
340
- const relatedKeys = get(findRelatedKeysState(key))
341
- for (const relatedKey of relatedKeys) {
342
- const contentKey = relations.makeContentKey(key, relatedKey)
343
- return [relatedKey, get(findContentState(contentKey))]
344
- }
345
- },
346
- },
347
- store,
348
- )
349
- const getMultipleEntryStateFamily = () =>
350
- createSelectorFamily<[string, Content][], string>(
351
- {
352
- key: `${options.key}/multipleRelatedEntries`,
353
- get:
354
- (key) =>
355
- ({ get }) => {
356
- const relatedKeys = get(findRelatedKeysState(key))
357
- return [...relatedKeys].map((relatedKey) => {
358
- const contentKey = relations.makeContentKey(key, relatedKey)
359
- return [relatedKey, get(findContentState(contentKey))]
360
- })
361
- },
362
- },
363
- store,
364
- )
287
+ const createSingleKeyStateFamily = () =>
288
+ createSelectorFamily<string | null, string>(
289
+ {
290
+ key: `${options.key}/singleRelatedKey`,
291
+ get:
292
+ (key) =>
293
+ ({ get }) => {
294
+ const relatedKeys = get(findRelatedKeysState(key))
295
+ for (const relatedKey of relatedKeys) {
296
+ return relatedKey
297
+ }
298
+ return null
299
+ },
300
+ },
301
+ store,
302
+ )
303
+ const getMultipleKeyStateFamily = () => {
304
+ return createSelectorFamily<string[], string>(
305
+ {
306
+ key: `${options.key}/multipleRelatedKeys`,
307
+ get:
308
+ (key) =>
309
+ ({ get }) => {
310
+ const jsonFamily = getJsonFamily(findRelatedKeysState, store)
311
+ const json = get(jsonFamily(key))
312
+ return json.members
313
+ },
314
+ },
315
+ store,
316
+ )
317
+ }
318
+ const createSingleEntryStateFamily = () =>
319
+ createSelectorFamily<[string, Content] | null, string>(
320
+ {
321
+ key: `${options.key}/singleRelatedEntry`,
322
+ get:
323
+ (key) =>
324
+ ({ get }) => {
325
+ const relatedKeys = get(findRelatedKeysState(key))
326
+ for (const relatedKey of relatedKeys) {
327
+ const contentKey = relations.makeContentKey(key, relatedKey)
328
+ return [relatedKey, get(findContentState(contentKey))]
329
+ }
330
+ return null
331
+ },
332
+ },
333
+ store,
334
+ )
335
+ const getMultipleEntryStateFamily = () =>
336
+ createSelectorFamily<[string, Content][], string>(
337
+ {
338
+ key: `${options.key}/multipleRelatedEntries`,
339
+ get:
340
+ (key) =>
341
+ ({ get }) => {
342
+ const jsonFamily = getJsonFamily(findRelatedKeysState, store)
343
+ const json = get(jsonFamily(key))
344
+ return json.members.map((relatedKey) => {
345
+ const contentKey = relations.makeContentKey(key, relatedKey)
346
+ return [relatedKey, get(findContentState(contentKey))]
347
+ })
348
+ },
349
+ },
350
+ store,
351
+ )
365
352
 
366
- switch (options.cardinality) {
367
- case `1:1`: {
368
- const findSingleRelatedKeyState = createSingleKeyStateFamily()
369
- const stateKeyA = `${a}KeyOf${capitalize(b)}` as const
370
- const stateKeyB = `${b}KeyOf${capitalize(a)}` as const
371
- const findStateBase = {
372
- [stateKeyA]: findSingleRelatedKeyState,
373
- [stateKeyB]: findSingleRelatedKeyState,
374
- } as JoinState<ASide, BSide, Cardinality, Content>
375
- let findState: JoinState<ASide, BSide, Cardinality, Content>
376
- if (defaultContent) {
377
- const findSingleRelatedEntryState = createSingleEntryStateFamily()
378
- const entriesStateKeyA = `${a}EntryOf${capitalize(b)}` as const
379
- const entriesStateKeyB = `${b}EntryOf${capitalize(a)}` as const
380
- const findStateWithContent = {
381
- [entriesStateKeyA]: findSingleRelatedEntryState,
382
- [entriesStateKeyB]: findSingleRelatedEntryState,
353
+ switch (options.cardinality) {
354
+ case `1:1`: {
355
+ const findSingleRelatedKeyState = createSingleKeyStateFamily()
356
+ const stateKeyA = `${a}KeyOf${capitalize(b)}` as const
357
+ const stateKeyB = `${b}KeyOf${capitalize(a)}` as const
358
+ const findStateBase = {
359
+ [stateKeyA]: findSingleRelatedKeyState,
360
+ [stateKeyB]: findSingleRelatedKeyState,
361
+ } as JoinState<ASide, BSide, Cardinality, Content>
362
+ let findState: JoinState<ASide, BSide, Cardinality, Content>
363
+ if (defaultContent) {
364
+ const findSingleRelatedEntryState = createSingleEntryStateFamily()
365
+ const entriesStateKeyA = `${a}EntryOf${capitalize(b)}` as const
366
+ const entriesStateKeyB = `${b}EntryOf${capitalize(a)}` as const
367
+ const findStateWithContent = {
368
+ [entriesStateKeyA]: findSingleRelatedEntryState,
369
+ [entriesStateKeyB]: findSingleRelatedEntryState,
370
+ }
371
+ findState = Object.assign(findStateBase, findStateWithContent)
372
+ } else {
373
+ findState = findStateBase
383
374
  }
384
- findState = Object.assign(findStateBase, findStateWithContent)
385
- } else {
386
- findState = findStateBase
387
- }
388
- return {
389
- relations,
390
- findState,
375
+ this.relations = relations
376
+ this.findState = findState
377
+ break
391
378
  }
392
- }
393
- case `1:n`: {
394
- const findSingleRelatedKeyState = createSingleKeyStateFamily()
395
- const findMultipleRelatedKeysState = getMultipleKeyStateFamily()
396
- const stateKeyA = `${a}KeyOf${capitalize(b)}` as const
397
- const stateKeyB = `${b}KeysOf${capitalize(a)}` as const
398
- const findStateBase = {
399
- [stateKeyA]: findSingleRelatedKeyState,
400
- [stateKeyB]: findMultipleRelatedKeysState,
401
- } as JoinState<ASide, BSide, Cardinality, Content>
402
- let findState: JoinState<ASide, BSide, Cardinality, Content>
403
- if (defaultContent) {
404
- const findSingleRelatedEntryState = createSingleEntryStateFamily()
405
- const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
406
- const entriesStateKeyA = `${a}EntryOf${capitalize(b)}` as const
407
- const entriesStateKeyB = `${b}EntriesOf${capitalize(a)}` as const
408
- const findStateWithContent = {
409
- [entriesStateKeyA]: findSingleRelatedEntryState,
410
- [entriesStateKeyB]: findMultipleRelatedEntriesState,
379
+ case `1:n`: {
380
+ const findSingleRelatedKeyState = createSingleKeyStateFamily()
381
+ const findMultipleRelatedKeysState = getMultipleKeyStateFamily()
382
+ const stateKeyA = `${a}KeyOf${capitalize(b)}` as const
383
+ const stateKeyB = `${b}KeysOf${capitalize(a)}` as const
384
+ const findStateBase = {
385
+ [stateKeyA]: findSingleRelatedKeyState,
386
+ [stateKeyB]: findMultipleRelatedKeysState,
387
+ } as JoinState<ASide, BSide, Cardinality, Content>
388
+ let findState: JoinState<ASide, BSide, Cardinality, Content>
389
+ if (defaultContent) {
390
+ const findSingleRelatedEntryState = createSingleEntryStateFamily()
391
+ const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
392
+ const entriesStateKeyA = `${a}EntryOf${capitalize(b)}` as const
393
+ const entriesStateKeyB = `${b}EntriesOf${capitalize(a)}` as const
394
+ const findStateWithContent = {
395
+ [entriesStateKeyA]: findSingleRelatedEntryState,
396
+ [entriesStateKeyB]: findMultipleRelatedEntriesState,
397
+ }
398
+ findState = Object.assign(findStateBase, findStateWithContent)
399
+ } else {
400
+ findState = findStateBase
411
401
  }
412
- findState = Object.assign(findStateBase, findStateWithContent)
413
- } else {
414
- findState = findStateBase
402
+ this.relations = relations
403
+ this.findState = findState
404
+ break
415
405
  }
416
- return {
417
- relations,
418
- findState,
419
- }
420
- }
421
- case `n:n`: {
422
- const findMultipleRelatedKeysState = getMultipleKeyStateFamily()
423
- const stateKeyA = `${a}KeysOf${capitalize(b)}` as const
424
- const stateKeyB = `${b}KeysOf${capitalize(a)}` as const
425
- const findStateBase = {
426
- [stateKeyA]: findMultipleRelatedKeysState,
427
- [stateKeyB]: findMultipleRelatedKeysState,
428
- } as JoinState<ASide, BSide, Cardinality, Content>
429
- let findState: JoinState<ASide, BSide, Cardinality, Content>
430
- if (defaultContent) {
431
- const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
432
- const entriesStateKeyA = `${a}EntriesOf${capitalize(b)}` as const
433
- const entriesStateKeyB = `${b}EntriesOf${capitalize(a)}` as const
434
- const findStateWithContent = {
435
- [entriesStateKeyA]: findMultipleRelatedEntriesState,
436
- [entriesStateKeyB]: findMultipleRelatedEntriesState,
406
+ default: {
407
+ const findMultipleRelatedKeysState = getMultipleKeyStateFamily()
408
+ const stateKeyA = `${a}KeysOf${capitalize(b)}` as const
409
+ const stateKeyB = `${b}KeysOf${capitalize(a)}` as const
410
+ const findStateBase = {
411
+ [stateKeyA]: findMultipleRelatedKeysState,
412
+ [stateKeyB]: findMultipleRelatedKeysState,
413
+ } as JoinState<ASide, BSide, Cardinality, Content>
414
+ let findState: JoinState<ASide, BSide, Cardinality, Content>
415
+ if (defaultContent) {
416
+ const findMultipleRelatedEntriesState = getMultipleEntryStateFamily()
417
+ const entriesStateKeyA = `${a}EntriesOf${capitalize(b)}` as const
418
+ const entriesStateKeyB = `${b}EntriesOf${capitalize(a)}` as const
419
+ const findStateWithContent = {
420
+ [entriesStateKeyA]: findMultipleRelatedEntriesState,
421
+ [entriesStateKeyB]: findMultipleRelatedEntriesState,
422
+ }
423
+ findState = Object.assign(findStateBase, findStateWithContent)
424
+ } else {
425
+ findState = findStateBase
437
426
  }
438
- findState = Object.assign(findStateBase, findStateWithContent)
439
- } else {
440
- findState = findStateBase
441
- }
442
- return {
443
- relations,
444
- findState,
427
+ this.relations = relations
428
+ this.findState = findState
445
429
  }
446
430
  }
447
- default:
448
- throw new Error(`Invalid cardinality: ${options.cardinality}`)
449
431
  }
450
432
  }
433
+ export function join<
434
+ const ASide extends string,
435
+ const BSide extends string,
436
+ const Cardinality extends `1:1` | `1:n` | `n:n`,
437
+ >(
438
+ options: JoinOptions<ASide, BSide, Cardinality, null>,
439
+ defaultContent?: undefined,
440
+ store?: Store,
441
+ ): {
442
+ readonly relations: Junction<ASide, BSide, null>
443
+ readonly findState: JoinState<ASide, BSide, Cardinality, null>
444
+ readonly transact: (
445
+ transactors: Transactors,
446
+ run: (join: Join<ASide, BSide, Cardinality, null>) => void,
447
+ ) => void
448
+ readonly core: {
449
+ readonly findRelatedKeysState: MutableAtomFamily<
450
+ SetRTX<string>,
451
+ SetRTXJson<string>,
452
+ string
453
+ >
454
+ }
455
+ }
456
+ export function join<
457
+ const ASide extends string,
458
+ const BSide extends string,
459
+ const Cardinality extends `1:1` | `1:n` | `n:n`,
460
+ const Content extends Json.Object,
461
+ >(
462
+ options: JoinOptions<ASide, BSide, Cardinality, Content>,
463
+ defaultContent: Content,
464
+ store?: Store,
465
+ ): {
466
+ readonly relations: Junction<ASide, BSide, Content>
467
+ readonly findState: JoinState<ASide, BSide, Cardinality, Content>
468
+ readonly transact: (
469
+ transactors: Transactors,
470
+ run: (join: Join<ASide, BSide, Cardinality, Content>) => void,
471
+ ) => void
472
+ readonly core: {
473
+ readonly findRelatedKeysState: MutableAtomFamily<
474
+ SetRTX<string>,
475
+ SetRTXJson<string>,
476
+ string
477
+ >
478
+ }
479
+ }
480
+ export function join<
481
+ ASide extends string,
482
+ BSide extends string,
483
+ Cardinality extends `1:1` | `1:n` | `n:n`,
484
+ Content extends Json.Object,
485
+ >(
486
+ options: JoinOptions<ASide, BSide, Cardinality, Content>,
487
+ defaultContent: Content | undefined,
488
+ store: Store = IMPLICIT.STORE,
489
+ ): Join<ASide, BSide, Cardinality, Content> {
490
+ return new Join(options, defaultContent, store)
491
+ }