teamplay 0.5.0-alpha.25 → 0.5.0-alpha.27
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 +2 -1
- package/dist/index.js +1 -1
- package/dist/orm/Compat/SignalCompat.js +1 -20
- package/dist/orm/Root.d.ts +4 -0
- package/dist/orm/Root.js +16 -0
- package/dist/orm/SignalBase.d.ts +2 -0
- package/dist/orm/SignalBase.js +9 -1
- package/dist/orm/sub.d.ts +12 -7
- package/dist/orm/sub.js +87 -30
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -53,7 +53,8 @@ export { default as signal } from './orm/getSignal.js';
|
|
|
53
53
|
export { GLOBAL_ROOT_ID } from './orm/Root.js';
|
|
54
54
|
export declare const $: RootSignal;
|
|
55
55
|
export default $;
|
|
56
|
-
export { default as sub } from './orm/sub.js';
|
|
56
|
+
export { default as sub, unsub } from './orm/sub.js';
|
|
57
|
+
export type { SubMode, SubOptions } from './orm/sub.js';
|
|
57
58
|
export { default as useSub, useAsyncSub, useBatchSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from './react/useSub.js';
|
|
58
59
|
export { default as useSuspendMemo, useSuspendMemoByKey } from './react/useSuspendMemo.js';
|
|
59
60
|
export declare const observer: ObserverFunction;
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ export { GLOBAL_ROOT_ID } from "./orm/Root.js";
|
|
|
14
14
|
const getRuntimeRootSignal = _getRootSignal;
|
|
15
15
|
export const $ = getRuntimeRootSignal({ rootId: GLOBAL_ROOT_ID, rootFunction: universal$ });
|
|
16
16
|
export default $;
|
|
17
|
-
export { default as sub } from "./orm/sub.js";
|
|
17
|
+
export { default as sub, unsub } from "./orm/sub.js";
|
|
18
18
|
export { default as useSub, useAsyncSub, useBatchSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from "./react/useSub.js";
|
|
19
19
|
export { default as useSuspendMemo, useSuspendMemoByKey } from "./react/useSuspendMemo.js";
|
|
20
20
|
export const observer = runtimeObserver;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { raw, observe, unobserve } from '@nx-js/observer-util';
|
|
2
2
|
import arrayDiff from 'arraydiff';
|
|
3
3
|
import { Signal, GETTERS, DEFAULT_GETTERS, SEGMENTS, isPublicCollection, isPublicCollectionSignal, isPublicDocumentSignal } from "../SignalBase.js";
|
|
4
|
-
import { getRoot, ROOT, ROOT_ID, getRootSignal, GLOBAL_ROOT_ID
|
|
4
|
+
import { getRoot, ROOT, ROOT_ID, getRootSignal, GLOBAL_ROOT_ID } from "../Root.js";
|
|
5
5
|
import { docSubscriptions } from '../Doc.js';
|
|
6
6
|
import { IS_QUERY, getQuerySignal, querySubscriptions } from '../Query.js';
|
|
7
7
|
import { AGGREGATIONS, IS_AGGREGATION, aggregationSubscriptions, getAggregationSignal } from '../Aggregation.js';
|
|
@@ -16,7 +16,6 @@ import { runInBatch } from '../batchScheduler.js';
|
|
|
16
16
|
import { runInSilentContext, runInModelEventsSilentContext, isSilentContextActive } from './silentContext.js';
|
|
17
17
|
import universal$ from "../../react/universal$.js";
|
|
18
18
|
import { getRootContext } from "../rootContext.js";
|
|
19
|
-
import disposeRootContext from "../disposeRootContext.js";
|
|
20
19
|
import { arrayInsertPrivateData, arrayMovePrivateData, arrayPopPrivateData, arrayPushPrivateData, arrayRemovePrivateData, arrayShiftPrivateData, arrayUnshiftPrivateData, delPrivateData, setReplacePrivateData, stringInsertPrivateData, stringRemovePrivateData } from '../privateData.js';
|
|
21
20
|
class SignalCompat extends Signal {
|
|
22
21
|
static ID_FIELDS = ['_id', 'id'];
|
|
@@ -92,24 +91,6 @@ class SignalCompat extends Signal {
|
|
|
92
91
|
return this.extra.get();
|
|
93
92
|
return undefined;
|
|
94
93
|
}
|
|
95
|
-
close(callback) {
|
|
96
|
-
if (arguments.length > 1)
|
|
97
|
-
throw Error('Signal.close() expects zero or one argument');
|
|
98
|
-
if (callback != null && typeof callback !== 'function') {
|
|
99
|
-
throw Error('Signal.close() expects callback to be a function');
|
|
100
|
-
}
|
|
101
|
-
const $root = getRoot(this) || this;
|
|
102
|
-
const rootId = $root?.[ROOT_ID];
|
|
103
|
-
unregisterRootFinalizer($root);
|
|
104
|
-
disposeRootContext(rootId)
|
|
105
|
-
.then(() => callback?.())
|
|
106
|
-
.catch(err => {
|
|
107
|
-
if (callback)
|
|
108
|
-
callback(err);
|
|
109
|
-
else
|
|
110
|
-
console.error(err);
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
94
|
silent(value) {
|
|
114
95
|
if (arguments.length > 1)
|
|
115
96
|
throw Error('Signal.silent() expects zero or one argument');
|
package/dist/orm/Root.d.ts
CHANGED
|
@@ -14,8 +14,12 @@ export type RootSignalRuntime = SignalBaseInstance & {
|
|
|
14
14
|
[ROOT]?: RootSignalRuntime;
|
|
15
15
|
[ROOT_ID]?: string;
|
|
16
16
|
};
|
|
17
|
+
export type RootCloseCallback = (err?: unknown) => void;
|
|
17
18
|
export declare function getRootSignal({ rootFunction, fetchOnly, rootId, ...options }?: RootSignalOptions): RootSignalRuntime;
|
|
18
19
|
export declare function getRoot(signal: RootSignalRuntime | undefined): RootSignalRuntime | undefined;
|
|
20
|
+
export declare function closeRootSignalAsync(signal: RootSignalRuntime | undefined): Promise<void>;
|
|
21
|
+
export declare function closeRootSignal(signal: RootSignalRuntime | undefined): Promise<void>;
|
|
22
|
+
export declare function closeRootSignal(signal: RootSignalRuntime | undefined, callback?: RootCloseCallback): void;
|
|
19
23
|
export declare function getRootFetchOnly(rootOrRootId: RootSignalRuntime | string | undefined): boolean;
|
|
20
24
|
export declare function getRootTransportMode(rootOrRootId: RootSignalRuntime | string | undefined, intent?: RootTransportIntent): RootTransportIntent;
|
|
21
25
|
export declare function registerRootFinalizer($root: RootSignalRuntime | undefined): void;
|
package/dist/orm/Root.js
CHANGED
|
@@ -43,6 +43,22 @@ export function getRoot(signal) {
|
|
|
43
43
|
else
|
|
44
44
|
return undefined;
|
|
45
45
|
}
|
|
46
|
+
export function closeRootSignalAsync(signal) {
|
|
47
|
+
const $root = getRoot(signal) || signal;
|
|
48
|
+
const rootId = $root?.[ROOT_ID];
|
|
49
|
+
unregisterRootFinalizer($root);
|
|
50
|
+
return disposeRootContext(rootId);
|
|
51
|
+
}
|
|
52
|
+
export function closeRootSignal(signal, callback) {
|
|
53
|
+
const promise = closeRootSignalAsync(signal);
|
|
54
|
+
if (!callback)
|
|
55
|
+
return promise;
|
|
56
|
+
promise
|
|
57
|
+
.then(() => callback?.())
|
|
58
|
+
.catch(err => {
|
|
59
|
+
callback(err);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
46
62
|
export function getRootFetchOnly(rootOrRootId) {
|
|
47
63
|
const $root = typeof rootOrRootId === 'string'
|
|
48
64
|
? undefined
|
package/dist/orm/SignalBase.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ export declare class Signal<TValue = unknown> extends Function {
|
|
|
45
45
|
* @param fn Function to execute inside the batch.
|
|
46
46
|
*/
|
|
47
47
|
batch<TResult>(fn: () => TResult): TResult;
|
|
48
|
+
close(): Promise<void>;
|
|
49
|
+
close(callback: (err?: unknown) => void): void;
|
|
48
50
|
/**
|
|
49
51
|
* Internal read hook used by `.get()` and `.peek()`.
|
|
50
52
|
* @param method Storage read function to use for the current signal path.
|
package/dist/orm/SignalBase.js
CHANGED
|
@@ -20,7 +20,7 @@ import getSignal, { rawSignal } from "./getSignal.js";
|
|
|
20
20
|
import { docSubscriptions } from './Doc.js';
|
|
21
21
|
import { IS_QUERY, HASH, QUERIES } from './Query.js';
|
|
22
22
|
import { AGGREGATIONS, IS_AGGREGATION, getAggregationCollectionName, getAggregationDocId } from './Aggregation.js';
|
|
23
|
-
import { ROOT_FUNCTION, ROOT_ID, getRoot } from "./Root.js";
|
|
23
|
+
import { ROOT_FUNCTION, ROOT_ID, closeRootSignal, getRoot } from "./Root.js";
|
|
24
24
|
import { DEFAULT_ID_FIELDS, getIdFieldsForSegments, isIdFieldPath, isPlainObject, isPublicDocPath, normalizeIdFields, prepareAddPayload, resolveAddDocId } from "./idFields.js";
|
|
25
25
|
import { isCompatEnv } from './compatEnv.js';
|
|
26
26
|
import { resolveRefSegmentsSafe, resolveRefSignalSafe } from './Compat/refFallback.js';
|
|
@@ -181,6 +181,14 @@ export class Signal extends Function {
|
|
|
181
181
|
throw Error('Signal.batch() expects a function argument');
|
|
182
182
|
return runInBatch(fn);
|
|
183
183
|
}
|
|
184
|
+
close(callback) {
|
|
185
|
+
if (arguments.length > 1)
|
|
186
|
+
throw Error('Signal.close() expects zero or one argument');
|
|
187
|
+
if (callback != null && typeof callback !== 'function') {
|
|
188
|
+
throw Error('Signal.close() expects callback to be a function');
|
|
189
|
+
}
|
|
190
|
+
return callback ? closeRootSignal(this, callback) : closeRootSignal(this);
|
|
191
|
+
}
|
|
184
192
|
/**
|
|
185
193
|
* Internal read hook used by `.get()` and `.peek()`.
|
|
186
194
|
* @param method Storage read function to use for the current signal path.
|
package/dist/orm/sub.d.ts
CHANGED
|
@@ -1,40 +1,44 @@
|
|
|
1
1
|
import type { AggregationFunction, AggregationParams, ClientAggregationFunction } from '@teamplay/utils/aggregation';
|
|
2
2
|
import type { CollectionSignal, ComputedQueryParamsInput, DocumentSignal, MaybePromise, MaybePromiseSubResult, QueryParams, RegisteredAggregationInput, SignalModelConstructor, SubResult, TypedAggregationInput, TypedAggregationSignal, WildcardSignalPath } from './Signal.js';
|
|
3
|
+
export type SubMode = 'auto' | 'fetch' | 'subscribe';
|
|
4
|
+
export interface SubOptions {
|
|
5
|
+
mode?: SubMode;
|
|
6
|
+
}
|
|
3
7
|
/**
|
|
4
8
|
* Subscribe to an aggregation with explicit output typing outside React.
|
|
5
9
|
* @param $aggregation Typed aggregation input.
|
|
6
10
|
* @param params Parameters passed to the aggregation.
|
|
7
11
|
*/
|
|
8
|
-
export default function sub<TDocument, TDocumentModel extends SignalModelConstructor<TDocument>>($aggregation: TypedAggregationInput<TDocument, TDocumentModel>, params?: AggregationParams): MaybePromise<TypedAggregationSignal<TDocument, TDocumentModel>>;
|
|
12
|
+
export default function sub<TDocument, TDocumentModel extends SignalModelConstructor<TDocument>>($aggregation: TypedAggregationInput<TDocument, TDocumentModel>, params?: AggregationParams, options?: SubOptions): MaybePromise<TypedAggregationSignal<TDocument, TDocumentModel>>;
|
|
9
13
|
/**
|
|
10
14
|
* Subscribe to a registered collection aggregation outside React.
|
|
11
15
|
* @param $aggregation Aggregation header generated by StartupJS model loading.
|
|
12
16
|
* @param params Parameters passed to the aggregation.
|
|
13
17
|
*/
|
|
14
|
-
export default function sub<TCollection extends string, TOutput = unknown>($aggregation: RegisteredAggregationInput<TCollection, TOutput>, params?: AggregationParams): MaybePromise<SubResult<RegisteredAggregationInput<TCollection, TOutput>>>;
|
|
18
|
+
export default function sub<TCollection extends string, TOutput = unknown>($aggregation: RegisteredAggregationInput<TCollection, TOutput>, params?: AggregationParams, options?: SubOptions): MaybePromise<SubResult<RegisteredAggregationInput<TCollection, TOutput>>>;
|
|
15
19
|
/**
|
|
16
20
|
* Subscribe to a client aggregation outside React.
|
|
17
21
|
* @param $aggregation Aggregation function created with `aggregation(collection, fn)`.
|
|
18
22
|
* @param params Parameters passed to the aggregation.
|
|
19
23
|
*/
|
|
20
|
-
export default function sub<TOutput, TCollection extends string>($aggregation: ClientAggregationFunction<TOutput, TCollection>, params?: AggregationParams): MaybePromise<SubResult<ClientAggregationFunction<TOutput, TCollection>>>;
|
|
24
|
+
export default function sub<TOutput, TCollection extends string>($aggregation: ClientAggregationFunction<TOutput, TCollection>, params?: AggregationParams, options?: SubOptions): MaybePromise<SubResult<ClientAggregationFunction<TOutput, TCollection>>>;
|
|
21
25
|
/**
|
|
22
26
|
* Subscribe to an unregistered aggregation outside React.
|
|
23
27
|
* @param $aggregation Aggregation function.
|
|
24
28
|
* @param params Parameters passed to the aggregation.
|
|
25
29
|
*/
|
|
26
|
-
export default function sub<TOutput = unknown, TCollection extends string = string>($aggregation: AggregationFunction<TOutput, TCollection>, params?: AggregationParams): MaybePromise<SubResult<AggregationFunction<TOutput, TCollection>>>;
|
|
30
|
+
export default function sub<TOutput = unknown, TCollection extends string = string>($aggregation: AggregationFunction<TOutput, TCollection>, params?: AggregationParams, options?: SubOptions): MaybePromise<SubResult<AggregationFunction<TOutput, TCollection>>>;
|
|
27
31
|
/**
|
|
28
32
|
* Subscribe to a document signal outside React and return it when ready.
|
|
29
33
|
* @param $signal Document signal to subscribe to.
|
|
30
34
|
*/
|
|
31
|
-
export default function sub<TSignal extends DocumentSignal<any, any, any>>($signal: TSignal): MaybePromiseSubResult<TSignal>;
|
|
35
|
+
export default function sub<TSignal extends DocumentSignal<any, any, any>>($signal: TSignal, options?: SubOptions): MaybePromiseSubResult<TSignal>;
|
|
32
36
|
/**
|
|
33
37
|
* Subscribe to a collection query outside React and return a query signal when ready.
|
|
34
38
|
* @param $collection Collection signal to query.
|
|
35
39
|
* @param params Mongo-style query params, including filters and `$sort`.
|
|
36
40
|
*/
|
|
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
|
|
41
|
+
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>, options?: SubOptions): MaybePromiseSubResult<CollectionSignal<TDocument, TCollectionModel, TDocumentModel, TCollectionPath>, QueryParams<TDocument>>;
|
|
38
42
|
/**
|
|
39
43
|
* Subscribe to a collection query with computed string keys outside React.
|
|
40
44
|
* This fallback preserves Mongo-style computed paths such as `{ [`likes.${id}`]: true }`.
|
|
@@ -42,4 +46,5 @@ export default function sub<TDocument, TCollectionModel extends SignalModelConst
|
|
|
42
46
|
* @param $collection Collection signal to query.
|
|
43
47
|
* @param params Mongo-style query params with a widened computed key.
|
|
44
48
|
*/
|
|
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
|
|
49
|
+
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>, options?: SubOptions): MaybePromiseSubResult<CollectionSignal<TDocument, TCollectionModel, TDocumentModel, TCollectionPath>, TParams>;
|
|
50
|
+
export declare function unsub($signal: unknown): Promise<void> | void;
|
package/dist/orm/sub.js
CHANGED
|
@@ -3,9 +3,11 @@ import Signal, { SEGMENTS, isPublicCollectionSignal, isPublicDocumentSignal } fr
|
|
|
3
3
|
import { docSubscriptions } from './Doc.js';
|
|
4
4
|
import { querySubscriptions, getQuerySignal } from './Query.js';
|
|
5
5
|
import { aggregationSubscriptions, getAggregationSignal } from './Aggregation.js';
|
|
6
|
-
import { getRoot } from "./Root.js";
|
|
6
|
+
import { getRoot, ROOT_ID } from "./Root.js";
|
|
7
|
+
import { isRootContextClosed } from "./rootContext.js";
|
|
7
8
|
import isServer from "../utils/isServer.js";
|
|
8
|
-
|
|
9
|
+
const SUB_RECORDS = new WeakMap();
|
|
10
|
+
export default function sub($signal, params, options) {
|
|
9
11
|
// TODO: temporarily disable support for multiple subscriptions
|
|
10
12
|
// since this has to be properly cached using useDeferredSignal() in useSub()
|
|
11
13
|
// if (Array.isArray($signal)) {
|
|
@@ -16,26 +18,26 @@ export default function sub($signal, params) {
|
|
|
16
18
|
if (Array.isArray($signal))
|
|
17
19
|
throw Error('sub() does not support multiple subscriptions yet');
|
|
18
20
|
if (isRuntimePublicDocumentSignal($signal)) {
|
|
19
|
-
if (arguments.length >
|
|
21
|
+
if (arguments.length > 2) {
|
|
20
22
|
throw Error(ERRORS.subDocArguments($signal, ...Array.from(arguments).slice(1)));
|
|
21
23
|
}
|
|
22
|
-
return doc$($signal);
|
|
24
|
+
return doc$($signal, parseSubOptions(params));
|
|
23
25
|
}
|
|
24
26
|
else if (isRuntimePublicCollectionSignal($signal)) {
|
|
25
|
-
if (arguments.length
|
|
27
|
+
if (arguments.length < 2 || arguments.length > 3) {
|
|
26
28
|
throw Error(ERRORS.subQueryArguments($signal, params, ...Array.from(arguments).slice(2)));
|
|
27
29
|
}
|
|
28
|
-
return query$($signal, params);
|
|
30
|
+
return query$($signal, params, parseSubOptions(options));
|
|
29
31
|
}
|
|
30
32
|
else if (isClientAggregationFunction($signal)) {
|
|
31
|
-
return getAggregationFromFunction($signal, $signal.collection, params);
|
|
33
|
+
return getAggregationFromFunction($signal, $signal.collection, params, parseSubOptions(options));
|
|
32
34
|
}
|
|
33
35
|
else if (isAggregationHeader($signal)) {
|
|
34
36
|
const aggregationParams = {
|
|
35
37
|
$aggregationName: $signal.name,
|
|
36
38
|
$params: sanitizeAggregationParams(params)
|
|
37
39
|
};
|
|
38
|
-
return aggregation$($signal.collection, aggregationParams);
|
|
40
|
+
return aggregation$($signal.collection, aggregationParams, undefined, parseSubOptions(options));
|
|
39
41
|
}
|
|
40
42
|
else if (isAggregationFunction($signal)) {
|
|
41
43
|
if (isServer) {
|
|
@@ -46,7 +48,7 @@ export default function sub($signal, params) {
|
|
|
46
48
|
}
|
|
47
49
|
const aggregationParams = { ...serverParams };
|
|
48
50
|
delete aggregationParams.$collection;
|
|
49
|
-
return getAggregationFromFunction($signal, collection, aggregationParams);
|
|
51
|
+
return getAggregationFromFunction($signal, collection, aggregationParams, parseSubOptions(options));
|
|
50
52
|
}
|
|
51
53
|
else {
|
|
52
54
|
throw Error(ERRORS.gotAggregationFunction($signal));
|
|
@@ -59,7 +61,25 @@ export default function sub($signal, params) {
|
|
|
59
61
|
throw Error('Invalid args passed for sub()');
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
|
-
function
|
|
64
|
+
export function unsub($signal) {
|
|
65
|
+
if (!($signal instanceof Signal))
|
|
66
|
+
return;
|
|
67
|
+
const record = takeSubRecord($signal);
|
|
68
|
+
if (!record)
|
|
69
|
+
return;
|
|
70
|
+
record.disposed = true;
|
|
71
|
+
const $root = getRoot($signal);
|
|
72
|
+
const rootId = $root?.[ROOT_ID];
|
|
73
|
+
if (isRootContextClosed(rootId))
|
|
74
|
+
return;
|
|
75
|
+
if (record.kind === 'doc')
|
|
76
|
+
return docSubscriptions.unsubscribe($signal, { intent: record.intent });
|
|
77
|
+
if (record.kind === 'query')
|
|
78
|
+
return querySubscriptions.unsubscribe($signal, { intent: record.intent });
|
|
79
|
+
if (record.kind === 'aggregation')
|
|
80
|
+
return aggregationSubscriptions.unsubscribe($signal, { intent: record.intent });
|
|
81
|
+
}
|
|
82
|
+
function getAggregationFromFunction(fn, collection, params, subOptions) {
|
|
63
83
|
const aggregationParams = sanitizeAggregationParams(params);
|
|
64
84
|
let session;
|
|
65
85
|
if (isRecord(aggregationParams) && aggregationParams.$session) {
|
|
@@ -70,15 +90,13 @@ function getAggregationFromFunction(fn, collection, params) {
|
|
|
70
90
|
// should match the context in @teamplay/backend/features/serverAggregate.js
|
|
71
91
|
const context = { collection, session, isServer };
|
|
72
92
|
const result = fn(aggregationParams, context);
|
|
73
|
-
return aggregation$(collection, Array.isArray(result) ? { $aggregate: result } : result);
|
|
93
|
+
return aggregation$(collection, Array.isArray(result) ? { $aggregate: result } : result, undefined, subOptions);
|
|
74
94
|
}
|
|
75
|
-
function doc$($doc) {
|
|
76
|
-
const promise = docSubscriptions.subscribe($doc);
|
|
77
|
-
|
|
78
|
-
return $doc;
|
|
79
|
-
return new Promise(resolve => promise.then(() => resolve($doc)));
|
|
95
|
+
function doc$($doc, subOptions) {
|
|
96
|
+
const promise = docSubscriptions.subscribe($doc, { intent: subOptions.intent });
|
|
97
|
+
return returnSubscribedSignal($doc, 'doc', subOptions.intent, promise);
|
|
80
98
|
}
|
|
81
|
-
function query$($collection, params) {
|
|
99
|
+
function query$($collection, params, subOptions) {
|
|
82
100
|
const collectionName = $collection[SEGMENTS][0];
|
|
83
101
|
if (typeof collectionName !== 'string')
|
|
84
102
|
throw Error(ERRORS.queryCollectionName($collection));
|
|
@@ -86,20 +104,17 @@ function query$($collection, params) {
|
|
|
86
104
|
throw Error(ERRORS.queryParamsObject(collectionName, params));
|
|
87
105
|
const signalOptions = getQuerySignalOptions($collection);
|
|
88
106
|
const queryParams = params;
|
|
89
|
-
if (queryParams?.$aggregate || queryParams?.$aggregationName)
|
|
90
|
-
return aggregation$(collectionName, params, signalOptions);
|
|
107
|
+
if (queryParams?.$aggregate || queryParams?.$aggregationName) {
|
|
108
|
+
return aggregation$(collectionName, params, signalOptions, subOptions);
|
|
109
|
+
}
|
|
91
110
|
const $query = getQuerySignal(collectionName, params, signalOptions);
|
|
92
|
-
const promise = querySubscriptions.subscribe($query);
|
|
93
|
-
|
|
94
|
-
return $query;
|
|
95
|
-
return new Promise(resolve => promise.then(() => resolve($query)));
|
|
111
|
+
const promise = querySubscriptions.subscribe($query, { intent: subOptions.intent });
|
|
112
|
+
return returnSubscribedSignal($query, 'query', subOptions.intent, promise);
|
|
96
113
|
}
|
|
97
|
-
function aggregation$(collectionName, params, signalOptions) {
|
|
114
|
+
function aggregation$(collectionName, params, signalOptions, subOptions = parseSubOptions()) {
|
|
98
115
|
const $aggregationQuery = getAggregationSignal(collectionName, params, signalOptions);
|
|
99
|
-
const promise = aggregationSubscriptions.subscribe($aggregationQuery);
|
|
100
|
-
|
|
101
|
-
return $aggregationQuery;
|
|
102
|
-
return new Promise(resolve => promise.then(() => resolve($aggregationQuery)));
|
|
116
|
+
const promise = aggregationSubscriptions.subscribe($aggregationQuery, { intent: subOptions.intent });
|
|
117
|
+
return returnSubscribedSignal($aggregationQuery, 'aggregation', subOptions.intent, promise);
|
|
103
118
|
}
|
|
104
119
|
function api$(_fn, _args) {
|
|
105
120
|
throw Error('sub() for async functions is not implemented yet');
|
|
@@ -133,14 +148,56 @@ function isRuntimePublicCollectionSignal(value) {
|
|
|
133
148
|
function isApiFunction(value) {
|
|
134
149
|
return typeof value === 'function' && !(value instanceof Signal);
|
|
135
150
|
}
|
|
151
|
+
function parseSubOptions(options) {
|
|
152
|
+
const mode = options?.mode ?? 'auto';
|
|
153
|
+
if (mode !== 'auto' && mode !== 'fetch' && mode !== 'subscribe') {
|
|
154
|
+
throw Error(`sub() option mode must be "auto", "fetch", or "subscribe". Got: ${mode}`);
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
intent: mode === 'fetch' ? 'fetch' : 'subscribe'
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function returnSubscribedSignal($signal, kind, intent, promise) {
|
|
161
|
+
if (!promise) {
|
|
162
|
+
addSubRecord($signal, kind, intent);
|
|
163
|
+
return $signal;
|
|
164
|
+
}
|
|
165
|
+
return promise.then(() => {
|
|
166
|
+
addSubRecord($signal, kind, intent);
|
|
167
|
+
return $signal;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function addSubRecord($signal, kind, intent) {
|
|
171
|
+
let records = SUB_RECORDS.get($signal);
|
|
172
|
+
if (!records) {
|
|
173
|
+
records = [];
|
|
174
|
+
SUB_RECORDS.set($signal, records);
|
|
175
|
+
}
|
|
176
|
+
records.push({ kind, intent, disposed: false });
|
|
177
|
+
}
|
|
178
|
+
function takeSubRecord($signal) {
|
|
179
|
+
const records = SUB_RECORDS.get($signal);
|
|
180
|
+
if (!records)
|
|
181
|
+
return;
|
|
182
|
+
for (let i = records.length - 1; i >= 0; i--) {
|
|
183
|
+
const record = records[i];
|
|
184
|
+
if (record.disposed)
|
|
185
|
+
continue;
|
|
186
|
+
records.splice(i, 1);
|
|
187
|
+
if (records.length === 0)
|
|
188
|
+
SUB_RECORDS.delete($signal);
|
|
189
|
+
return record;
|
|
190
|
+
}
|
|
191
|
+
SUB_RECORDS.delete($signal);
|
|
192
|
+
}
|
|
136
193
|
const ERRORS = {
|
|
137
194
|
subDocArguments: ($signal, ...args) => `
|
|
138
|
-
sub($doc) accepts
|
|
195
|
+
sub($doc) accepts one or two arguments - the document signal and optional options.
|
|
139
196
|
Doc: ${$signal[SEGMENTS]}
|
|
140
197
|
Got args: ${[$signal, ...args]}
|
|
141
198
|
`,
|
|
142
199
|
subQueryArguments: ($signal, params, ...args) => `
|
|
143
|
-
sub($collection, params) accepts
|
|
200
|
+
sub($collection, params) accepts two or three arguments - the collection signal, query params, and optional options.
|
|
144
201
|
If you want to subscribe to all documents in a collection, pass an empty object: sub($collection, {}).
|
|
145
202
|
Collection: ${$signal[SEGMENTS]}
|
|
146
203
|
Params: ${params}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teamplay",
|
|
3
|
-
"version": "0.5.0-alpha.
|
|
3
|
+
"version": "0.5.0-alpha.27",
|
|
4
4
|
"description": "Full-stack signals ORM with multiplayer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -134,5 +134,5 @@
|
|
|
134
134
|
]
|
|
135
135
|
},
|
|
136
136
|
"license": "MIT",
|
|
137
|
-
"gitHead": "
|
|
137
|
+
"gitHead": "cbdbd79ede32eab577708675ab7a50c205bed50b"
|
|
138
138
|
}
|