@dxos/echo 0.8.4-main.67995b8 → 0.8.4-main.72ec0f3

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.
Files changed (313) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/browser/chunk-BIDAASFK.mjs +3727 -0
  3. package/dist/lib/browser/chunk-BIDAASFK.mjs.map +7 -0
  4. package/dist/lib/browser/chunk-ZDLCWGEW.mjs +410 -0
  5. package/dist/lib/browser/chunk-ZDLCWGEW.mjs.map +7 -0
  6. package/dist/lib/browser/chunk-ZFRJKT4A.mjs +585 -0
  7. package/dist/lib/browser/chunk-ZFRJKT4A.mjs.map +7 -0
  8. package/dist/lib/browser/index.mjs +17 -4
  9. package/dist/lib/browser/internal/index.mjs +336 -0
  10. package/dist/lib/browser/internal/index.mjs.map +7 -0
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/query/index.mjs +13 -0
  13. package/dist/lib/browser/query/index.mjs.map +7 -0
  14. package/dist/lib/browser/testing/index.mjs +231 -34
  15. package/dist/lib/browser/testing/index.mjs.map +4 -4
  16. package/dist/lib/node-esm/chunk-3SVRRCUU.mjs +3727 -0
  17. package/dist/lib/node-esm/chunk-3SVRRCUU.mjs.map +7 -0
  18. package/dist/lib/node-esm/chunk-CGDHRZWH.mjs +585 -0
  19. package/dist/lib/node-esm/chunk-CGDHRZWH.mjs.map +7 -0
  20. package/dist/lib/node-esm/chunk-HWS6VBQC.mjs +410 -0
  21. package/dist/lib/node-esm/chunk-HWS6VBQC.mjs.map +7 -0
  22. package/dist/lib/node-esm/index.mjs +17 -4
  23. package/dist/lib/node-esm/internal/index.mjs +336 -0
  24. package/dist/lib/node-esm/internal/index.mjs.map +7 -0
  25. package/dist/lib/node-esm/meta.json +1 -1
  26. package/dist/lib/node-esm/query/index.mjs +13 -0
  27. package/dist/lib/node-esm/query/index.mjs.map +7 -0
  28. package/dist/lib/node-esm/testing/index.mjs +231 -34
  29. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  30. package/dist/types/src/Obj.d.ts +127 -19
  31. package/dist/types/src/Obj.d.ts.map +1 -1
  32. package/dist/types/src/Ref.d.ts +1 -1
  33. package/dist/types/src/Ref.d.ts.map +1 -1
  34. package/dist/types/src/Relation.d.ts +11 -8
  35. package/dist/types/src/Relation.d.ts.map +1 -1
  36. package/dist/types/src/Tag.d.ts +17 -0
  37. package/dist/types/src/Tag.d.ts.map +1 -0
  38. package/dist/types/src/Type.d.ts +17 -18
  39. package/dist/types/src/Type.d.ts.map +1 -1
  40. package/dist/types/src/errors.d.ts +68 -0
  41. package/dist/types/src/errors.d.ts.map +1 -0
  42. package/dist/types/src/index.d.ts +4 -1
  43. package/dist/types/src/index.d.ts.map +1 -1
  44. package/dist/types/src/internal/ast/annotation-helper.d.ts +8 -0
  45. package/dist/types/src/internal/ast/annotation-helper.d.ts.map +1 -0
  46. package/dist/types/src/internal/ast/annotations.d.ts +131 -0
  47. package/dist/types/src/internal/ast/annotations.d.ts.map +1 -0
  48. package/dist/types/src/internal/ast/annotations.test.d.ts +2 -0
  49. package/dist/types/src/internal/ast/annotations.test.d.ts.map +1 -0
  50. package/dist/types/src/internal/ast/entity-kind.d.ts +10 -0
  51. package/dist/types/src/internal/ast/entity-kind.d.ts.map +1 -0
  52. package/dist/types/src/internal/ast/index.d.ts +5 -0
  53. package/dist/types/src/internal/ast/index.d.ts.map +1 -0
  54. package/dist/types/src/internal/ast/types.d.ts +6 -0
  55. package/dist/types/src/internal/ast/types.d.ts.map +1 -0
  56. package/dist/types/src/internal/formats/date.d.ts +63 -0
  57. package/dist/types/src/internal/formats/date.d.ts.map +1 -0
  58. package/dist/types/src/internal/formats/date.test.d.ts +2 -0
  59. package/dist/types/src/internal/formats/date.test.d.ts.map +1 -0
  60. package/dist/types/src/internal/formats/format.d.ts +30 -0
  61. package/dist/types/src/internal/formats/format.d.ts.map +1 -0
  62. package/dist/types/src/internal/formats/format.test.d.ts +2 -0
  63. package/dist/types/src/internal/formats/format.test.d.ts.map +1 -0
  64. package/dist/types/src/internal/formats/index.d.ts +8 -0
  65. package/dist/types/src/internal/formats/index.d.ts.map +1 -0
  66. package/dist/types/src/internal/formats/number.d.ts +31 -0
  67. package/dist/types/src/internal/formats/number.d.ts.map +1 -0
  68. package/dist/types/src/internal/formats/object.d.ts +35 -0
  69. package/dist/types/src/internal/formats/object.d.ts.map +1 -0
  70. package/dist/types/src/internal/formats/select.d.ts +11 -0
  71. package/dist/types/src/internal/formats/select.d.ts.map +1 -0
  72. package/dist/types/src/internal/formats/string.d.ts +38 -0
  73. package/dist/types/src/internal/formats/string.d.ts.map +1 -0
  74. package/dist/types/src/internal/formats/types.d.ts +68 -0
  75. package/dist/types/src/internal/formats/types.d.ts.map +1 -0
  76. package/dist/types/src/internal/index.d.ts +15 -0
  77. package/dist/types/src/internal/index.d.ts.map +1 -0
  78. package/dist/types/src/internal/json/annotations.d.ts +19 -0
  79. package/dist/types/src/internal/json/annotations.d.ts.map +1 -0
  80. package/dist/types/src/internal/json/effect-schema.test.d.ts +2 -0
  81. package/dist/types/src/internal/json/effect-schema.test.d.ts.map +1 -0
  82. package/dist/types/src/internal/json/index.d.ts +2 -0
  83. package/dist/types/src/internal/json/index.d.ts.map +1 -0
  84. package/dist/types/src/internal/json/json-schema.d.ts +28 -0
  85. package/dist/types/src/internal/json/json-schema.d.ts.map +1 -0
  86. package/dist/types/src/internal/json/json-schema.test.d.ts +2 -0
  87. package/dist/types/src/internal/json/json-schema.test.d.ts.map +1 -0
  88. package/dist/types/src/internal/json-schema/index.d.ts +3 -0
  89. package/dist/types/src/internal/json-schema/index.d.ts.map +1 -0
  90. package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts +7 -0
  91. package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts.map +1 -0
  92. package/dist/types/src/internal/json-schema/json-schema-type.d.ts +250 -0
  93. package/dist/types/src/internal/json-schema/json-schema-type.d.ts.map +1 -0
  94. package/dist/types/src/internal/object/accessors.d.ts +37 -0
  95. package/dist/types/src/internal/object/accessors.d.ts.map +1 -0
  96. package/dist/types/src/internal/object/common.d.ts +18 -0
  97. package/dist/types/src/internal/object/common.d.ts.map +1 -0
  98. package/dist/types/src/internal/object/create.d.ts +40 -0
  99. package/dist/types/src/internal/object/create.d.ts.map +1 -0
  100. package/dist/types/src/internal/object/create.test.d.ts +2 -0
  101. package/dist/types/src/internal/object/create.test.d.ts.map +1 -0
  102. package/dist/types/src/internal/object/deleted.d.ts +6 -0
  103. package/dist/types/src/internal/object/deleted.d.ts.map +1 -0
  104. package/dist/types/src/internal/object/entity.d.ts +33 -0
  105. package/dist/types/src/internal/object/entity.d.ts.map +1 -0
  106. package/dist/types/src/internal/object/expando.d.ts +14 -0
  107. package/dist/types/src/internal/object/expando.d.ts.map +1 -0
  108. package/dist/types/src/internal/object/ids.d.ts +6 -0
  109. package/dist/types/src/internal/object/ids.d.ts.map +1 -0
  110. package/dist/types/src/internal/object/index.d.ts +16 -0
  111. package/dist/types/src/internal/object/index.d.ts.map +1 -0
  112. package/dist/types/src/internal/object/inspect.d.ts +2 -0
  113. package/dist/types/src/internal/object/inspect.d.ts.map +1 -0
  114. package/dist/types/src/internal/object/json-serializer.d.ts +32 -0
  115. package/dist/types/src/internal/object/json-serializer.d.ts.map +1 -0
  116. package/dist/types/src/internal/object/json-serializer.test.d.ts +2 -0
  117. package/dist/types/src/internal/object/json-serializer.test.d.ts.map +1 -0
  118. package/dist/types/src/internal/object/meta.d.ts +31 -0
  119. package/dist/types/src/internal/object/meta.d.ts.map +1 -0
  120. package/dist/types/src/internal/object/model.d.ts +117 -0
  121. package/dist/types/src/internal/object/model.d.ts.map +1 -0
  122. package/dist/types/src/internal/object/relation.d.ts +17 -0
  123. package/dist/types/src/internal/object/relation.d.ts.map +1 -0
  124. package/dist/types/src/internal/object/schema-validator.d.ts +15 -0
  125. package/dist/types/src/internal/object/schema-validator.d.ts.map +1 -0
  126. package/dist/types/src/internal/object/schema-validator.test.d.ts +2 -0
  127. package/dist/types/src/internal/object/schema-validator.test.d.ts.map +1 -0
  128. package/dist/types/src/internal/object/typed-object.d.ts +31 -0
  129. package/dist/types/src/internal/object/typed-object.d.ts.map +1 -0
  130. package/dist/types/src/internal/object/typed-object.test.d.ts +2 -0
  131. package/dist/types/src/internal/object/typed-object.test.d.ts.map +1 -0
  132. package/dist/types/src/internal/object/typename.d.ts +15 -0
  133. package/dist/types/src/internal/object/typename.d.ts.map +1 -0
  134. package/dist/types/src/internal/object/version.d.ts +14 -0
  135. package/dist/types/src/internal/object/version.d.ts.map +1 -0
  136. package/dist/types/src/internal/projection/compose.d.ts +6 -0
  137. package/dist/types/src/internal/projection/compose.d.ts.map +1 -0
  138. package/dist/types/src/internal/projection/compose.test.d.ts +2 -0
  139. package/dist/types/src/internal/projection/compose.test.d.ts.map +1 -0
  140. package/dist/types/src/internal/projection/index.d.ts +2 -0
  141. package/dist/types/src/internal/projection/index.d.ts.map +1 -0
  142. package/dist/types/src/internal/proxy/handler.test.d.ts +2 -0
  143. package/dist/types/src/internal/proxy/handler.test.d.ts.map +1 -0
  144. package/dist/types/src/internal/proxy/reactive-object.d.ts +15 -0
  145. package/dist/types/src/internal/proxy/reactive-object.d.ts.map +1 -0
  146. package/dist/types/src/internal/proxy/schema.test.d.ts +2 -0
  147. package/dist/types/src/internal/proxy/schema.test.d.ts.map +1 -0
  148. package/dist/types/src/internal/proxy/typed-handler.d.ts +44 -0
  149. package/dist/types/src/internal/proxy/typed-handler.d.ts.map +1 -0
  150. package/dist/types/src/internal/proxy/typed-handler.test.d.ts +2 -0
  151. package/dist/types/src/internal/proxy/typed-handler.test.d.ts.map +1 -0
  152. package/dist/types/src/internal/proxy/typed-object.test.d.ts +2 -0
  153. package/dist/types/src/internal/proxy/typed-object.test.d.ts.map +1 -0
  154. package/dist/types/src/internal/query/index.d.ts +2 -0
  155. package/dist/types/src/internal/query/index.d.ts.map +1 -0
  156. package/dist/types/src/internal/query/query.d.ts +17 -0
  157. package/dist/types/src/internal/query/query.d.ts.map +1 -0
  158. package/dist/types/src/internal/ref/index.d.ts +3 -0
  159. package/dist/types/src/internal/ref/index.d.ts.map +1 -0
  160. package/dist/types/src/internal/ref/ref-array.d.ts +21 -0
  161. package/dist/types/src/internal/ref/ref-array.d.ts.map +1 -0
  162. package/dist/types/src/internal/ref/ref.d.ts +206 -0
  163. package/dist/types/src/internal/ref/ref.d.ts.map +1 -0
  164. package/dist/types/src/internal/ref/ref.test.d.ts +2 -0
  165. package/dist/types/src/internal/ref/ref.test.d.ts.map +1 -0
  166. package/dist/types/src/internal/schema/echo-schema.d.ts +168 -0
  167. package/dist/types/src/internal/schema/echo-schema.d.ts.map +1 -0
  168. package/dist/types/src/internal/schema/index.d.ts +7 -0
  169. package/dist/types/src/internal/schema/index.d.ts.map +1 -0
  170. package/dist/types/src/internal/schema/manipulation.d.ts +10 -0
  171. package/dist/types/src/internal/schema/manipulation.d.ts.map +1 -0
  172. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts +18 -0
  173. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts.map +1 -0
  174. package/dist/types/src/internal/schema/snapshot.d.ts +6 -0
  175. package/dist/types/src/internal/schema/snapshot.d.ts.map +1 -0
  176. package/dist/types/src/internal/schema/stored-schema.d.ts +13 -0
  177. package/dist/types/src/internal/schema/stored-schema.d.ts.map +1 -0
  178. package/dist/types/src/internal/testing/index.d.ts +3 -0
  179. package/dist/types/src/internal/testing/index.d.ts.map +1 -0
  180. package/dist/types/src/internal/testing/types.d.ts +381 -0
  181. package/dist/types/src/internal/testing/types.d.ts.map +1 -0
  182. package/dist/types/src/internal/testing/utils.d.ts +10 -0
  183. package/dist/types/src/internal/testing/utils.d.ts.map +1 -0
  184. package/dist/types/src/internal/types/index.d.ts +3 -0
  185. package/dist/types/src/internal/types/index.d.ts.map +1 -0
  186. package/dist/types/src/internal/types/types.d.ts +79 -0
  187. package/dist/types/src/internal/types/types.d.ts.map +1 -0
  188. package/dist/types/src/internal/types/types.test.d.ts +2 -0
  189. package/dist/types/src/internal/types/types.test.d.ts.map +1 -0
  190. package/dist/types/src/internal/types/util.d.ts +5 -0
  191. package/dist/types/src/internal/types/util.d.ts.map +1 -0
  192. package/dist/types/src/query/index.d.ts +1 -1
  193. package/dist/types/src/query/index.d.ts.map +1 -1
  194. package/dist/types/src/query/{dsl.d.ts → query.d.ts} +52 -22
  195. package/dist/types/src/query/query.d.ts.map +1 -0
  196. package/dist/types/src/query/query.test.d.ts +2 -0
  197. package/dist/types/src/query/query.test.d.ts.map +1 -0
  198. package/dist/types/src/testing/echo-schema.d.ts +7 -0
  199. package/dist/types/src/testing/echo-schema.d.ts.map +1 -0
  200. package/dist/types/src/testing/index.d.ts +2 -0
  201. package/dist/types/src/testing/index.d.ts.map +1 -1
  202. package/dist/types/src/testing/types.d.ts +170 -55
  203. package/dist/types/src/testing/types.d.ts.map +1 -1
  204. package/dist/types/tsconfig.tsbuildinfo +1 -1
  205. package/package.json +40 -28
  206. package/src/Obj.ts +298 -29
  207. package/src/Ref.ts +1 -2
  208. package/src/Relation.ts +25 -13
  209. package/src/Tag.ts +39 -0
  210. package/src/Type.ts +32 -31
  211. package/src/errors.ts +18 -0
  212. package/src/index.ts +5 -1
  213. package/src/internal/ast/annotation-helper.ts +22 -0
  214. package/src/internal/ast/annotations.test.ts +98 -0
  215. package/src/internal/ast/annotations.ts +226 -0
  216. package/src/internal/ast/entity-kind.ts +15 -0
  217. package/src/internal/ast/index.ts +8 -0
  218. package/src/internal/ast/types.ts +17 -0
  219. package/src/internal/formats/date.test.ts +56 -0
  220. package/src/internal/formats/date.ts +217 -0
  221. package/src/internal/formats/format.test.ts +77 -0
  222. package/src/internal/formats/format.ts +52 -0
  223. package/src/internal/formats/index.ts +12 -0
  224. package/src/internal/formats/number.ts +89 -0
  225. package/src/internal/formats/object.ts +80 -0
  226. package/src/internal/formats/select.ts +16 -0
  227. package/src/internal/formats/string.ts +76 -0
  228. package/src/internal/formats/types.ts +175 -0
  229. package/src/internal/index.ts +22 -0
  230. package/src/internal/json/annotations.ts +50 -0
  231. package/src/internal/json/effect-schema.test.ts +143 -0
  232. package/src/internal/json/index.ts +5 -0
  233. package/src/internal/json/json-schema.test.ts +849 -0
  234. package/src/internal/json/json-schema.ts +519 -0
  235. package/src/internal/json-schema/index.ts +6 -0
  236. package/src/internal/json-schema/json-schema-normalize.ts +109 -0
  237. package/src/internal/json-schema/json-schema-type.ts +403 -0
  238. package/src/internal/object/accessors.ts +153 -0
  239. package/src/internal/object/common.ts +76 -0
  240. package/src/internal/object/create.test.ts +118 -0
  241. package/src/internal/object/create.ts +96 -0
  242. package/src/internal/object/deleted.ts +19 -0
  243. package/src/internal/object/entity.ts +248 -0
  244. package/src/internal/object/expando.ts +21 -0
  245. package/src/internal/object/ids.ts +12 -0
  246. package/src/internal/object/index.ts +19 -0
  247. package/src/internal/object/inspect.ts +48 -0
  248. package/src/internal/object/json-serializer.test.ts +99 -0
  249. package/src/internal/object/json-serializer.ts +225 -0
  250. package/src/internal/object/meta.ts +61 -0
  251. package/src/internal/object/model.ts +170 -0
  252. package/src/internal/object/relation.ts +24 -0
  253. package/src/internal/object/schema-validator.test.ts +186 -0
  254. package/src/internal/object/schema-validator.ts +241 -0
  255. package/src/internal/object/typed-object.test.ts +34 -0
  256. package/src/internal/object/typed-object.ts +88 -0
  257. package/src/internal/object/typename.ts +61 -0
  258. package/src/internal/object/version.ts +22 -0
  259. package/src/internal/projection/compose.test.ts +43 -0
  260. package/src/internal/projection/compose.ts +36 -0
  261. package/src/internal/projection/index.ts +5 -0
  262. package/src/internal/proxy/handler.test.ts +163 -0
  263. package/src/internal/proxy/reactive-object.ts +108 -0
  264. package/src/internal/proxy/schema.test.ts +136 -0
  265. package/src/internal/proxy/typed-handler.test.ts +102 -0
  266. package/src/internal/proxy/typed-handler.ts +228 -0
  267. package/src/internal/proxy/typed-object.test.ts +100 -0
  268. package/src/internal/query/index.ts +5 -0
  269. package/src/internal/query/query.ts +23 -0
  270. package/src/internal/ref/index.ts +6 -0
  271. package/src/internal/ref/ref-array.ts +39 -0
  272. package/src/internal/ref/ref.test.ts +100 -0
  273. package/src/internal/ref/ref.ts +521 -0
  274. package/src/internal/schema/echo-schema.ts +383 -0
  275. package/src/internal/schema/index.ts +10 -0
  276. package/src/internal/schema/manipulation.ts +92 -0
  277. package/src/internal/schema/runtime-schema-registry.ts +78 -0
  278. package/src/internal/schema/snapshot.ts +25 -0
  279. package/src/internal/schema/stored-schema.ts +26 -0
  280. package/src/internal/testing/index.ts +6 -0
  281. package/src/internal/testing/types.ts +144 -0
  282. package/src/internal/testing/utils.ts +54 -0
  283. package/src/internal/types/index.ts +6 -0
  284. package/src/internal/types/types.test.ts +48 -0
  285. package/src/internal/types/types.ts +176 -0
  286. package/src/internal/types/util.ts +9 -0
  287. package/src/query/index.ts +2 -1
  288. package/src/query/query.test.ts +401 -0
  289. package/src/query/{dsl.ts → query.ts} +188 -45
  290. package/src/test/api.test.ts +17 -10
  291. package/src/testing/echo-schema.ts +39 -0
  292. package/src/testing/index.ts +2 -0
  293. package/src/testing/types.ts +40 -23
  294. package/dist/lib/browser/chunk-EUA7CM23.mjs +0 -619
  295. package/dist/lib/browser/chunk-EUA7CM23.mjs.map +0 -7
  296. package/dist/lib/node-esm/chunk-IV6BWGHK.mjs +0 -619
  297. package/dist/lib/node-esm/chunk-IV6BWGHK.mjs.map +0 -7
  298. package/dist/types/src/experimental/database.d.ts +0 -8
  299. package/dist/types/src/experimental/database.d.ts.map +0 -1
  300. package/dist/types/src/experimental/index.d.ts +0 -1
  301. package/dist/types/src/experimental/index.d.ts.map +0 -1
  302. package/dist/types/src/experimental/queue.d.ts +0 -8
  303. package/dist/types/src/experimental/queue.d.ts.map +0 -1
  304. package/dist/types/src/experimental/space.d.ts +0 -8
  305. package/dist/types/src/experimental/space.d.ts.map +0 -1
  306. package/dist/types/src/query/dsl.d.ts.map +0 -1
  307. package/dist/types/src/query/dsl.test.d.ts +0 -2
  308. package/dist/types/src/query/dsl.test.d.ts.map +0 -1
  309. package/src/experimental/database.ts +0 -11
  310. package/src/experimental/index.ts +0 -7
  311. package/src/experimental/queue.ts +0 -11
  312. package/src/experimental/space.ts +0 -11
  313. package/src/query/dsl.test.ts +0 -323
