@dxos/echo 0.8.4-main.8360d9e660 → 0.8.4-main.8baae0fced
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/LICENSE +102 -5
- package/README.md +3 -3
- package/dist/lib/neutral/Annotation.mjs +5 -3
- package/dist/lib/neutral/Database.mjs +8 -4
- package/dist/lib/neutral/Entity.mjs +16 -14
- package/dist/lib/neutral/Err.mjs +1 -1
- package/dist/lib/neutral/Extension.mjs +18 -0
- package/dist/lib/neutral/Extension.mjs.map +7 -0
- package/dist/lib/neutral/Feed.mjs +23 -18
- package/dist/lib/neutral/Filter.mjs +23 -13
- package/dist/lib/neutral/Format.mjs +3 -3
- package/dist/lib/neutral/JsonSchema.mjs +8 -8
- package/dist/lib/neutral/Key.mjs +1 -1
- package/dist/lib/neutral/Migration.mjs +17 -0
- package/dist/lib/neutral/Migration.mjs.map +7 -0
- package/dist/lib/neutral/Obj.mjs +16 -13
- package/dist/lib/neutral/Order.mjs +1 -1
- package/dist/lib/neutral/Query.mjs +19 -17
- package/dist/lib/neutral/QueryResult.mjs +1 -1
- package/dist/lib/neutral/Ref.mjs +9 -7
- package/dist/lib/neutral/Relation.mjs +15 -14
- package/dist/lib/neutral/SchemaRegistry.mjs +1 -1
- package/dist/lib/neutral/Tag.mjs +14 -13
- package/dist/lib/neutral/Type.mjs +10 -10
- package/dist/lib/neutral/{chunk-FZO7LQO7.mjs → chunk-44HT3MEC.mjs} +2 -2
- package/dist/lib/neutral/{chunk-ROAGDPV7.mjs → chunk-4A2GS5LQ.mjs} +12 -8
- package/dist/lib/neutral/chunk-4A2GS5LQ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-OENWMTE6.mjs → chunk-5SL5LDLD.mjs} +4 -2
- package/dist/lib/neutral/chunk-5SL5LDLD.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-ANHVGJI4.mjs → chunk-7RVZT53K.mjs} +1 -1
- package/dist/lib/neutral/{chunk-YWXWXIE5.mjs → chunk-APHSOTIX.mjs} +2 -2
- package/dist/lib/neutral/{chunk-YWXWXIE5.mjs.map → chunk-APHSOTIX.mjs.map} +2 -2
- package/dist/lib/neutral/{chunk-6DNYDXCV.mjs → chunk-B2P7IVG3.mjs} +61 -14
- package/dist/lib/neutral/chunk-B2P7IVG3.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-BNCCGLJN.mjs → chunk-BICZKPQG.mjs} +1 -1
- package/dist/lib/neutral/{chunk-43Y5DOS6.mjs → chunk-BMB7IHGB.mjs} +16 -66
- package/dist/lib/neutral/chunk-BMB7IHGB.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-6K2MVI2O.mjs → chunk-BUBEC474.mjs} +4 -4
- package/dist/lib/neutral/{chunk-YMNSMKKW.mjs → chunk-C4PSESGN.mjs} +6 -22
- package/dist/lib/neutral/{chunk-YMNSMKKW.mjs.map → chunk-C4PSESGN.mjs.map} +3 -3
- package/dist/lib/neutral/chunk-FIWO2FZK.mjs +36 -0
- package/dist/lib/neutral/chunk-FIWO2FZK.mjs.map +7 -0
- package/dist/lib/neutral/chunk-GWFFC34K.mjs +50 -0
- package/dist/lib/neutral/chunk-GWFFC34K.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-NXMFBIT5.mjs → chunk-HKETO4L4.mjs} +72 -6
- package/dist/lib/neutral/chunk-HKETO4L4.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-NEGC54NE.mjs → chunk-I2DARWPX.mjs} +17 -19
- package/dist/lib/neutral/chunk-I2DARWPX.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-7VNVH63N.mjs → chunk-IVSI7QO6.mjs} +50 -20
- package/dist/lib/neutral/chunk-IVSI7QO6.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-BOZZPUXE.mjs → chunk-MLS7U7AT.mjs} +12 -65
- package/dist/lib/neutral/chunk-MLS7U7AT.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-WYOKA6AE.mjs → chunk-N4B7FHQT.mjs} +2 -2
- package/dist/lib/neutral/{chunk-WYOKA6AE.mjs.map → chunk-N4B7FHQT.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-FXEG7EOK.mjs → chunk-N7VOEPSV.mjs} +6 -3
- package/dist/lib/neutral/{chunk-FXEG7EOK.mjs.map → chunk-N7VOEPSV.mjs.map} +3 -3
- package/dist/lib/neutral/{chunk-UTBRYVQC.mjs → chunk-QRZ2I3ZM.mjs} +2 -2
- package/dist/lib/neutral/{chunk-SEMVAGBM.mjs → chunk-TNBK56IN.mjs} +19 -24
- package/dist/lib/neutral/chunk-TNBK56IN.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-B5OXLWZL.mjs → chunk-TRPZU2HV.mjs} +2 -2
- package/dist/lib/neutral/{chunk-UI6MWK5W.mjs → chunk-TTCSATUD.mjs} +1 -1
- package/dist/lib/neutral/{chunk-OMUPQMLR.mjs → chunk-V72DY6LU.mjs} +1 -1
- package/dist/lib/neutral/{chunk-6GPU7XC3.mjs → chunk-VW42HESL.mjs} +54 -17
- package/dist/lib/neutral/chunk-VW42HESL.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-4JRI2ZJI.mjs → chunk-X3356HPV.mjs} +120 -12
- package/dist/lib/neutral/chunk-X3356HPV.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-W47JKR3X.mjs → chunk-XEXM5HWQ.mjs} +18 -46
- package/dist/lib/neutral/chunk-XEXM5HWQ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-C4JZK4J7.mjs → chunk-Z5GKP74O.mjs} +231 -479
- package/dist/lib/neutral/chunk-Z5GKP74O.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-UBEZSGXY.mjs → chunk-ZISMEVKD.mjs} +1 -1
- package/dist/lib/neutral/{chunk-UBEZSGXY.mjs.map → chunk-ZISMEVKD.mjs.map} +2 -2
- package/dist/lib/neutral/index.mjs +38 -28
- package/dist/lib/neutral/internal/index.mjs +15 -9
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/testing/index.mjs +185 -129
- package/dist/lib/neutral/testing/index.mjs.map +3 -3
- package/dist/types/src/Annotation.d.ts +1 -1
- package/dist/types/src/Annotation.d.ts.map +1 -1
- package/dist/types/src/Collection.d.ts.map +1 -1
- package/dist/types/src/Database.d.ts +14 -2
- package/dist/types/src/Database.d.ts.map +1 -1
- package/dist/types/src/Dataset.d.ts +2 -1
- package/dist/types/src/Dataset.d.ts.map +1 -1
- package/dist/types/src/Entity.d.ts +17 -11
- package/dist/types/src/Entity.d.ts.map +1 -1
- package/dist/types/src/Err.d.ts +18 -18
- package/dist/types/src/Err.d.ts.map +1 -1
- package/dist/types/src/Extension.d.ts +80 -0
- package/dist/types/src/Extension.d.ts.map +1 -0
- package/dist/types/src/Extension.test.d.ts +2 -0
- package/dist/types/src/Extension.test.d.ts.map +1 -0
- package/dist/types/src/Feed.d.ts +62 -21
- package/dist/types/src/Feed.d.ts.map +1 -1
- package/dist/types/src/Filter.d.ts +54 -4
- package/dist/types/src/Filter.d.ts.map +1 -1
- package/dist/types/src/Filter.test.d.ts +2 -0
- package/dist/types/src/Filter.test.d.ts.map +1 -0
- package/dist/types/src/Hypergraph.d.ts +3 -3
- package/dist/types/src/Hypergraph.d.ts.map +1 -1
- package/dist/types/src/Json.d.ts +33 -0
- package/dist/types/src/Json.d.ts.map +1 -0
- package/dist/types/src/Json.test.d.ts +2 -0
- package/dist/types/src/Json.test.d.ts.map +1 -0
- package/dist/types/src/JsonSchema.d.ts +1 -1
- package/dist/types/src/Migration.d.ts +69 -0
- package/dist/types/src/Migration.d.ts.map +1 -0
- package/dist/types/src/Obj.d.ts +42 -28
- package/dist/types/src/Obj.d.ts.map +1 -1
- package/dist/types/src/Order.d.ts.map +1 -1
- package/dist/types/src/Query.d.ts +13 -2
- package/dist/types/src/Query.d.ts.map +1 -1
- package/dist/types/src/Ref.d.ts +1 -0
- package/dist/types/src/Ref.d.ts.map +1 -1
- package/dist/types/src/Relation.d.ts +17 -18
- package/dist/types/src/Relation.d.ts.map +1 -1
- package/dist/types/src/Tag.d.ts +2 -2
- package/dist/types/src/Tag.d.ts.map +1 -1
- package/dist/types/src/Type.d.ts +3 -3
- package/dist/types/src/Type.d.ts.map +1 -1
- package/dist/types/src/View.d.ts +1 -1
- package/dist/types/src/View.d.ts.map +1 -1
- package/dist/types/src/exemplars.test.d.ts +2 -0
- package/dist/types/src/exemplars.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +3 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/annotations.d.ts +12 -2
- package/dist/types/src/internal/Annotation/annotations.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/sorting.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/util.d.ts +1 -1
- package/dist/types/src/internal/Annotation/util.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/api.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/model.d.ts +2 -0
- package/dist/types/src/internal/Entity/model.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/object.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/relation.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/version.d.ts.map +1 -1
- package/dist/types/src/internal/Format/date.d.ts.map +1 -1
- package/dist/types/src/internal/Format/format.d.ts.map +1 -1
- package/dist/types/src/internal/Format/number.d.ts.map +1 -1
- package/dist/types/src/internal/Format/object.d.ts.map +1 -1
- package/dist/types/src/internal/Format/types.d.ts.map +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema-normalize.d.ts.map +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts +28 -28
- package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts.map +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema.d.ts +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/clone.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/common.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/create-object.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/deleted.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/ids.d.ts +1 -1
- package/dist/types/src/internal/Obj/ids.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/json-serializer.d.ts +4 -3
- package/dist/types/src/internal/Obj/json-serializer.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/set-value.d.ts +1 -1
- package/dist/types/src/internal/Obj/set-value.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/snapshot.d.ts.map +1 -1
- package/dist/types/src/internal/Query.d.ts +10 -0
- package/dist/types/src/internal/Query.d.ts.map +1 -0
- package/dist/types/src/internal/Ref/ref-array.d.ts.map +1 -1
- package/dist/types/src/internal/Ref/ref.d.ts +14 -1
- package/dist/types/src/internal/Ref/ref.d.ts.map +1 -1
- package/dist/types/src/internal/Type/compose.d.ts.map +1 -1
- package/dist/types/src/internal/Type/echo-schema.d.ts +2 -2
- package/dist/types/src/internal/Type/echo-schema.d.ts.map +1 -1
- package/dist/types/src/internal/Type/manipulation.d.ts.map +1 -1
- package/dist/types/src/internal/common/api/meta.d.ts +3 -3
- package/dist/types/src/internal/common/api/meta.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/change-context.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/change-context.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/define-hidden-property.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/errors.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/errors.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/event-batch.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/json-serializer.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/make-object.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/ownership.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/proxy-utils.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/reactive-array.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/reactive.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/reactive.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/reactive.test.d.ts +2 -0
- package/dist/types/src/internal/common/proxy/reactive.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/schema-validator.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/typed-handler.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/base.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/entity.d.ts +4 -4
- package/dist/types/src/internal/common/types/entity.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/meta.d.ts +10 -0
- package/dist/types/src/internal/common/types/meta.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/version.d.ts +1 -1
- package/dist/types/src/internal/index.d.ts +1 -0
- package/dist/types/src/internal/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-data.d.ts +8 -8
- package/dist/types/src/testing/test-data.d.ts.map +1 -1
- package/dist/types/src/testing/test-schema.d.ts +53 -53
- package/dist/types/src/testing/test-schema.d.ts.map +1 -1
- package/dist/types/src/testing/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +25 -15
- package/src/Annotation.ts +1 -0
- package/src/Collection.ts +2 -2
- package/src/Database.ts +50 -15
- package/src/Entity.ts +18 -12
- package/src/Extension.test.ts +235 -0
- package/src/Extension.ts +122 -0
- package/src/Feed.ts +107 -34
- package/src/Filter.test.ts +90 -0
- package/src/Filter.ts +97 -3
- package/src/Hypergraph.ts +3 -3
- package/src/Json.test.ts +175 -0
- package/src/Json.ts +102 -0
- package/src/Migration.ts +106 -0
- package/src/Obj.test.ts +105 -13
- package/src/Obj.ts +154 -33
- package/src/Query.test.ts +199 -9
- package/src/Query.ts +58 -8
- package/src/Ref.ts +2 -0
- package/src/Relation.ts +24 -20
- package/src/Type.ts +1 -1
- package/src/View.ts +1 -1
- package/src/exemplars.test.ts +21 -0
- package/src/index.ts +4 -0
- package/src/internal/Annotation/annotations.test.ts +51 -2
- package/src/internal/Annotation/annotations.ts +33 -14
- package/src/internal/Annotation/sorting.ts +0 -1
- package/src/internal/Entity/api.ts +0 -1
- package/src/internal/Entity/model.ts +2 -0
- package/src/internal/Entity/object.ts +0 -1
- package/src/internal/Entity/version.ts +0 -1
- package/src/internal/Format/date.test.ts +0 -1
- package/src/internal/Format/format.test.ts +0 -1
- package/src/internal/JsonSchema/json-schema-type.ts +1 -1
- package/src/internal/JsonSchema/json-schema.test.ts +1 -2
- package/src/internal/JsonSchema/json-schema.ts +1 -2
- package/src/internal/Obj/clone.ts +1 -1
- package/src/internal/Obj/create-object.test.ts +2 -4
- package/src/internal/Obj/create-object.ts +2 -3
- package/src/internal/Obj/deleted.ts +1 -1
- package/src/internal/Obj/ids.ts +1 -1
- package/src/internal/Obj/json-serializer.test.ts +49 -5
- package/src/internal/Obj/json-serializer.ts +47 -25
- package/src/internal/Obj/set-value.test.ts +24 -24
- package/src/internal/Obj/set-value.ts +1 -1
- package/src/internal/Query.ts +156 -0
- package/src/internal/Ref/ref-array.ts +0 -1
- package/src/internal/Ref/ref.test.ts +0 -1
- package/src/internal/Ref/ref.ts +18 -1
- package/src/internal/Type/compose.test.ts +0 -1
- package/src/internal/Type/echo-schema.ts +3 -4
- package/src/internal/common/README.md +1 -1
- package/src/internal/common/api/meta.ts +3 -3
- package/src/internal/common/proxy/change-context.ts +1 -1
- package/src/internal/common/proxy/change.test.ts +94 -94
- package/src/internal/common/proxy/errors.ts +2 -2
- package/src/internal/common/proxy/handler.test.ts +0 -2
- package/src/internal/common/proxy/json-serializer.ts +4 -1
- package/src/internal/common/proxy/make-object.ts +0 -1
- package/src/internal/common/proxy/ownership.ts +0 -1
- package/src/internal/common/proxy/reactive-array.ts +1 -1
- package/src/internal/common/proxy/reactive.test.ts +54 -0
- package/src/internal/common/proxy/reactive.ts +11 -3
- package/src/internal/common/proxy/typed-handler.test.ts +0 -1
- package/src/internal/common/proxy/typed-handler.ts +8 -10
- package/src/internal/common/proxy/typed-object.test.ts +2 -3
- package/src/internal/common/types/entity.ts +1 -1
- package/src/internal/common/types/meta.ts +12 -1
- package/src/internal/index.ts +1 -0
- package/src/testing/api.test.ts +0 -1
- package/src/testing/test-data.ts +157 -98
- package/dist/lib/neutral/chunk-43Y5DOS6.mjs.map +0 -7
- package/dist/lib/neutral/chunk-4JRI2ZJI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-6DNYDXCV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-6GPU7XC3.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7VNVH63N.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BOZZPUXE.mjs.map +0 -7
- package/dist/lib/neutral/chunk-C4JZK4J7.mjs.map +0 -7
- package/dist/lib/neutral/chunk-NEGC54NE.mjs.map +0 -7
- package/dist/lib/neutral/chunk-NXMFBIT5.mjs.map +0 -7
- package/dist/lib/neutral/chunk-OENWMTE6.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ROAGDPV7.mjs.map +0 -7
- package/dist/lib/neutral/chunk-SEMVAGBM.mjs.map +0 -7
- package/dist/lib/neutral/chunk-W47JKR3X.mjs.map +0 -7
- /package/dist/lib/neutral/{chunk-FZO7LQO7.mjs.map → chunk-44HT3MEC.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-ANHVGJI4.mjs.map → chunk-7RVZT53K.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-BNCCGLJN.mjs.map → chunk-BICZKPQG.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-6K2MVI2O.mjs.map → chunk-BUBEC474.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-UTBRYVQC.mjs.map → chunk-QRZ2I3ZM.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-B5OXLWZL.mjs.map → chunk-TRPZU2HV.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-UI6MWK5W.mjs.map → chunk-TTCSATUD.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-OMUPQMLR.mjs.map → chunk-V72DY6LU.mjs.map} +0 -0
package/src/Obj.ts
CHANGED
|
@@ -5,22 +5,25 @@
|
|
|
5
5
|
// @import-as-namespace
|
|
6
6
|
|
|
7
7
|
import * as Effect from 'effect/Effect';
|
|
8
|
+
import * as Equal from 'effect/Equal';
|
|
8
9
|
import * as Function from 'effect/Function';
|
|
9
10
|
import * as Option from 'effect/Option';
|
|
10
11
|
import * as Schema from 'effect/Schema';
|
|
12
|
+
import * as Utils from 'effect/Utils';
|
|
11
13
|
|
|
12
14
|
import type { ForeignKey } from '@dxos/echo-protocol';
|
|
13
15
|
import { createJsonPath } from '@dxos/effect';
|
|
14
|
-
import { assertArgument } from '@dxos/invariant';
|
|
16
|
+
import { assertArgument, invariant } from '@dxos/invariant';
|
|
15
17
|
import { type DXN, ObjectId } from '@dxos/keys';
|
|
16
|
-
import { assumeType } from '@dxos/util';
|
|
18
|
+
import { assumeType, deepMapValues } from '@dxos/util';
|
|
17
19
|
|
|
18
20
|
import type * as Database from './Database';
|
|
19
21
|
import * as Entity from './Entity';
|
|
20
22
|
import * as Err from './Err';
|
|
21
|
-
import * as objInternal from './internal/Obj';
|
|
22
23
|
import * as internal from './internal';
|
|
23
|
-
import
|
|
24
|
+
import { getProxyTarget, isProxy } from './internal/common/proxy/proxy-utils';
|
|
25
|
+
import * as objInternal from './internal/Obj';
|
|
26
|
+
import * as Ref from './Ref';
|
|
24
27
|
import type * as Type from './Type';
|
|
25
28
|
|
|
26
29
|
/**
|
|
@@ -81,8 +84,6 @@ export const Unknown: Type.Obj<Unknown> = Schema.Struct({
|
|
|
81
84
|
}) as unknown as Type.Obj<Unknown>,
|
|
82
85
|
);
|
|
83
86
|
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
87
|
/**
|
|
87
88
|
* Object with arbitrary properties.
|
|
88
89
|
*
|
|
@@ -303,7 +304,7 @@ export const clone: <T extends Unknown>(obj: T, opts?: CloneOptions) => T = objI
|
|
|
303
304
|
|
|
304
305
|
/**
|
|
305
306
|
* Makes all properties mutable recursively.
|
|
306
|
-
* Used to provide a mutable view of an object within `Obj.
|
|
307
|
+
* Used to provide a mutable view of an object within `Obj.update`.
|
|
307
308
|
*/
|
|
308
309
|
export type Mutable<T> = internal.Mutable<T>;
|
|
309
310
|
|
|
@@ -311,33 +312,33 @@ export type Mutable<T> = internal.Mutable<T>;
|
|
|
311
312
|
* Perform mutations on an echo object within a controlled context.
|
|
312
313
|
*
|
|
313
314
|
* All mutations within the callback are batched and trigger a single notification
|
|
314
|
-
* when the callback completes. Direct mutations outside of `Obj.
|
|
315
|
+
* when the callback completes. Direct mutations outside of `Obj.update` will throw
|
|
315
316
|
* an error for echo objects.
|
|
316
317
|
*
|
|
317
318
|
* This function also works with nested objects within echo objects (e.g., Template structs)
|
|
318
319
|
* that are reactive at runtime.
|
|
319
320
|
*
|
|
320
|
-
* @param obj - The echo object to mutate. Use `Relation.
|
|
321
|
+
* @param obj - The echo object to mutate. Use `Relation.update` for relations.
|
|
321
322
|
* @param callback - The callback that performs mutations on the object.
|
|
322
323
|
*
|
|
323
324
|
* @example
|
|
324
325
|
* ```ts
|
|
325
326
|
* const person = Obj.make(Person, { name: 'John', age: 25 });
|
|
326
327
|
*
|
|
327
|
-
* // Mutate within Obj.
|
|
328
|
-
* Obj.
|
|
329
|
-
*
|
|
330
|
-
*
|
|
328
|
+
* // Mutate within Obj.update
|
|
329
|
+
* Obj.update(person, (obj) => {
|
|
330
|
+
* obj.name = 'Jane';
|
|
331
|
+
* obj.age = 30;
|
|
331
332
|
* });
|
|
332
333
|
* // ONE notification fires here
|
|
333
334
|
*
|
|
334
335
|
* // Direct mutation throws
|
|
335
|
-
* person.name = 'Bob'; // Error: Cannot modify outside Obj.
|
|
336
|
+
* person.name = 'Bob'; // Error: Cannot modify outside Obj.update()
|
|
336
337
|
* ```
|
|
337
338
|
*
|
|
338
|
-
* Note: Only accepts objects. Use `Relation.
|
|
339
|
+
* Note: Only accepts objects. Use `Relation.update` for relations.
|
|
339
340
|
*/
|
|
340
|
-
export const
|
|
341
|
+
export const update = <T extends Unknown>(obj: T, callback: internal.ChangeCallback<T>): void => {
|
|
341
342
|
internal.change(obj, callback);
|
|
342
343
|
};
|
|
343
344
|
|
|
@@ -372,7 +373,7 @@ export const getValue = (obj: Unknown | Snapshot, path: readonly (string | numbe
|
|
|
372
373
|
* whether to initialize nested data as an empty object or array.
|
|
373
374
|
*
|
|
374
375
|
* Similar to lodash.set and setDeep from @dxos/util, but schema-aware.
|
|
375
|
-
* Must be called within an `Obj.
|
|
376
|
+
* Must be called within an `Obj.update` callback.
|
|
376
377
|
*
|
|
377
378
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
378
379
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -386,8 +387,8 @@ export const getValue = (obj: Unknown | Snapshot, path: readonly (string | numbe
|
|
|
386
387
|
* ```ts
|
|
387
388
|
* const person = Obj.make(Person, { name: 'John' });
|
|
388
389
|
* // Person schema has: addresses: Schema.Array(Address)
|
|
389
|
-
* Obj.
|
|
390
|
-
* Obj.setValue(
|
|
390
|
+
* Obj.update(person, (obj) => {
|
|
391
|
+
* Obj.setValue(obj, ['addresses', 0, 'street'], '123 Main St');
|
|
391
392
|
* });
|
|
392
393
|
* // Creates: person.addresses = [{ street: '123 Main St' }]
|
|
393
394
|
* ```
|
|
@@ -469,16 +470,19 @@ export const getDXN = (entity: Unknown | Snapshot): DXN => {
|
|
|
469
470
|
/**
|
|
470
471
|
* @returns The DXN of the object's type.
|
|
471
472
|
* @example dxn:com.example.type.person:1.0.0
|
|
473
|
+
* @throws If the object is missing its type (corrupted object).
|
|
472
474
|
*/
|
|
473
|
-
|
|
474
|
-
|
|
475
|
+
export const getTypeDXN = (obj: Unknown | Snapshot): DXN => {
|
|
476
|
+
const type = internal.getTypeDXN(obj);
|
|
477
|
+
invariant(type != null, 'Corrupted object: missing type.');
|
|
478
|
+
return type;
|
|
479
|
+
};
|
|
475
480
|
|
|
476
481
|
/**
|
|
477
482
|
* Get the schema of the object.
|
|
478
483
|
* Returns the branded ECHO schema used to create the object.
|
|
479
484
|
*/
|
|
480
|
-
|
|
481
|
-
export const getSchema: (obj: unknown | undefined) => Type.AnyEntity | undefined = internal.getSchema as any;
|
|
485
|
+
export const getSchema: (obj: Unknown | Snapshot) => Type.AnyEntity | undefined = internal.getSchema as any;
|
|
482
486
|
|
|
483
487
|
/**
|
|
484
488
|
* @returns The typename of the object's type.
|
|
@@ -516,7 +520,7 @@ export const Meta = internal.MetaId;
|
|
|
516
520
|
export type ReadonlyMeta = internal.ReadonlyMeta;
|
|
517
521
|
|
|
518
522
|
/**
|
|
519
|
-
* Mutable meta type returned by `Obj.getMeta` inside an `Obj.
|
|
523
|
+
* Mutable meta type returned by `Obj.getMeta` inside an `Obj.update` callback.
|
|
520
524
|
*/
|
|
521
525
|
export type Meta = internal.Meta;
|
|
522
526
|
|
|
@@ -524,7 +528,7 @@ export type Meta = internal.Meta;
|
|
|
524
528
|
// TODO(dmaretskyi): Allow returning undefined.
|
|
525
529
|
/**
|
|
526
530
|
* Get the metadata for an object.
|
|
527
|
-
* Returns mutable meta when passed a mutable object (inside `Obj.
|
|
531
|
+
* Returns mutable meta when passed a mutable object (inside `Obj.update` callback).
|
|
528
532
|
* Returns read-only meta when passed a regular object or snapshot.
|
|
529
533
|
*
|
|
530
534
|
* @example
|
|
@@ -533,8 +537,8 @@ export type Meta = internal.Meta;
|
|
|
533
537
|
* const meta = Obj.getMeta(person); // ReadonlyMeta
|
|
534
538
|
*
|
|
535
539
|
* // Mutable access inside change callback
|
|
536
|
-
* Obj.
|
|
537
|
-
* const meta = Obj.getMeta(
|
|
540
|
+
* Obj.update(person, (obj) => {
|
|
541
|
+
* const meta = Obj.getMeta(obj); // ObjectMeta (mutable)
|
|
538
542
|
* meta.tags ??= [];
|
|
539
543
|
* meta.tags.push('important');
|
|
540
544
|
* });
|
|
@@ -558,7 +562,7 @@ export const getKeys: {
|
|
|
558
562
|
|
|
559
563
|
/**
|
|
560
564
|
* Delete all keys from the object for the specified source.
|
|
561
|
-
* Must be called within an `Obj.
|
|
565
|
+
* Must be called within an `Obj.update` callback.
|
|
562
566
|
*
|
|
563
567
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
564
568
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -567,7 +571,7 @@ export const deleteKeys = (entity: Mutable<Unknown>, source: string): void => in
|
|
|
567
571
|
|
|
568
572
|
/**
|
|
569
573
|
* Add a tag to the object.
|
|
570
|
-
* Must be called within an `Obj.
|
|
574
|
+
* Must be called within an `Obj.update` callback.
|
|
571
575
|
*
|
|
572
576
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
573
577
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -576,7 +580,7 @@ export const addTag = (entity: Mutable<Unknown>, tag: string): void => internal.
|
|
|
576
580
|
|
|
577
581
|
/**
|
|
578
582
|
* Remove a tag from the object.
|
|
579
|
-
* Must be called within an `Obj.
|
|
583
|
+
* Must be called within an `Obj.update` callback.
|
|
580
584
|
*
|
|
581
585
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
582
586
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -602,7 +606,7 @@ export const getLabel = (entity: Unknown | Snapshot): string | undefined => inte
|
|
|
602
606
|
|
|
603
607
|
/**
|
|
604
608
|
* Set the label of the object.
|
|
605
|
-
* Must be called within an `Obj.
|
|
609
|
+
* Must be called within an `Obj.update` callback.
|
|
606
610
|
*
|
|
607
611
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
608
612
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -617,7 +621,7 @@ export const getDescription = (entity: Unknown | Snapshot): string | undefined =
|
|
|
617
621
|
|
|
618
622
|
/**
|
|
619
623
|
* Set the description of the object.
|
|
620
|
-
* Must be called within an `Obj.
|
|
624
|
+
* Must be called within an `Obj.update` callback.
|
|
621
625
|
*
|
|
622
626
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
623
627
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -660,6 +664,123 @@ export const setParent = (entity: Unknown, parent: Any | undefined) => {
|
|
|
660
664
|
assumeType<internal.InternalObjectProps>(entity);
|
|
661
665
|
assumeType<internal.InternalObjectProps | undefined>(parent);
|
|
662
666
|
entity[internal.ParentId] = parent;
|
|
667
|
+
return entity;
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
interface UpdateFromOptions<T> {
|
|
671
|
+
exclude?: (keyof T)[];
|
|
672
|
+
include?: (keyof T)[];
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const valuesEqual = (left: unknown, right: unknown): boolean => {
|
|
676
|
+
if (left === right) {
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
679
|
+
if (left === null || right === null) {
|
|
680
|
+
return left === right;
|
|
681
|
+
}
|
|
682
|
+
if (typeof left !== 'object' || typeof right !== 'object') {
|
|
683
|
+
return Utils.structuralRegion(() => Equal.equals(left, right));
|
|
684
|
+
}
|
|
685
|
+
if (Ref.isRef(left) && Ref.isRef(right)) {
|
|
686
|
+
return left.dxn.toString() === right.dxn.toString();
|
|
687
|
+
}
|
|
688
|
+
if (Ref.isRef(left) || Ref.isRef(right)) {
|
|
689
|
+
return false;
|
|
690
|
+
}
|
|
691
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
692
|
+
if (left.length !== right.length) {
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
for (let index = 0; index < left.length; index++) {
|
|
696
|
+
if (!valuesEqual(left[index], right[index])) {
|
|
697
|
+
return false;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
const leftRecord = left as Record<string, unknown>;
|
|
706
|
+
const rightRecord = right as Record<string, unknown>;
|
|
707
|
+
const keys = new Set([
|
|
708
|
+
...Object.keys(leftRecord).filter((key) => key !== 'id'),
|
|
709
|
+
...Object.keys(rightRecord).filter((key) => key !== 'id'),
|
|
710
|
+
]);
|
|
711
|
+
for (const key of keys) {
|
|
712
|
+
const leftHas = Object.hasOwn(leftRecord, key);
|
|
713
|
+
const rightHas = Object.hasOwn(rightRecord, key);
|
|
714
|
+
const leftValue = leftHas ? leftRecord[key] : undefined;
|
|
715
|
+
const rightValue = rightHas ? rightRecord[key] : undefined;
|
|
716
|
+
if (!valuesEqual(leftValue, rightValue)) {
|
|
717
|
+
return false;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return true;
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Breaks reactive proxies on assigned values so echo-db assignment accepts nested structs (same idea as link assignment).
|
|
725
|
+
*/
|
|
726
|
+
const prepareAssignValue = (value: unknown): unknown =>
|
|
727
|
+
deepMapValues(value, (nested, recurse) => {
|
|
728
|
+
if (nested === null || typeof nested !== 'object') {
|
|
729
|
+
return nested;
|
|
730
|
+
}
|
|
731
|
+
if (Ref.isRef(nested)) {
|
|
732
|
+
return nested;
|
|
733
|
+
}
|
|
734
|
+
if (Array.isArray(nested)) {
|
|
735
|
+
return recurse(nested);
|
|
736
|
+
}
|
|
737
|
+
if (isProxy(nested)) {
|
|
738
|
+
return recurse({ ...getProxyTarget(nested) });
|
|
739
|
+
}
|
|
740
|
+
return recurse(nested);
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* For each key present on `source` (except `id`), assigns `target[key]` when the current value differs.
|
|
745
|
+
* References are compared by target DXN; other values use Effect `Equal.equals` inside a structural region,
|
|
746
|
+
* with recursive comparison for arrays and plain object-shaped property bags (excluding `id`).
|
|
747
|
+
*
|
|
748
|
+
* Must be called within an `Obj.update` callback.
|
|
749
|
+
*
|
|
750
|
+
* @returns Whether any property was updated.
|
|
751
|
+
*/
|
|
752
|
+
export const updateFrom = <T extends Unknown>(
|
|
753
|
+
target: Mutable<T>,
|
|
754
|
+
source: T,
|
|
755
|
+
options?: UpdateFromOptions<T>,
|
|
756
|
+
): boolean => {
|
|
757
|
+
assertArgument(isObject(target), 'Expected an echo object target.');
|
|
758
|
+
assertArgument(isObject(source), 'Expected an echo object source.');
|
|
759
|
+
let keys = Object.keys(source as Record<string, unknown>).filter((key) => key !== 'id');
|
|
760
|
+
if (options?.include !== undefined) {
|
|
761
|
+
const include = new Set(options.include.map((key) => String(key)));
|
|
762
|
+
keys = keys.filter((key) => include.has(key));
|
|
763
|
+
}
|
|
764
|
+
if (options?.exclude !== undefined) {
|
|
765
|
+
const exclude = new Set(options.exclude.map((key) => String(key)));
|
|
766
|
+
keys = keys.filter((key) => !exclude.has(key));
|
|
767
|
+
}
|
|
768
|
+
let updated = false;
|
|
769
|
+
const sourceRecord = source as Record<string, unknown>;
|
|
770
|
+
const targetRecord = target as Record<string, unknown>;
|
|
771
|
+
for (const key of keys) {
|
|
772
|
+
if (!Object.hasOwn(sourceRecord, key)) {
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
const nextValue = sourceRecord[key];
|
|
776
|
+
const prevValue = Object.hasOwn(targetRecord, key) ? targetRecord[key] : undefined;
|
|
777
|
+
if (valuesEqual(prevValue, nextValue)) {
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
targetRecord[key] = prepareAssignValue(nextValue) as never;
|
|
781
|
+
updated = true;
|
|
782
|
+
}
|
|
783
|
+
return updated;
|
|
663
784
|
};
|
|
664
785
|
|
|
665
786
|
//
|
|
@@ -691,7 +812,7 @@ export const toJSON = (entity: Unknown | Snapshot): JSON => objInternal.objectTo
|
|
|
691
812
|
*/
|
|
692
813
|
export const fromJSON: (
|
|
693
814
|
json: unknown,
|
|
694
|
-
options?: { refResolver?: Ref.Resolver; dxn?: DXN; database?: Database.Database },
|
|
815
|
+
options?: { refResolver?: Ref.Resolver; dxn?: DXN; database?: Database.Database; parent?: Unknown },
|
|
695
816
|
) => Promise<Unknown> = objInternal.objectFromJSON as any;
|
|
696
817
|
|
|
697
818
|
/**
|
package/src/Query.test.ts
CHANGED
|
@@ -6,7 +6,7 @@ import * as Schema from 'effect/Schema';
|
|
|
6
6
|
import { describe, expect, test } from 'vitest';
|
|
7
7
|
|
|
8
8
|
import { QueryAST } from '@dxos/echo-protocol';
|
|
9
|
-
import { DXN } from '@dxos/keys';
|
|
9
|
+
import { DXN, ObjectId, SpaceId } from '@dxos/keys';
|
|
10
10
|
import { log } from '@dxos/log';
|
|
11
11
|
|
|
12
12
|
import * as Dataset from './Dataset';
|
|
@@ -523,7 +523,7 @@ describe('query api', () => {
|
|
|
523
523
|
"from": {
|
|
524
524
|
"_tag": "scope",
|
|
525
525
|
"scope": {
|
|
526
|
-
"
|
|
526
|
+
"allFeedsFromSpaces": true,
|
|
527
527
|
},
|
|
528
528
|
},
|
|
529
529
|
"query": {
|
|
@@ -560,12 +560,20 @@ describe('query api', () => {
|
|
|
560
560
|
});
|
|
561
561
|
});
|
|
562
562
|
|
|
563
|
-
test('Query.type(...).from(feed) sets queue scope', () => {
|
|
564
|
-
const
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
563
|
+
test('Query.type(...).from(feed) sets queue scope', async () => {
|
|
564
|
+
const spaceId = SpaceId.random();
|
|
565
|
+
const feedId = ObjectId.random();
|
|
566
|
+
const feedDXN = DXN.parse(`dxn:echo:${spaceId}:${feedId}`);
|
|
567
|
+
const feed = (await Obj.fromJSON(
|
|
568
|
+
{
|
|
569
|
+
'@type': 'dxn:type:org.dxos.type.feed:0.1.0',
|
|
570
|
+
id: feedId,
|
|
571
|
+
name: 'test-feed',
|
|
572
|
+
},
|
|
573
|
+
{ dxn: feedDXN },
|
|
574
|
+
)) as Feed.Feed;
|
|
575
|
+
|
|
576
|
+
const expectedQueueDXN = new DXN(DXN.kind.QUEUE, ['data', spaceId, feedId]);
|
|
569
577
|
|
|
570
578
|
const query = Query.type(TestSchema.Person).from(feed);
|
|
571
579
|
Schema.validateSync(QueryAST.Query)(query.ast);
|
|
@@ -574,7 +582,7 @@ describe('query api', () => {
|
|
|
574
582
|
from: {
|
|
575
583
|
_tag: 'scope',
|
|
576
584
|
scope: {
|
|
577
|
-
|
|
585
|
+
feeds: [expectedQueueDXN.toString()],
|
|
578
586
|
},
|
|
579
587
|
},
|
|
580
588
|
query: {
|
|
@@ -587,6 +595,60 @@ describe('query api', () => {
|
|
|
587
595
|
});
|
|
588
596
|
});
|
|
589
597
|
|
|
598
|
+
test('Query.from(non-feed) throws TypeError', () => {
|
|
599
|
+
const person = Obj.make(TestSchema.Person, { name: 'Fred' });
|
|
600
|
+
expect(() => Query.select(Filter.type(TestSchema.Person)).from(person as any)).toThrow(TypeError);
|
|
601
|
+
expect(() => Query.select(Filter.type(TestSchema.Person)).from(person as any)).toThrow(
|
|
602
|
+
/Query\.from\(\) expects Feed objects/,
|
|
603
|
+
);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
test('Query.from(undefined) throws TypeError', () => {
|
|
607
|
+
expect(() => Query.select(Filter.type(TestSchema.Person)).from(undefined as any)).toThrow(TypeError);
|
|
608
|
+
expect(() => Query.select(Filter.type(TestSchema.Person)).from(undefined as any)).toThrow(
|
|
609
|
+
/Query\.from\(\) requires a valid data source argument/,
|
|
610
|
+
);
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
test('Query.from(null) throws TypeError', () => {
|
|
614
|
+
expect(() => Query.select(Filter.type(TestSchema.Person)).from(null as any)).toThrow(TypeError);
|
|
615
|
+
expect(() => Query.select(Filter.type(TestSchema.Person)).from(null as any)).toThrow(
|
|
616
|
+
/Query\.from\(\) requires a valid data source argument/,
|
|
617
|
+
);
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
test('Query.pretty surfaces debugLabel from options', () => {
|
|
621
|
+
const query = Query.select(Filter.type(TestSchema.Person)).debugLabel('my-label');
|
|
622
|
+
expect(Query.pretty(query)).toContain('debugLabel');
|
|
623
|
+
expect(Query.pretty(query)).toContain('"my-label"');
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
test('Query.debugLabel merges onto existing options clause', () => {
|
|
627
|
+
const query = Query.select(Filter.type(TestSchema.Person))
|
|
628
|
+
.options({ deleted: 'exclude' })
|
|
629
|
+
.debugLabel('timer-probe');
|
|
630
|
+
const pretty = Query.pretty(query);
|
|
631
|
+
expect(pretty).toContain('deleted');
|
|
632
|
+
expect(pretty).toContain('debugLabel');
|
|
633
|
+
expect(pretty).toContain('"timer-probe"');
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
test('Query.pretty returns human-readable query string', () => {
|
|
637
|
+
const query = Query.select(Filter.type(TestSchema.Person, { name: 'Fred' }));
|
|
638
|
+
const pretty = Query.pretty(query);
|
|
639
|
+
expect(pretty).toContain('Query.select');
|
|
640
|
+
expect(pretty).toContain('Filter.type');
|
|
641
|
+
expect(pretty).toContain('com.example.type.person');
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
test('Query.pretty handles complex queries', () => {
|
|
645
|
+
const query = Query.select(Filter.and(Filter.type(TestSchema.Person), Filter.id(ObjectId.random()))).limit(10);
|
|
646
|
+
const pretty = Query.pretty(query);
|
|
647
|
+
expect(pretty).toContain('Query.select');
|
|
648
|
+
expect(pretty).toContain('Filter.and');
|
|
649
|
+
expect(pretty).toContain('limit(10)');
|
|
650
|
+
});
|
|
651
|
+
|
|
590
652
|
test.skip('chain', () => {
|
|
591
653
|
// NOTE: Can't support props without type since they can't be inferred.
|
|
592
654
|
// const f1: Filter<Person> = Filter.props({ name: 'Fred' });
|
|
@@ -622,11 +684,139 @@ describe('query api', () => {
|
|
|
622
684
|
});
|
|
623
685
|
});
|
|
624
686
|
|
|
687
|
+
describe('Filter.childOf', () => {
|
|
688
|
+
test('childOf with Ref', () => {
|
|
689
|
+
const parentDXN = DXN.fromSpaceAndObjectId(SpaceId.random(), ObjectId.random());
|
|
690
|
+
const parentRef = Ref.fromDXN(parentDXN);
|
|
691
|
+
const filter = Filter.childOf(parentRef);
|
|
692
|
+
|
|
693
|
+
expect(filter.ast).toMatchObject({
|
|
694
|
+
type: 'child-of',
|
|
695
|
+
parents: [parentDXN.toString()],
|
|
696
|
+
transitive: true,
|
|
697
|
+
});
|
|
698
|
+
Schema.validateSync(QueryAST.Filter)(filter.ast);
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
test('childOf with object', () => {
|
|
702
|
+
const parent = Obj.make(TestSchema.Person, { name: 'Parent' });
|
|
703
|
+
const filter = Filter.childOf(parent);
|
|
704
|
+
|
|
705
|
+
expect(filter.ast).toMatchObject({
|
|
706
|
+
type: 'child-of',
|
|
707
|
+
transitive: true,
|
|
708
|
+
});
|
|
709
|
+
expect(filter.ast.type === 'child-of' && filter.ast.parents.length).toBe(1);
|
|
710
|
+
Schema.validateSync(QueryAST.Filter)(filter.ast);
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
test('childOf with array of Refs', () => {
|
|
714
|
+
const dxn1 = DXN.fromSpaceAndObjectId(SpaceId.random(), ObjectId.random());
|
|
715
|
+
const dxn2 = DXN.fromSpaceAndObjectId(SpaceId.random(), ObjectId.random());
|
|
716
|
+
const filter = Filter.childOf([Ref.fromDXN(dxn1), Ref.fromDXN(dxn2)]);
|
|
717
|
+
|
|
718
|
+
expect(filter.ast).toMatchObject({
|
|
719
|
+
type: 'child-of',
|
|
720
|
+
parents: [dxn1.toString(), dxn2.toString()],
|
|
721
|
+
transitive: true,
|
|
722
|
+
});
|
|
723
|
+
Schema.validateSync(QueryAST.Filter)(filter.ast);
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
test('childOf with transitive=false', () => {
|
|
727
|
+
const parentRef = Ref.fromDXN(DXN.fromSpaceAndObjectId(SpaceId.random(), ObjectId.random()));
|
|
728
|
+
const filter = Filter.childOf(parentRef, { transitive: false });
|
|
729
|
+
|
|
730
|
+
expect(filter.ast).toMatchObject({
|
|
731
|
+
type: 'child-of',
|
|
732
|
+
parents: [parentRef.dxn.toString()],
|
|
733
|
+
transitive: false,
|
|
734
|
+
});
|
|
735
|
+
Schema.validateSync(QueryAST.Filter)(filter.ast);
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
test('childOf in select query', () => {
|
|
739
|
+
const parentDXN = DXN.fromSpaceAndObjectId(SpaceId.random(), ObjectId.random());
|
|
740
|
+
const parentRef = Ref.fromDXN(parentDXN);
|
|
741
|
+
const query = Query.select(Filter.childOf(parentRef));
|
|
742
|
+
|
|
743
|
+
expect(query.ast).toMatchObject({
|
|
744
|
+
type: 'select',
|
|
745
|
+
filter: {
|
|
746
|
+
type: 'child-of',
|
|
747
|
+
parents: [parentDXN.toString()],
|
|
748
|
+
transitive: true,
|
|
749
|
+
},
|
|
750
|
+
});
|
|
751
|
+
Schema.validateSync(QueryAST.Query)(query.ast);
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
test('childOf combined with type filter', () => {
|
|
755
|
+
const parentDXN = DXN.fromSpaceAndObjectId(SpaceId.random(), ObjectId.random());
|
|
756
|
+
const parentRef = Ref.fromDXN(parentDXN);
|
|
757
|
+
const query = Query.select(Filter.and(Filter.type(TestSchema.Person), Filter.childOf(parentRef)));
|
|
758
|
+
|
|
759
|
+
Schema.validateSync(QueryAST.Query)(query.ast);
|
|
760
|
+
expect(query.ast).toMatchObject({
|
|
761
|
+
type: 'select',
|
|
762
|
+
filter: {
|
|
763
|
+
type: 'and',
|
|
764
|
+
filters: [
|
|
765
|
+
{ type: 'object', typename: 'dxn:type:com.example.type.person:0.1.0' },
|
|
766
|
+
{ type: 'child-of', parents: [parentDXN.toString()], transitive: true },
|
|
767
|
+
],
|
|
768
|
+
},
|
|
769
|
+
});
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
test('childOf pretty-prints correctly', () => {
|
|
773
|
+
const parentRef = Ref.fromDXN(DXN.fromSpaceAndObjectId(SpaceId.random(), ObjectId.random()));
|
|
774
|
+
const filter = Filter.childOf(parentRef);
|
|
775
|
+
const pretty = Filter.pretty(filter);
|
|
776
|
+
expect(pretty).toContain('Filter.childOf');
|
|
777
|
+
expect(pretty).toContain('transitive: true');
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
test('childOf with mixed objects and Refs', () => {
|
|
781
|
+
const parent = Obj.make(TestSchema.Person, { name: 'Parent' });
|
|
782
|
+
const refDXN = DXN.fromSpaceAndObjectId(SpaceId.random(), ObjectId.random());
|
|
783
|
+
const parentRef = Ref.fromDXN(refDXN);
|
|
784
|
+
const filter = Filter.childOf([parent, parentRef]);
|
|
785
|
+
|
|
786
|
+
expect(filter.ast).toMatchObject({
|
|
787
|
+
type: 'child-of',
|
|
788
|
+
transitive: true,
|
|
789
|
+
});
|
|
790
|
+
expect(filter.ast.type === 'child-of' && filter.ast.parents.length).toBe(2);
|
|
791
|
+
Schema.validateSync(QueryAST.Filter)(filter.ast);
|
|
792
|
+
});
|
|
793
|
+
});
|
|
794
|
+
|
|
625
795
|
describe('Filter', () => {
|
|
626
796
|
test('Filter.or(Filter.typename(...))', () => {
|
|
627
797
|
const filter = Filter.or(Filter.typename('com.example.type.person'));
|
|
628
798
|
// TODO(dmaretskyi): Give vitest type-tests a try.
|
|
629
799
|
const _isAssignable: Obj.Unknown = null as any as Filter.Type<typeof filter>;
|
|
630
800
|
});
|
|
801
|
+
|
|
802
|
+
test('Filter.pretty returns human-readable filter string', () => {
|
|
803
|
+
const filter = Filter.type(TestSchema.Person, { name: 'Fred' });
|
|
804
|
+
const pretty = Filter.pretty(filter);
|
|
805
|
+
expect(pretty).toContain('Filter.type');
|
|
806
|
+
expect(pretty).toContain('com.example.type.person');
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
test('Filter.pretty handles complex filters', () => {
|
|
810
|
+
const filter = Filter.and(Filter.type(TestSchema.Person), Filter.id(ObjectId.random()));
|
|
811
|
+
const pretty = Filter.pretty(filter);
|
|
812
|
+
expect(pretty).toContain('Filter.and');
|
|
813
|
+
expect(pretty).toContain('Filter.type');
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
test('Filter.pretty handles or filters', () => {
|
|
817
|
+
const filter = Filter.or(Filter.type(TestSchema.Person), Filter.type(TestSchema.Organization));
|
|
818
|
+
const pretty = Filter.pretty(filter);
|
|
819
|
+
expect(pretty).toContain('Filter.or');
|
|
820
|
+
});
|
|
631
821
|
});
|
|
632
822
|
});
|