@dxos/echo 0.8.4-main.c85a9c8dae → 0.8.4-main.d05539e30a
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 -11
- 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 -14
- package/dist/lib/neutral/Filter.mjs +23 -10
- package/dist/lib/neutral/Format.mjs +3 -3
- package/dist/lib/neutral/JsonSchema.mjs +8 -7
- 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 -10
- package/dist/lib/neutral/Order.mjs +1 -1
- package/dist/lib/neutral/Query.mjs +19 -13
- package/dist/lib/neutral/QueryResult.mjs +1 -1
- package/dist/lib/neutral/Ref.mjs +9 -7
- package/dist/lib/neutral/Relation.mjs +15 -11
- package/dist/lib/neutral/SchemaRegistry.mjs +1 -1
- package/dist/lib/neutral/Tag.mjs +14 -10
- package/dist/lib/neutral/Type.mjs +10 -7
- package/dist/lib/neutral/{chunk-DZQSL6RW.mjs → chunk-44HT3MEC.mjs} +2 -2
- package/dist/lib/neutral/{chunk-DZQSL6RW.mjs.map → chunk-44HT3MEC.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-OVUBTQLT.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-APHSOTIX.mjs +34 -0
- package/dist/lib/neutral/chunk-APHSOTIX.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-ALOGSVBP.mjs → chunk-APJKDGFL.mjs} +72 -6
- package/dist/lib/neutral/chunk-APJKDGFL.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-T6JEFNP6.mjs → chunk-BICZKPQG.mjs} +1 -1
- package/dist/lib/neutral/{chunk-T6JEFNP6.mjs.map → chunk-BICZKPQG.mjs.map} +1 -1
- package/dist/lib/neutral/chunk-BMB7IHGB.mjs +346 -0
- package/dist/lib/neutral/chunk-BMB7IHGB.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-PP4DNUZU.mjs → chunk-G54OX4IX.mjs} +1418 -2885
- package/dist/lib/neutral/chunk-G54OX4IX.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-5ELDDYWE.mjs → chunk-I2DARWPX.mjs} +17 -19
- package/dist/lib/neutral/chunk-I2DARWPX.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-KGV3QIRX.mjs → chunk-J54QMAKF.mjs} +125 -17
- package/dist/lib/neutral/chunk-J54QMAKF.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-BRJSLACP.mjs → chunk-MGSQGHOD.mjs} +71 -17
- package/dist/lib/neutral/chunk-MGSQGHOD.mjs.map +7 -0
- package/dist/lib/neutral/chunk-MLS7U7AT.mjs +734 -0
- package/dist/lib/neutral/chunk-MLS7U7AT.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-4KG6IGL4.mjs → chunk-N4B7FHQT.mjs} +4 -4
- package/dist/lib/neutral/{chunk-4KG6IGL4.mjs.map → chunk-N4B7FHQT.mjs.map} +2 -2
- package/dist/lib/neutral/{chunk-QXF3LGN2.mjs → chunk-N7VOEPSV.mjs} +8 -3
- package/dist/lib/neutral/chunk-N7VOEPSV.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-T4MPQJ7X.mjs → chunk-PSZBLH53.mjs} +6 -22
- package/dist/lib/neutral/chunk-PSZBLH53.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-ZWKJ4LZJ.mjs → chunk-PT37DG2F.mjs} +23 -51
- package/dist/lib/neutral/chunk-PT37DG2F.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-GAWKQ5DZ.mjs → chunk-Q2KKKJSV.mjs} +5 -5
- package/dist/lib/neutral/chunk-Q2KKKJSV.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-AQP4QKYP.mjs → chunk-Q7ZL2P5H.mjs} +56 -19
- package/dist/lib/neutral/chunk-Q7ZL2P5H.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-O3TZFQCT.mjs → chunk-QRZ2I3ZM.mjs} +2 -2
- package/dist/lib/neutral/chunk-QRZ2I3ZM.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-W7OP5HGZ.mjs → chunk-SCPFDS2E.mjs} +14 -10
- package/dist/lib/neutral/chunk-SCPFDS2E.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-F7KMHDPJ.mjs → chunk-TNBK56IN.mjs} +54 -31
- package/dist/lib/neutral/chunk-TNBK56IN.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-M2KVTHZM.mjs → chunk-TRPZU2HV.mjs} +10 -10
- package/dist/lib/neutral/chunk-TRPZU2HV.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-ZTUBYOGB.mjs → chunk-TTCSATUD.mjs} +1 -1
- package/dist/lib/neutral/chunk-TTCSATUD.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-OMUPQMLR.mjs → chunk-V72DY6LU.mjs} +1 -1
- package/dist/lib/neutral/chunk-ZFACXBY6.mjs +136 -0
- package/dist/lib/neutral/chunk-ZFACXBY6.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-MXQJZCPY.mjs → chunk-ZISMEVKD.mjs} +1 -1
- package/dist/lib/neutral/chunk-ZISMEVKD.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +38 -25
- package/dist/lib/neutral/internal/index.mjs +50 -38
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/testing/index.mjs +196 -136
- package/dist/lib/neutral/testing/index.mjs.map +3 -3
- package/dist/types/src/Annotation.d.ts +3 -3
- 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 +16 -4
- 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 +65 -24
- 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/Format.d.ts +1 -1
- package/dist/types/src/Format.d.ts.map +1 -1
- package/dist/types/src/Hypergraph.d.ts +9 -4
- 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 +5 -5
- package/dist/types/src/JsonSchema.d.ts.map +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 +46 -30
- 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 +12 -11
- package/dist/types/src/Ref.d.ts.map +1 -1
- package/dist/types/src/Relation.d.ts +16 -16
- package/dist/types/src/Relation.d.ts.map +1 -1
- package/dist/types/src/SchemaRegistry.d.ts +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 +10 -9
- 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/{annotations → Annotation}/annotations.d.ts +33 -2
- package/dist/types/src/internal/Annotation/annotations.d.ts.map +1 -0
- package/dist/types/src/internal/Annotation/annotations.test.d.ts.map +1 -0
- package/dist/types/src/internal/Annotation/index.d.ts +4 -0
- package/dist/types/src/internal/Annotation/index.d.ts.map +1 -0
- package/dist/types/src/internal/{api → Annotation}/sorting.d.ts +1 -1
- package/dist/types/src/internal/Annotation/sorting.d.ts.map +1 -0
- package/dist/types/src/internal/{annotations → Annotation}/util.d.ts +2 -2
- package/dist/types/src/internal/Annotation/util.d.ts.map +1 -0
- package/dist/types/src/internal/{api/entity.d.ts → Entity/api.d.ts} +2 -2
- package/dist/types/src/internal/Entity/api.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/entity.d.ts +2 -2
- package/dist/types/src/internal/Entity/entity.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/index.d.ts +2 -0
- package/dist/types/src/internal/Entity/index.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/model.d.ts +4 -26
- package/dist/types/src/internal/Entity/model.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/object.d.ts +2 -2
- package/dist/types/src/internal/Entity/object.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/relation.d.ts +3 -30
- package/dist/types/src/internal/Entity/relation.d.ts.map +1 -0
- package/dist/types/src/internal/Entity/util.d.ts.map +1 -0
- package/dist/types/src/internal/{api → Entity}/version.d.ts +1 -1
- package/dist/types/src/internal/Entity/version.d.ts.map +1 -0
- package/dist/types/src/internal/Format/date.d.ts.map +1 -0
- package/dist/types/src/internal/Format/date.test.d.ts.map +1 -0
- package/dist/types/src/internal/Format/format.d.ts.map +1 -0
- package/dist/types/src/internal/Format/format.test.d.ts.map +1 -0
- package/dist/types/src/internal/Format/index.d.ts.map +1 -0
- package/dist/types/src/internal/Format/number.d.ts.map +1 -0
- package/dist/types/src/internal/Format/object.d.ts.map +1 -0
- package/dist/types/src/internal/Format/select.d.ts.map +1 -0
- package/dist/types/src/internal/Format/string.d.ts.map +1 -0
- package/dist/types/src/internal/{formats → Format}/types.d.ts +1 -1
- package/dist/types/src/internal/Format/types.d.ts.map +1 -0
- package/dist/types/src/internal/{json-schema → JsonSchema}/annotations.d.ts +1 -1
- package/dist/types/src/internal/JsonSchema/annotations.d.ts.map +1 -0
- package/dist/types/src/internal/JsonSchema/effect-schema.test.d.ts.map +1 -0
- package/dist/types/src/internal/JsonSchema/index.d.ts.map +1 -0
- package/dist/types/src/internal/JsonSchema/json-schema-normalize.d.ts.map +1 -0
- package/dist/types/src/internal/{json-schema → JsonSchema}/json-schema-type.d.ts +23 -23
- package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts.map +1 -0
- package/dist/types/src/internal/{json-schema → JsonSchema}/json-schema.d.ts +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema.d.ts.map +1 -0
- package/dist/types/src/internal/JsonSchema/json-schema.test.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/clone.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/common.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/create-object.d.ts +2 -2
- package/dist/types/src/internal/Obj/create-object.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/create-object.test.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/deleted.d.ts +1 -1
- package/dist/types/src/internal/Obj/deleted.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/ids.d.ts +1 -1
- package/dist/types/src/internal/Obj/ids.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/index.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/inspect.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/json-serializer.d.ts +13 -5
- package/dist/types/src/internal/Obj/json-serializer.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/json-serializer.test.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/schema-validator.d.ts +2 -0
- package/dist/types/src/internal/Obj/schema-validator.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/schema-validator.test.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/set-value.d.ts +2 -2
- package/dist/types/src/internal/Obj/set-value.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/set-value.test.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/snapshot.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/typed-object.d.ts +2 -2
- package/dist/types/src/internal/Obj/typed-object.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/typed-object.test.d.ts.map +1 -0
- 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/index.d.ts.map +1 -0
- package/dist/types/src/internal/{ref → Ref}/ref-array.d.ts +1 -1
- package/dist/types/src/internal/Ref/ref-array.d.ts.map +1 -0
- package/dist/types/src/internal/{ref → Ref}/ref.d.ts +15 -2
- package/dist/types/src/internal/Ref/ref.d.ts.map +1 -0
- package/dist/types/src/internal/Ref/ref.test.d.ts.map +1 -0
- package/dist/types/src/internal/{schema → Type}/compose.d.ts +1 -1
- package/dist/types/src/internal/Type/compose.d.ts.map +1 -0
- package/dist/types/src/internal/Type/compose.test.d.ts.map +1 -0
- package/dist/types/src/internal/{schema → Type}/echo-schema.d.ts +6 -6
- package/dist/types/src/internal/Type/echo-schema.d.ts.map +1 -0
- package/dist/types/src/internal/Type/index.d.ts.map +1 -0
- package/dist/types/src/internal/Type/manipulation.d.ts.map +1 -0
- package/dist/types/src/internal/{schema → Type}/persistent-schema.d.ts +2 -2
- package/dist/types/src/internal/Type/persistent-schema.d.ts.map +1 -0
- package/dist/types/src/internal/{api → common/api}/index.d.ts +0 -4
- package/dist/types/src/internal/common/api/index.d.ts.map +1 -0
- package/dist/types/src/internal/{api → common/api}/meta.d.ts +3 -3
- package/dist/types/src/internal/common/api/meta.d.ts.map +1 -0
- package/dist/types/src/internal/common/index.d.ts +4 -0
- package/dist/types/src/internal/common/index.d.ts.map +1 -0
- package/dist/types/src/internal/{proxy → common/proxy}/change-context.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/change-context.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/change.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/define-hidden-property.d.ts.map +1 -0
- package/dist/types/src/internal/{proxy → common/proxy}/errors.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/errors.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/event-batch.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/handler.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/index.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/json-serializer.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/make-object.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/ownership.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/proxy-types.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/proxy-utils.d.ts.map +1 -0
- package/dist/types/src/internal/{proxy → common/proxy}/reactive-array.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/reactive-array.d.ts.map +1 -0
- package/dist/types/src/internal/{proxy → common/proxy}/reactive.d.ts +2 -2
- package/dist/types/src/internal/{proxy → 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 -0
- package/dist/types/src/internal/common/proxy/schema.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/symbols.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/typed-handler.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/typed-handler.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/typed-object.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/types/base.d.ts.map +1 -0
- package/dist/types/src/internal/{types → common/types}/entity.d.ts +4 -4
- package/dist/types/src/internal/common/types/entity.d.ts.map +1 -0
- package/dist/types/src/internal/{types → common/types}/index.d.ts +1 -0
- package/dist/types/src/internal/common/types/index.d.ts.map +1 -0
- package/dist/types/src/internal/{types → common/types}/meta.d.ts +13 -3
- package/dist/types/src/internal/common/types/meta.d.ts.map +1 -0
- package/dist/types/src/internal/common/types/model-symbols.d.ts +54 -0
- package/dist/types/src/internal/common/types/model-symbols.d.ts.map +1 -0
- package/dist/types/src/internal/common/types/typename.d.ts.map +1 -0
- package/dist/types/src/internal/{types → common/types}/version.d.ts +1 -1
- package/dist/types/src/internal/common/types/version.d.ts.map +1 -0
- package/dist/types/src/internal/index.d.ts +9 -10
- 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 +6 -3
- package/src/Collection.ts +8 -1
- package/src/Database.ts +55 -18
- package/src/Dataset.ts +2 -0
- package/src/Entity.ts +20 -11
- package/src/Err.ts +2 -0
- package/src/Extension.test.ts +235 -0
- package/src/Extension.ts +122 -0
- package/src/Feed.ts +118 -37
- package/src/Filter.test.ts +90 -0
- package/src/Filter.ts +99 -3
- package/src/Format.ts +1 -1
- package/src/Hypergraph.ts +10 -5
- package/src/Json.test.ts +175 -0
- package/src/Json.ts +102 -0
- package/src/JsonSchema.ts +7 -5
- package/src/Migration.ts +106 -0
- package/src/Obj.test.ts +107 -15
- package/src/Obj.ts +167 -40
- package/src/Order.ts +2 -0
- package/src/Query.test.ts +222 -32
- package/src/Query.ts +62 -10
- package/src/Ref.ts +16 -12
- package/src/Relation.test.ts +2 -2
- package/src/Relation.ts +28 -21
- package/src/SchemaRegistry.ts +1 -1
- package/src/Tag.ts +3 -1
- package/src/Type.ts +14 -11
- package/src/View.ts +9 -2
- package/src/exemplars.test.ts +21 -0
- package/src/index.ts +4 -0
- package/src/internal/{annotations → Annotation}/annotations.test.ts +56 -7
- package/src/internal/{annotations → Annotation}/annotations.ts +84 -20
- package/src/internal/{annotations → Annotation}/index.ts +1 -0
- package/src/internal/{api → Annotation}/sorting.ts +2 -4
- package/src/internal/{annotations → Annotation}/util.ts +1 -1
- package/src/internal/{api/entity.ts → Entity/api.ts} +3 -2
- package/src/internal/{entities → Entity}/entity.ts +2 -2
- package/src/internal/{entities → Entity}/index.ts +2 -0
- package/src/internal/{entities → Entity}/model.ts +15 -42
- package/src/internal/{entities → Entity}/object.ts +2 -3
- package/src/internal/{entities → Entity}/relation.ts +19 -36
- package/src/internal/{api → Entity}/version.ts +2 -2
- package/src/internal/{formats → Format}/date.test.ts +1 -2
- package/src/internal/{formats → Format}/format.test.ts +1 -2
- package/src/internal/{formats → Format}/types.ts +2 -2
- package/src/internal/{json-schema → JsonSchema}/annotations.ts +3 -3
- package/src/internal/{json-schema → JsonSchema}/json-schema-type.ts +4 -4
- package/src/internal/{json-schema → JsonSchema}/json-schema.test.ts +48 -49
- package/src/internal/{json-schema → JsonSchema}/json-schema.ts +3 -4
- package/src/internal/{object → Obj}/clone.ts +3 -3
- package/src/internal/{object → Obj}/common.ts +2 -2
- package/src/internal/{object → Obj}/create-object.test.ts +5 -7
- package/src/internal/{object → Obj}/create-object.ts +5 -6
- package/src/internal/{object → Obj}/deleted.ts +2 -2
- package/src/internal/{object → Obj}/ids.ts +1 -1
- package/src/internal/{object → Obj}/inspect.ts +2 -2
- package/src/internal/{object → Obj}/json-serializer.test.ts +8 -9
- package/src/internal/{object → Obj}/json-serializer.ts +44 -26
- package/src/internal/{object → Obj}/schema-validator.ts +1 -1
- package/src/internal/{object → Obj}/set-value.test.ts +24 -24
- package/src/internal/{object → Obj}/set-value.ts +3 -3
- package/src/internal/{object → Obj}/snapshot.ts +14 -5
- package/src/internal/{object → Obj}/typed-object.test.ts +3 -3
- package/src/internal/{object → Obj}/typed-object.ts +2 -2
- package/src/internal/Query.ts +156 -0
- package/src/internal/{ref → Ref}/ref-array.ts +1 -2
- package/src/internal/{ref → Ref}/ref.test.ts +4 -5
- package/src/internal/{ref → Ref}/ref.ts +20 -3
- package/src/internal/{schema → Type}/compose.test.ts +5 -6
- package/src/internal/{schema → Type}/compose.ts +1 -1
- package/src/internal/{schema → Type}/echo-schema.ts +7 -8
- package/src/internal/{schema → Type}/manipulation.ts +1 -1
- package/src/internal/{schema → Type}/persistent-schema.ts +7 -7
- package/src/internal/{README.md → common/README.md} +1 -1
- package/src/internal/{api → common/api}/index.ts +0 -4
- package/src/internal/{api → common/api}/meta.ts +3 -3
- package/src/internal/common/index.ts +7 -0
- package/src/internal/{proxy → common/proxy}/change-context.ts +1 -1
- package/src/internal/{proxy → common/proxy}/change.test.ts +97 -97
- package/src/internal/{proxy → common/proxy}/errors.ts +2 -2
- package/src/internal/{proxy → common/proxy}/handler.test.ts +2 -4
- package/src/internal/{proxy → common/proxy}/json-serializer.ts +6 -3
- package/src/internal/{proxy → common/proxy}/make-object.ts +1 -2
- package/src/internal/{proxy → common/proxy}/ownership.ts +0 -1
- package/src/internal/{proxy → common/proxy}/reactive-array.ts +1 -1
- package/src/internal/common/proxy/reactive.test.ts +54 -0
- package/src/internal/{proxy → common/proxy}/reactive.ts +12 -4
- package/src/internal/{proxy → common/proxy}/schema.test.ts +10 -10
- package/src/internal/{proxy → common/proxy}/typed-handler.test.ts +6 -7
- package/src/internal/{proxy → common/proxy}/typed-handler.ts +10 -13
- package/src/internal/{proxy → common/proxy}/typed-object.test.ts +5 -6
- package/src/internal/{types → common/types}/entity.ts +1 -1
- package/src/internal/{types → common/types}/index.ts +1 -0
- package/src/internal/{types → common/types}/meta.ts +13 -2
- package/src/internal/common/types/model-symbols.ts +69 -0
- package/src/internal/index.ts +9 -31
- package/src/testing/api.test.ts +2 -3
- package/src/testing/test-data.ts +157 -98
- package/src/testing/test-schema.ts +9 -9
- package/dist/lib/neutral/chunk-5ELDDYWE.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ALOGSVBP.mjs.map +0 -7
- package/dist/lib/neutral/chunk-AQP4QKYP.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BRJSLACP.mjs.map +0 -7
- package/dist/lib/neutral/chunk-F7KMHDPJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-GAWKQ5DZ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-GFNCSK7F.mjs +0 -101
- package/dist/lib/neutral/chunk-GFNCSK7F.mjs.map +0 -7
- package/dist/lib/neutral/chunk-KGV3QIRX.mjs.map +0 -7
- package/dist/lib/neutral/chunk-M2KVTHZM.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MXQJZCPY.mjs.map +0 -7
- package/dist/lib/neutral/chunk-O3TZFQCT.mjs.map +0 -7
- package/dist/lib/neutral/chunk-OVUBTQLT.mjs.map +0 -7
- package/dist/lib/neutral/chunk-PP4DNUZU.mjs.map +0 -7
- package/dist/lib/neutral/chunk-QXF3LGN2.mjs.map +0 -7
- package/dist/lib/neutral/chunk-T4MPQJ7X.mjs.map +0 -7
- package/dist/lib/neutral/chunk-W7OP5HGZ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ZTUBYOGB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ZWKJ4LZJ.mjs.map +0 -7
- package/dist/types/src/internal/annotations/annotations.d.ts.map +0 -1
- package/dist/types/src/internal/annotations/annotations.test.d.ts.map +0 -1
- package/dist/types/src/internal/annotations/index.d.ts +0 -3
- package/dist/types/src/internal/annotations/index.d.ts.map +0 -1
- package/dist/types/src/internal/annotations/util.d.ts.map +0 -1
- package/dist/types/src/internal/api/annotations.d.ts +0 -23
- package/dist/types/src/internal/api/annotations.d.ts.map +0 -1
- package/dist/types/src/internal/api/entity.d.ts.map +0 -1
- package/dist/types/src/internal/api/index.d.ts.map +0 -1
- package/dist/types/src/internal/api/meta.d.ts.map +0 -1
- package/dist/types/src/internal/api/sorting.d.ts.map +0 -1
- package/dist/types/src/internal/api/version.d.ts.map +0 -1
- package/dist/types/src/internal/entities/entity.d.ts.map +0 -1
- package/dist/types/src/internal/entities/index.d.ts.map +0 -1
- package/dist/types/src/internal/entities/model.d.ts.map +0 -1
- package/dist/types/src/internal/entities/object.d.ts.map +0 -1
- package/dist/types/src/internal/entities/relation.d.ts.map +0 -1
- package/dist/types/src/internal/entities/util.d.ts.map +0 -1
- package/dist/types/src/internal/formats/date.d.ts.map +0 -1
- package/dist/types/src/internal/formats/date.test.d.ts.map +0 -1
- package/dist/types/src/internal/formats/format.d.ts.map +0 -1
- package/dist/types/src/internal/formats/format.test.d.ts.map +0 -1
- package/dist/types/src/internal/formats/index.d.ts.map +0 -1
- package/dist/types/src/internal/formats/number.d.ts.map +0 -1
- package/dist/types/src/internal/formats/object.d.ts.map +0 -1
- package/dist/types/src/internal/formats/select.d.ts.map +0 -1
- package/dist/types/src/internal/formats/string.d.ts.map +0 -1
- package/dist/types/src/internal/formats/types.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/annotations.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/effect-schema.test.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/index.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/json-schema-type.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/json-schema.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/json-schema.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/clone.d.ts.map +0 -1
- package/dist/types/src/internal/object/common.d.ts.map +0 -1
- package/dist/types/src/internal/object/create-object.d.ts.map +0 -1
- package/dist/types/src/internal/object/create-object.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/deleted.d.ts.map +0 -1
- package/dist/types/src/internal/object/ids.d.ts.map +0 -1
- package/dist/types/src/internal/object/index.d.ts.map +0 -1
- package/dist/types/src/internal/object/inspect.d.ts.map +0 -1
- package/dist/types/src/internal/object/json-serializer.d.ts.map +0 -1
- package/dist/types/src/internal/object/json-serializer.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/schema-validator.d.ts +0 -2
- package/dist/types/src/internal/object/schema-validator.d.ts.map +0 -1
- package/dist/types/src/internal/object/schema-validator.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/set-value.d.ts.map +0 -1
- package/dist/types/src/internal/object/set-value.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/snapshot.d.ts.map +0 -1
- package/dist/types/src/internal/object/typed-object.d.ts.map +0 -1
- package/dist/types/src/internal/object/typed-object.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/change-context.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/change.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/define-hidden-property.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/errors.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/event-batch.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/handler.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/index.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/json-serializer.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/make-object.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/ownership.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/proxy-types.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/proxy-utils.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/reactive-array.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/schema-validator.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/schema.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/symbols.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/typed-handler.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/typed-handler.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/typed-object.test.d.ts.map +0 -1
- package/dist/types/src/internal/ref/index.d.ts.map +0 -1
- package/dist/types/src/internal/ref/ref-array.d.ts.map +0 -1
- package/dist/types/src/internal/ref/ref.d.ts.map +0 -1
- package/dist/types/src/internal/ref/ref.test.d.ts.map +0 -1
- package/dist/types/src/internal/schema/compose.d.ts.map +0 -1
- package/dist/types/src/internal/schema/compose.test.d.ts.map +0 -1
- package/dist/types/src/internal/schema/echo-schema.d.ts.map +0 -1
- package/dist/types/src/internal/schema/index.d.ts.map +0 -1
- package/dist/types/src/internal/schema/manipulation.d.ts.map +0 -1
- package/dist/types/src/internal/schema/persistent-schema.d.ts.map +0 -1
- package/dist/types/src/internal/types/base.d.ts.map +0 -1
- package/dist/types/src/internal/types/entity.d.ts.map +0 -1
- package/dist/types/src/internal/types/index.d.ts.map +0 -1
- package/dist/types/src/internal/types/meta.d.ts.map +0 -1
- package/dist/types/src/internal/types/typename.d.ts.map +0 -1
- package/dist/types/src/internal/types/version.d.ts.map +0 -1
- package/src/internal/api/annotations.ts +0 -60
- /package/dist/lib/neutral/{chunk-ANHVGJI4.mjs.map → chunk-7RVZT53K.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-OMUPQMLR.mjs.map → chunk-V72DY6LU.mjs.map} +0 -0
- /package/dist/types/src/internal/{annotations → Annotation}/annotations.test.d.ts +0 -0
- /package/dist/types/src/internal/{entities → Entity}/util.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/date.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/date.test.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/format.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/format.test.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/index.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/number.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/object.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/select.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/string.d.ts +0 -0
- /package/dist/types/src/internal/{json-schema → JsonSchema}/effect-schema.test.d.ts +0 -0
- /package/dist/types/src/internal/{json-schema → JsonSchema}/index.d.ts +0 -0
- /package/dist/types/src/internal/{json-schema → JsonSchema}/json-schema-normalize.d.ts +0 -0
- /package/dist/types/src/internal/{json-schema → JsonSchema}/json-schema.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/clone.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/common.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/create-object.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/index.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/inspect.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/json-serializer.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/schema-validator.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/set-value.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/snapshot.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/typed-object.test.d.ts +0 -0
- /package/dist/types/src/internal/{ref → Ref}/index.d.ts +0 -0
- /package/dist/types/src/internal/{ref → Ref}/ref.test.d.ts +0 -0
- /package/dist/types/src/internal/{schema → Type}/compose.test.d.ts +0 -0
- /package/dist/types/src/internal/{schema → Type}/index.d.ts +0 -0
- /package/dist/types/src/internal/{schema → Type}/manipulation.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/change.test.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/define-hidden-property.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/event-batch.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/handler.test.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/index.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/json-serializer.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/make-object.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/ownership.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/proxy-types.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/proxy-utils.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/schema-validator.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/schema.test.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/symbols.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/typed-handler.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/typed-handler.test.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/typed-object.test.d.ts +0 -0
- /package/dist/types/src/internal/{types → common/types}/base.d.ts +0 -0
- /package/dist/types/src/internal/{types → common/types}/typename.d.ts +0 -0
- /package/src/internal/{entities → Entity}/util.ts +0 -0
- /package/src/internal/{formats → Format}/date.ts +0 -0
- /package/src/internal/{formats → Format}/format.ts +0 -0
- /package/src/internal/{formats → Format}/index.ts +0 -0
- /package/src/internal/{formats → Format}/number.ts +0 -0
- /package/src/internal/{formats → Format}/object.ts +0 -0
- /package/src/internal/{formats → Format}/select.ts +0 -0
- /package/src/internal/{formats → Format}/string.ts +0 -0
- /package/src/internal/{json-schema → JsonSchema}/effect-schema.test.ts +0 -0
- /package/src/internal/{json-schema → JsonSchema}/index.ts +0 -0
- /package/src/internal/{json-schema → JsonSchema}/json-schema-normalize.ts +0 -0
- /package/src/internal/{object → Obj}/index.ts +0 -0
- /package/src/internal/{object → Obj}/schema-validator.test.ts +0 -0
- /package/src/internal/{ref → Ref}/index.ts +0 -0
- /package/src/internal/{schema → Type}/index.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/define-hidden-property.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/event-batch.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/index.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/proxy-types.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/proxy-utils.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/schema-validator.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/symbols.ts +0 -0
- /package/src/internal/{types → common/types}/base.ts +0 -0
- /package/src/internal/{types → common/types}/typename.ts +0 -0
- /package/src/internal/{types → common/types}/version.ts +0 -0
package/src/Extension.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// @import-as-namespace
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2026 DXOS.org
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import * as Function from 'effect/Function';
|
|
7
|
+
import * as Option from 'effect/Option';
|
|
8
|
+
import * as Schema from 'effect/Schema';
|
|
9
|
+
import type * as Types from 'effect/Types';
|
|
10
|
+
|
|
11
|
+
// @import-as-namespace
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Extensions allow objects to contain typed properties that are not part of the schema.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export const TypeId = '~@dxos/echo/Extension' as const;
|
|
18
|
+
export type TypeId = typeof TypeId;
|
|
19
|
+
|
|
20
|
+
export interface Extension<T> extends Record<
|
|
21
|
+
TypeId,
|
|
22
|
+
{
|
|
23
|
+
_Type: T;
|
|
24
|
+
}
|
|
25
|
+
> {
|
|
26
|
+
readonly [TypeId]: {
|
|
27
|
+
_Type: T;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
readonly key: Key;
|
|
31
|
+
readonly valueSchema: Schema.Schema<T>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a new typed extension.
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* const ColorExtension = Extension.make('color', Schema.String);
|
|
39
|
+
*
|
|
40
|
+
* const obj = Obj.make(Person, {
|
|
41
|
+
* [Obj.Meta]: { keys: [{ source: 'external', id: '123' }] },
|
|
42
|
+
* name: 'John',
|
|
43
|
+
* email: 'john@example.com',
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* Obj.update(obj, (obj) => {
|
|
47
|
+
* Extension.set(obj.extensions, ColorExtension, 'red');
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* console.log(Extension.get(obj.extensions, ColorExtension)); // 'red'
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export const make = <S extends Schema.Schema.AnyNoContext>(
|
|
54
|
+
key: string,
|
|
55
|
+
valueSchema: S,
|
|
56
|
+
): Extension<Schema.Schema.Type<S>> => {
|
|
57
|
+
return {
|
|
58
|
+
[TypeId]: {} as any,
|
|
59
|
+
key: Key.make(key),
|
|
60
|
+
valueSchema,
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Unique identifier for an extension.
|
|
66
|
+
*/
|
|
67
|
+
// TODO(dmaretskyi): filter to be fully qualified: (e.g., org.dxos.extension.color)
|
|
68
|
+
export const Key = Schema.String.pipe(Schema.brand('~@dxos/echo/ExtensionKey'));
|
|
69
|
+
export type Key = Schema.Schema.Type<typeof Key>;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Set of extension values.
|
|
73
|
+
*
|
|
74
|
+
* Can be used inside an object/relation schema:
|
|
75
|
+
*
|
|
76
|
+
* ```ts
|
|
77
|
+
* const Person = Schema.Struct({
|
|
78
|
+
* name: Schema.String,
|
|
79
|
+
* extensions: Extension.Values,
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export const Values = Schema.Record({ key: Key, value: Schema.Unknown });
|
|
84
|
+
export interface Values extends Schema.Schema.Type<typeof Values> {}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get the value of an extension from a set of values.
|
|
88
|
+
*/
|
|
89
|
+
export const get: {
|
|
90
|
+
<T>(extension: Extension<T>): (values: Values) => Option.Option<T>;
|
|
91
|
+
<T>(values: Values, extension: Extension<T>): Option.Option<T>;
|
|
92
|
+
} = Function.dual<
|
|
93
|
+
<T>(extension: Extension<T>) => (values: Values) => Option.Option<T>,
|
|
94
|
+
<T>(values: Values, extension: Extension<T>) => Option.Option<T>
|
|
95
|
+
>(2, (values, extension) => {
|
|
96
|
+
if (!(extension.key in values)) {
|
|
97
|
+
return Option.none();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return Function.pipe(values[extension.key], Schema.decodeUnknownSync(extension.valueSchema), Option.some);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Set the value of an extension in a set of values.
|
|
105
|
+
*
|
|
106
|
+
* Can also be used within Obj.update callback:
|
|
107
|
+
*
|
|
108
|
+
* ```ts
|
|
109
|
+
* Obj.update(obj, (obj) => {
|
|
110
|
+
* Extension.set(obj.extensions, ColorExtension, 'red');
|
|
111
|
+
* });
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export const set: {
|
|
115
|
+
<T>(extension: Extension<T>, value: T): (values: Values) => void;
|
|
116
|
+
<T>(values: Types.Mutable<Values>, extension: Extension<T>, value: T): void;
|
|
117
|
+
} = Function.dual<
|
|
118
|
+
<T>(extension: Extension<T>, value: T) => (values: Values) => void,
|
|
119
|
+
<T>(values: Types.Mutable<Values>, extension: Extension<T>, value: T) => void
|
|
120
|
+
>(3, (values, extension, value) => {
|
|
121
|
+
values[extension.key] = Schema.encodeSync(extension.valueSchema)(value);
|
|
122
|
+
});
|
package/src/Feed.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
// @import-as-namespace
|
|
6
|
+
|
|
5
7
|
import * as Context from 'effect/Context';
|
|
6
8
|
import * as Effect from 'effect/Effect';
|
|
7
9
|
import * as Layer from 'effect/Layer';
|
|
@@ -10,6 +12,7 @@ import * as Schema from 'effect/Schema';
|
|
|
10
12
|
|
|
11
13
|
import { DXN } from '@dxos/keys';
|
|
12
14
|
|
|
15
|
+
import * as Annotation from './Annotation';
|
|
13
16
|
import type * as Entity from './Entity';
|
|
14
17
|
import type * as Filter from './Filter';
|
|
15
18
|
import * as internal from './internal';
|
|
@@ -23,7 +26,7 @@ import * as Type from './Type';
|
|
|
23
26
|
*
|
|
24
27
|
* @example
|
|
25
28
|
* ```ts
|
|
26
|
-
* const feed = Obj.make(Feed.Feed, { name: 'notifications', kind: 'dxos.
|
|
29
|
+
* const feed = Obj.make(Feed.Feed, { name: 'notifications', kind: 'org.dxos.plugin.notifications.v1' });
|
|
27
30
|
* ```
|
|
28
31
|
*/
|
|
29
32
|
export const Feed = Schema.Struct({
|
|
@@ -31,11 +34,24 @@ export const Feed = Schema.Struct({
|
|
|
31
34
|
name: Schema.String.pipe(Schema.optional),
|
|
32
35
|
/** Identifier for the feed's kind (e.g., plugin id). */
|
|
33
36
|
kind: Schema.String.pipe(internal.FormInputAnnotation.set(false), Schema.optional),
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Feed namespace.
|
|
40
|
+
* Controls how feed data is stored and replicated.
|
|
41
|
+
* - `data`: Data feed (default).
|
|
42
|
+
* - `trace`: Trace feed.
|
|
43
|
+
*/
|
|
44
|
+
namespace: Schema.optional(Schema.Literal('data', 'trace')),
|
|
34
45
|
}).pipe(
|
|
35
46
|
Type.object({
|
|
36
|
-
typename: 'dxos.
|
|
47
|
+
typename: 'org.dxos.type.feed',
|
|
37
48
|
version: '0.1.0',
|
|
38
49
|
}),
|
|
50
|
+
internal.SystemTypeAnnotation.set(true),
|
|
51
|
+
Annotation.IconAnnotation.set({
|
|
52
|
+
icon: 'ph--rows--regular',
|
|
53
|
+
hue: 'yellow',
|
|
54
|
+
}),
|
|
39
55
|
);
|
|
40
56
|
|
|
41
57
|
/**
|
|
@@ -47,12 +63,6 @@ export interface Feed extends Schema.Schema.Type<typeof Feed> {}
|
|
|
47
63
|
// Types
|
|
48
64
|
//
|
|
49
65
|
|
|
50
|
-
/**
|
|
51
|
-
* Meta key source for storing the backing DXN bound to a feed object.
|
|
52
|
-
*/
|
|
53
|
-
// TODO(dmaretskyi): Enforce that Feed ObjectId = feed storage ID. And remove this key.
|
|
54
|
-
export const DXN_KEY = 'dxos.org/key/feed';
|
|
55
|
-
|
|
56
66
|
/**
|
|
57
67
|
* Opaque cursor for iterating over feed items.
|
|
58
68
|
*/
|
|
@@ -70,6 +80,16 @@ export interface RetentionOptions {
|
|
|
70
80
|
cursor?: string;
|
|
71
81
|
}
|
|
72
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Sync options for a feed.
|
|
85
|
+
*/
|
|
86
|
+
export interface SyncOptions {
|
|
87
|
+
/** Push local changes to the server. Defaults to true. */
|
|
88
|
+
shouldPush?: boolean;
|
|
89
|
+
/** Pull remote changes from the server. Defaults to true. */
|
|
90
|
+
shouldPull?: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
73
93
|
//
|
|
74
94
|
// Factory
|
|
75
95
|
//
|
|
@@ -79,21 +99,24 @@ export interface RetentionOptions {
|
|
|
79
99
|
*
|
|
80
100
|
* @example
|
|
81
101
|
* ```ts
|
|
82
|
-
* const feed = Feed.make({ name: 'notifications', kind: 'dxos.
|
|
102
|
+
* const feed = Feed.make({ name: 'notifications', kind: 'org.dxos.plugin.notifications.v1' });
|
|
83
103
|
* ```
|
|
84
104
|
*/
|
|
85
105
|
// TODO(wittjosiah): How to control the feed namespace (data/trace)? Why do feeds have namespaces?
|
|
86
|
-
export const make = (props: Obj.MakeProps<typeof Feed>): Feed => Obj.make(Feed, props);
|
|
106
|
+
export const make = (props: Obj.MakeProps<typeof Feed> = {}): Feed => Obj.make(Feed, props);
|
|
87
107
|
|
|
88
108
|
/**
|
|
89
|
-
*
|
|
109
|
+
* Derives the queue DXN from the feed object's DXN.
|
|
110
|
+
* Returns `undefined` when the feed is not stored in a space yet.
|
|
90
111
|
*
|
|
91
|
-
*
|
|
112
|
+
* Used internally by the feed service layer.
|
|
92
113
|
*/
|
|
93
|
-
// TODO(wittjosiah): Align backing feed dxn's with object DXN.
|
|
94
114
|
export const getQueueDxn = (feed: Feed): DXN | undefined => {
|
|
95
|
-
const
|
|
96
|
-
|
|
115
|
+
const self = Obj.getDXN(feed).asEchoDXN();
|
|
116
|
+
if (!self || !self.spaceId) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
return new DXN(DXN.kind.QUEUE, [feed.namespace ?? 'data', self.spaceId, self.echoId]);
|
|
97
120
|
};
|
|
98
121
|
|
|
99
122
|
//
|
|
@@ -105,8 +128,8 @@ export const getQueueDxn = (feed: Feed): DXN | undefined => {
|
|
|
105
128
|
* Provides the bridge to the underlying storage implementation.
|
|
106
129
|
* Must be provided by the application layer (e.g., echo-db).
|
|
107
130
|
*/
|
|
108
|
-
export class
|
|
109
|
-
|
|
131
|
+
export class FeedService extends Context.Tag('@dxos/echo/Feed/FeedService')<
|
|
132
|
+
FeedService,
|
|
110
133
|
{
|
|
111
134
|
/**
|
|
112
135
|
* Appends items to a feed.
|
|
@@ -126,24 +149,61 @@ export class Service extends Context.Tag('@dxos/echo/Feed/Service')<
|
|
|
126
149
|
<Q extends Query.Any>(feed: Feed, query: Q): QueryResult.QueryResult<Query.Type<Q>>;
|
|
127
150
|
<F extends Filter.Any>(feed: Feed, filter: F): QueryResult.QueryResult<Filter.Type<F>>;
|
|
128
151
|
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Syncs the feed with the server.
|
|
155
|
+
*/
|
|
156
|
+
sync(feed: Feed, options?: SyncOptions): Promise<void>;
|
|
129
157
|
}
|
|
130
158
|
>() {}
|
|
131
159
|
|
|
160
|
+
/**
|
|
161
|
+
* @deprecated Use `FeedService` instead.
|
|
162
|
+
*/
|
|
163
|
+
export type Service = FeedService;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @deprecated Use `FeedService` instead.
|
|
167
|
+
*/
|
|
168
|
+
export const Service = FeedService;
|
|
169
|
+
|
|
132
170
|
/**
|
|
133
171
|
* Layer that provides a Feed service that throws when accessed.
|
|
134
172
|
* Useful as a default layer when no feed service is available.
|
|
135
173
|
*/
|
|
136
|
-
export const notAvailable: Layer.Layer<
|
|
174
|
+
export const notAvailable: Layer.Layer<FeedService> = Layer.succeed(FeedService, {
|
|
137
175
|
append: () => {
|
|
138
|
-
throw new Error('Feed.
|
|
176
|
+
throw new Error('Feed.FeedService not available');
|
|
139
177
|
},
|
|
140
178
|
remove: () => {
|
|
141
|
-
throw new Error('Feed.
|
|
179
|
+
throw new Error('Feed.FeedService not available');
|
|
142
180
|
},
|
|
143
181
|
query: () => {
|
|
144
|
-
throw new Error('Feed.
|
|
182
|
+
throw new Error('Feed.FeedService not available');
|
|
145
183
|
},
|
|
146
|
-
|
|
184
|
+
sync: () => {
|
|
185
|
+
throw new Error('Feed.FeedService not available');
|
|
186
|
+
},
|
|
187
|
+
} as Context.Tag.Service<FeedService>);
|
|
188
|
+
|
|
189
|
+
//
|
|
190
|
+
// Context (per-call) service
|
|
191
|
+
//
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Effect service exposing a single `Feed.Feed` as the "current" feed for a call site.
|
|
195
|
+
*
|
|
196
|
+
* @deprecated Prefer threading a `Feed.Feed` explicitly through function signatures
|
|
197
|
+
* over hiding it behind a context service.
|
|
198
|
+
*/
|
|
199
|
+
export class ContextFeedService extends Context.Tag('@dxos/echo/Feed/ContextFeedService')<
|
|
200
|
+
ContextFeedService,
|
|
201
|
+
{
|
|
202
|
+
readonly feed: Feed;
|
|
203
|
+
}
|
|
204
|
+
>() {
|
|
205
|
+
static layer = (feed: Feed): Layer.Layer<ContextFeedService> => Layer.succeed(ContextFeedService, { feed });
|
|
206
|
+
}
|
|
147
207
|
|
|
148
208
|
//
|
|
149
209
|
// Operations
|
|
@@ -157,9 +217,9 @@ export const notAvailable: Layer.Layer<Service> = Layer.succeed(Service, {
|
|
|
157
217
|
* yield* Feed.append(feed, [Obj.make(Notification, { title: 'Hello' })]);
|
|
158
218
|
* ```
|
|
159
219
|
*/
|
|
160
|
-
export const append = (feed: Feed, items: Entity.Unknown[]): Effect.Effect<void, never,
|
|
220
|
+
export const append = (feed: Feed, items: Entity.Unknown[]): Effect.Effect<void, never, FeedService> =>
|
|
161
221
|
Effect.gen(function* () {
|
|
162
|
-
const service = yield*
|
|
222
|
+
const service = yield* FeedService;
|
|
163
223
|
yield* Effect.promise(() => service.append(feed, items));
|
|
164
224
|
});
|
|
165
225
|
|
|
@@ -172,9 +232,9 @@ export const append = (feed: Feed, items: Entity.Unknown[]): Effect.Effect<void,
|
|
|
172
232
|
* ```
|
|
173
233
|
*/
|
|
174
234
|
// TODO(dmaretskyi): Should we allow snapshots here? - what does it mean to remove a snapshot?
|
|
175
|
-
export const remove = (feed: Feed, items: (Entity.Unknown | Obj.Snapshot)[]): Effect.Effect<void, never,
|
|
235
|
+
export const remove = (feed: Feed, items: (Entity.Unknown | Obj.Snapshot)[]): Effect.Effect<void, never, FeedService> =>
|
|
176
236
|
Effect.gen(function* () {
|
|
177
|
-
const service = yield*
|
|
237
|
+
const service = yield* FeedService;
|
|
178
238
|
const ids = items.map((item) => item.id);
|
|
179
239
|
yield* Effect.promise(() => service.remove(feed, ids));
|
|
180
240
|
});
|
|
@@ -193,10 +253,16 @@ export const remove = (feed: Feed, items: (Entity.Unknown | Obj.Snapshot)[]): Ef
|
|
|
193
253
|
// const object = yield* feed.pipe(Feed.query(Filter.type(Person))).first;
|
|
194
254
|
// ... unify for Database and schema queries.
|
|
195
255
|
export const query: {
|
|
196
|
-
<Q extends Query.Any>(
|
|
197
|
-
|
|
256
|
+
<Q extends Query.Any>(
|
|
257
|
+
feed: Feed,
|
|
258
|
+
query: Q,
|
|
259
|
+
): Effect.Effect<QueryResult.QueryResult<Query.Type<Q>>, never, FeedService>;
|
|
260
|
+
<F extends Filter.Any>(
|
|
261
|
+
feed: Feed,
|
|
262
|
+
filter: F,
|
|
263
|
+
): Effect.Effect<QueryResult.QueryResult<Filter.Type<F>>, never, FeedService>;
|
|
198
264
|
} = (feed: Feed, queryOrFilter: Query.Any | Filter.Any) =>
|
|
199
|
-
|
|
265
|
+
FeedService.pipe(Effect.map((service) => service.query(feed, queryOrFilter as any) as QueryResult.QueryResult<any>));
|
|
200
266
|
|
|
201
267
|
/**
|
|
202
268
|
* Executes a feed query once and returns the results.
|
|
@@ -207,11 +273,26 @@ export const query: {
|
|
|
207
273
|
* ```
|
|
208
274
|
*/
|
|
209
275
|
export const runQuery: {
|
|
210
|
-
<Q extends Query.Any>(feed: Feed, query: Q): Effect.Effect<Query.Type<Q>[], never,
|
|
211
|
-
<F extends Filter.Any>(feed: Feed, filter: F): Effect.Effect<Filter.Type<F>[], never,
|
|
276
|
+
<Q extends Query.Any>(feed: Feed, query: Q): Effect.Effect<Query.Type<Q>[], never, FeedService>;
|
|
277
|
+
<F extends Filter.Any>(feed: Feed, filter: F): Effect.Effect<Filter.Type<F>[], never, FeedService>;
|
|
212
278
|
} = (feed: Feed, queryOrFilter: Query.Any | Filter.Any) =>
|
|
213
279
|
query(feed, queryOrFilter as any).pipe(Effect.flatMap((queryResult) => Effect.promise(() => queryResult.run())));
|
|
214
280
|
|
|
281
|
+
/**
|
|
282
|
+
* Syncs the feed with the server.
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* ```ts
|
|
286
|
+
* yield* Feed.sync(feed);
|
|
287
|
+
* yield* Feed.sync(feed, { shouldPush: false });
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
export const sync = (feed: Feed, options?: SyncOptions): Effect.Effect<void, never, FeedService> =>
|
|
291
|
+
Effect.gen(function* () {
|
|
292
|
+
const service = yield* FeedService;
|
|
293
|
+
yield* Effect.promise(() => service.sync(feed, options));
|
|
294
|
+
});
|
|
295
|
+
|
|
215
296
|
/**
|
|
216
297
|
* Creates a cursor for iterating over feed items.
|
|
217
298
|
* Currently stubbed — cursor operations are not yet implemented.
|
|
@@ -223,32 +304,32 @@ export const runQuery: {
|
|
|
223
304
|
* ```
|
|
224
305
|
*/
|
|
225
306
|
// TODO(wittjosiah): Implement cursor operations. Use Effect streams?
|
|
226
|
-
export const cursor = <T = Obj.Snapshot>(_feed: Feed): Effect.Effect<Cursor<T>, never,
|
|
307
|
+
export const cursor = <T = Obj.Snapshot>(_feed: Feed): Effect.Effect<Cursor<T>, never, FeedService> =>
|
|
227
308
|
Effect.succeed({ _tag: 'Cursor' } as Cursor<T>);
|
|
228
309
|
|
|
229
310
|
/**
|
|
230
311
|
* Returns the next item from a feed cursor.
|
|
231
312
|
* Currently stubbed — cursor operations are not yet implemented.
|
|
232
313
|
*/
|
|
233
|
-
export const next = <T = Obj.Snapshot>(_cursor: Cursor<T>): Effect.Effect<T, never,
|
|
314
|
+
export const next = <T = Obj.Snapshot>(_cursor: Cursor<T>): Effect.Effect<T, never, FeedService> =>
|
|
234
315
|
Effect.die('Feed.next is not yet implemented');
|
|
235
316
|
|
|
236
317
|
/**
|
|
237
318
|
* Returns the next item from a feed cursor as an Option.
|
|
238
319
|
* Currently stubbed — cursor operations are not yet implemented.
|
|
239
320
|
*/
|
|
240
|
-
export const nextOption = <T = Obj.Snapshot>(_cursor: Cursor<T>): Effect.Effect<Option.Option<T>, never,
|
|
321
|
+
export const nextOption = <T = Obj.Snapshot>(_cursor: Cursor<T>): Effect.Effect<Option.Option<T>, never, FeedService> =>
|
|
241
322
|
Effect.die('Feed.nextOption is not yet implemented');
|
|
242
323
|
|
|
243
324
|
/**
|
|
244
325
|
* Sets the local retention policy for a feed.
|
|
245
|
-
* Currently stubbed —
|
|
326
|
+
* Currently stubbed — feeds do not yet support retention.
|
|
246
327
|
*
|
|
247
328
|
* @example
|
|
248
329
|
* ```ts
|
|
249
330
|
* yield* Feed.setRetention(feed, { count: 1000 });
|
|
250
331
|
* ```
|
|
251
332
|
*/
|
|
252
|
-
// TODO(
|
|
253
|
-
export const setRetention = (_feed: Feed, _options: RetentionOptions): Effect.Effect<void, never,
|
|
333
|
+
// TODO(dmaretskyi): Implement when feed retention is supported.
|
|
334
|
+
export const setRetention = (_feed: Feed, _options: RetentionOptions): Effect.Effect<void, never, FeedService> =>
|
|
254
335
|
Effect.void;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import * as Filter from './Filter';
|
|
8
|
+
|
|
9
|
+
describe('Filter timestamp builders', () => {
|
|
10
|
+
test('updated({ after }) produces correct AST', () => {
|
|
11
|
+
const ts = 1700000000000;
|
|
12
|
+
const f = Filter.updated({ after: ts });
|
|
13
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'updatedAt', operator: 'gte', value: ts });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('updated({ before }) produces correct AST', () => {
|
|
17
|
+
const ts = 1700000000000;
|
|
18
|
+
const f = Filter.updated({ before: ts });
|
|
19
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'updatedAt', operator: 'lte', value: ts });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('created({ after }) produces correct AST', () => {
|
|
23
|
+
const ts = 1700000000000;
|
|
24
|
+
const f = Filter.created({ after: ts });
|
|
25
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'createdAt', operator: 'gte', value: ts });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('created({ before }) produces correct AST', () => {
|
|
29
|
+
const ts = 1700000000000;
|
|
30
|
+
const f = Filter.created({ before: ts });
|
|
31
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'createdAt', operator: 'lte', value: ts });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('updated() accepts Date objects', () => {
|
|
35
|
+
const date = new Date('2026-03-20T21:00:00Z');
|
|
36
|
+
const f = Filter.updated({ after: date });
|
|
37
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'updatedAt', operator: 'gte', value: date.getTime() });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('created() accepts Date objects', () => {
|
|
41
|
+
const date = new Date('2026-03-20T09:00:00Z');
|
|
42
|
+
const f = Filter.created({ before: date });
|
|
43
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'createdAt', operator: 'lte', value: date.getTime() });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('updated({ after, before }) produces AND of two timestamp nodes', () => {
|
|
47
|
+
const from = 1700000000000;
|
|
48
|
+
const to = 1700086400000;
|
|
49
|
+
const f = Filter.updated({ after: from, before: to });
|
|
50
|
+
expect(f.ast).toEqual({
|
|
51
|
+
type: 'and',
|
|
52
|
+
filters: [
|
|
53
|
+
{ type: 'timestamp', field: 'updatedAt', operator: 'gte', value: from },
|
|
54
|
+
{ type: 'timestamp', field: 'updatedAt', operator: 'lte', value: to },
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('updated({ after, before }) accepts Date objects', () => {
|
|
60
|
+
const from = new Date('2026-03-19T00:00:00Z');
|
|
61
|
+
const to = new Date('2026-03-20T00:00:00Z');
|
|
62
|
+
const f = Filter.updated({ after: from, before: to });
|
|
63
|
+
expect(f.ast).toEqual({
|
|
64
|
+
type: 'and',
|
|
65
|
+
filters: [
|
|
66
|
+
{ type: 'timestamp', field: 'updatedAt', operator: 'gte', value: from.getTime() },
|
|
67
|
+
{ type: 'timestamp', field: 'updatedAt', operator: 'lte', value: to.getTime() },
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('timestamp filters compose with and()', () => {
|
|
73
|
+
const typeFilter = Filter.everything();
|
|
74
|
+
const timeFilter = Filter.updated({ after: 1700000000000 });
|
|
75
|
+
const combined = Filter.and(typeFilter, timeFilter);
|
|
76
|
+
expect(combined.ast.type).toBe('and');
|
|
77
|
+
expect((combined.ast as any).filters).toHaveLength(2);
|
|
78
|
+
expect((combined.ast as any).filters[1]).toEqual({
|
|
79
|
+
type: 'timestamp',
|
|
80
|
+
field: 'updatedAt',
|
|
81
|
+
operator: 'gte',
|
|
82
|
+
value: 1700000000000,
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('timestamp filters pass the is() check', () => {
|
|
87
|
+
const f = Filter.updated({ after: Date.now() });
|
|
88
|
+
expect(Filter.is(f)).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
});
|
package/src/Filter.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
// @import-as-namespace
|
|
6
|
+
|
|
5
7
|
import * as Match from 'effect/Match';
|
|
6
8
|
import * as Schema from 'effect/Schema';
|
|
7
9
|
import * as SchemaAST from 'effect/SchemaAST';
|
|
@@ -12,11 +14,12 @@ import { assertArgument } from '@dxos/invariant';
|
|
|
12
14
|
import { DXN, ObjectId } from '@dxos/keys';
|
|
13
15
|
|
|
14
16
|
import * as internal from './internal';
|
|
17
|
+
import type * as Obj from './Obj';
|
|
15
18
|
import * as Ref from './Ref';
|
|
16
19
|
|
|
17
20
|
export interface Filter<T> {
|
|
18
21
|
// TODO(dmaretskyi): See new effect-schema approach to variance.
|
|
19
|
-
'~Filter': { value: Types.
|
|
22
|
+
'~Filter': { value: Types.Covariant<T> };
|
|
20
23
|
|
|
21
24
|
ast: QueryAST.Filter;
|
|
22
25
|
}
|
|
@@ -155,6 +158,37 @@ export const tag = (tag: string): Any => {
|
|
|
155
158
|
});
|
|
156
159
|
};
|
|
157
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Options for {@link key} filter.
|
|
163
|
+
*/
|
|
164
|
+
export type KeyFilterOptions = {
|
|
165
|
+
/**
|
|
166
|
+
* Optional semver range expression (e.g. `^1.2.3`, `~2.0.0`, `>=1.0.0 <2.0.0`).
|
|
167
|
+
* Matches the object's meta `version` field against the range.
|
|
168
|
+
* If omitted, matches any version (including objects with no version).
|
|
169
|
+
*/
|
|
170
|
+
version?: string;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Filter by registry key stored in object meta.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* Filter.key('org.example.type.foo');
|
|
179
|
+
* Filter.key('org.example.type.foo', { version: '^1.2.3' });
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export const key = (key: string, options?: KeyFilterOptions): Any => {
|
|
183
|
+
return new FilterClass({
|
|
184
|
+
type: 'object',
|
|
185
|
+
typename: null,
|
|
186
|
+
props: {},
|
|
187
|
+
metaKey: key,
|
|
188
|
+
metaVersion: options?.version,
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
158
192
|
/**
|
|
159
193
|
* Filter by properties.
|
|
160
194
|
*/
|
|
@@ -276,7 +310,7 @@ export const lte = <T>(value: T): Filter<T | undefined> => {
|
|
|
276
310
|
* Predicate for property to be in the provided array.
|
|
277
311
|
* @param values - Values to check against.
|
|
278
312
|
*/
|
|
279
|
-
const in$ = <T>(...values: T[]): Filter<T
|
|
313
|
+
const in$ = <T>(...values: T[]): Filter<T> => {
|
|
280
314
|
return new FilterClass({
|
|
281
315
|
type: 'in',
|
|
282
316
|
values,
|
|
@@ -300,7 +334,7 @@ export const contains = <T>(value: T): Filter<readonly T[] | undefined> => {
|
|
|
300
334
|
* @param from - Start of the range (inclusive).
|
|
301
335
|
* @param to - End of the range (exclusive).
|
|
302
336
|
*/
|
|
303
|
-
export const between = <T>(from: T, to: T): Filter<
|
|
337
|
+
export const between = <T>(from: T, to: T): Filter<T> => {
|
|
304
338
|
return new FilterClass({
|
|
305
339
|
type: 'range',
|
|
306
340
|
from,
|
|
@@ -308,6 +342,63 @@ export const between = <T>(from: T, to: T): Filter<unknown> => {
|
|
|
308
342
|
});
|
|
309
343
|
};
|
|
310
344
|
|
|
345
|
+
type TimeRange = { after?: Date | number; before?: Date | number };
|
|
346
|
+
|
|
347
|
+
const _toUnixMs = (date: Date | number): number => (typeof date === 'number' ? date : date.getTime());
|
|
348
|
+
|
|
349
|
+
const _timeRangeFilter = (field: 'updatedAt' | 'createdAt', range: TimeRange): Any => {
|
|
350
|
+
const filters: Any[] = [];
|
|
351
|
+
if (range.after != null) {
|
|
352
|
+
filters.push(new FilterClass({ type: 'timestamp', field, operator: 'gte', value: _toUnixMs(range.after) }));
|
|
353
|
+
}
|
|
354
|
+
if (range.before != null) {
|
|
355
|
+
filters.push(new FilterClass({ type: 'timestamp', field, operator: 'lte', value: _toUnixMs(range.before) }));
|
|
356
|
+
}
|
|
357
|
+
if (filters.length === 0) {
|
|
358
|
+
return everything();
|
|
359
|
+
}
|
|
360
|
+
return filters.length === 1 ? filters[0] : and(...filters);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Filter objects by updatedAt timestamp.
|
|
365
|
+
*/
|
|
366
|
+
export const updated = (range: TimeRange): Any => _timeRangeFilter('updatedAt', range);
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Filter objects by createdAt timestamp.
|
|
370
|
+
*/
|
|
371
|
+
export const created = (range: TimeRange): Any => _timeRangeFilter('createdAt', range);
|
|
372
|
+
|
|
373
|
+
export type ChildOfOptions = {
|
|
374
|
+
/** Whether to match transitively (grandchildren, etc.). Defaults to true. */
|
|
375
|
+
transitive?: boolean;
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Filter objects that are children of the specified parent(s).
|
|
380
|
+
* Accepts ECHO objects, Refs, or arrays of either.
|
|
381
|
+
* Refs are resolved to DXNs without loading; objects use {@link Obj.getDXN}.
|
|
382
|
+
* With transitive=true (default), also matches grandchildren and beyond.
|
|
383
|
+
*/
|
|
384
|
+
export const childOf = (
|
|
385
|
+
parents: Obj.Unknown | Ref.Unknown | readonly (Obj.Unknown | Ref.Unknown)[],
|
|
386
|
+
options?: ChildOfOptions,
|
|
387
|
+
): Any => {
|
|
388
|
+
const items = Array.isArray(parents) ? parents : [parents];
|
|
389
|
+
const dxns = items.map((item) => {
|
|
390
|
+
if (Ref.isRef(item)) {
|
|
391
|
+
return item.dxn.toString();
|
|
392
|
+
}
|
|
393
|
+
return internal.getDXN(item).toString();
|
|
394
|
+
});
|
|
395
|
+
return new FilterClass({
|
|
396
|
+
type: 'child-of',
|
|
397
|
+
parents: dxns,
|
|
398
|
+
transitive: options?.transitive ?? true,
|
|
399
|
+
});
|
|
400
|
+
};
|
|
401
|
+
|
|
311
402
|
/**
|
|
312
403
|
* Negate the filter.
|
|
313
404
|
*/
|
|
@@ -387,3 +478,8 @@ const processPredicate = (predicate: any): QueryAST.Filter => {
|
|
|
387
478
|
Match.orElse((value) => eq(value).ast),
|
|
388
479
|
);
|
|
389
480
|
};
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Returns a human-readable string representation of a Filter AST.
|
|
484
|
+
*/
|
|
485
|
+
export const pretty = (filter: Any): string => internal.prettyFilter(filter.ast);
|