@@ -2,20 +2,53 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
6
- import type { Simplify } from 'effect/Schema';
5
+ import type * as EffectArray from 'effect/Array';
6
+ import * as Match from 'effect/Match';
7
+ import * as Schema from 'effect/Schema';
8
+ import type * as Types from 'effect/Types';
7
9
 
8
10
  import { raise } from '@dxos/debug';
9
11
  import { type ForeignKey, type QueryAST } from '@dxos/echo-protocol';
10
- import { getTypeReference } from '@dxos/echo-schema';
11
12
  import { assertArgument } from '@dxos/invariant';
12
13
  import { DXN, ObjectId } from '@dxos/keys';
13
14
 
15
+ import { getTypeReference } from '../internal';
16
+ import type * as Obj from '../Obj';
14
17
  import * as Ref from '../Ref';
15
18
  import type * as Type from '../Type';
16
19
 
17
20
  // TODO(dmaretskyi): Split up into interfaces for objects and relations so they can have separate verbs.
18
21
  // TODO(dmaretskyi): Undirected relation traversals.
22
+ // TODO(wittjosiah): Make Filter & Query pipeable.
23
+
24
+ export interface Order<T> {
25
+ // TODO(dmaretskyi): See new effect-schema approach to variance.
26
+ '~Order': { value: T };
27
+
28
+ ast: QueryAST.Order;
29
+ }
30
+
31
+ class OrderClass implements Order<any> {
32
+ private static variance: Order<any>['~Order'] = {} as Order<any>['~Order'];
33
+
34
+ static is(value: unknown): value is Order<any> {
35
+ return typeof value === 'object' && value !== null && '~Order' in value;
36
+ }
37
+
38
+ constructor(public readonly ast: QueryAST.Order) {}
39
+
40
+ '~Order' = OrderClass.variance;
41
+ }
42
+
43
+ export namespace Order {
44
+ export const natural: Order<any> = new OrderClass({ kind: 'natural' });
45
+ export const property = <T>(property: keyof T & string, direction: QueryAST.OrderDirection): Order<T> =>
46
+ new OrderClass({
47
+ kind: 'property',
48
+ property,
49
+ direction,
50
+ });
51
+ }
19
52
 
