teamplay 0.5.0-alpha.2 → 0.5.0-alpha.21
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/index.d.ts +22 -8
- package/dist/index.js +1 -4
- package/dist/orm/Aggregation.d.ts +6 -4
- package/dist/orm/Aggregation.js +39 -11
- package/dist/orm/Compat/SignalCompat.js +141 -409
- package/dist/orm/Compat/queryReadiness.d.ts +13 -5
- package/dist/orm/Compat/silentContext.js +4 -22
- package/dist/orm/Compat/startStopCompat.js +33 -0
- package/dist/orm/Doc.js +48 -3
- package/dist/orm/Query.d.ts +1 -0
- package/dist/orm/Query.js +67 -22
- package/dist/orm/Signal.d.ts +3 -3
- package/dist/orm/SignalBase.d.ts +27 -2
- package/dist/orm/SignalBase.js +296 -5
- package/dist/orm/addModel.d.ts +9 -2
- package/dist/orm/getSignal.js +0 -2
- package/dist/orm/index.d.ts +2 -2
- package/dist/orm/privateData.d.ts +7 -22
- package/dist/orm/signalMetadata.d.ts +1 -1
- package/dist/orm/signalMetadata.js +29 -3
- package/dist/orm/signalReads.d.ts +1 -1
- package/dist/orm/signalReads.js +7 -7
- package/dist/orm/signalSymbols.js +1 -1
- package/dist/orm/sub.d.ts +9 -1
- package/dist/orm/subscriptionGcDelay.js +2 -6
- package/dist/orm/types/baseMethods.d.ts +2 -1
- package/dist/orm/types/jsonSchema.d.ts +3 -3
- package/dist/orm/types/modelManifest.d.ts +12 -1
- package/dist/orm/types/query.d.ts +7 -1
- package/dist/orm/types/signal.d.ts +44 -15
- package/dist/react/convertToObserver.js +1 -4
- package/dist/react/promiseBatcher.js +1 -1
- package/dist/react/renderAttemptDestroyer.d.ts +0 -8
- package/dist/react/renderAttemptDestroyer.js +2 -28
- package/dist/react/trapRender.js +3 -3
- package/dist/react/useSub.d.ts +104 -5
- package/dist/react/useSub.js +191 -32
- package/dist/react/useSuspendMemo.js +1 -5
- package/dist/server.d.ts +1 -1
- package/package.json +16 -10
- package/dist/orm/Compat/hooksCompat.d.ts +0 -33
- package/dist/orm/Compat/hooksCompat.js +0 -360
- package/dist/react/compatComponentRegistry.d.ts +0 -4
- package/dist/react/compatComponentRegistry.js +0 -19
package/dist/orm/SignalBase.js
CHANGED
|
@@ -12,15 +12,17 @@
|
|
|
12
12
|
* 3. If extremely late bindings are enabled, to prevent name collisions when accessing fields
|
|
13
13
|
* in the raw data tree which have the same name as signal's methods
|
|
14
14
|
*/
|
|
15
|
+
import { raw } from '@nx-js/observer-util';
|
|
16
|
+
import arrayDiff from 'arraydiff';
|
|
15
17
|
import uuid from '@teamplay/utils/uuid';
|
|
16
|
-
import { get as _get, setPublicDoc as _setPublicDoc, dataTreeRaw, getRaw, getLogicalRootSnapshot, incrementPublic as _incrementPublic, arrayPushPublic as _arrayPushPublic, arrayUnshiftPublic as _arrayUnshiftPublic, arrayInsertPublic as _arrayInsertPublic, arrayPopPublic as _arrayPopPublic, arrayShiftPublic as _arrayShiftPublic, arrayRemovePublic as _arrayRemovePublic, arrayMovePublic as _arrayMovePublic, stringInsertPublic as _stringInsertPublic, stringRemovePublic as _stringRemovePublic } from './dataTree.js';
|
|
18
|
+
import { get as _get, setPublicDoc as _setPublicDoc, setPublicDocReplace as _setPublicDocReplace, del as _del, dataTreeRaw, getRaw, getLogicalRootSnapshot, incrementPublic as _incrementPublic, arrayPushPublic as _arrayPushPublic, arrayUnshiftPublic as _arrayUnshiftPublic, arrayInsertPublic as _arrayInsertPublic, arrayPopPublic as _arrayPopPublic, arrayShiftPublic as _arrayShiftPublic, arrayRemovePublic as _arrayRemovePublic, arrayMovePublic as _arrayMovePublic, stringInsertPublic as _stringInsertPublic, stringRemovePublic as _stringRemovePublic } from './dataTree.js';
|
|
17
19
|
import getSignal, { rawSignal } from "./getSignal.js";
|
|
18
20
|
import { docSubscriptions } from './Doc.js';
|
|
19
21
|
import { IS_QUERY, HASH, QUERIES } from './Query.js';
|
|
20
|
-
import { AGGREGATIONS, getAggregationCollectionName, getAggregationDocId } from './Aggregation.js';
|
|
22
|
+
import { AGGREGATIONS, IS_AGGREGATION, getAggregationCollectionName, getAggregationDocId } from './Aggregation.js';
|
|
21
23
|
import { ROOT_FUNCTION, ROOT_ID, getRoot } from "./Root.js";
|
|
22
24
|
import { isPrivateMutationForbidden } from "./connection.js";
|
|
23
|
-
import { DEFAULT_ID_FIELDS, getIdFieldsForSegments, prepareAddPayload, resolveAddDocId } from "./idFields.js";
|
|
25
|
+
import { DEFAULT_ID_FIELDS, getIdFieldsForSegments, isIdFieldPath, isPlainObject, isPublicDocPath, normalizeIdFields, prepareAddPayload, resolveAddDocId } from "./idFields.js";
|
|
24
26
|
import { isCompatEnv } from './compatEnv.js';
|
|
25
27
|
import { resolveRefSegmentsSafe, resolveRefSignalSafe } from './Compat/refFallback.js';
|
|
26
28
|
import { compatStartOnRoot, compatStopOnRoot, joinScopePath } from './Compat/startStopCompat.js';
|
|
@@ -147,6 +149,12 @@ export class Signal extends Function {
|
|
|
147
149
|
get [Symbol.toStringTag]() {
|
|
148
150
|
return 'Signal';
|
|
149
151
|
}
|
|
152
|
+
/** Return the owning root signal. */
|
|
153
|
+
root() {
|
|
154
|
+
if (arguments.length > 0)
|
|
155
|
+
throw Error('Signal.root() does not accept any arguments');
|
|
156
|
+
return getRoot(this) || this;
|
|
157
|
+
}
|
|
150
158
|
/**
|
|
151
159
|
* Return the parent signal `levels` above this signal.
|
|
152
160
|
* @param levels Number of parent levels to walk upward. Defaults to `1`.
|
|
@@ -196,6 +204,28 @@ export class Signal extends Function {
|
|
|
196
204
|
throw Error('Signal.getIds() does not accept any arguments');
|
|
197
205
|
return getSignalIds(this, SIGNAL_READ_CONTEXT);
|
|
198
206
|
}
|
|
207
|
+
/** Return query extra data, aggregation data, or undefined for ordinary signals. */
|
|
208
|
+
getExtra() {
|
|
209
|
+
if (arguments.length > 0)
|
|
210
|
+
throw Error('Signal.getExtra() does not accept any arguments');
|
|
211
|
+
if (this[IS_AGGREGATION])
|
|
212
|
+
return this.get();
|
|
213
|
+
if (this[IS_QUERY])
|
|
214
|
+
return this.extra.get();
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
/** Return a shallow copy of the current value. */
|
|
218
|
+
getCopy() {
|
|
219
|
+
if (arguments.length > 0)
|
|
220
|
+
throw Error('Signal.getCopy() does not accept any arguments');
|
|
221
|
+
return shallowCopy(this.get());
|
|
222
|
+
}
|
|
223
|
+
/** Return a deep copy of the current value. */
|
|
224
|
+
getDeepCopy() {
|
|
225
|
+
if (arguments.length > 0)
|
|
226
|
+
throw Error('Signal.getDeepCopy() does not accept any arguments');
|
|
227
|
+
return deepCopy(this.get());
|
|
228
|
+
}
|
|
199
229
|
/** Read the current value without tracking it for reactive rendering. */
|
|
200
230
|
peek() {
|
|
201
231
|
if (arguments.length > 0)
|
|
@@ -205,7 +235,10 @@ export class Signal extends Function {
|
|
|
205
235
|
/** Return the document id represented by this document signal. */
|
|
206
236
|
getId() {
|
|
207
237
|
const $root = getRoot(this) || this;
|
|
208
|
-
|
|
238
|
+
const rootId = $root?.[ROOT_ID];
|
|
239
|
+
return getSignalId(this, rootId, segments => (isPrivateSignalSegments(segments)
|
|
240
|
+
? getPrivateData(rootId, segments)
|
|
241
|
+
: _get(getSignalStorageSegments({ [SEGMENTS]: segments }))));
|
|
209
242
|
}
|
|
210
243
|
/** Return the public collection name this signal belongs to. */
|
|
211
244
|
getCollection() {
|
|
@@ -247,6 +280,86 @@ export class Signal extends Function {
|
|
|
247
280
|
throw Error('Signal.set() expects a single argument');
|
|
248
281
|
await setSignalValue(this, SIGNAL_VALUE_MUTATION_CONTEXT, value);
|
|
249
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Replace this signal's value without deep-diffing object/array branches.
|
|
285
|
+
* @param value New value to store at this signal path.
|
|
286
|
+
*/
|
|
287
|
+
async setReplace(value) {
|
|
288
|
+
if (arguments.length > 1)
|
|
289
|
+
throw Error('Signal.setReplace() expects a single argument');
|
|
290
|
+
const segments = this[SEGMENTS];
|
|
291
|
+
if (segments.length === 0)
|
|
292
|
+
throw Error('Can\'t set the root signal data');
|
|
293
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
294
|
+
if (isIdFieldPath(segments, idFields))
|
|
295
|
+
return;
|
|
296
|
+
const nextValue = isPublicDocPath(segments)
|
|
297
|
+
? normalizeIdFields(value, idFields, segments[1])
|
|
298
|
+
: value;
|
|
299
|
+
if (isPublicCollection(segments[0])) {
|
|
300
|
+
if (value === undefined) {
|
|
301
|
+
await _setPublicDoc(segments, nextValue);
|
|
302
|
+
if (segments.length === 2) {
|
|
303
|
+
_del(segments);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
await _setPublicDocReplace(segments, nextValue);
|
|
308
|
+
}
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (isPrivateMutationForbidden()) {
|
|
312
|
+
throw Error(`
|
|
313
|
+
Can't modify private collections data when 'publicOnly' is enabled.
|
|
314
|
+
On the server you can only work with public collections.
|
|
315
|
+
`);
|
|
316
|
+
}
|
|
317
|
+
setReplacePrivateData(getSignalOwningRootId(this), segments, nextValue);
|
|
318
|
+
}
|
|
319
|
+
/** Set the current value only when it is null or undefined. */
|
|
320
|
+
async setNull(value) {
|
|
321
|
+
if (arguments.length > 1)
|
|
322
|
+
throw Error('Signal.setNull() expects a single argument');
|
|
323
|
+
if (this.get() != null)
|
|
324
|
+
return;
|
|
325
|
+
await this.setReplace(value);
|
|
326
|
+
}
|
|
327
|
+
/** Replace the current value unless it is exactly equal to the new value. */
|
|
328
|
+
async setDiff(value) {
|
|
329
|
+
if (arguments.length > 1)
|
|
330
|
+
throw Error('Signal.setDiff() expects a single argument');
|
|
331
|
+
const before = this.peek();
|
|
332
|
+
if (racerEqual(before, value))
|
|
333
|
+
return;
|
|
334
|
+
await this.setReplace(value);
|
|
335
|
+
}
|
|
336
|
+
/** Recursively diff objects and arrays at the current signal path. */
|
|
337
|
+
async setDiffDeep(value) {
|
|
338
|
+
if (arguments.length > 1)
|
|
339
|
+
throw Error('Signal.setDiffDeep() expects a single argument');
|
|
340
|
+
await runInBatch(() => setDiffDeepOnSignal(this, value));
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Set multiple object fields with per-key replace semantics.
|
|
344
|
+
* Unlike assign(), null is stored as null and undefined follows setReplace() semantics.
|
|
345
|
+
* @param object Object containing fields to set.
|
|
346
|
+
*/
|
|
347
|
+
async setEach(object) {
|
|
348
|
+
if (arguments.length > 1)
|
|
349
|
+
throw Error('Signal.setEach() expects a single argument');
|
|
350
|
+
if (!object)
|
|
351
|
+
return;
|
|
352
|
+
if (typeof object !== 'object') {
|
|
353
|
+
throw Error('Signal.setEach() expects an object argument, got: ' + typeof object);
|
|
354
|
+
}
|
|
355
|
+
await runInBatch(async () => {
|
|
356
|
+
const promises = [];
|
|
357
|
+
for (const key of Object.keys(object)) {
|
|
358
|
+
promises.push(this[key].setReplace(object[key]));
|
|
359
|
+
}
|
|
360
|
+
await Promise.all(promises);
|
|
361
|
+
});
|
|
362
|
+
}
|
|
250
363
|
/**
|
|
251
364
|
* Set multiple object fields at once. Fields set to `null` or `undefined` are deleted.
|
|
252
365
|
* @param value Object containing fields to set or delete.
|
|
@@ -477,6 +590,183 @@ export class Signal extends Function {
|
|
|
477
590
|
await deleteSignalValue(this, SIGNAL_VALUE_MUTATION_CONTEXT);
|
|
478
591
|
}
|
|
479
592
|
}
|
|
593
|
+
async function setDiffDeepOnSignal($target, value) {
|
|
594
|
+
if ($target[SEGMENTS].length === 0)
|
|
595
|
+
throw Error('Can\'t set the root signal data');
|
|
596
|
+
await diffDeepOnSignal($target, $target.peek(), value);
|
|
597
|
+
}
|
|
598
|
+
async function diffDeepOnSignal($signal, before, after) {
|
|
599
|
+
if (before === after)
|
|
600
|
+
return;
|
|
601
|
+
if (Array.isArray(before) && Array.isArray(after)) {
|
|
602
|
+
const diff = arrayDiff(before, after, deepEqual);
|
|
603
|
+
if (!diff.length)
|
|
604
|
+
return;
|
|
605
|
+
const index = getSingleArrayReplacementIndex(diff);
|
|
606
|
+
if (index != null) {
|
|
607
|
+
await diffDeepOnSignal(getChildSignal($signal, index), before[index], after[index]);
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
await applyArrayDiff($signal, diff);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
if (isDiffableObject(before, after)) {
|
|
614
|
+
const preservePath = $signal[SEGMENTS];
|
|
615
|
+
for (const key of Object.keys(before)) {
|
|
616
|
+
if (Object.prototype.hasOwnProperty.call(after, key))
|
|
617
|
+
continue;
|
|
618
|
+
await deleteForDiffDeep(getChildSignal($signal, key), preservePath);
|
|
619
|
+
}
|
|
620
|
+
for (const key of Object.keys(after)) {
|
|
621
|
+
await diffDeepOnSignal(getChildSignal($signal, key), before[key], after[key]);
|
|
622
|
+
}
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
await $signal.setReplace(after);
|
|
626
|
+
}
|
|
627
|
+
function isDiffableObject(before, after) {
|
|
628
|
+
if (!isPlainObject(before) || !isPlainObject(after))
|
|
629
|
+
return false;
|
|
630
|
+
if (isReactLike(before) || isReactLike(after))
|
|
631
|
+
return false;
|
|
632
|
+
return true;
|
|
633
|
+
}
|
|
634
|
+
function isReactLike(value) {
|
|
635
|
+
return !!(value && typeof value === 'object' && typeof value.$$typeof === 'symbol');
|
|
636
|
+
}
|
|
637
|
+
function getSingleArrayReplacementIndex(diff) {
|
|
638
|
+
if (!Array.isArray(diff) || diff.length !== 2)
|
|
639
|
+
return null;
|
|
640
|
+
const first = diff[0];
|
|
641
|
+
const second = diff[1];
|
|
642
|
+
if (first instanceof arrayDiff.RemoveDiff &&
|
|
643
|
+
second instanceof arrayDiff.InsertDiff &&
|
|
644
|
+
first.index === second.index &&
|
|
645
|
+
first.howMany === 1 &&
|
|
646
|
+
second.values.length === 1) {
|
|
647
|
+
return first.index;
|
|
648
|
+
}
|
|
649
|
+
return null;
|
|
650
|
+
}
|
|
651
|
+
async function applyArrayDiff($signal, diff) {
|
|
652
|
+
for (const item of diff) {
|
|
653
|
+
if (item instanceof arrayDiff.InsertDiff) {
|
|
654
|
+
await $signal.insert(item.index, item.values);
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
if (item instanceof arrayDiff.RemoveDiff) {
|
|
658
|
+
await $signal.remove(item.index, item.howMany);
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if (item instanceof arrayDiff.MoveDiff) {
|
|
662
|
+
await $signal.move(item.from, item.to, item.howMany);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
async function deleteForDiffDeep($signal, preservePath) {
|
|
667
|
+
const segments = $signal[SEGMENTS];
|
|
668
|
+
const idFields = getIdFieldsForSegments(segments);
|
|
669
|
+
if (isIdFieldPath(segments, idFields))
|
|
670
|
+
return;
|
|
671
|
+
if (isPublicCollection(segments[0])) {
|
|
672
|
+
await $signal.del();
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
if (isPrivateMutationForbidden()) {
|
|
676
|
+
throw Error(`
|
|
677
|
+
Can't modify private collections data when 'publicOnly' is enabled.
|
|
678
|
+
On the server you can only work with public collections.
|
|
679
|
+
`);
|
|
680
|
+
}
|
|
681
|
+
delPrivateData(getSignalOwningRootId($signal), segments, { preservePath });
|
|
682
|
+
}
|
|
683
|
+
function getChildSignal($parent, key) {
|
|
684
|
+
return getSignal(getRoot($parent) || $parent, [...$parent[SEGMENTS], key]);
|
|
685
|
+
}
|
|
686
|
+
function deepEqual(left, right) {
|
|
687
|
+
if (left === right)
|
|
688
|
+
return true;
|
|
689
|
+
if (left == null || right == null)
|
|
690
|
+
return false;
|
|
691
|
+
if (typeof left !== 'object' || typeof right !== 'object')
|
|
692
|
+
return false;
|
|
693
|
+
if (Array.isArray(left) !== Array.isArray(right))
|
|
694
|
+
return false;
|
|
695
|
+
if (Array.isArray(left)) {
|
|
696
|
+
if (left.length !== right.length)
|
|
697
|
+
return false;
|
|
698
|
+
for (let i = 0; i < left.length; i++) {
|
|
699
|
+
if (!deepEqual(left[i], right[i]))
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
return true;
|
|
703
|
+
}
|
|
704
|
+
if (!isPlainObject(left) || !isPlainObject(right))
|
|
705
|
+
return false;
|
|
706
|
+
const leftKeys = Object.keys(left);
|
|
707
|
+
const rightKeys = Object.keys(right);
|
|
708
|
+
if (leftKeys.length !== rightKeys.length)
|
|
709
|
+
return false;
|
|
710
|
+
for (const key of leftKeys) {
|
|
711
|
+
if (!Object.prototype.hasOwnProperty.call(right, key))
|
|
712
|
+
return false;
|
|
713
|
+
if (!deepEqual(left[key], right[key]))
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
function racerEqual(left, right) {
|
|
719
|
+
return left === right || (Number.isNaN(left) && Number.isNaN(right));
|
|
720
|
+
}
|
|
721
|
+
function shallowCopy(value) {
|
|
722
|
+
const rawValue = raw(value);
|
|
723
|
+
if (Array.isArray(rawValue))
|
|
724
|
+
return rawValue.slice();
|
|
725
|
+
if (rawValue && typeof rawValue === 'object')
|
|
726
|
+
return { ...rawValue };
|
|
727
|
+
return rawValue;
|
|
728
|
+
}
|
|
729
|
+
function deepCopy(value) {
|
|
730
|
+
const rawValue = raw(value);
|
|
731
|
+
if (!rawValue || typeof rawValue !== 'object')
|
|
732
|
+
return rawValue;
|
|
733
|
+
if (typeof globalThis.structuredClone === 'function') {
|
|
734
|
+
try {
|
|
735
|
+
return globalThis.structuredClone(rawValue);
|
|
736
|
+
}
|
|
737
|
+
catch { }
|
|
738
|
+
}
|
|
739
|
+
return racerDeepCopy(rawValue);
|
|
740
|
+
}
|
|
741
|
+
// Racer-style deep copy:
|
|
742
|
+
// - Preserves prototypes by instantiating via `new value.constructor()`
|
|
743
|
+
// - Copies own enumerable props recursively
|
|
744
|
+
// - Keeps functions as-is (no cloning)
|
|
745
|
+
// - Handles Date by creating a new Date
|
|
746
|
+
// Limitations: does not handle cyclic refs, Map/Set/RegExp/TypedArray, non-enumerables.
|
|
747
|
+
function racerDeepCopy(value) {
|
|
748
|
+
if (value instanceof Date)
|
|
749
|
+
return new Date(value);
|
|
750
|
+
if (typeof value === 'object') {
|
|
751
|
+
if (value === null)
|
|
752
|
+
return null;
|
|
753
|
+
if (Array.isArray(value)) {
|
|
754
|
+
const array = [];
|
|
755
|
+
for (let i = value.length; i--;) {
|
|
756
|
+
array[i] = racerDeepCopy(value[i]);
|
|
757
|
+
}
|
|
758
|
+
return array;
|
|
759
|
+
}
|
|
760
|
+
const object = new value.constructor();
|
|
761
|
+
for (const key in value) {
|
|
762
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
763
|
+
object[key] = racerDeepCopy(value[key]);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
return object;
|
|
767
|
+
}
|
|
768
|
+
return value;
|
|
769
|
+
}
|
|
480
770
|
// dot syntax returns a child signal only if no such method or property exists
|
|
481
771
|
export const regularBindings = {
|
|
482
772
|
apply(signal, thisArg, argumentsList) {
|
|
@@ -510,8 +800,9 @@ export const extremelyLateBindings = {
|
|
|
510
800
|
if (segments[0] === AGGREGATIONS) {
|
|
511
801
|
const aggregationDocId = getAggregationDocId(segments, getRoot(signal)?.[ROOT_ID]);
|
|
512
802
|
if (aggregationDocId) {
|
|
513
|
-
if (segments.length === 3 && key === 'set')
|
|
803
|
+
if (segments.length === 3 && (key === 'set' || key === 'setReplace')) {
|
|
514
804
|
throw Error(ERRORS.setAggregationDoc(segments, key));
|
|
805
|
+
}
|
|
515
806
|
const collectionName = getAggregationCollectionName(segments);
|
|
516
807
|
const subDocSegments = segments.slice(3);
|
|
517
808
|
const $original = getSignal(getRoot(signal), [collectionName, aggregationDocId, ...subDocSegments]);
|
package/dist/orm/addModel.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { SignalClass } from './Signal.js';
|
|
2
|
-
import type { TeamplayModels } from '../index.js';
|
|
2
|
+
import type { TeamplayModels, TeamplayPluginModels } from '../index.js';
|
|
3
3
|
import type { PathSegment } from './types/path.js';
|
|
4
4
|
export declare const MODELS: Record<string, SignalClass<any>>;
|
|
5
|
-
|
|
5
|
+
type UnionToIntersection<TValue> = (TValue extends unknown ? (value: TValue) => void : never) extends (value: infer Intersection) => void ? Intersection : never;
|
|
6
|
+
type RegistryValues<TRegistry> = TRegistry[keyof TRegistry & string];
|
|
7
|
+
type MergeRegistry<TRegistry> = [
|
|
8
|
+
RegistryValues<TRegistry>
|
|
9
|
+
] extends [never] ? {} : UnionToIntersection<RegistryValues<TRegistry>>;
|
|
10
|
+
type EffectiveTeamplayModels = TeamplayModels & MergeRegistry<TeamplayPluginModels>;
|
|
11
|
+
export default function addModel<TPattern extends string>(pattern: TPattern, Model: TPattern extends keyof EffectiveTeamplayModels ? EffectiveTeamplayModels[TPattern] : SignalClass<any>): void;
|
|
6
12
|
export declare function findModel(segments: PathSegment[]): SignalClass<any> | undefined;
|
|
13
|
+
export {};
|
package/dist/orm/getSignal.js
CHANGED
|
@@ -94,8 +94,6 @@ function getDefaultProxyHandlers({ useExtremelyLateBindings } = {}) {
|
|
|
94
94
|
return undefined;
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
-
if (key === 'root')
|
|
98
|
-
return Reflect.get(signal, key, receiver);
|
|
99
97
|
return baseHandlers.get
|
|
100
98
|
? baseHandlers.get(signal, key, receiver)
|
|
101
99
|
: Reflect.get(signal, key, receiver);
|
package/dist/orm/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { belongsTo, hasMany, hasOne } from './associations.js';
|
|
2
|
-
export type { AggregationSignal, ArraySignal, CollectionAggregationSignal, CollectionQuerySignal, CollectionSignal, CollectionSignalFromSpec, CollectionSpec, CollectionsFromManifest, DocumentSignal, FromJsonSchema, JsonSchema, JsonSchemaSpec, ModelEntry, ModelManifest, PathModelsFromManifest, PublicSignal, RuntimeSignalConstructor, RuntimeSignalInstance, WildcardPathSegment, WildcardSignalPath, AppendPath, JoinPath, QueryParams, QuerySignal, RegisteredAggregationInput, SignalBaseInstance, SignalClass, SignalChild, SignalConstructor, SignalForKind, SignalKind, SignalModelConstructor, TypedAggregationInput, TypedAggregationSignal, TypedSignal, ZodLikeSchema, ZodSchemaSpec } from './Signal.js';
|
|
3
|
-
export type { RootSignal, TeamplayCollections, TeamplayModels, TeamplaySignalFields } from '../index.js';
|
|
2
|
+
export type { AggregationSignal, ArraySignal, CollectionAggregationSignal, CollectionQuerySignal, CollectionSignal, CollectionSignalFromSpec, CollectionSpec, CollectionsFromManifest, ComputedQueryParamsInput, DocumentSignal, FromJsonSchema, JsonSchema, JsonSchemaSpec, ModelEntry, ModelManifest, PathModelsFromManifest, PrivateCollectionsFromManifest, PrivateSignalFromSpec, PublicSignal, RuntimeSignalConstructor, RuntimeSignalInstance, WildcardPathSegment, WildcardSignalPath, AppendPath, JoinPath, QueryParams, QueryParamsInput, QuerySignal, RegisteredAggregationInput, RootPrivateCollections, SignalBaseInstance, SignalClass, SignalChild, SignalConstructor, SignalForKind, SignalKind, SignalModelConstructor, TypedAggregationInput, TypedAggregationSignal, TypedSignal, ZodLikeSchema, ZodSchemaSpec } from './Signal.js';
|
|
3
|
+
export type { RootSignal, TeamplayCollections, TeamplayFeature, TeamplayFeatures, TeamplayModels, TeamplayPluginCollections, TeamplayPluginPrivateCollections, TeamplayPluginModels, TeamplayPluginOption, TeamplayPluginOptions, TeamplayPluginSignalFields, TeamplayPrivateCollections, TeamplaySignalFields } from '../index.js';
|
|
4
4
|
export declare const BaseModel: import("./Signal.js").SignalConstructor;
|
|
5
5
|
export default BaseModel;
|
|
6
6
|
export { defineModels, default as initModels, getModels, resetModelsForTests } from './initModels.js';
|
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
export function getPrivateData(rootId: any, logicalSegments: any, raw?: boolean): unknown;
|
|
10
|
-
export function setPrivateData(rootId: any, logicalSegments: any, value: any): void;
|
|
11
|
-
export function setReplacePrivateData(rootId: any, logicalSegments: any, value: any): void;
|
|
12
|
-
export function delPrivateData(rootId: any, logicalSegments: any, options?: {}): void;
|
|
13
|
-
export function arrayPushPrivateData(rootId: any, logicalSegments: any, value: any): number | undefined;
|
|
14
|
-
export function arrayUnshiftPrivateData(rootId: any, logicalSegments: any, value: any): number | undefined;
|
|
15
|
-
export function arrayInsertPrivateData(rootId: any, logicalSegments: any, index: any, values: any): number | undefined;
|
|
16
|
-
export function arrayPopPrivateData(rootId: any, logicalSegments: any): any;
|
|
17
|
-
export function arrayShiftPrivateData(rootId: any, logicalSegments: any): any;
|
|
18
|
-
export function arrayRemovePrivateData(rootId: any, logicalSegments: any, index: any, howMany?: number): any[] | undefined;
|
|
19
|
-
export function arrayMovePrivateData(rootId: any, logicalSegments: any, from: any, to: any, howMany?: number): any[] | undefined;
|
|
20
|
-
export function stringInsertPrivateData(rootId: any, logicalSegments: any, index: any, text: any): any;
|
|
21
|
-
export function stringRemovePrivateData(rootId: any, logicalSegments: any, index: any, howMany: any): any;
|
|
22
|
-
export function getPrivateDataSnapshot(rootId: any): any;
|
|
1
|
+
import type { PathSegment } from './types/path.js'
|
|
2
|
+
|
|
3
|
+
export function getPrivateData (
|
|
4
|
+
rootId: string | undefined,
|
|
5
|
+
logicalSegments: readonly PathSegment[],
|
|
6
|
+
raw?: boolean
|
|
7
|
+
): unknown
|
|
@@ -12,6 +12,6 @@ export declare function getSignalPath($signal: Pick<SignalMetadataOwner, typeof
|
|
|
12
12
|
export declare function getSignalLeaf($signal: Pick<SignalMetadataOwner, typeof SEGMENTS>): string;
|
|
13
13
|
export declare function getSignalParentSegments($signal: Pick<SignalMetadataOwner, typeof SEGMENTS>, levels: unknown, argumentCount: number): PathSegment[];
|
|
14
14
|
export declare function normalizeParentLevels(levels: unknown, argumentCount: number): number;
|
|
15
|
-
export declare function getSignalId($signal: Pick<SignalMetadataOwner, typeof SEGMENTS>, rootId?: string): string |
|
|
15
|
+
export declare function getSignalId($signal: Pick<SignalMetadataOwner, typeof SEGMENTS>, rootId?: string, readPath?: (segments: PathSegment[]) => unknown): string | undefined;
|
|
16
16
|
export declare function getSignalCollection($signal: SignalMetadataOwner): PathSegment | undefined;
|
|
17
17
|
export declare function getSignalAssociations($rawSignal: Pick<SignalMetadataOwner, 'constructor'>): readonly unknown[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AGGREGATIONS, getAggregationCollectionName, getAggregationDocId } from './Aggregation.js';
|
|
2
|
+
import { isPrivateCollectionSegments } from "./rootScope.js";
|
|
2
3
|
import { SEGMENTS } from "./signalSymbols.js";
|
|
3
4
|
export function getSignalPath($signal) {
|
|
4
5
|
return $signal[SEGMENTS].join('.');
|
|
@@ -27,16 +28,23 @@ export function normalizeParentLevels(levels, argumentCount) {
|
|
|
27
28
|
throw Error('Signal.parent() expects a positive integer');
|
|
28
29
|
return levels;
|
|
29
30
|
}
|
|
30
|
-
export function getSignalId($signal, rootId) {
|
|
31
|
+
export function getSignalId($signal, rootId, readPath) {
|
|
31
32
|
const segments = $signal[SEGMENTS];
|
|
32
33
|
if (segments.length === 0)
|
|
33
34
|
throw Error('Can\'t get the id of the root signal');
|
|
34
35
|
if (segments.length === 1)
|
|
35
36
|
throw Error('Can\'t get the id of a collection');
|
|
37
|
+
if (isDirectPublicDocumentSegments(segments))
|
|
38
|
+
return getLeafId(segments);
|
|
36
39
|
if (segments[0] === AGGREGATIONS && segments.length === 3) {
|
|
37
|
-
return getAggregationDocId(segments, rootId);
|
|
40
|
+
return getAggregationDocId(segments, rootId, readPath);
|
|
38
41
|
}
|
|
39
|
-
|
|
42
|
+
if (readPath) {
|
|
43
|
+
const valueId = getValueIdFromPaths(segments, readPath);
|
|
44
|
+
if (valueId.found)
|
|
45
|
+
return valueId.id;
|
|
46
|
+
}
|
|
47
|
+
return getLeafId(segments);
|
|
40
48
|
}
|
|
41
49
|
export function getSignalCollection($signal) {
|
|
42
50
|
const segments = $signal[SEGMENTS];
|
|
@@ -54,3 +62,21 @@ export function getSignalCollection($signal) {
|
|
|
54
62
|
export function getSignalAssociations($rawSignal) {
|
|
55
63
|
return $rawSignal.constructor.associations || [];
|
|
56
64
|
}
|
|
65
|
+
function getValueIdFromPaths(segments, readPath) {
|
|
66
|
+
const underscoreId = readPath([...segments, '_id']);
|
|
67
|
+
if (typeof underscoreId === 'string')
|
|
68
|
+
return { found: true, id: underscoreId };
|
|
69
|
+
const id = readPath([...segments, 'id']);
|
|
70
|
+
if (typeof id === 'string')
|
|
71
|
+
return { found: true, id };
|
|
72
|
+
if (underscoreId !== undefined || id !== undefined)
|
|
73
|
+
return { found: true };
|
|
74
|
+
return { found: false };
|
|
75
|
+
}
|
|
76
|
+
function isDirectPublicDocumentSegments(segments) {
|
|
77
|
+
return segments.length === 2 && !isPrivateCollectionSegments(segments);
|
|
78
|
+
}
|
|
79
|
+
function getLeafId(segments) {
|
|
80
|
+
const leaf = segments[segments.length - 1];
|
|
81
|
+
return typeof leaf === 'string' ? leaf : undefined;
|
|
82
|
+
}
|
|
@@ -21,6 +21,6 @@ export interface SignalReadContext<TSignal extends SignalReadOwner> {
|
|
|
21
21
|
}
|
|
22
22
|
export declare function readSignalValue<TSignal extends SignalReadOwner, TValue>($signal: TSignal, context: SignalReadContext<TSignal>, method: SignalReadMethod<TValue>, rawMethod: SignalReadMethod): TValue;
|
|
23
23
|
export declare function getSignalValue<TSignal extends SignalReadOwner, TValue>($signal: TSignal, context: SignalReadContext<TSignal>, method: SignalReadMethod<TValue>, rawMethod: SignalReadMethod): TValue;
|
|
24
|
-
export declare function getSignalIds<TSignal extends SignalReadOwner>($signal: TSignal, context: SignalReadContext<TSignal>):
|
|
24
|
+
export declare function getSignalIds<TSignal extends SignalReadOwner>($signal: TSignal, context: SignalReadContext<TSignal>): string[];
|
|
25
25
|
export declare function isQueryIdsValueSignal<TSignal extends SignalReadOwner>($signal: TSignal): boolean;
|
|
26
26
|
export declare function isAggregationValueSignal<TSignal extends SignalReadOwner>($signal: TSignal): boolean;
|
package/dist/orm/signalReads.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AGGREGATIONS, IS_AGGREGATION } from './Aggregation.js';
|
|
1
|
+
import { AGGREGATIONS, IS_AGGREGATION, getAggregationCollectionName, getAggregationRowId } from './Aggregation.js';
|
|
2
2
|
import { HASH, IS_QUERY, QUERIES } from './Query.js';
|
|
3
3
|
import { SEGMENTS } from "./signalSymbols.js";
|
|
4
4
|
export function readSignalValue($signal, context, method, rawMethod) {
|
|
@@ -23,7 +23,7 @@ export function getSignalValue($signal, context, method, rawMethod) {
|
|
|
23
23
|
context.warn('Signal.get() on Query didn\'t find ids', $signal[SEGMENTS]);
|
|
24
24
|
return [];
|
|
25
25
|
}
|
|
26
|
-
return ids;
|
|
26
|
+
return ids.filter(isString);
|
|
27
27
|
}
|
|
28
28
|
return readSignalValue($signal, context, method, rawMethod);
|
|
29
29
|
}
|
|
@@ -35,13 +35,14 @@ export function getSignalIds($signal, context) {
|
|
|
35
35
|
context.warn('Signal.getIds() on Query didn\'t find ids', [QUERIES, getQueryHashSegment($signal), 'ids']);
|
|
36
36
|
return [];
|
|
37
37
|
}
|
|
38
|
-
return ids;
|
|
38
|
+
return ids.filter(isString);
|
|
39
39
|
}
|
|
40
40
|
if ($signal[IS_AGGREGATION]) {
|
|
41
41
|
const docs = context.readPrivateData(rootId, $signal[SEGMENTS], false);
|
|
42
42
|
if (!Array.isArray(docs))
|
|
43
43
|
return [];
|
|
44
|
-
|
|
44
|
+
const collectionName = getAggregationCollectionName($signal[SEGMENTS]);
|
|
45
|
+
return docs.map(doc => getAggregationRowId(doc, collectionName)).filter(isString);
|
|
45
46
|
}
|
|
46
47
|
context.error('Signal.getIds() can only be used on query signals or aggregation signals. ' +
|
|
47
48
|
'Received a regular signal: ' + JSON.stringify($signal[SEGMENTS]));
|
|
@@ -55,9 +56,8 @@ export function isAggregationValueSignal($signal) {
|
|
|
55
56
|
const segments = $signal[SEGMENTS];
|
|
56
57
|
return segments.length >= 2 && segments[0] === AGGREGATIONS;
|
|
57
58
|
}
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
return row._id || row.id;
|
|
59
|
+
function isString(value) {
|
|
60
|
+
return typeof value === 'string';
|
|
61
61
|
}
|
|
62
62
|
function getQueryHashSegment($signal) {
|
|
63
63
|
return $signal[HASH];
|
|
@@ -2,4 +2,4 @@ export const SEGMENTS = Symbol('path segments targeting the particular node in t
|
|
|
2
2
|
export const ARRAY_METHOD = Symbol('run array method on the signal');
|
|
3
3
|
export const GET = Symbol('get the value of the signal - either observed or raw');
|
|
4
4
|
export const GETTERS = Symbol('get the list of this signal\'s getters');
|
|
5
|
-
export const DEFAULT_GETTERS = ['path', 'id', 'get', 'peek', 'getId', 'map', 'reduce', 'find', 'getIds', 'getExtra', 'getCollection'];
|
|
5
|
+
export const DEFAULT_GETTERS = ['path', 'root', 'id', 'get', 'peek', 'getId', 'map', 'reduce', 'find', 'getIds', 'getExtra', 'getCopy', 'getDeepCopy', 'getCollection'];
|
package/dist/orm/sub.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AggregationFunction, AggregationParams, ClientAggregationFunction } from '@teamplay/utils/aggregation';
|
|
2
|
-
import type { CollectionSignal, DocumentSignal, MaybePromise, MaybePromiseSubResult, QueryParams, RegisteredAggregationInput, SignalModelConstructor, SubResult, TypedAggregationInput, TypedAggregationSignal, WildcardSignalPath } from './Signal.js';
|
|
2
|
+
import type { CollectionSignal, ComputedQueryParamsInput, DocumentSignal, MaybePromise, MaybePromiseSubResult, QueryParams, RegisteredAggregationInput, SignalModelConstructor, SubResult, TypedAggregationInput, TypedAggregationSignal, WildcardSignalPath } from './Signal.js';
|
|
3
3
|
/**
|
|
4
4
|
* Subscribe to an aggregation with explicit output typing outside React.
|
|
5
5
|
* @param $aggregation Typed aggregation input.
|
|
@@ -35,3 +35,11 @@ export default function sub<TSignal extends DocumentSignal<any, any, any>>($sign
|
|
|
35
35
|
* @param params Mongo-style query params, including filters and `$sort`.
|
|
36
36
|
*/
|
|
37
37
|
export default function sub<TDocument, TCollectionModel extends SignalModelConstructor<TDocument[]>, TDocumentModel extends SignalModelConstructor<TDocument>, TCollectionPath extends WildcardSignalPath>($collection: CollectionSignal<TDocument, TCollectionModel, TDocumentModel, TCollectionPath>, params: QueryParams<TDocument>): MaybePromiseSubResult<CollectionSignal<TDocument, TCollectionModel, TDocumentModel, TCollectionPath>, QueryParams<TDocument>>;
|
|
38
|
+
/**
|
|
39
|
+
* Subscribe to a collection query with computed string keys outside React.
|
|
40
|
+
* This fallback preserves Mongo-style computed paths such as `{ [`likes.${id}`]: true }`.
|
|
41
|
+
* Literal query objects should use the stricter overload above.
|
|
42
|
+
* @param $collection Collection signal to query.
|
|
43
|
+
* @param params Mongo-style query params with a widened computed key.
|
|
44
|
+
*/
|
|
45
|
+
export default function sub<TDocument, TCollectionModel extends SignalModelConstructor<TDocument[]>, TDocumentModel extends SignalModelConstructor<TDocument>, TCollectionPath extends WildcardSignalPath, TParams extends object>($collection: CollectionSignal<TDocument, TCollectionModel, TDocumentModel, TCollectionPath>, params: TParams & ComputedQueryParamsInput<TParams>): MaybePromiseSubResult<CollectionSignal<TDocument, TCollectionModel, TDocumentModel, TCollectionPath>, TParams>;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const DEFAULT_COMPAT_SUBSCRIPTION_GC_DELAY = 3000;
|
|
3
|
-
const DEFAULT_SUBSCRIPTION_GC_DELAY = 0;
|
|
1
|
+
const DEFAULT_SUBSCRIPTION_GC_DELAY = 3000;
|
|
4
2
|
let subscriptionGcDelay = getDefaultSubscriptionGcDelay();
|
|
5
3
|
export function getSubscriptionGcDelay() {
|
|
6
4
|
return subscriptionGcDelay;
|
|
@@ -17,9 +15,7 @@ export function setSubscriptionGcDelay(ms) {
|
|
|
17
15
|
return subscriptionGcDelay;
|
|
18
16
|
}
|
|
19
17
|
export function getDefaultSubscriptionGcDelay() {
|
|
20
|
-
return
|
|
21
|
-
? DEFAULT_COMPAT_SUBSCRIPTION_GC_DELAY
|
|
22
|
-
: DEFAULT_SUBSCRIPTION_GC_DELAY;
|
|
18
|
+
return DEFAULT_SUBSCRIPTION_GC_DELAY;
|
|
23
19
|
}
|
|
24
20
|
export function __resetSubscriptionGcDelayForTests() {
|
|
25
21
|
subscriptionGcDelay = getDefaultSubscriptionGcDelay();
|
|
@@ -6,7 +6,7 @@ export interface SignalMetadataMethods {
|
|
|
6
6
|
readonly [Symbol.toStringTag]: string;
|
|
7
7
|
parent: (levels?: number) => unknown;
|
|
8
8
|
id: () => string;
|
|
9
|
-
getId: () => string |
|
|
9
|
+
getId: () => string | undefined;
|
|
10
10
|
getCollection: () => string;
|
|
11
11
|
getAssociations: () => readonly unknown[];
|
|
12
12
|
}
|
|
@@ -14,6 +14,7 @@ export interface SignalValueMethods<TValue> {
|
|
|
14
14
|
get: () => TValue;
|
|
15
15
|
peek: () => TValue;
|
|
16
16
|
set: (value: TValue) => Promise<void>;
|
|
17
|
+
setReplace: (value: TValue) => Promise<void>;
|
|
17
18
|
assign: (value: NonNullable<TValue> extends object ? Partial<NonNullable<TValue>> : never) => Promise<void>;
|
|
18
19
|
del: () => Promise<void>;
|
|
19
20
|
increment: (value?: number) => Promise<number>;
|
|
@@ -38,7 +38,7 @@ type SimplifiedProperties<TSchema> = {
|
|
|
38
38
|
type HasSimplifiedProperties<TSchema> = keyof SimplifiedProperties<TSchema> extends never ? false : true;
|
|
39
39
|
type SchemaProperties<TSchema> = TSchema extends {
|
|
40
40
|
readonly properties: infer Properties;
|
|
41
|
-
} ? IsFullObjectSchema<TSchema> extends true ? Properties : HasSimplifiedProperties<TSchema> extends true ? SimplifiedProperties<TSchema> : Record<
|
|
41
|
+
} ? IsFullObjectSchema<TSchema> extends true ? Properties : HasSimplifiedProperties<TSchema> extends true ? SimplifiedProperties<TSchema> : Record<never, never> : IsFullObjectSchema<TSchema> extends true ? Record<never, never> : HasSimplifiedProperties<TSchema> extends true ? SimplifiedProperties<TSchema> : Record<never, never>;
|
|
42
42
|
type ExplicitRequiredKeys<TSchema, TProperties> = TSchema extends {
|
|
43
43
|
readonly required?: infer Required;
|
|
44
44
|
} ? Required extends readonly string[] ? Extract<Required[number], keyof TProperties & string> : never : never;
|
|
@@ -50,10 +50,10 @@ type SimplifiedRequiredKeys<TProperties> = {
|
|
|
50
50
|
type RequiredKeys<TSchema, TProperties> = ExplicitRequiredKeys<TSchema, TProperties> | SimplifiedRequiredKeys<TProperties>;
|
|
51
51
|
type PatternPropertiesFromJsonSchema<TSchema> = TSchema extends {
|
|
52
52
|
readonly patternProperties?: infer PatternProperties;
|
|
53
|
-
} ? PatternProperties extends
|
|
53
|
+
} ? PatternProperties extends object ? keyof PatternProperties extends never ? {} : Record<string, FromJsonSchema<PatternProperties[keyof PatternProperties]>> : {} : {};
|
|
54
54
|
type AdditionalPropertiesFromJsonSchema<TSchema> = TSchema extends {
|
|
55
55
|
readonly additionalProperties?: infer AdditionalProperties;
|
|
56
|
-
} ? AdditionalProperties extends JsonSchema ? Record<string, FromJsonSchema<AdditionalProperties>> : {} : {};
|
|
56
|
+
} ? AdditionalProperties extends false ? {} : AdditionalProperties extends JsonSchema ? Record<string, FromJsonSchema<AdditionalProperties>> : {} : {};
|
|
57
57
|
type ObjectFromJsonSchema<TSchema> = SchemaProperties<TSchema> extends infer Properties ? Properties extends Record<string, unknown> ? Prettify<{
|
|
58
58
|
[K in RequiredKeys<TSchema, Properties>]-?: FromJsonSchema<Properties[K]>;
|
|
59
59
|
} & {
|