@dxos/echo 0.8.4-main.74a063c4e0 → 0.8.4-main.765dc60934
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 +6 -4
- package/dist/lib/neutral/Entity.mjs +16 -14
- package/dist/lib/neutral/Err.mjs +1 -1
- package/dist/lib/neutral/Extension.mjs +1 -1
- package/dist/lib/neutral/Feed.mjs +21 -17
- package/dist/lib/neutral/Filter.mjs +15 -11
- 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 +14 -14
- package/dist/lib/neutral/Order.mjs +1 -1
- package/dist/lib/neutral/Query.mjs +17 -17
- package/dist/lib/neutral/QueryResult.mjs +1 -1
- package/dist/lib/neutral/Ref.mjs +9 -7
- package/dist/lib/neutral/Relation.mjs +15 -15
- package/dist/lib/neutral/SchemaRegistry.mjs +1 -1
- package/dist/lib/neutral/Tag.mjs +14 -14
- package/dist/lib/neutral/Type.mjs +10 -10
- package/dist/lib/neutral/{chunk-GZQTCRJB.mjs → chunk-44HT3MEC.mjs} +2 -2
- package/dist/lib/neutral/{chunk-ZIXGDU6F.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-MYMU4TWK.mjs → chunk-7VWWUTRQ.mjs} +38 -17
- package/dist/lib/neutral/chunk-7VWWUTRQ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-66GBFH43.mjs → chunk-A6IYRT5A.mjs} +17 -45
- package/dist/lib/neutral/chunk-A6IYRT5A.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-R72KFH2X.mjs → chunk-APHSOTIX.mjs} +2 -2
- package/dist/lib/neutral/{chunk-XZJUNTML.mjs → chunk-APJKDGFL.mjs} +36 -6
- package/dist/lib/neutral/chunk-APJKDGFL.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-BNCCGLJN.mjs → chunk-BICZKPQG.mjs} +1 -1
- package/dist/lib/neutral/{chunk-QWAOTFCY.mjs → chunk-BMB7IHGB.mjs} +16 -66
- package/dist/lib/neutral/chunk-BMB7IHGB.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-KPY6FC5I.mjs → chunk-BVOWYVTD.mjs} +17 -12
- package/dist/lib/neutral/chunk-BVOWYVTD.mjs.map +7 -0
- package/dist/lib/neutral/chunk-FIWO2FZK.mjs +36 -0
- package/dist/lib/neutral/chunk-FIWO2FZK.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-WMFVS4KR.mjs → chunk-G54OX4IX.mjs} +102 -480
- package/dist/lib/neutral/chunk-G54OX4IX.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-7QQMUDE6.mjs → chunk-GMS5PKGQ.mjs} +59 -12
- package/dist/lib/neutral/chunk-GMS5PKGQ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-YS6Q3XAD.mjs → chunk-GWFFC34K.mjs} +1 -1
- package/dist/lib/neutral/{chunk-YS6Q3XAD.mjs.map → chunk-GWFFC34K.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-EBVB5NOH.mjs → chunk-I2DARWPX.mjs} +15 -20
- package/dist/lib/neutral/chunk-I2DARWPX.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-FNEFSO2C.mjs → chunk-MLS7U7AT.mjs} +12 -65
- package/dist/lib/neutral/{chunk-FNEFSO2C.mjs.map → chunk-MLS7U7AT.mjs.map} +2 -2
- package/dist/lib/neutral/{chunk-TBKX6JQO.mjs → chunk-N4B7FHQT.mjs} +1 -1
- package/dist/lib/neutral/{chunk-46QNGNTY.mjs → chunk-N7VOEPSV.mjs} +6 -3
- package/dist/lib/neutral/{chunk-46QNGNTY.mjs.map → chunk-N7VOEPSV.mjs.map} +3 -3
- package/dist/lib/neutral/{chunk-MZXWVR3T.mjs → chunk-PSZBLH53.mjs} +6 -22
- package/dist/lib/neutral/{chunk-MZXWVR3T.mjs.map → chunk-PSZBLH53.mjs.map} +2 -2
- package/dist/lib/neutral/{chunk-XZM7FERR.mjs → chunk-QBIKZ3TY.mjs} +4 -4
- package/dist/lib/neutral/{chunk-E5PBQJWV.mjs → chunk-QRZ2I3ZM.mjs} +2 -2
- package/dist/lib/neutral/{chunk-2U2BZDLU.mjs → chunk-SCPFDS2E.mjs} +12 -8
- package/dist/lib/neutral/chunk-SCPFDS2E.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-VCAP4OOT.mjs → chunk-SKDTKHDC.mjs} +21 -5
- package/dist/lib/neutral/chunk-SKDTKHDC.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-6URFBQJH.mjs → chunk-TNBK56IN.mjs} +11 -22
- package/dist/lib/neutral/chunk-TNBK56IN.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-DQYLD2RB.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-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 +33 -27
- package/dist/lib/neutral/internal/index.mjs +11 -9
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/testing/index.mjs +183 -128
- 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 +6 -1
- package/dist/types/src/Database.d.ts.map +1 -1
- package/dist/types/src/Dataset.d.ts +1 -1
- package/dist/types/src/Entity.d.ts +15 -9
- 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 +4 -4
- package/dist/types/src/Extension.d.ts.map +1 -1
- package/dist/types/src/Feed.d.ts +37 -2
- package/dist/types/src/Feed.d.ts.map +1 -1
- package/dist/types/src/Filter.d.ts +34 -0
- package/dist/types/src/Filter.d.ts.map +1 -1
- 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 +23 -21
- 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 +5 -1
- 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 +15 -15
- 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.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 +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/annotations.d.ts +11 -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/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 +2 -1
- 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.map +1 -1
- package/dist/types/src/internal/Ref/ref.d.ts +13 -0
- 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 +1 -1
- 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/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 +3 -3
- 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/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 +19 -14
- package/src/Annotation.ts +1 -0
- package/src/Collection.ts +1 -1
- package/src/Database.ts +36 -14
- package/src/Entity.ts +16 -9
- package/src/Extension.ts +3 -3
- package/src/Feed.ts +54 -2
- package/src/Filter.ts +61 -0
- 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 +23 -23
- package/src/Obj.ts +28 -25
- package/src/Query.test.ts +129 -5
- package/src/Query.ts +32 -7
- package/src/Ref.ts +2 -0
- package/src/Relation.ts +21 -17
- package/src/exemplars.test.ts +21 -0
- package/src/index.ts +3 -0
- package/src/internal/Annotation/annotations.ts +19 -7
- package/src/internal/Entity/model.ts +2 -0
- package/src/internal/Obj/ids.ts +1 -1
- package/src/internal/Obj/json-serializer.test.ts +2 -2
- package/src/internal/Obj/json-serializer.ts +17 -10
- package/src/internal/Obj/set-value.test.ts +24 -24
- package/src/internal/Obj/set-value.ts +1 -1
- package/src/internal/Query.ts +28 -4
- package/src/internal/Ref/ref.ts +17 -0
- package/src/internal/Type/echo-schema.ts +1 -1
- 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 +66 -66
- package/src/internal/common/proxy/errors.ts +2 -2
- 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 -2
- package/src/internal/common/proxy/typed-handler.ts +7 -7
- package/src/internal/common/proxy/typed-object.test.ts +1 -1
- package/src/internal/common/types/meta.ts +12 -0
- package/src/testing/test-data.ts +157 -97
- package/dist/lib/neutral/chunk-2U2BZDLU.mjs.map +0 -7
- package/dist/lib/neutral/chunk-66GBFH43.mjs.map +0 -7
- package/dist/lib/neutral/chunk-6URFBQJH.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7QQMUDE6.mjs.map +0 -7
- package/dist/lib/neutral/chunk-EBVB5NOH.mjs.map +0 -7
- package/dist/lib/neutral/chunk-KPY6FC5I.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MYMU4TWK.mjs.map +0 -7
- package/dist/lib/neutral/chunk-QWAOTFCY.mjs.map +0 -7
- package/dist/lib/neutral/chunk-VCAP4OOT.mjs.map +0 -7
- package/dist/lib/neutral/chunk-WMFVS4KR.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XZJUNTML.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ZIXGDU6F.mjs.map +0 -7
- /package/dist/lib/neutral/{chunk-GZQTCRJB.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-R72KFH2X.mjs.map → chunk-APHSOTIX.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-BNCCGLJN.mjs.map → chunk-BICZKPQG.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-TBKX6JQO.mjs.map → chunk-N4B7FHQT.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-XZM7FERR.mjs.map → chunk-QBIKZ3TY.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-E5PBQJWV.mjs.map → chunk-QRZ2I3ZM.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-DQYLD2RB.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/Query.test.ts
CHANGED
|
@@ -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": {
|
|
@@ -563,17 +563,17 @@ describe('query api', () => {
|
|
|
563
563
|
test('Query.type(...).from(feed) sets queue scope', async () => {
|
|
564
564
|
const spaceId = SpaceId.random();
|
|
565
565
|
const feedId = ObjectId.random();
|
|
566
|
-
const
|
|
566
|
+
const feedDXN = DXN.parse(`dxn:echo:${spaceId}:${feedId}`);
|
|
567
567
|
const feed = (await Obj.fromJSON(
|
|
568
568
|
{
|
|
569
569
|
'@type': 'dxn:type:org.dxos.type.feed:0.1.0',
|
|
570
570
|
id: feedId,
|
|
571
571
|
name: 'test-feed',
|
|
572
572
|
},
|
|
573
|
-
{ dxn:
|
|
573
|
+
{ dxn: feedDXN },
|
|
574
574
|
)) as Feed.Feed;
|
|
575
575
|
|
|
576
|
-
const
|
|
576
|
+
const expectedQueueDXN = new DXN(DXN.kind.QUEUE, ['data', spaceId, feedId]);
|
|
577
577
|
|
|
578
578
|
const query = Query.type(TestSchema.Person).from(feed);
|
|
579
579
|
Schema.validateSync(QueryAST.Query)(query.ast);
|
|
@@ -582,7 +582,7 @@ describe('query api', () => {
|
|
|
582
582
|
from: {
|
|
583
583
|
_tag: 'scope',
|
|
584
584
|
scope: {
|
|
585
|
-
|
|
585
|
+
feeds: [expectedQueueDXN.toString()],
|
|
586
586
|
},
|
|
587
587
|
},
|
|
588
588
|
query: {
|
|
@@ -617,6 +617,22 @@ describe('query api', () => {
|
|
|
617
617
|
);
|
|
618
618
|
});
|
|
619
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
|
+
|
|
620
636
|
test('Query.pretty returns human-readable query string', () => {
|
|
621
637
|
const query = Query.select(Filter.type(TestSchema.Person, { name: 'Fred' }));
|
|
622
638
|
const pretty = Query.pretty(query);
|
|
@@ -668,6 +684,114 @@ describe('query api', () => {
|
|
|
668
684
|
});
|
|
669
685
|
});
|
|
670
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
|
+
|
|
671
795
|
describe('Filter', () => {
|
|
672
796
|
test('Filter.or(Filter.typename(...))', () => {
|
|
673
797
|
const filter = Filter.or(Filter.typename('com.example.type.person'));
|
package/src/Query.ts
CHANGED
|
@@ -207,6 +207,11 @@ export interface Query<T> {
|
|
|
207
207
|
* Add options to a query.
|
|
208
208
|
*/
|
|
209
209
|
'options'(options: QueryAST.QueryOptions): Query<T>;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Attach a diagnostic label for logs and tooling (execution semantics unchanged).
|
|
213
|
+
*/
|
|
214
|
+
'debugLabel'(label: string): Query<T>;
|
|
210
215
|
}
|
|
211
216
|
|
|
212
217
|
export type Any = Query<any>;
|
|
@@ -354,7 +359,7 @@ class QueryClass implements Any {
|
|
|
354
359
|
from: {
|
|
355
360
|
_tag: 'scope',
|
|
356
361
|
scope: {
|
|
357
|
-
...(options?.includeFeeds ? {
|
|
362
|
+
...(options?.includeFeeds ? { allFeedsFromSpaces: true } : {}),
|
|
358
363
|
},
|
|
359
364
|
},
|
|
360
365
|
});
|
|
@@ -379,7 +384,7 @@ class QueryClass implements Any {
|
|
|
379
384
|
_tag: 'scope',
|
|
380
385
|
scope: {
|
|
381
386
|
spaceIds: databases.map((db) => db.spaceId),
|
|
382
|
-
...(options?.includeFeeds ? {
|
|
387
|
+
...(options?.includeFeeds ? { allFeedsFromSpaces: true } : {}),
|
|
383
388
|
},
|
|
384
389
|
},
|
|
385
390
|
});
|
|
@@ -405,10 +410,15 @@ class QueryClass implements Any {
|
|
|
405
410
|
}
|
|
406
411
|
}
|
|
407
412
|
|
|
408
|
-
const
|
|
409
|
-
const
|
|
413
|
+
const feedItems = items as Feed.Feed[];
|
|
414
|
+
const feedDXNs = feedItems.map((feed) => {
|
|
410
415
|
const dxn = Feed.getQueueDxn(feed);
|
|
411
|
-
|
|
416
|
+
if (!dxn) {
|
|
417
|
+
throw new TypeError(
|
|
418
|
+
`Query.from() expects persisted Feed objects with a queue DXN; got feed without a space (id=${Obj.getDXN(feed).toString()}).`,
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
return dxn.toString();
|
|
412
422
|
});
|
|
413
423
|
return new QueryClass({
|
|
414
424
|
type: 'from',
|
|
@@ -416,7 +426,7 @@ class QueryClass implements Any {
|
|
|
416
426
|
from: {
|
|
417
427
|
_tag: 'scope',
|
|
418
428
|
scope: {
|
|
419
|
-
|
|
429
|
+
feeds: feedDXNs,
|
|
420
430
|
},
|
|
421
431
|
},
|
|
422
432
|
});
|
|
@@ -429,6 +439,21 @@ class QueryClass implements Any {
|
|
|
429
439
|
options,
|
|
430
440
|
});
|
|
431
441
|
}
|
|
442
|
+
|
|
443
|
+
debugLabel(label: string): Any {
|
|
444
|
+
if (this.ast.type === 'options') {
|
|
445
|
+
return new QueryClass({
|
|
446
|
+
type: 'options',
|
|
447
|
+
query: this.ast.query,
|
|
448
|
+
options: { ...this.ast.options, debugLabel: label },
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
return new QueryClass({
|
|
452
|
+
type: 'options',
|
|
453
|
+
query: this.ast,
|
|
454
|
+
options: { debugLabel: label },
|
|
455
|
+
});
|
|
456
|
+
}
|
|
432
457
|
}
|
|
433
458
|
|
|
434
459
|
export const is = (value: unknown): value is Any => {
|
|
@@ -531,7 +556,7 @@ export const from = (
|
|
|
531
556
|
return wrapper.from(source as any, options);
|
|
532
557
|
};
|
|
533
558
|
|
|
534
|
-
const SCOPE_KEYS = new Set(['spaceIds', '
|
|
559
|
+
const SCOPE_KEYS = new Set(['spaceIds', 'feeds', 'allFeedsFromSpaces']);
|
|
535
560
|
|
|
536
561
|
/** Detect a raw Scope object (plain object with only Scope-valid keys). */
|
|
537
562
|
const _isScope = (value: unknown): value is QueryAST.Scope => {
|
package/src/Ref.ts
CHANGED
|
@@ -85,6 +85,8 @@ export const make = refInternal.Ref.make;
|
|
|
85
85
|
// TODO(dmaretskyi): Consider just allowing `make` to accept DXN.
|
|
86
86
|
export const fromDXN = refInternal.Ref.fromDXN;
|
|
87
87
|
|
|
88
|
+
export const hasObjectId = refInternal.Ref.hasObjectId;
|
|
89
|
+
|
|
88
90
|
// TODO(wittjosiah): Factor out?
|
|
89
91
|
export const isRefType = (ast: SchemaAST.AST): boolean => {
|
|
90
92
|
return SchemaAST.getAnnotation<JsonSchema.JsonSchema>(ast, SchemaAST.JSONSchemaAnnotationId).pipe(
|
package/src/Relation.ts
CHANGED
|
@@ -237,7 +237,9 @@ export const getSource = <T extends Unknown | Snapshot>(relation: T): SourceOf<T
|
|
|
237
237
|
assertArgument(isRelation(relation), 'Expected a relation');
|
|
238
238
|
assumeType<internal.InternalObjectProps>(relation);
|
|
239
239
|
const obj = (relation as internal.InternalObjectProps)[internal.RelationSourceId];
|
|
240
|
-
|
|
240
|
+
if (obj === undefined) {
|
|
241
|
+
throw new Error(`Relation source could not be resolved.`);
|
|
242
|
+
}
|
|
241
243
|
return obj as SourceOf<T>;
|
|
242
244
|
};
|
|
243
245
|
|
|
@@ -250,7 +252,9 @@ export const getTarget = <T extends Unknown | Snapshot>(relation: T): TargetOf<T
|
|
|
250
252
|
assertArgument(isRelation(relation), 'Expected a relation');
|
|
251
253
|
assumeType<internal.InternalObjectProps>(relation);
|
|
252
254
|
const obj = (relation as internal.InternalObjectProps)[internal.RelationTargetId];
|
|
253
|
-
|
|
255
|
+
if (obj === undefined) {
|
|
256
|
+
throw new Error(`Relation target could not be resolved.`);
|
|
257
|
+
}
|
|
254
258
|
return obj as TargetOf<T>;
|
|
255
259
|
};
|
|
256
260
|
|
|
@@ -260,7 +264,7 @@ export const getTarget = <T extends Unknown | Snapshot>(relation: T): TargetOf<T
|
|
|
260
264
|
|
|
261
265
|
/**
|
|
262
266
|
* Makes all properties mutable recursively.
|
|
263
|
-
* Used to provide a mutable view of a relation within `Relation.
|
|
267
|
+
* Used to provide a mutable view of a relation within `Relation.update`.
|
|
264
268
|
*/
|
|
265
269
|
export type Mutable<T> = internal.Mutable<T>;
|
|
266
270
|
|
|
@@ -268,10 +272,10 @@ export type Mutable<T> = internal.Mutable<T>;
|
|
|
268
272
|
* Perform mutations on an echo relation within a controlled context.
|
|
269
273
|
*
|
|
270
274
|
* All mutations within the callback are batched and trigger a single notification
|
|
271
|
-
* when the callback completes. Direct mutations outside of `Relation.
|
|
275
|
+
* when the callback completes. Direct mutations outside of `Relation.update` will throw
|
|
272
276
|
* an error for echo relations.
|
|
273
277
|
*
|
|
274
|
-
* @param relation - The echo relation to mutate. Use `Obj.
|
|
278
|
+
* @param relation - The echo relation to mutate. Use `Obj.update` for objects.
|
|
275
279
|
* @param callback - The callback that performs mutations on the relation.
|
|
276
280
|
*
|
|
277
281
|
* @example
|
|
@@ -282,15 +286,15 @@ export type Mutable<T> = internal.Mutable<T>;
|
|
|
282
286
|
* role: 'Engineer',
|
|
283
287
|
* });
|
|
284
288
|
*
|
|
285
|
-
* // Mutate within Relation.
|
|
286
|
-
* Relation.
|
|
289
|
+
* // Mutate within Relation.update
|
|
290
|
+
* Relation.update(worksFor, (obj) => {
|
|
287
291
|
* obj.role = 'Senior Engineer';
|
|
288
292
|
* });
|
|
289
293
|
* ```
|
|
290
294
|
*
|
|
291
|
-
* Note: Only accepts relations. Use `Obj.
|
|
295
|
+
* Note: Only accepts relations. Use `Obj.update` for objects.
|
|
292
296
|
*/
|
|
293
|
-
export const
|
|
297
|
+
export const update = <T extends Unknown>(relation: T, callback: internal.ChangeCallback<T>): void => {
|
|
294
298
|
internal.change(relation, callback);
|
|
295
299
|
};
|
|
296
300
|
|
|
@@ -333,7 +337,7 @@ export const getValue = (rel: Unknown | Snapshot, path: readonly (string | numbe
|
|
|
333
337
|
|
|
334
338
|
/**
|
|
335
339
|
* Set a deeply nested property on a relation.
|
|
336
|
-
* Must be called within a `Relation.
|
|
340
|
+
* Must be called within a `Relation.update` callback.
|
|
337
341
|
*
|
|
338
342
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
339
343
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -395,13 +399,13 @@ export const Meta = internal.MetaId;
|
|
|
395
399
|
export type ReadonlyMeta = internal.ReadonlyMeta;
|
|
396
400
|
|
|
397
401
|
/**
|
|
398
|
-
* Mutable meta type returned by `Relation.getMeta` inside a `Relation.
|
|
402
|
+
* Mutable meta type returned by `Relation.getMeta` inside a `Relation.update` callback.
|
|
399
403
|
*/
|
|
400
404
|
export type Meta = internal.Meta;
|
|
401
405
|
|
|
402
406
|
/**
|
|
403
407
|
* Get the metadata for a relation.
|
|
404
|
-
* Returns mutable meta when passed a mutable relation (inside `Relation.
|
|
408
|
+
* Returns mutable meta when passed a mutable relation (inside `Relation.update` callback).
|
|
405
409
|
* Returns read-only meta when passed a regular relation or snapshot.
|
|
406
410
|
*/
|
|
407
411
|
// TODO(wittjosiah): When passed a Snapshot, should return a snapshot of meta, not the live meta proxy.
|
|
@@ -419,7 +423,7 @@ export const getKeys = (entity: Unknown | Snapshot, source: string): ForeignKey[
|
|
|
419
423
|
|
|
420
424
|
/**
|
|
421
425
|
* Delete all keys from the relation for the specified source.
|
|
422
|
-
* Must be called within a `Relation.
|
|
426
|
+
* Must be called within a `Relation.update` callback.
|
|
423
427
|
*
|
|
424
428
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
425
429
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -428,7 +432,7 @@ export const deleteKeys = (entity: Mutable<Unknown>, source: string): void => in
|
|
|
428
432
|
|
|
429
433
|
/**
|
|
430
434
|
* Add a tag to the relation.
|
|
431
|
-
* Must be called within a `Relation.
|
|
435
|
+
* Must be called within a `Relation.update` callback.
|
|
432
436
|
*
|
|
433
437
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
434
438
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -437,7 +441,7 @@ export const addTag = (entity: Mutable<Unknown>, tag: string): void => internal.
|
|
|
437
441
|
|
|
438
442
|
/**
|
|
439
443
|
* Remove a tag from the relation.
|
|
440
|
-
* Must be called within a `Relation.
|
|
444
|
+
* Must be called within a `Relation.update` callback.
|
|
441
445
|
*
|
|
442
446
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
443
447
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -462,7 +466,7 @@ export const getLabel = (entity: Unknown | Snapshot): string | undefined => inte
|
|
|
462
466
|
|
|
463
467
|
/**
|
|
464
468
|
* Set the label of the relation.
|
|
465
|
-
* Must be called within a `Relation.
|
|
469
|
+
* Must be called within a `Relation.update` callback.
|
|
466
470
|
*
|
|
467
471
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
468
472
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -477,7 +481,7 @@ export const getDescription = (entity: Unknown | Snapshot): string | undefined =
|
|
|
477
481
|
|
|
478
482
|
/**
|
|
479
483
|
* Set the description of the relation.
|
|
480
|
-
* Must be called within a `Relation.
|
|
484
|
+
* Must be called within a `Relation.update` callback.
|
|
481
485
|
*
|
|
482
486
|
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
483
487
|
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import * as Obj from './Obj';
|
|
8
|
+
import { TestSchema } from './testing';
|
|
9
|
+
import type * as Type from './Type';
|
|
10
|
+
|
|
11
|
+
describe('Exemplars', () => {
|
|
12
|
+
test('factory', ({ expect }) => {
|
|
13
|
+
const factory = <S extends Type.AnyObj>(schema: S) => {
|
|
14
|
+
return (props: Obj.MakeProps<S>) => Obj.make(schema, props);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const makePerson = factory(TestSchema.Person);
|
|
18
|
+
const person = makePerson({ name: 'John Doe' });
|
|
19
|
+
expect(person.name).toBe('John Doe');
|
|
20
|
+
});
|
|
21
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -9,13 +9,16 @@ export { DXN } from '@dxos/keys';
|
|
|
9
9
|
export * as Annotation from './Annotation';
|
|
10
10
|
export * as Database from './Database';
|
|
11
11
|
export * as Entity from './Entity';
|
|
12
|
+
// TODO(burdon): Rename to Error (less problematic than Obj/Object).
|
|
12
13
|
export * as Err from './Err';
|
|
13
14
|
export * as Feed from './Feed';
|
|
14
15
|
export * as Filter from './Filter';
|
|
15
16
|
export * as Format from './Format';
|
|
16
17
|
export * as Hypergraph from './Hypergraph';
|
|
18
|
+
export * as Json from './Json';
|
|
17
19
|
export * as JsonSchema from './JsonSchema';
|
|
18
20
|
export * as Key from './Key';
|
|
21
|
+
export * as Migration from './Migration';
|
|
19
22
|
export * as Obj from './Obj';
|
|
20
23
|
export * as Order from './Order';
|
|
21
24
|
export * as Query from './Query';
|
|
@@ -90,10 +90,10 @@ export const getTypeDXNFromSpecifier = (input: Schema.Schema.All | string): DXN
|
|
|
90
90
|
* Example: `org.dxos.type.message`
|
|
91
91
|
*/
|
|
92
92
|
// TODO(wittjosiah): Factor out to DXN spec.
|
|
93
|
-
// TODO(wittjosiah): Switch to atproto NSID regex once legacy typenames are fully migrated:
|
|
94
|
-
// /^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z0-9]{0,62})?)$/
|
|
95
93
|
export const TypenameSchema = Schema.String.pipe(
|
|
96
|
-
Schema.pattern(
|
|
94
|
+
Schema.pattern(
|
|
95
|
+
/^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z0-9]{0,62})?)$/,
|
|
96
|
+
),
|
|
97
97
|
).annotations({
|
|
98
98
|
description: 'Fully qualified globally unique typename in reverse-DNS form.',
|
|
99
99
|
example: 'org.dxos.type.message',
|
|
@@ -443,7 +443,6 @@ export const setDescriptionWithSchema = <S extends Schema.Schema.Any>(
|
|
|
443
443
|
* Identifies if a property should be included in a form or not.
|
|
444
444
|
* By default, all properties are included in forms, so this is opt-out.
|
|
445
445
|
*/
|
|
446
|
-
// TODO(burdon): UI concern.
|
|
447
446
|
export const FormInputAnnotationId = Symbol.for('@dxos/schema/annotation/FormInput');
|
|
448
447
|
export const FormInputAnnotation = createAnnotationHelper<boolean>(FormInputAnnotationId);
|
|
449
448
|
|
|
@@ -482,7 +481,7 @@ export const makeUserAnnotation = <T>(props: MakeAnnoationsProps<T>): Annotation
|
|
|
482
481
|
|
|
483
482
|
const getFromAst = (ast: SchemaAST.AST) =>
|
|
484
483
|
SchemaAST.getAnnotation<PropertyMetaAnnotation>(PropertyMetaAnnotationId)(ast).pipe(
|
|
485
|
-
Option.
|
|
484
|
+
Option.flatMap((meta) => Option.fromNullable(meta[props.id])),
|
|
486
485
|
Option.map(Schema.decodeUnknownSync(props.schema)),
|
|
487
486
|
);
|
|
488
487
|
|
|
@@ -533,6 +532,19 @@ export const IconAnnotation = makeUserAnnotation<IconAnnotation>({
|
|
|
533
532
|
schema: IconAnnotationSchema,
|
|
534
533
|
});
|
|
535
534
|
|
|
535
|
+
/**
|
|
536
|
+
* Indicates that this entity's icon should be resolved from a property whose value is a `Ref`
|
|
537
|
+
* to another entity. Consumers (e.g. graph node builders) resolve the ref target and use that
|
|
538
|
+
* target's schema `IconAnnotation` in place of the static one declared on this schema.
|
|
539
|
+
*
|
|
540
|
+
* Useful for wrapper schemas that delegate their visual identity to a referenced sub-entity
|
|
541
|
+
* (e.g. a generic `Game` whose icon should come from its `variant` ref's typed state).
|
|
542
|
+
*/
|
|
543
|
+
export const IconFromRefAnnotation = makeUserAnnotation<string>({
|
|
544
|
+
id: 'org.dxos.annotation.icon.from-ref',
|
|
545
|
+
schema: Schema.String,
|
|
546
|
+
});
|
|
547
|
+
|
|
536
548
|
/**
|
|
537
549
|
* Get the label of an entity.
|
|
538
550
|
* Accepts both reactive entities and snapshots.
|
|
@@ -546,7 +558,7 @@ export const getLabel = (entity: AnyProperties): string | undefined => {
|
|
|
546
558
|
|
|
547
559
|
/**
|
|
548
560
|
* Set the label of an entity.
|
|
549
|
-
* Must be called within an Obj.
|
|
561
|
+
* Must be called within an Obj.update or Relation.update callback.
|
|
550
562
|
*/
|
|
551
563
|
export const setLabel = (entity: Mutable<AnyProperties>, label: string) => {
|
|
552
564
|
const schema = getSchema(entity);
|
|
@@ -568,7 +580,7 @@ export const getDescription = (entity: AnyProperties): string | undefined => {
|
|
|
568
580
|
|
|
569
581
|
/**
|
|
570
582
|
* Set the description of an entity.
|
|
571
|
-
* Must be called within an Obj.
|
|
583
|
+
* Must be called within an Obj.update or Relation.update callback.
|
|
572
584
|
*/
|
|
573
585
|
export const setDescription = (entity: Mutable<AnyProperties>, description: string) => {
|
|
574
586
|
const schema = getSchema(entity);
|
package/src/internal/Obj/ids.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { DXN, ObjectId, QueueSubspaceTags, SpaceId } from '@dxos/keys';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @deprecated Use `db.
|
|
8
|
+
* @deprecated Use `Feed.make(...)` + `db.add(feed)` then `Feed.getQueueDxn(feed)`.
|
|
9
9
|
*/
|
|
10
10
|
// TODO(burdon): Move to @dxos/keys.
|
|
11
11
|
export const createQueueDXN = (spaceId = SpaceId.random(), queueId = ObjectId.random()) =>
|
|
@@ -20,8 +20,8 @@ import { objectFromJSON, objectToJSON } from './json-serializer';
|
|
|
20
20
|
describe('Object JSON serializer', () => {
|
|
21
21
|
test('should serialize and deserialize object', async () => {
|
|
22
22
|
const contact = makeObject(TestSchema.Person, { name: 'Alice' });
|
|
23
|
-
Obj.
|
|
24
|
-
getMetaChecked(
|
|
23
|
+
Obj.update(contact, (contact) => {
|
|
24
|
+
getMetaChecked(contact).keys.push({ id: '12345', source: 'example.com' });
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
const task = createObject(TestSchema.Task, {
|
|
@@ -80,7 +80,12 @@ export const objectToJSON = <T extends AnyEntity>(obj: T): SerializedObject<T> =
|
|
|
80
80
|
*/
|
|
81
81
|
export const objectFromJSON = async (
|
|
82
82
|
jsonData: unknown,
|
|
83
|
-
{
|
|
83
|
+
{
|
|
84
|
+
refResolver,
|
|
85
|
+
dxn,
|
|
86
|
+
database,
|
|
87
|
+
parent,
|
|
88
|
+
}: { refResolver?: RefResolver; dxn?: DXN; database?: Database.Database; parent?: Obj.Unknown } = {},
|
|
84
89
|
): Promise<AnyEntity> => {
|
|
85
90
|
assumeType<ObjectJSON>(jsonData);
|
|
86
91
|
assertArgument(typeof jsonData === 'object' && jsonData !== null, 'jsonData', 'expect object');
|
|
@@ -111,15 +116,15 @@ export const objectFromJSON = async (
|
|
|
111
116
|
const isRelation =
|
|
112
117
|
typeof jsonData[ATTR_RELATION_SOURCE] === 'string' || typeof jsonData[ATTR_RELATION_TARGET] === 'string';
|
|
113
118
|
if (isRelation) {
|
|
114
|
-
const
|
|
115
|
-
const
|
|
119
|
+
const sourceDXN: DXN = DXN.parse(jsonData[ATTR_RELATION_SOURCE] ?? raise(new TypeError('Missing relation source')));
|
|
120
|
+
const targetDXN: DXN = DXN.parse(jsonData[ATTR_RELATION_TARGET] ?? raise(new TypeError('Missing relation target')));
|
|
116
121
|
|
|
117
|
-
const source = (await refResolver?.resolve(
|
|
118
|
-
const target = (await refResolver?.resolve(
|
|
122
|
+
const source = (await refResolver?.resolve(sourceDXN)) as AnyEntity | undefined;
|
|
123
|
+
const target = (await refResolver?.resolve(targetDXN)) as AnyEntity | undefined;
|
|
119
124
|
|
|
120
125
|
defineHiddenProperty(obj, KindId, EntityKind.Relation);
|
|
121
|
-
defineHiddenProperty(obj, RelationSourceDXNId,
|
|
122
|
-
defineHiddenProperty(obj, RelationTargetDXNId,
|
|
126
|
+
defineHiddenProperty(obj, RelationSourceDXNId, sourceDXN);
|
|
127
|
+
defineHiddenProperty(obj, RelationTargetDXNId, targetDXN);
|
|
123
128
|
defineHiddenProperty(obj, RelationSourceId, source);
|
|
124
129
|
defineHiddenProperty(obj, RelationTargetId, target);
|
|
125
130
|
} else {
|
|
@@ -137,8 +142,10 @@ export const objectFromJSON = async (
|
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
if (jsonData[ATTR_PARENT]) {
|
|
140
|
-
const
|
|
141
|
-
const
|
|
145
|
+
const parentDXN = DXN.parse(jsonData[ATTR_PARENT]);
|
|
146
|
+
const resolvedParent = (await refResolver?.resolve(parentDXN)) as Obj.Unknown | undefined;
|
|
147
|
+
defineHiddenProperty(obj, ParentId, resolvedParent);
|
|
148
|
+
} else if (parent) {
|
|
142
149
|
defineHiddenProperty(obj, ParentId, parent);
|
|
143
150
|
}
|
|
144
151
|
|
|
@@ -177,7 +184,7 @@ const stripInternalJsonKeys = (jsonData: unknown) => {
|
|
|
177
184
|
[ATTR_TYPE]: _type,
|
|
178
185
|
[ATTR_META]: _meta,
|
|
179
186
|
[ATTR_DELETED]: _deleted,
|
|
180
|
-
[ATTR_SELF_DXN]:
|
|
187
|
+
[ATTR_SELF_DXN]: _selfDXN,
|
|
181
188
|
[ATTR_RELATION_SOURCE]: _relationSource,
|
|
182
189
|
[ATTR_RELATION_TARGET]: _relationTarget,
|
|
183
190
|
...props
|