@instantdb/core 0.22.86-experimental.separate-attrs.20122276424.1 → 0.22.86-experimental.split-store.20178922132.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.
- package/dist/commonjs/Reactor.d.ts +20 -6
- package/dist/commonjs/Reactor.d.ts.map +1 -1
- package/dist/commonjs/Reactor.js +97 -42
- package/dist/commonjs/Reactor.js.map +1 -1
- package/dist/commonjs/SyncTable.d.ts +4 -1
- package/dist/commonjs/SyncTable.d.ts.map +1 -1
- package/dist/commonjs/SyncTable.js +35 -37
- package/dist/commonjs/SyncTable.js.map +1 -1
- package/dist/commonjs/instaml.d.ts +17 -4
- package/dist/commonjs/instaml.d.ts.map +1 -1
- package/dist/commonjs/instaml.js +105 -76
- package/dist/commonjs/instaml.js.map +1 -1
- package/dist/commonjs/instaql.d.ts +2 -1
- package/dist/commonjs/instaql.d.ts.map +1 -1
- package/dist/commonjs/instaql.js +65 -63
- package/dist/commonjs/instaql.js.map +1 -1
- package/dist/commonjs/reactorTypes.d.ts +29 -0
- package/dist/commonjs/reactorTypes.d.ts.map +1 -0
- package/dist/commonjs/reactorTypes.js +3 -0
- package/dist/commonjs/reactorTypes.js.map +1 -0
- package/dist/commonjs/store.d.ts +44 -21
- package/dist/commonjs/store.d.ts.map +1 -1
- package/dist/commonjs/store.js +164 -69
- package/dist/commonjs/store.js.map +1 -1
- package/dist/esm/Reactor.d.ts +20 -6
- package/dist/esm/Reactor.d.ts.map +1 -1
- package/dist/esm/Reactor.js +98 -43
- package/dist/esm/Reactor.js.map +1 -1
- package/dist/esm/SyncTable.d.ts +4 -1
- package/dist/esm/SyncTable.d.ts.map +1 -1
- package/dist/esm/SyncTable.js +35 -37
- package/dist/esm/SyncTable.js.map +1 -1
- package/dist/esm/instaml.d.ts +17 -4
- package/dist/esm/instaml.d.ts.map +1 -1
- package/dist/esm/instaml.js +102 -71
- package/dist/esm/instaml.js.map +1 -1
- package/dist/esm/instaql.d.ts +2 -1
- package/dist/esm/instaql.d.ts.map +1 -1
- package/dist/esm/instaql.js +65 -63
- package/dist/esm/instaql.js.map +1 -1
- package/dist/esm/reactorTypes.d.ts +29 -0
- package/dist/esm/reactorTypes.d.ts.map +1 -0
- package/dist/esm/reactorTypes.js +2 -0
- package/dist/esm/reactorTypes.js.map +1 -0
- package/dist/esm/store.d.ts +44 -21
- package/dist/esm/store.d.ts.map +1 -1
- package/dist/esm/store.js +161 -69
- package/dist/esm/store.js.map +1 -1
- package/dist/standalone/index.js +1517 -1345
- package/dist/standalone/index.umd.cjs +3 -3
- package/package.json +2 -2
- package/src/Reactor.js +126 -58
- package/src/SyncTable.ts +85 -45
- package/src/{instaml.js → instaml.ts} +195 -95
- package/src/instaql.ts +86 -60
- package/src/reactorTypes.ts +32 -0
- package/src/store.ts +209 -79
|
@@ -1,13 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
allMapValues,
|
|
3
|
+
AttrsStore,
|
|
4
|
+
getAttrByFwdIdentName,
|
|
5
|
+
getAttrByReverseIdentName,
|
|
6
|
+
Store,
|
|
7
|
+
} from './store.ts';
|
|
2
8
|
import { getOps, isLookup, parseLookup } from './instatx.ts';
|
|
3
9
|
import { immutableRemoveUndefined } from './utils/object.js';
|
|
4
10
|
import { coerceToDate } from './utils/dates.ts';
|
|
5
11
|
import uuid from './utils/uuid.ts';
|
|
12
|
+
import {
|
|
13
|
+
EntitiesWithLinks,
|
|
14
|
+
IContainEntitiesAndLinks,
|
|
15
|
+
LinkDef,
|
|
16
|
+
} from './schemaTypes.ts';
|
|
17
|
+
import { InstantDBAttr, InstantDBIdent } from './attrTypes.ts';
|
|
18
|
+
|
|
19
|
+
export type AttrMapping = {
|
|
20
|
+
attrIdMap: Record<string, string>;
|
|
21
|
+
refSwapAttrIds: Set<string>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type TXStep = any[];
|
|
6
25
|
|
|
7
26
|
// Rewrites optimistic attrs with the attrs we get back from the server.
|
|
8
|
-
export function rewriteStep(attrMapping, txStep) {
|
|
27
|
+
export function rewriteStep(attrMapping: AttrMapping, txStep: TXStep): TXStep {
|
|
9
28
|
const { attrIdMap, refSwapAttrIds } = attrMapping;
|
|
10
|
-
const rewritten = [];
|
|
29
|
+
const rewritten: TXStep = [];
|
|
11
30
|
for (const part of txStep) {
|
|
12
31
|
const newValue = attrIdMap[part];
|
|
13
32
|
|
|
@@ -35,22 +54,6 @@ export function rewriteStep(attrMapping, txStep) {
|
|
|
35
54
|
return rewritten;
|
|
36
55
|
}
|
|
37
56
|
|
|
38
|
-
export function getAttrByFwdIdentName(attrs, inputEtype, inputIdentName) {
|
|
39
|
-
return Object.values(attrs).find((attr) => {
|
|
40
|
-
const [_id, etype, label] = attr['forward-identity'];
|
|
41
|
-
return etype === inputEtype && label === inputIdentName;
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function getAttrByReverseIdentName(attrs, inputEtype, inputIdentName) {
|
|
46
|
-
return Object.values(attrs).find((attr) => {
|
|
47
|
-
const revIdent = attr['reverse-identity'];
|
|
48
|
-
if (!revIdent) return false;
|
|
49
|
-
const [_id, etype, label] = revIdent;
|
|
50
|
-
return etype === inputEtype && label === inputIdentName;
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
57
|
function explodeLookupRef(eid) {
|
|
55
58
|
if (Array.isArray(eid)) {
|
|
56
59
|
return eid;
|
|
@@ -64,7 +67,7 @@ function explodeLookupRef(eid) {
|
|
|
64
67
|
return entries[0];
|
|
65
68
|
}
|
|
66
69
|
|
|
67
|
-
function isRefLookupIdent(attrs, etype, identName) {
|
|
70
|
+
function isRefLookupIdent(attrs: AttrsStore, etype: string, identName: string) {
|
|
68
71
|
return (
|
|
69
72
|
identName.indexOf('.') !== -1 &&
|
|
70
73
|
// attr names can have `.` in them, so use the attr we find with a `.`
|
|
@@ -82,7 +85,11 @@ function extractRefLookupFwdName(identName) {
|
|
|
82
85
|
return fwdName;
|
|
83
86
|
}
|
|
84
87
|
|
|
85
|
-
function lookupIdentToAttr(
|
|
88
|
+
function lookupIdentToAttr(
|
|
89
|
+
attrs: AttrsStore,
|
|
90
|
+
etype: string,
|
|
91
|
+
identName: string,
|
|
92
|
+
) {
|
|
86
93
|
if (!isRefLookupIdent(attrs, etype, identName)) {
|
|
87
94
|
return getAttrByFwdIdentName(attrs, etype, identName);
|
|
88
95
|
}
|
|
@@ -109,7 +116,7 @@ function lookupPairOfEid(eid) {
|
|
|
109
116
|
: explodeLookupRef(eid);
|
|
110
117
|
}
|
|
111
118
|
|
|
112
|
-
function extractLookup(attrs, etype, eid) {
|
|
119
|
+
function extractLookup(attrs: AttrsStore, etype: string, eid: string) {
|
|
113
120
|
const lookupPair = lookupPairOfEid(eid);
|
|
114
121
|
|
|
115
122
|
if (lookupPair === null) {
|
|
@@ -124,7 +131,12 @@ function extractLookup(attrs, etype, eid) {
|
|
|
124
131
|
return [attr.id, value];
|
|
125
132
|
}
|
|
126
133
|
|
|
127
|
-
function withIdAttrForLookup(
|
|
134
|
+
function withIdAttrForLookup(
|
|
135
|
+
attrs: AttrsStore,
|
|
136
|
+
etype: string,
|
|
137
|
+
eidA: string,
|
|
138
|
+
txSteps: TXStep[],
|
|
139
|
+
) {
|
|
128
140
|
const lookup = extractLookup(attrs, etype, eidA);
|
|
129
141
|
if (!Array.isArray(lookup)) {
|
|
130
142
|
return txSteps;
|
|
@@ -132,63 +144,72 @@ function withIdAttrForLookup(attrs, etype, eidA, txSteps) {
|
|
|
132
144
|
const idTuple = [
|
|
133
145
|
'add-triple',
|
|
134
146
|
lookup,
|
|
135
|
-
getAttrByFwdIdentName(attrs, etype, 'id')
|
|
147
|
+
getAttrByFwdIdentName(attrs, etype, 'id')?.id,
|
|
136
148
|
lookup,
|
|
137
149
|
];
|
|
138
150
|
return [idTuple].concat(txSteps);
|
|
139
151
|
}
|
|
140
152
|
|
|
141
|
-
function expandLink({
|
|
153
|
+
function expandLink({ attrsStore }: Ctx, [etype, eidA, obj]) {
|
|
142
154
|
const addTriples = Object.entries(obj).flatMap(([label, eidOrEids]) => {
|
|
143
155
|
const eids = Array.isArray(eidOrEids) ? eidOrEids : [eidOrEids];
|
|
144
|
-
const fwdAttr = getAttrByFwdIdentName(
|
|
145
|
-
const revAttr = getAttrByReverseIdentName(
|
|
156
|
+
const fwdAttr = getAttrByFwdIdentName(attrsStore, etype, label);
|
|
157
|
+
const revAttr = getAttrByReverseIdentName(attrsStore, etype, label);
|
|
146
158
|
return eids.map((eidB) => {
|
|
147
159
|
const txStep = fwdAttr
|
|
148
160
|
? [
|
|
149
161
|
'add-triple',
|
|
150
|
-
extractLookup(
|
|
162
|
+
extractLookup(attrsStore, etype, eidA),
|
|
151
163
|
fwdAttr.id,
|
|
152
|
-
|
|
164
|
+
// XXX: Better error here
|
|
165
|
+
extractLookup(attrsStore, fwdAttr!['reverse-identity']![1], eidB),
|
|
153
166
|
]
|
|
154
167
|
: [
|
|
155
168
|
'add-triple',
|
|
156
|
-
|
|
157
|
-
revAttr
|
|
158
|
-
|
|
169
|
+
// XXX: Better error here
|
|
170
|
+
extractLookup(attrsStore, revAttr!['forward-identity']![1], eidB),
|
|
171
|
+
revAttr?.id,
|
|
172
|
+
extractLookup(attrsStore, etype, eidA),
|
|
159
173
|
];
|
|
160
174
|
return txStep;
|
|
161
175
|
});
|
|
162
176
|
});
|
|
163
|
-
return withIdAttrForLookup(
|
|
177
|
+
return withIdAttrForLookup(attrsStore, etype, eidA, addTriples);
|
|
164
178
|
}
|
|
165
179
|
|
|
166
|
-
function expandUnlink({
|
|
180
|
+
function expandUnlink({ attrsStore }: Ctx, [etype, eidA, obj]) {
|
|
167
181
|
const retractTriples = Object.entries(obj).flatMap(([label, eidOrEids]) => {
|
|
168
182
|
const eids = Array.isArray(eidOrEids) ? eidOrEids : [eidOrEids];
|
|
169
|
-
const fwdAttr = getAttrByFwdIdentName(
|
|
170
|
-
const revAttr = getAttrByReverseIdentName(
|
|
183
|
+
const fwdAttr = getAttrByFwdIdentName(attrsStore, etype, label);
|
|
184
|
+
const revAttr = getAttrByReverseIdentName(attrsStore, etype, label);
|
|
171
185
|
return eids.map((eidB) => {
|
|
172
186
|
const txStep = fwdAttr
|
|
173
187
|
? [
|
|
174
188
|
'retract-triple',
|
|
175
|
-
extractLookup(
|
|
189
|
+
extractLookup(attrsStore, etype, eidA),
|
|
176
190
|
fwdAttr.id,
|
|
177
|
-
|
|
191
|
+
// XXX: Better error here
|
|
192
|
+
extractLookup(attrsStore, fwdAttr!['reverse-identity']![1], eidB),
|
|
178
193
|
]
|
|
179
194
|
: [
|
|
180
195
|
'retract-triple',
|
|
181
|
-
|
|
182
|
-
revAttr
|
|
183
|
-
|
|
196
|
+
// XXX: Better error here
|
|
197
|
+
extractLookup(attrsStore, revAttr!['forward-identity'][1], eidB),
|
|
198
|
+
revAttr!.id,
|
|
199
|
+
extractLookup(attrsStore, etype, eidA),
|
|
184
200
|
];
|
|
185
201
|
return txStep;
|
|
186
202
|
});
|
|
187
203
|
});
|
|
188
|
-
return withIdAttrForLookup(
|
|
204
|
+
return withIdAttrForLookup(attrsStore, etype, eidA, retractTriples);
|
|
189
205
|
}
|
|
190
206
|
|
|
191
|
-
function checkEntityExists(
|
|
207
|
+
function checkEntityExists(
|
|
208
|
+
stores: (Store | undefined)[],
|
|
209
|
+
attrsStore: AttrsStore,
|
|
210
|
+
etype: string,
|
|
211
|
+
eid: string,
|
|
212
|
+
) {
|
|
192
213
|
if (Array.isArray(eid)) {
|
|
193
214
|
// lookup ref
|
|
194
215
|
const [entity_a, entity_v] = eid;
|
|
@@ -209,7 +230,7 @@ function checkEntityExists(stores, etype, eid) {
|
|
|
209
230
|
const av = store?.eav.get(eid);
|
|
210
231
|
if (av) {
|
|
211
232
|
for (const attr_id of av.keys()) {
|
|
212
|
-
if (
|
|
233
|
+
if (attrsStore.getAttr(attr_id)?.['forward-identity'][1] == etype) {
|
|
213
234
|
return true;
|
|
214
235
|
}
|
|
215
236
|
}
|
|
@@ -219,26 +240,34 @@ function checkEntityExists(stores, etype, eid) {
|
|
|
219
240
|
return false;
|
|
220
241
|
}
|
|
221
242
|
|
|
222
|
-
|
|
243
|
+
type Ctx = {
|
|
244
|
+
stores: (Store | undefined)[];
|
|
245
|
+
attrsStore: AttrsStore;
|
|
246
|
+
schema: Schema;
|
|
247
|
+
useDateObjects: boolean | null;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
function convertOpts({ stores, attrsStore }: Ctx, [etype, eid, obj_, opts]) {
|
|
223
251
|
return opts?.upsert === false
|
|
224
252
|
? { mode: 'update' }
|
|
225
253
|
: opts?.upsert === true
|
|
226
254
|
? null
|
|
227
|
-
: checkEntityExists(stores, etype, eid)
|
|
255
|
+
: checkEntityExists(stores, attrsStore, etype, eid)
|
|
228
256
|
? { mode: 'update' }
|
|
229
257
|
: null; // auto mode chooses between update and upsert, not update and create, just in case
|
|
230
258
|
}
|
|
231
259
|
|
|
232
|
-
function expandCreate(ctx, step) {
|
|
233
|
-
const {
|
|
260
|
+
function expandCreate(ctx: Ctx, step) {
|
|
261
|
+
const { attrsStore } = ctx;
|
|
234
262
|
const [etype, eid, obj_, opts] = step;
|
|
235
263
|
const obj = immutableRemoveUndefined(obj_);
|
|
236
|
-
const lookup = extractLookup(
|
|
264
|
+
const lookup = extractLookup(attrsStore, etype, eid);
|
|
237
265
|
// id first so that we don't clobber updates on the lookup field
|
|
238
266
|
const attrTuples = [['id', lookup]]
|
|
239
267
|
.concat(Object.entries(obj))
|
|
240
|
-
.map(([identName, value]) => {
|
|
241
|
-
|
|
268
|
+
.map(([identName, value]: [string, any]) => {
|
|
269
|
+
// XXX: missing attr?
|
|
270
|
+
const attr = getAttrByFwdIdentName(attrsStore, etype, identName)!;
|
|
242
271
|
|
|
243
272
|
if (attr['checked-data-type'] === 'date' && ctx.useDateObjects) {
|
|
244
273
|
value = coerceToDate(value);
|
|
@@ -249,17 +278,17 @@ function expandCreate(ctx, step) {
|
|
|
249
278
|
return attrTuples;
|
|
250
279
|
}
|
|
251
280
|
|
|
252
|
-
function expandUpdate(ctx, step) {
|
|
253
|
-
const {
|
|
281
|
+
function expandUpdate(ctx: Ctx, step) {
|
|
282
|
+
const { attrsStore } = ctx;
|
|
254
283
|
const [etype, eid, obj_, opts] = step;
|
|
255
284
|
const obj = immutableRemoveUndefined(obj_);
|
|
256
|
-
const lookup = extractLookup(
|
|
285
|
+
const lookup = extractLookup(attrsStore, etype, eid);
|
|
257
286
|
const serverOpts = convertOpts(ctx, [etype, lookup, obj_, opts]);
|
|
258
287
|
// id first so that we don't clobber updates on the lookup field
|
|
259
288
|
const attrTuples = [['id', lookup]]
|
|
260
289
|
.concat(Object.entries(obj))
|
|
261
|
-
.map(([identName, value]) => {
|
|
262
|
-
const attr = getAttrByFwdIdentName(
|
|
290
|
+
.map(([identName, value]: [string, any]) => {
|
|
291
|
+
const attr = getAttrByFwdIdentName(attrsStore, etype, identName)!;
|
|
263
292
|
|
|
264
293
|
if (attr['checked-data-type'] === 'date' && ctx.useDateObjects) {
|
|
265
294
|
value = coerceToDate(value);
|
|
@@ -276,19 +305,19 @@ function expandUpdate(ctx, step) {
|
|
|
276
305
|
return attrTuples;
|
|
277
306
|
}
|
|
278
307
|
|
|
279
|
-
function expandDelete({
|
|
280
|
-
const lookup = extractLookup(
|
|
308
|
+
function expandDelete({ attrsStore }: Ctx, [etype, eid]) {
|
|
309
|
+
const lookup = extractLookup(attrsStore, etype, eid);
|
|
281
310
|
return [['delete-entity', lookup, etype]];
|
|
282
311
|
}
|
|
283
312
|
|
|
284
|
-
function expandDeepMerge(ctx, step) {
|
|
285
|
-
const {
|
|
313
|
+
function expandDeepMerge(ctx: Ctx, step) {
|
|
314
|
+
const { attrsStore } = ctx;
|
|
286
315
|
const [etype, eid, obj_, opts] = step;
|
|
287
316
|
const obj = immutableRemoveUndefined(obj_);
|
|
288
|
-
const lookup = extractLookup(
|
|
317
|
+
const lookup = extractLookup(attrsStore, etype, eid);
|
|
289
318
|
const serverOpts = convertOpts(ctx, [etype, lookup, obj_, opts]);
|
|
290
319
|
const attrTuples = Object.entries(obj).map(([identName, value]) => {
|
|
291
|
-
const attr = getAttrByFwdIdentName(
|
|
320
|
+
const attr = getAttrByFwdIdentName(attrsStore, etype, identName)!;
|
|
292
321
|
return [
|
|
293
322
|
'deep-merge-triple',
|
|
294
323
|
lookup,
|
|
@@ -301,7 +330,7 @@ function expandDeepMerge(ctx, step) {
|
|
|
301
330
|
const idTuple = [
|
|
302
331
|
'add-triple',
|
|
303
332
|
lookup,
|
|
304
|
-
getAttrByFwdIdentName(
|
|
333
|
+
getAttrByFwdIdentName(attrsStore, etype, 'id')!.id,
|
|
305
334
|
lookup,
|
|
306
335
|
...(serverOpts ? [serverOpts] : []),
|
|
307
336
|
];
|
|
@@ -310,8 +339,8 @@ function expandDeepMerge(ctx, step) {
|
|
|
310
339
|
return [idTuple].concat(attrTuples);
|
|
311
340
|
}
|
|
312
341
|
|
|
313
|
-
function expandRuleParams({
|
|
314
|
-
const lookup = extractLookup(
|
|
342
|
+
function expandRuleParams({ attrsStore }: Ctx, [etype, eid, ruleParams]) {
|
|
343
|
+
const lookup = extractLookup(attrsStore, etype, eid);
|
|
315
344
|
return [['rule-params', lookup, etype, ruleParams]];
|
|
316
345
|
}
|
|
317
346
|
|
|
@@ -325,7 +354,7 @@ function removeIdFromArgs(step) {
|
|
|
325
354
|
return [op, etype, eid, newObj, ...(opts ? [opts] : [])];
|
|
326
355
|
}
|
|
327
356
|
|
|
328
|
-
function toTxSteps(ctx, step) {
|
|
357
|
+
function toTxSteps(ctx: Ctx, step) {
|
|
329
358
|
const [action, ...args] = removeIdFromArgs(step);
|
|
330
359
|
switch (action) {
|
|
331
360
|
case 'merge':
|
|
@@ -398,8 +427,12 @@ function createObjectAttr(schema, etype, label, props) {
|
|
|
398
427
|
};
|
|
399
428
|
}
|
|
400
429
|
|
|
401
|
-
|
|
402
|
-
|
|
430
|
+
type Link = LinkDef<any, any, any, any, any, any, any>;
|
|
431
|
+
type Schema = IContainEntitiesAndLinks<any, any>;
|
|
432
|
+
|
|
433
|
+
function findSchemaLink(schema: Schema, etype, label): Link | undefined {
|
|
434
|
+
const links: Link[] = Object.values(schema.links);
|
|
435
|
+
const found = links.find((x: Link) => {
|
|
403
436
|
return (
|
|
404
437
|
(x.forward.on === etype && x.forward.label === label) ||
|
|
405
438
|
(x.reverse.on === etype && x.reverse.label === label)
|
|
@@ -408,7 +441,7 @@ function findSchemaLink(schema, etype, label) {
|
|
|
408
441
|
return found;
|
|
409
442
|
}
|
|
410
443
|
|
|
411
|
-
function refPropsFromSchema(schema, etype, label) {
|
|
444
|
+
function refPropsFromSchema(schema: Schema, etype, label) {
|
|
412
445
|
const found = findSchemaLink(schema, etype, label);
|
|
413
446
|
if (!found) {
|
|
414
447
|
throw new Error(`Couldn't find the link ${etype}.${label} in your schema`);
|
|
@@ -424,18 +457,26 @@ function refPropsFromSchema(schema, etype, label) {
|
|
|
424
457
|
};
|
|
425
458
|
}
|
|
426
459
|
|
|
427
|
-
function createRefAttr(
|
|
460
|
+
function createRefAttr(
|
|
461
|
+
schema: Schema,
|
|
462
|
+
etype: string,
|
|
463
|
+
label: string,
|
|
464
|
+
props?: Partial<InstantDBAttr> | undefined,
|
|
465
|
+
): InstantDBAttr {
|
|
428
466
|
const schemaRefProps = schema
|
|
429
467
|
? refPropsFromSchema(schema, etype, label)
|
|
430
468
|
: null;
|
|
431
469
|
const attrId = uuid();
|
|
432
|
-
const fwdIdent = [uuid(), etype, label];
|
|
433
|
-
const revIdent = [uuid(), label, etype];
|
|
470
|
+
const fwdIdent: InstantDBIdent = [uuid(), etype, label];
|
|
471
|
+
const revIdent: InstantDBIdent = [uuid(), label, etype];
|
|
434
472
|
return {
|
|
435
473
|
id: attrId,
|
|
474
|
+
// @ts-ignore: ts thinks it's any[]
|
|
436
475
|
'forward-identity': fwdIdent,
|
|
476
|
+
// @ts-ignore: ts thinks it's any[]
|
|
437
477
|
'reverse-identity': revIdent,
|
|
438
478
|
'value-type': 'ref',
|
|
479
|
+
// @ts-ignore: ts thinks it's type string
|
|
439
480
|
cardinality: 'many',
|
|
440
481
|
'unique?': false,
|
|
441
482
|
'index?': false,
|
|
@@ -459,11 +500,14 @@ const SUPPORTS_LOOKUP_ACTIONS = new Set([
|
|
|
459
500
|
'ruleParams',
|
|
460
501
|
]);
|
|
461
502
|
|
|
462
|
-
const lookupProps = { 'unique?': true, 'index?': true };
|
|
463
|
-
const refLookupProps = {
|
|
503
|
+
const lookupProps: Partial<InstantDBAttr> = { 'unique?': true, 'index?': true };
|
|
504
|
+
const refLookupProps: Partial<InstantDBAttr> = {
|
|
505
|
+
...lookupProps,
|
|
506
|
+
cardinality: 'one',
|
|
507
|
+
};
|
|
464
508
|
|
|
465
509
|
function lookupPairsOfOp(op) {
|
|
466
|
-
const res = [];
|
|
510
|
+
const res: { etype: string; lookupPair: any; linkLabel?: string }[] = [];
|
|
467
511
|
const [action, etype, eid, obj] = op;
|
|
468
512
|
if (!SUPPORTS_LOOKUP_ACTIONS.has(action)) {
|
|
469
513
|
return res;
|
|
@@ -491,24 +535,72 @@ function lookupPairsOfOp(op) {
|
|
|
491
535
|
return res;
|
|
492
536
|
}
|
|
493
537
|
|
|
494
|
-
function createMissingAttrs(
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
538
|
+
function createMissingAttrs(
|
|
539
|
+
{ attrsStore, schema }: Ctx,
|
|
540
|
+
ops,
|
|
541
|
+
): [AttrsStore, TXStep[]] {
|
|
542
|
+
const addedIds = new Set();
|
|
543
|
+
const localAttrs: InstantDBAttr[] = [];
|
|
544
|
+
const addOps: TXStep[] = [];
|
|
545
|
+
|
|
546
|
+
function attrByFwdIdent(etype, label): InstantDBAttr | undefined {
|
|
547
|
+
return (
|
|
548
|
+
getAttrByFwdIdentName(attrsStore, etype, label) ||
|
|
549
|
+
localAttrs.find(
|
|
550
|
+
(x) =>
|
|
551
|
+
x['forward-identity'][1] === etype &&
|
|
552
|
+
x['forward-identity'][2] === label,
|
|
553
|
+
)
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function attrByRevIdent(etype, label): InstantDBAttr | undefined {
|
|
558
|
+
return (
|
|
559
|
+
getAttrByReverseIdentName(attrsStore, etype, label) ||
|
|
560
|
+
localAttrs.find(
|
|
561
|
+
(x) =>
|
|
562
|
+
x['reverse-identity']?.[1] === etype &&
|
|
563
|
+
x['reverse-identity']?.[2] === label,
|
|
564
|
+
)
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function addAttr(attr: InstantDBAttr) {
|
|
569
|
+
localAttrs.push(attr);
|
|
498
570
|
addOps.push(['add-attr', attr]);
|
|
499
571
|
addedIds.add(attr.id);
|
|
500
572
|
}
|
|
501
|
-
function addUnsynced(
|
|
502
|
-
|
|
573
|
+
function addUnsynced(
|
|
574
|
+
attr:
|
|
575
|
+
| (InstantDBAttr & { isUnsynced?: boolean })
|
|
576
|
+
| InstantDBAttr
|
|
577
|
+
| undefined,
|
|
578
|
+
) {
|
|
579
|
+
if (
|
|
580
|
+
attr &&
|
|
581
|
+
'isUnsynced' in attr &&
|
|
582
|
+
attr.isUnsynced &&
|
|
583
|
+
!addedIds.has(attr.id)
|
|
584
|
+
) {
|
|
585
|
+
localAttrs.push(attr);
|
|
503
586
|
addOps.push(['add-attr', attr]);
|
|
504
587
|
addedIds.add(attr.id);
|
|
505
588
|
}
|
|
506
589
|
}
|
|
507
590
|
|
|
591
|
+
function isRefLookupIdentLocal(etype: string, identName: string) {
|
|
592
|
+
return (
|
|
593
|
+
identName.indexOf('.') !== -1 &&
|
|
594
|
+
// attr names can have `.` in them, so use the attr we find with a `.`
|
|
595
|
+
// before assuming it's a ref lookup.
|
|
596
|
+
!attrByRevIdent(etype, identName)
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
|
|
508
600
|
// Adds attrs needed for a ref lookup
|
|
509
601
|
function addForRef(etype, label) {
|
|
510
|
-
const fwdAttr =
|
|
511
|
-
const revAttr =
|
|
602
|
+
const fwdAttr = attrByFwdIdent(etype, label);
|
|
603
|
+
const revAttr = attrByRevIdent(etype, label);
|
|
512
604
|
addUnsynced(fwdAttr);
|
|
513
605
|
addUnsynced(revAttr);
|
|
514
606
|
if (!fwdAttr && !revAttr) {
|
|
@@ -530,18 +622,18 @@ function createMissingAttrs({ attrs: existingAttrs, schema }, ops) {
|
|
|
530
622
|
|
|
531
623
|
// Figure out the link etype so we can make sure we have the attrs
|
|
532
624
|
// for the link lookup
|
|
533
|
-
const fwdAttr =
|
|
534
|
-
const revAttr =
|
|
625
|
+
const fwdAttr = attrByFwdIdent(etype, linkLabel);
|
|
626
|
+
const revAttr = attrByRevIdent(etype, linkLabel);
|
|
535
627
|
addUnsynced(fwdAttr);
|
|
536
628
|
addUnsynced(revAttr);
|
|
537
629
|
const linkEtype =
|
|
538
630
|
fwdAttr?.['reverse-identity']?.[1] ||
|
|
539
631
|
revAttr?.['forward-identity']?.[1] ||
|
|
540
632
|
linkLabel;
|
|
541
|
-
if (
|
|
633
|
+
if (isRefLookupIdentLocal(linkEtype, identName)) {
|
|
542
634
|
addForRef(linkEtype, extractRefLookupFwdName(identName));
|
|
543
635
|
} else {
|
|
544
|
-
const attr =
|
|
636
|
+
const attr = attrByFwdIdent(linkEtype, identName);
|
|
545
637
|
if (!attr) {
|
|
546
638
|
addAttr(
|
|
547
639
|
createObjectAttr(schema, linkEtype, identName, lookupProps),
|
|
@@ -549,10 +641,10 @@ function createMissingAttrs({ attrs: existingAttrs, schema }, ops) {
|
|
|
549
641
|
}
|
|
550
642
|
addUnsynced(attr);
|
|
551
643
|
}
|
|
552
|
-
} else if (
|
|
644
|
+
} else if (isRefLookupIdentLocal(etype, identName)) {
|
|
553
645
|
addForRef(etype, extractRefLookupFwdName(identName));
|
|
554
646
|
} else {
|
|
555
|
-
const attr =
|
|
647
|
+
const attr = attrByFwdIdent(etype, identName);
|
|
556
648
|
if (!attr) {
|
|
557
649
|
addAttr(createObjectAttr(schema, etype, identName, lookupProps));
|
|
558
650
|
}
|
|
@@ -565,14 +657,14 @@ function createMissingAttrs({ attrs: existingAttrs, schema }, ops) {
|
|
|
565
657
|
for (const op of ops) {
|
|
566
658
|
const [action, etype, eid, obj] = op;
|
|
567
659
|
if (OBJ_ACTIONS.has(action)) {
|
|
568
|
-
const idAttr =
|
|
660
|
+
const idAttr = attrByFwdIdent(etype, 'id');
|
|
569
661
|
addUnsynced(idAttr);
|
|
570
662
|
if (!idAttr) {
|
|
571
663
|
addAttr(createObjectAttr(schema, etype, 'id', { 'unique?': true }));
|
|
572
664
|
}
|
|
573
665
|
|
|
574
666
|
for (const label of Object.keys(obj)) {
|
|
575
|
-
const fwdAttr =
|
|
667
|
+
const fwdAttr = attrByFwdIdent(etype, label);
|
|
576
668
|
addUnsynced(fwdAttr);
|
|
577
669
|
if (UPDATE_ACTIONS.has(action)) {
|
|
578
670
|
if (!fwdAttr) {
|
|
@@ -587,7 +679,7 @@ function createMissingAttrs({ attrs: existingAttrs, schema }, ops) {
|
|
|
587
679
|
}
|
|
588
680
|
}
|
|
589
681
|
if (REF_ACTIONS.has(action)) {
|
|
590
|
-
const revAttr =
|
|
682
|
+
const revAttr = attrByRevIdent(etype, label);
|
|
591
683
|
if (!fwdAttr && !revAttr) {
|
|
592
684
|
addAttr(createRefAttr(schema, etype, label));
|
|
593
685
|
}
|
|
@@ -596,14 +688,22 @@ function createMissingAttrs({ attrs: existingAttrs, schema }, ops) {
|
|
|
596
688
|
}
|
|
597
689
|
}
|
|
598
690
|
}
|
|
599
|
-
|
|
691
|
+
|
|
692
|
+
if (localAttrs.length) {
|
|
693
|
+
const nextAttrs = { ...attrsStore.attrs };
|
|
694
|
+
for (const attr of localAttrs) {
|
|
695
|
+
nextAttrs[attr.id] = attr;
|
|
696
|
+
}
|
|
697
|
+
return [new AttrsStore(nextAttrs, attrsStore.linkIndex), addOps];
|
|
698
|
+
}
|
|
699
|
+
return [attrsStore, addOps];
|
|
600
700
|
}
|
|
601
701
|
|
|
602
|
-
export function transform(ctx, inputChunks) {
|
|
702
|
+
export function transform(ctx: Ctx, inputChunks) {
|
|
603
703
|
const chunks = Array.isArray(inputChunks) ? inputChunks : [inputChunks];
|
|
604
704
|
const ops = chunks.flatMap((tx) => getOps(tx));
|
|
605
705
|
const [newAttrs, addAttrTxSteps] = createMissingAttrs(ctx, ops);
|
|
606
|
-
const newCtx = { ...ctx,
|
|
706
|
+
const newCtx = { ...ctx, attrsStore: newAttrs };
|
|
607
707
|
const txSteps = ops.flatMap((op) => toTxSteps(newCtx, op));
|
|
608
708
|
return [...addAttrTxSteps, ...txSteps];
|
|
609
709
|
}
|