20
53
  export interface Query<T> {
21
54
  // TODO(dmaretskyi): See new effect-schema approach to variance.
@@ -33,10 +66,18 @@ export interface Query<T> {
33
66
 
34
67
  /**
35
68
  * Traverse an outgoing reference.
36
- * @param key - Property path inside T that is a reference.
69
+ * @param key - Property path inside T that is a reference or optional reference.
37
70
  * @returns Query for the target of the reference.
38
71
  */
39
- reference<K extends RefPropKey<T>>(key: K): Query<T[K] extends Ref.Any ? Ref.Target<T[K]> : never>;
72
+ reference<K extends RefPropKey<T>>(
73
+ key: K,
74
+ ): Query<
75
+ T[K] extends Ref.Any
76
+ ? Ref.Target<T[K]>
77
+ : T[K] extends Ref.Any | undefined
78
+ ? Ref.Target<Exclude<T[K], undefined>>
79
+ : never
80
+ >;
40
81
 
41
82
  /**
42
83
  * Find objects referencing this object.
@@ -47,7 +88,7 @@ export interface Query<T> {
47
88
  // TODO(dmaretskyi): any way to enforce `Ref.Target<Schema.Schema.Type<S>[key]> == T`?
48
89
  // TODO(dmaretskyi): Ability to go through arrays of references.
49
90
  referencedBy<S extends Schema.Schema.All>(
50
- target: S,
91
+ target: S | string,
51
92
  key: RefPropKey<Schema.Schema.Type<S>>,
52
93
  ): Query<Schema.Schema.Type<S>>;
53
94
 
@@ -58,7 +99,7 @@ export interface Query<T> {
58
99
  * @param predicates - Predicates to filter the relation objects.
59
100
  */
60
101
  sourceOf<S extends Schema.Schema.All>(
61
- relation: S,
102
+ relation: S | string,
62
103
  predicates?: Filter.Props<Schema.Schema.Type<S>>,
63
104
  ): Query<Schema.Schema.Type<S>>;
64
105
 
@@ -69,7 +110,7 @@ export interface Query<T> {
69
110
  * @param predicates - Predicates to filter the relation objects.
70
111
  */
71
112
  targetOf<S extends Schema.Schema.All>(
72
- relation: S,
113
+ relation: S | string,
73
114
  predicates?: Filter.Props<Schema.Schema.Type<S>>,
74
115
  ): Query<Schema.Schema.Type<S>>;
75
116
 
@@ -85,6 +126,14 @@ export interface Query<T> {
85
126
  */
86
127
  target(): Query<Type.Relation.Target<T>>;
87
128
 
129
+ /**
130
+ * Order the query results.
131
+ * Orders are specified in priority order. The first order will be applied first, etc.
132
+ * @param order - Order to sort the results.
133
+ * @returns Query for the ordered results.
134
+ */
135
+ orderBy(...order: EffectArray.NonEmptyArray<Order<T>>): Query<T>;
136
+
88
137
  /**
89
138
  * Add options to a query.
90
139
  */
@@ -94,6 +143,9 @@ export interface Query<T> {
94
143
  interface QueryAPI {
95
144
  is(value: unknown): value is Query.Any;
96
145
 
146
+ /** Construct a query from an ast. */
147
+ fromAst(ast: QueryAST.Query): Query<any>;
148
+
97
149
  /**
98
150
  * Select objects based on a filter.
99
151
  * @param filter - Filter to select the objects.
@@ -110,7 +162,7 @@ interface QueryAPI {
110
162
  * Shorthand for: `Query.select(Filter.type(schema, predicates))`.
111
163
  */
112
164
  type<S extends Schema.Schema.All>(
113
- schema: S,
165
+ schema: S | string,
114
166
  predicates?: Filter.Props<Schema.Schema.Type<S>>,
115
167
  ): Query<Schema.Schema.Type<S>>;
116
168
 
@@ -144,7 +196,7 @@ export declare namespace Query {
144
196
 
145
197
  export interface Filter<T> {
146
198
  // TODO(dmaretskyi): See new effect-schema approach to variance.
147
- '~Filter': { value: T };
199
+ '~Filter': { value: Types.Contravariant<T> };
148
200
 
149
201
  ast: QueryAST.Filter;
150
202
  }
@@ -154,48 +206,56 @@ type Intersection<Types extends readonly unknown[]> = Types extends [infer First
154
206
  : unknown;
155
207
 
156
208
  interface FilterAPI {
157
- is(value: unknown): value is Filter<any>;
209
+ is(value: unknown): value is Filter.Any;
210
+
211
+ /** Construct a filter from an ast. */
212
+ fromAst(ast: QueryAST.Filter): Filter<Obj.Any>;
158
213
 
159
214
  /**
160
215
  * Filter that matches all objects.
161
216
  */
162
- everything(): Filter<any>;
217
+ // TODO(dmaretskyi): `Obj.Any` would be more type-safe, but causes annoying errors in existing code
218
+ everything(): Filter<Obj.AnyProps>;
163
219
 
164
220
  /**
165
221
  * Filter that matches no objects.
166
222
  */
223
+ // TODO(dmaretskyi): Filter<never>?
167
224
  nothing(): Filter<any>;
168
225
 
169
226
  /**
170
227
  * Filter by object IDs.
171
228
  */
172
229
  // TODO(dmaretskyi): Rename to `Filter.id`.
173
- ids(...id: ObjectId[]): Filter<any>;
230
+ ids(...id: ObjectId[]): Filter<Obj.AnyProps>;
174
231
 
175
232
  /**
176
233
  * Filter by type.
177
234
  */
178
235
  type<S extends Schema.Schema.All>(
179
- schema: S,
236
+ schema: S | string,
180
237
  props?: Filter.Props<Schema.Schema.Type<S>>,
181
238
  ): Filter<Schema.Schema.Type<S>>;
182
239
 
183
240
  /**
184
241
  * Filter by non-qualified typename.
185
242
  */
186
- typename(typename: string): Filter<any>;
243
+ typename(typename: string): Filter<Obj.AnyProps>;
187
244
 
188
245
  /**
189
246
  * Filter by fully qualified type DXN.
190
247
  */
191
- typeDXN(dxn: DXN): Filter<any>;
248
+ typeDXN(dxn: DXN): Filter<Obj.AnyProps>;
249
+
250
+ /**
251
+ * Filter by tag.
252
+ */
253
+ tag(tag: string): Filter<Obj.Any>;
192
254
 
193
255
  /**
194
256
  * Filter by properties.
195
- *
196
- * INTERNAL API: Do not use.
197
257
  */
198
- _props<T>(props: Filter.Props<T>): Filter<T>;
258
+ props<T>(props: Filter.Props<T>): Filter<T>;
199
259
 
200
260
  /**
201
261
  * Full-text or vector search.
@@ -252,12 +312,18 @@ interface FilterAPI {
252
312
  */
253
313
  in<T>(...values: T[]): Filter<T>;
254
314
 
315
+ /**
316
+ * Predicate for an array property to contain the provided value.
317
+ * @param value - Value to check against.
318
+ */
319
+ contains<T>(value: T): Filter<readonly T[] | undefined>;
320
+
255
321
  /**
256
322
  * Predicate for property to be in the provided range.
257
323
  * @param from - Start of the range (inclusive).
258
324
  * @param to - End of the range (exclusive).
259
325
  */
260
- between<T>(from: T, to: T): Filter<T>;
326
+ between<T>(from: T, to: T): Filter<unknown>;
261
327
 
262
328
  /**
263
329
  * Negate the filter.
@@ -287,11 +353,12 @@ export declare namespace Filter {
287
353
 
288
354
  type Type<F extends Any> = F extends Filter<infer T> ? T : never;
289
355
 
290
- type And<FS extends readonly Any[]> = Simplify<Intersection<{ [K in keyof FS]: Type<FS[K]> }>>;
356
+ type And<FS extends readonly Any[]> = Schema.Simplify<Intersection<{ [K in keyof FS]: Type<FS[K]> }>>;
291
357
 
292
- type Or<FS extends readonly Any[]> = Simplify<{ [K in keyof FS]: Type<FS[K]> }[number]>;
358
+ type Or<FS extends readonly Any[]> = Schema.Simplify<{ [K in keyof FS]: Type<FS[K]> }[number]>;
293
359
  }
294
360
 
361
+ // TODO(dmaretskyi): Separate object instead of statics for better devex with type errors.
295
362
  class FilterClass implements Filter<any> {
296
363
  private static variance: Filter<any>['~Filter'] = {} as Filter<any>['~Filter'];
297
364
 
@@ -299,6 +366,10 @@ class FilterClass implements Filter<any> {
299
366
  return typeof value === 'object' && value !== null && '~Filter' in value;
300
367
  }
301
368
 
369
+ static fromAst(ast: QueryAST.Filter): Filter<any> {
370
+ return new FilterClass(ast);
371
+ }
372
+
302
373
  static everything(): FilterClass {
303
374
  return new FilterClass({
304
375
  type: 'object',
@@ -329,6 +400,7 @@ class FilterClass implements Filter<any> {
329
400
  static ids(...ids: ObjectId[]): Filter<any> {
330
401
  assertArgument(
331
402
  ids.every((id) => ObjectId.isValid(id)),
403
+ 'ids',
332
404
  'ids must be valid',
333
405
  );
334
406
 
@@ -345,10 +417,10 @@ class FilterClass implements Filter<any> {
345
417
  }
346
418
 
347
419
  static type<S extends Schema.Schema.All>(
348
- schema: S,
420
+ schema: S | string,
349
421
  props?: Filter.Props<Schema.Schema.Type<S>>,
350
422
  ): Filter<Schema.Schema.Type<S>> {
351
- const dxn = getTypeReference(schema)?.toDXN() ?? raise(new TypeError('Schema has no DXN'));
423
+ const dxn = getTypeDXNFromSpecifier(schema);
352
424
  return new FilterClass({
353
425
  type: 'object',
354
426
  typename: dxn.toString(),
@@ -357,7 +429,7 @@ class FilterClass implements Filter<any> {
357
429
  }
358
430
 
359
431
  static typename(typename: string): Filter<any> {
360
- assertArgument(!typename.startsWith('dxn:'), 'Typename must no be qualified');
432
+ assertArgument(!typename.startsWith('dxn:'), 'typename', 'Typename must no be qualified');
361
433
  return new FilterClass({
362
434
  type: 'object',
363
435
  typename: DXN.fromTypename(typename).toString(),
@@ -373,10 +445,14 @@ class FilterClass implements Filter<any> {
373
445
  });
374
446
  }
375
447
 
376
- /**
377
- * @internal
378
- */
379
- static _props<T>(props: Filter.Props<T>): Filter<T> {
448
+ static tag(tag: string): Filter<any> {
449
+ return new FilterClass({
450
+ type: 'tag',
451
+ tag,
452
+ });
453
+ }
454
+
455
+ static props<T>(props: Filter.Props<T>): Filter<T> {
380
456
  return new FilterClass({
381
457
  type: 'object',
382
458
  typename: null,
@@ -392,8 +468,11 @@ class FilterClass implements Filter<any> {
392
468
  });
393
469
  }
394
470
 
395
- static foreignKeys<S extends Schema.Schema.All>(schema: S, keys: ForeignKey[]): Filter<Schema.Schema.Type<S>> {
396
- const dxn = getTypeReference(schema)?.toDXN() ?? raise(new TypeError('Schema has no DXN'));
471
+ static foreignKeys<S extends Schema.Schema.All>(
472
+ schema: S | string,
473
+ keys: ForeignKey[],
474
+ ): Filter<Schema.Schema.Type<S>> {
475
+ const dxn = getTypeDXNFromSpecifier(schema);
397
476
  return new FilterClass({
398
477
  type: 'object',
399
478
  typename: dxn.toString(),
@@ -461,7 +540,14 @@ class FilterClass implements Filter<any> {
461
540
  });
462
541
  }
463
542
 
464
- static between<T>(from: T, to: T): Filter<T> {
543
+ static contains<T>(value: T): Filter<readonly T[] | undefined> {
544
+ return new FilterClass({
545
+ type: 'contains',
546
+ value,
547
+ });
548
+ }
549
+
550
+ static between<T>(from: T, to: T): Filter<unknown> {
465
551
  return new FilterClass({
466
552
  type: 'range',
467
553
  from,
@@ -506,7 +592,11 @@ type RefPropKey<T> = keyof T & string;
506
592
  const propsFilterToAst = (predicates: Filter.Props<any>): Pick<QueryAST.FilterObject, 'id' | 'props'> => {
507
593
  let idFilter: readonly ObjectId[] | undefined;
508
594
  if ('id' in predicates) {
509
- assertArgument(typeof predicates.id === 'string' || Array.isArray(predicates.id), 'invalid id filter');
595
+ assertArgument(
596
+ typeof predicates.id === 'string' || Array.isArray(predicates.id),
597
+ 'predicates.id',
598
+ 'invalid id filter',
599
+ );
510
600
  idFilter = typeof predicates.id === 'string' ? [predicates.id] : predicates.id;
511
601
  Schema.Array(ObjectId).pipe(Schema.validateSync)(idFilter);
512
602
  }
@@ -516,11 +606,38 @@ const propsFilterToAst = (predicates: Filter.Props<any>): Pick<QueryAST.FilterOb
516
606
  props: Object.fromEntries(
517
607
  Object.entries(predicates)
518
608
  .filter(([prop, _value]) => prop !== 'id')
519
- .map(([prop, predicate]) => [prop, Filter.is(predicate) ? predicate.ast : Filter.eq(predicate).ast]),
609
+ .map(([prop, predicate]) => [prop, processPredicate(predicate)]),
520
610
  ) as Record<string, QueryAST.Filter>,
521
611
  };
522
612
  };
523
613
 
614
+ const processPredicate = (predicate: any): QueryAST.Filter => {
615
+ return Match.value(predicate).pipe(
616
+ Match.withReturnType<QueryAST.Filter>(),
617
+ Match.when(Filter.is, (predicate) => predicate.ast),
618
+ // TODO(wittjosiah): Add support for array predicates.
619
+ Match.when(Array.isArray, (_predicate) => {
620
+ throw new Error('Array predicates are not yet supported.');
621
+ }),
622
+ Match.when(
623
+ (predicate: any) => !Ref.isRef(predicate) && typeof predicate === 'object' && predicate !== null,
624
+ (predicate) => {
625
+ const nestedProps = Object.fromEntries(
626
+ Object.entries(predicate).map(([key, value]) => [key, processPredicate(value)]),
627
+ );
628
+
629
+ return {
630
+ type: 'object',
631
+ typename: null,
632
+ props: nestedProps,
633
+ };
634
+ },
635
+ ),
636
+ Match.orElse((value) => Filter.eq(value).ast),
637
+ );
638
+ };
639
+
640
+ // TODO(dmaretskyi): Separate object instead of statics for better devex with type errors.
524
641
  class QueryClass implements Query<any> {
525
642
  private static variance: Query<any>['~Query'] = {} as Query<any>['~Query'];
526
643
 
@@ -528,6 +645,10 @@ class QueryClass implements Query<any> {
528
645
  return typeof value === 'object' && value !== null && '~Query' in value;
529
646
  }
530
647
 
648
+ static fromAst(ast: QueryAST.Query): Query<any> {
649
+ return new QueryClass(ast);
650
+ }
651
+
531
652
  static select<F extends Filter.Any>(filter: F): Query<Filter.Type<F>> {
532
653
  return new QueryClass({
533
654
  type: 'select',
@@ -535,7 +656,7 @@ class QueryClass implements Query<any> {
535
656
  });
536
657
  }
537
658
 
538
- static type(schema: Schema.Schema.All, predicates?: Filter.Props<unknown>): Query<any> {
659
+ static type(schema: Schema.Schema.All | string, predicates?: Filter.Props<unknown>): Query<any> {
539
660
  return new QueryClass({
540
661
  type: 'select',
541
662
  filter: FilterClass.type(schema, predicates).ast,
@@ -566,7 +687,7 @@ class QueryClass implements Query<any> {
566
687
 
567
688
  '~Query' = QueryClass.variance;
568
689
 
569
- select(filter: Filter<any> | Filter.Props<any>): Query<any> {
690
+ select(filter: Filter.Any | Filter.Props<any>): Query.Any {
570
691
  if (Filter.is(filter)) {
571
692
  return new QueryClass({
572
693
  type: 'filter',
@@ -577,12 +698,12 @@ class QueryClass implements Query<any> {
577
698
  return new QueryClass({
578
699
  type: 'filter',
579
700
  selection: this.ast,
580
- filter: FilterClass._props(filter).ast,
701
+ filter: FilterClass.props(filter).ast,
581
702
  });
582
703
  }
583
704
  }
584
705
 
585
- reference(key: string): Query<any> {
706
+ reference(key: string): Query.Any {
586
707
  return new QueryClass({
587
708
  type: 'reference-traversal',
588
709
  anchor: this.ast,
@@ -590,8 +711,8 @@ class QueryClass implements Query<any> {
590
711
  });
591
712
  }
592
713
 
593
- referencedBy(target: Schema.Schema.All, key: string): Query<any> {
594
- const dxn = getTypeReference(target)?.toDXN() ?? raise(new TypeError('Target schema has no DXN'));
714
+ referencedBy(target: Schema.Schema.All | string, key: string): Query.Any {
715
+ const dxn = getTypeDXNFromSpecifier(target);
595
716
  return new QueryClass({
596
717
  type: 'incoming-references',
597
718
  anchor: this.ast,
@@ -600,7 +721,7 @@ class QueryClass implements Query<any> {
600
721
  });
601
722
  }
602
723
 
603
- sourceOf(relation: Schema.Schema.All, predicates?: Filter.Props<unknown> | undefined): Query<any> {
724
+ sourceOf(relation: Schema.Schema.All | string, predicates?: Filter.Props<unknown> | undefined): Query.Any {
604
725
  return new QueryClass({
605
726
  type: 'relation',
606
727
  anchor: this.ast,
@@ -609,7 +730,7 @@ class QueryClass implements Query<any> {
609
730
  });
610
731
  }
611
732
 
612
- targetOf(relation: Schema.Schema.All, predicates?: Filter.Props<unknown> | undefined): Query<any> {
733
+ targetOf(relation: Schema.Schema.All | string, predicates?: Filter.Props<unknown> | undefined): Query.Any {
613
734
  return new QueryClass({
614
735
  type: 'relation',
615
736
  anchor: this.ast,
@@ -618,7 +739,7 @@ class QueryClass implements Query<any> {
618
739
  });
619
740
  }
620
741
 
621
- source(): Query<any> {
742
+ source(): Query.Any {
622
743
  return new QueryClass({
623
744
  type: 'relation-traversal',
624
745
  anchor: this.ast,
@@ -626,7 +747,7 @@ class QueryClass implements Query<any> {
626
747
  });
627
748
  }
628
749
 
629
- target(): Query<any> {
750
+ target(): Query.Any {
630
751
  return new QueryClass({
631
752
  type: 'relation-traversal',
632
753
  anchor: this.ast,
@@ -634,7 +755,15 @@ class QueryClass implements Query<any> {
634
755
  });
635
756
  }
636
757
 
637
- options(options: QueryAST.QueryOptions): Query<any> {
758
+ orderBy(...order: Order<any>[]): Query.Any {
759
+ return new QueryClass({
760
+ type: 'order',
761
+ query: this.ast,
762
+ order: order.map((o) => o.ast),
763
+ });
764
+ }
765
+
766
+ options(options: QueryAST.QueryOptions): Query.Any {
638
767
  return new QueryClass({
639
768
  type: 'options',
640
769
  query: this.ast,
@@ -644,3 +773,17 @@ class QueryClass implements Query<any> {
644
773
  }
645
774
 
646
775
  export const Query: QueryAPI = QueryClass;
776
+
777
+ /**
778
+ * @param input schema or a typename string
779
+ * @return type DXN
780
+ */
781
+ const getTypeDXNFromSpecifier = (input: Schema.Schema.All | string): DXN => {
782
+ if (Schema.isSchema(input)) {
783
+ return getTypeReference(input)?.toDXN() ?? raise(new TypeError('Schema has no DXN'));
784
+ } else {
785
+ assertArgument(typeof input === 'string', 'input');
786
+ assertArgument(!input.startsWith('dxn:'), 'input');
787
+ return DXN.fromTypename(input);
788
+ }
789
+ };
@@ -2,13 +2,13 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
8
  import { raise } from '@dxos/debug';
9
- import { FormatEnum, FormatAnnotation } from '@dxos/echo-schema';
9
+ import { FormatAnnotation, FormatEnum } from '@dxos/echo/internal';
10
10
 
11
- import { Obj, Ref, Relation, Type, type Live } from '../index';
11
+ import { type Live, Obj, Ref, Relation, Type } from '../index';
12
12
 
13
13
  namespace Testing {
14
14
  export const Organization = Schema.Struct({
@@ -151,22 +151,29 @@ describe('Experimental API review', () => {
151
151
  expect(Relation.getTarget(worksFor)).to.eq(organization);
152
152
  });
153
153
 
154
+ test('version', ({ expect }) => {
155
+ const person = Obj.make(Testing.Person, { name: 'Test' });
156
+ const version = Obj.version(person);
157
+ expect(Obj.isVersion(version)).to.be.true;
158
+ expect(Obj.versionValid(version)).to.be.false;
159
+ });
160
+
154
161
  test.skip('type narrowing', () => {
155
- const a: Obj.Any | Relation.Any = null as any;
162
+ const any: Obj.Any | Relation.Any = null as any;
156
163
 
157
164
  {
158
- if (Obj.isObject(a)) {
159
- a;
165
+ if (Obj.isObject(any)) {
166
+ any;
160
167
  } else {
161
- a;
168
+ any;
162
169
  }
163
170
  }
164
171
 
165
172
  {
166
- if (Relation.isRelation(a)) {
167
- a;
173
+ if (Relation.isRelation(any)) {
174
+ any;
168
175
  } else {
169
- a;
176
+ any;
170
177
  }
171
178
  }
172
179
  });
@@ -0,0 +1,39 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { effect } from '@preact/signals-core';
6
+ import type * as Schema from 'effect/Schema';
7
+
8
+ import { registerSignalsRuntime } from '@dxos/echo-signals';
9
+ import { assertArgument } from '@dxos/invariant';
10
+
11
+ import { EchoSchema, StoredSchema, getSchemaTypename, live, toJsonSchema } from '../internal';
12
+
13
+ // NOTE: Registration is done here is this is the module that calls out to `effect`.
14
+ registerSignalsRuntime();
15
+
16
+ /**
17
+ * Create a reactive mutable schema that updates when the JSON schema is updated.
18
+ */
19
+ // TODO(dmaretskyi): Should be replaced by registration of typed object.
20
+ export const createEchoSchema = (schema: Schema.Schema.AnyNoContext): EchoSchema => {
21
+ const typename = getSchemaTypename(schema);
22
+ assertArgument(typename, 'typename', 'Schema does not have a typename.');
23
+
24
+ const echoSchema = new EchoSchema(
25
+ live(StoredSchema, {
26
+ typename,
27
+ version: '0.1.0',
28
+ jsonSchema: toJsonSchema(schema),
29
+ }),
30
+ );
31
+
32
+ // TODO(burdon): Unsubscribe is never called.
33
+ effect(() => {
34
+ const _ = echoSchema.jsonSchema;
35
+ echoSchema._invalidate();
36
+ });
37
+
38
+ return echoSchema;
39
+ };
@@ -2,4 +2,6 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ export { prepareAstForCompare, Testing as TestingDeprecated, updateCounter } from '../internal/testing';
5
6
  export * from './types';
7
+ export * from './echo-schema';