@dxos/echo-pipeline 0.8.4-main.ae835ea → 0.8.4-main.bc2380dfbc

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 (221) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/{browser/chunk-WJJXJTNS.mjs → neutral/chunk-46DCRDA7.mjs} +44 -13
  4. package/dist/lib/neutral/chunk-46DCRDA7.mjs.map +7 -0
  5. package/dist/lib/{browser/chunk-FR6GJ4S4.mjs → neutral/chunk-LR7UFVQX.mjs} +145 -618
  6. package/dist/lib/neutral/chunk-LR7UFVQX.mjs.map +7 -0
  7. package/dist/lib/{browser → neutral}/filter/index.mjs +1 -2
  8. package/dist/lib/neutral/index.mjs +7332 -0
  9. package/dist/lib/neutral/index.mjs.map +7 -0
  10. package/dist/lib/neutral/meta.json +1 -0
  11. package/dist/lib/{browser → neutral}/testing/index.mjs +49 -292
  12. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  13. package/dist/types/src/automerge/automerge-host-subduction.test.d.ts +2 -0
  14. package/dist/types/src/automerge/automerge-host-subduction.test.d.ts.map +1 -0
  15. package/dist/types/src/automerge/automerge-host.d.ts +105 -27
  16. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  17. package/dist/types/src/automerge/automerge-repo-subduction.test.d.ts +2 -0
  18. package/dist/types/src/automerge/automerge-repo-subduction.test.d.ts.map +1 -0
  19. package/dist/types/src/automerge/automerge-repo.test.d.ts +1 -1
  20. package/dist/types/src/automerge/automerge-repo.test.d.ts.map +1 -1
  21. package/dist/types/src/automerge/automerge-subduction.test.d.ts +2 -0
  22. package/dist/types/src/automerge/automerge-subduction.test.d.ts.map +1 -0
  23. package/dist/types/src/automerge/collection-synchronizer.d.ts +22 -2
  24. package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
  25. package/dist/types/src/automerge/echo-data-monitor.d.ts.map +1 -1
  26. package/dist/types/src/automerge/echo-network-adapter.d.ts +17 -11
  27. package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
  28. package/dist/types/src/automerge/echo-replicator.d.ts +28 -16
  29. package/dist/types/src/automerge/echo-replicator.d.ts.map +1 -1
  30. package/dist/types/src/automerge/errors.d.ts +35 -0
  31. package/dist/types/src/automerge/errors.d.ts.map +1 -0
  32. package/dist/types/src/automerge/handle-state.d.ts +52 -0
  33. package/dist/types/src/automerge/handle-state.d.ts.map +1 -0
  34. package/dist/types/src/automerge/heads-store.d.ts +9 -2
  35. package/dist/types/src/automerge/heads-store.d.ts.map +1 -1
  36. package/dist/types/src/automerge/index.d.ts +2 -0
  37. package/dist/types/src/automerge/index.d.ts.map +1 -1
  38. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +10 -4
  39. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -1
  40. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts +8 -8
  41. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
  42. package/dist/types/src/automerge/mesh-echo-replicator.d.ts +6 -5
  43. package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
  44. package/dist/types/src/automerge/network-protocol.d.ts.map +1 -1
  45. package/dist/types/src/automerge/space-collection.d.ts.map +1 -1
  46. package/dist/types/src/common/feeds.d.ts.map +1 -1
  47. package/dist/types/src/common/space-id.d.ts.map +1 -1
  48. package/dist/types/src/db-host/automerge-data-source.d.ts +35 -0
  49. package/dist/types/src/db-host/automerge-data-source.d.ts.map +1 -0
  50. package/dist/types/src/db-host/automerge-data-source.test.d.ts +2 -0
  51. package/dist/types/src/db-host/automerge-data-source.test.d.ts.map +1 -0
  52. package/dist/types/src/db-host/automerge-metrics.d.ts.map +1 -1
  53. package/dist/types/src/db-host/data-service.d.ts +12 -6
  54. package/dist/types/src/db-host/data-service.d.ts.map +1 -1
  55. package/dist/types/src/db-host/database-root.d.ts +9 -3
  56. package/dist/types/src/db-host/database-root.d.ts.map +1 -1
  57. package/dist/types/src/db-host/documents-synchronizer.d.ts +30 -8
  58. package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
  59. package/dist/types/src/db-host/echo-host.d.ts +74 -28
  60. package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
  61. package/dist/types/src/db-host/index.d.ts +2 -0
  62. package/dist/types/src/db-host/index.d.ts.map +1 -1
  63. package/dist/types/src/db-host/invalidation-hint.d.ts +19 -0
  64. package/dist/types/src/db-host/invalidation-hint.d.ts.map +1 -0
  65. package/dist/types/src/db-host/local-queue-service.d.ts +19 -0
  66. package/dist/types/src/db-host/local-queue-service.d.ts.map +1 -0
  67. package/dist/types/src/db-host/query-invalidation.test.d.ts +2 -0
  68. package/dist/types/src/db-host/query-invalidation.test.d.ts.map +1 -0
  69. package/dist/types/src/db-host/query-service.d.ts +18 -10
  70. package/dist/types/src/db-host/query-service.d.ts.map +1 -1
  71. package/dist/types/src/db-host/queue-data-source.d.ts +38 -0
  72. package/dist/types/src/db-host/queue-data-source.d.ts.map +1 -0
  73. package/dist/types/src/db-host/queue-service.test.d.ts +2 -0
  74. package/dist/types/src/db-host/queue-service.test.d.ts.map +1 -0
  75. package/dist/types/src/db-host/space-state-manager.d.ts +3 -2
  76. package/dist/types/src/db-host/space-state-manager.d.ts.map +1 -1
  77. package/dist/types/src/db-host/stub.d.ts +11 -0
  78. package/dist/types/src/db-host/stub.d.ts.map +1 -0
  79. package/dist/types/src/edge/echo-edge-replicator.d.ts +7 -6
  80. package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
  81. package/dist/types/src/edge/echo-edge-subduction-replicator.d.ts +39 -0
  82. package/dist/types/src/edge/echo-edge-subduction-replicator.d.ts.map +1 -0
  83. package/dist/types/src/edge/echo-edge-subduction-replicator.test.d.ts +2 -0
  84. package/dist/types/src/edge/echo-edge-subduction-replicator.test.d.ts.map +1 -0
  85. package/dist/types/src/edge/index.d.ts +1 -0
  86. package/dist/types/src/edge/index.d.ts.map +1 -1
  87. package/dist/types/src/edge/inflight-request-limiter.d.ts.map +1 -1
  88. package/dist/types/src/filter/filter-match.d.ts +1 -1
  89. package/dist/types/src/filter/filter-match.d.ts.map +1 -1
  90. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  91. package/dist/types/src/pipeline/message-selector.d.ts.map +1 -1
  92. package/dist/types/src/pipeline/pipeline.d.ts +2 -2
  93. package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
  94. package/dist/types/src/pipeline/timeframe-clock.d.ts.map +1 -1
  95. package/dist/types/src/query/errors.d.ts +16 -20
  96. package/dist/types/src/query/errors.d.ts.map +1 -1
  97. package/dist/types/src/query/plan.d.ts +59 -8
  98. package/dist/types/src/query/plan.d.ts.map +1 -1
  99. package/dist/types/src/query/query-executor.d.ts +55 -12
  100. package/dist/types/src/query/query-executor.d.ts.map +1 -1
  101. package/dist/types/src/query/query-planner.d.ts +10 -1
  102. package/dist/types/src/query/query-planner.d.ts.map +1 -1
  103. package/dist/types/src/space/admission-discovery-extension.d.ts.map +1 -1
  104. package/dist/types/src/space/auth.d.ts +3 -3
  105. package/dist/types/src/space/auth.d.ts.map +1 -1
  106. package/dist/types/src/space/control-pipeline.d.ts +4 -3
  107. package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
  108. package/dist/types/src/space/space-manager.d.ts +7 -7
  109. package/dist/types/src/space/space-manager.d.ts.map +1 -1
  110. package/dist/types/src/space/space-protocol.d.ts +9 -8
  111. package/dist/types/src/space/space-protocol.d.ts.map +1 -1
  112. package/dist/types/src/space/space.d.ts +5 -5
  113. package/dist/types/src/space/space.d.ts.map +1 -1
  114. package/dist/types/src/testing/change-metadata.d.ts.map +1 -1
  115. package/dist/types/src/testing/index.d.ts +0 -2
  116. package/dist/types/src/testing/index.d.ts.map +1 -1
  117. package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
  118. package/dist/types/src/testing/test-feed-builder.d.ts.map +1 -1
  119. package/dist/types/src/testing/test-network-adapter.d.ts +1 -1
  120. package/dist/types/src/testing/test-network-adapter.d.ts.map +1 -1
  121. package/dist/types/src/testing/test-replicator.d.ts +13 -13
  122. package/dist/types/src/testing/test-replicator.d.ts.map +1 -1
  123. package/dist/types/src/util.d.ts.map +1 -1
  124. package/dist/types/tsconfig.tsbuildinfo +1 -1
  125. package/package.json +56 -54
  126. package/src/automerge/automerge-host-subduction.test.ts +263 -0
  127. package/src/automerge/automerge-host.test.ts +145 -32
  128. package/src/automerge/automerge-host.ts +442 -163
  129. package/src/automerge/automerge-repo-subduction.test.ts +1054 -0
  130. package/src/automerge/automerge-repo.test.ts +284 -77
  131. package/src/automerge/automerge-subduction.test.ts +330 -0
  132. package/src/automerge/collection-synchronizer.test.ts +96 -16
  133. package/src/automerge/collection-synchronizer.ts +125 -26
  134. package/src/automerge/echo-network-adapter.test.ts +2 -1
  135. package/src/automerge/echo-network-adapter.ts +44 -32
  136. package/src/automerge/echo-replicator.ts +30 -16
  137. package/src/automerge/errors.ts +10 -0
  138. package/src/automerge/handle-state.ts +62 -0
  139. package/src/automerge/heads-store.ts +42 -3
  140. package/src/automerge/index.ts +2 -0
  141. package/src/automerge/leveldb-storage-adapter.ts +70 -4
  142. package/src/automerge/mesh-echo-replicator-connection.ts +8 -8
  143. package/src/automerge/mesh-echo-replicator.ts +14 -11
  144. package/src/db-host/automerge-data-source.test.ts +299 -0
  145. package/src/db-host/automerge-data-source.ts +187 -0
  146. package/src/db-host/data-service.ts +27 -10
  147. package/src/db-host/database-root.ts +19 -7
  148. package/src/db-host/documents-synchronizer.test.ts +145 -14
  149. package/src/db-host/documents-synchronizer.ts +158 -59
  150. package/src/db-host/echo-host.ts +376 -90
  151. package/src/db-host/index.ts +2 -0
  152. package/src/db-host/invalidation-hint.ts +50 -0
  153. package/src/db-host/local-queue-service.ts +127 -0
  154. package/src/db-host/query-invalidation.test.ts +270 -0
  155. package/src/db-host/query-service.ts +108 -111
  156. package/src/db-host/queue-data-source.ts +160 -0
  157. package/src/db-host/queue-service.test.ts +145 -0
  158. package/src/db-host/space-state-manager.ts +11 -9
  159. package/src/db-host/stub.ts +33 -0
  160. package/src/edge/echo-edge-replicator.test.ts +9 -9
  161. package/src/edge/echo-edge-replicator.ts +50 -42
  162. package/src/edge/echo-edge-subduction-replicator.test.ts +158 -0
  163. package/src/edge/echo-edge-subduction-replicator.ts +377 -0
  164. package/src/edge/index.ts +1 -0
  165. package/src/filter/filter-match.test.ts +41 -25
  166. package/src/filter/filter-match.ts +75 -20
  167. package/src/metadata/metadata-store.ts +8 -5
  168. package/src/pipeline/pipeline-stress.test.ts +1 -3
  169. package/src/pipeline/pipeline.test.ts +0 -1
  170. package/src/pipeline/pipeline.ts +2 -3
  171. package/src/query/errors.ts +2 -2
  172. package/src/query/plan.ts +73 -9
  173. package/src/query/query-executor.ts +1064 -172
  174. package/src/query/query-planner.test.ts +854 -86
  175. package/src/query/query-planner.ts +444 -38
  176. package/src/space/admission-discovery-extension.ts +1 -1
  177. package/src/space/auth.ts +6 -6
  178. package/src/space/control-pipeline.test.ts +2 -2
  179. package/src/space/control-pipeline.ts +7 -7
  180. package/src/space/space-manager.ts +12 -17
  181. package/src/space/space-protocol.browser.test.ts +13 -12
  182. package/src/space/space-protocol.test.ts +13 -13
  183. package/src/space/space-protocol.ts +16 -15
  184. package/src/space/space.test.ts +2 -2
  185. package/src/space/space.ts +9 -10
  186. package/src/testing/index.ts +0 -2
  187. package/src/testing/test-agent-builder.ts +0 -1
  188. package/src/testing/test-network-adapter.ts +24 -3
  189. package/src/testing/test-replicator.ts +15 -20
  190. package/src/util.ts +7 -3
  191. package/dist/lib/browser/chunk-CGS2ULMK.mjs +0 -11
  192. package/dist/lib/browser/chunk-CGS2ULMK.mjs.map +0 -7
  193. package/dist/lib/browser/chunk-FR6GJ4S4.mjs.map +0 -7
  194. package/dist/lib/browser/chunk-WJJXJTNS.mjs.map +0 -7
  195. package/dist/lib/browser/index.mjs +0 -5492
  196. package/dist/lib/browser/index.mjs.map +0 -7
  197. package/dist/lib/browser/meta.json +0 -1
  198. package/dist/lib/browser/testing/index.mjs.map +0 -7
  199. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  200. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
  201. package/dist/lib/node-esm/chunk-JQCCVDLT.mjs +0 -2144
  202. package/dist/lib/node-esm/chunk-JQCCVDLT.mjs.map +0 -7
  203. package/dist/lib/node-esm/chunk-LEQ77KAT.mjs +0 -240
  204. package/dist/lib/node-esm/chunk-LEQ77KAT.mjs.map +0 -7
  205. package/dist/lib/node-esm/filter/index.mjs +0 -13
  206. package/dist/lib/node-esm/filter/index.mjs.map +0 -7
  207. package/dist/lib/node-esm/index.mjs +0 -5492
  208. package/dist/lib/node-esm/index.mjs.map +0 -7
  209. package/dist/lib/node-esm/meta.json +0 -1
  210. package/dist/lib/node-esm/testing/index.mjs +0 -764
  211. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  212. package/dist/types/src/db-host/documents-iterator.d.ts +0 -7
  213. package/dist/types/src/db-host/documents-iterator.d.ts.map +0 -1
  214. package/dist/types/src/testing/test-data.d.ts +0 -18
  215. package/dist/types/src/testing/test-data.d.ts.map +0 -1
  216. package/dist/types/src/testing/test-schema.d.ts +0 -37
  217. package/dist/types/src/testing/test-schema.d.ts.map +0 -1
  218. package/src/db-host/documents-iterator.ts +0 -74
  219. package/src/testing/test-data.ts +0 -127
  220. package/src/testing/test-schema.ts +0 -53
  221. /package/dist/lib/{browser → neutral}/filter/index.mjs.map +0 -0
@@ -1,3 +1,7 @@
1
+ //
2
+ // Copyright 2025 example.com
3
+ //
4
+
1
5
  //
2
6
  // Copyright 2025 DXOS.org
3
7
  //
@@ -6,9 +10,8 @@ import { describe, expect, test } from 'vitest';
6
10
 
7
11
  import { Filter, Order, Query } from '@dxos/echo';
8
12
  import { type QueryAST } from '@dxos/echo-protocol';
9
- import { SpaceId } from '@dxos/keys';
10
-
11
- import { TestSchema } from '../testing';
13
+ import { TestSchema } from '@dxos/echo/testing';
14
+ import { DXN, SpaceId } from '@dxos/keys';
12
15
 
13
16
  import { QueryPlanner } from './query-planner';
14
17
 
@@ -24,21 +27,32 @@ describe('QueryPlanner', () => {
24
27
  "steps": [
25
28
  {
26
29
  "_tag": "SelectStep",
30
+ "scope": {
31
+ "spaceIds": [
32
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
33
+ ],
34
+ },
27
35
  "selector": {
28
36
  "_tag": "TypeSelector",
29
37
  "inverted": false,
30
38
  "typename": [
31
- "dxn:type:dxos.org/type/Person:0.1.0",
39
+ "dxn:type:com.example.type.person:0.1.0",
32
40
  ],
33
41
  },
34
- "spaces": [
35
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
36
- ],
37
42
  },
38
43
  {
39
44
  "_tag": "FilterDeletedStep",
40
45
  "mode": "only-non-deleted",
41
46
  },
47
+ {
48
+ "_tag": "FilterStep",
49
+ "filter": {
50
+ "id": undefined,
51
+ "props": {},
52
+ "type": "object",
53
+ "typename": "dxn:type:com.example.type.person:0.1.0",
54
+ },
55
+ },
42
56
  {
43
57
  "_tag": "OrderStep",
44
58
  "order": [
@@ -61,21 +75,32 @@ describe('QueryPlanner', () => {
61
75
  "steps": [
62
76
  {
63
77
  "_tag": "SelectStep",
78
+ "scope": {
79
+ "spaceIds": [
80
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
81
+ ],
82
+ },
64
83
  "selector": {
65
84
  "_tag": "TypeSelector",
66
85
  "inverted": false,
67
86
  "typename": [
68
- "dxn:type:dxos.org/type/Person:0.1.0",
87
+ "dxn:type:com.example.type.person:0.1.0",
69
88
  ],
70
89
  },
71
- "spaces": [
72
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
73
- ],
74
90
  },
75
91
  {
76
92
  "_tag": "FilterDeletedStep",
77
93
  "mode": "only-non-deleted",
78
94
  },
95
+ {
96
+ "_tag": "FilterStep",
97
+ "filter": {
98
+ "id": undefined,
99
+ "props": {},
100
+ "type": "object",
101
+ "typename": "dxn:type:com.example.type.person:0.1.0",
102
+ },
103
+ },
79
104
  {
80
105
  "_tag": "OrderStep",
81
106
  "order": [
@@ -100,16 +125,18 @@ describe('QueryPlanner', () => {
100
125
  "steps": [
101
126
  {
102
127
  "_tag": "SelectStep",
128
+ "scope": {
129
+ "spaceIds": [
130
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
131
+ ],
132
+ },
103
133
  "selector": {
104
134
  "_tag": "TypeSelector",
105
135
  "inverted": false,
106
136
  "typename": [
107
- "dxn:type:dxos.org/type/Person:0.1.0",
137
+ "dxn:type:com.example.type.person:0.1.0",
108
138
  ],
109
139
  },
110
- "spaces": [
111
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
112
- ],
113
140
  },
114
141
  {
115
142
  "_tag": "FilterDeletedStep",
@@ -127,7 +154,7 @@ describe('QueryPlanner', () => {
127
154
  },
128
155
  },
129
156
  "type": "object",
130
- "typename": null,
157
+ "typename": "dxn:type:com.example.type.person:0.1.0",
131
158
  },
132
159
  },
133
160
  {
@@ -145,7 +172,9 @@ describe('QueryPlanner', () => {
145
172
 
146
173
  test('get all orgs Fred worked for since 2020', () => {
147
174
  const query = Query.select(Filter.type(TestSchema.Person, { id: '01JVS9YYT5VMVJW0GGTM1YHCCH' }))
148
- .sourceOf(TestSchema.WorksFor, { since: Filter.gt('2020') })
175
+ .sourceOf(TestSchema.EmployedBy, {
176
+ since: Filter.gt<string | undefined>('2020'),
177
+ })
149
178
  .target();
150
179
 
151
180
  const plan = planner.createPlan(withSpaceIdOptions(query.ast));
@@ -154,15 +183,17 @@ describe('QueryPlanner', () => {
154
183
  "steps": [
155
184
  {
156
185
  "_tag": "SelectStep",
186
+ "scope": {
187
+ "spaceIds": [
188
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
189
+ ],
190
+ },
157
191
  "selector": {
158
192
  "_tag": "IdSelector",
159
193
  "objectIds": [
160
194
  "01JVS9YYT5VMVJW0GGTM1YHCCH",
161
195
  ],
162
196
  },
163
- "spaces": [
164
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
165
- ],
166
197
  },
167
198
  {
168
199
  "_tag": "FilterDeletedStep",
@@ -174,7 +205,7 @@ describe('QueryPlanner', () => {
174
205
  "id": undefined,
175
206
  "props": {},
176
207
  "type": "object",
177
- "typename": "dxn:type:dxos.org/type/Person:0.1.0",
208
+ "typename": "dxn:type:com.example.type.person:0.1.0",
178
209
  },
179
210
  },
180
211
  {
@@ -200,7 +231,7 @@ describe('QueryPlanner', () => {
200
231
  },
201
232
  },
202
233
  "type": "object",
203
- "typename": "dxn:type:dxos.org/type/WorksFor:0.1.0",
234
+ "typename": "dxn:type:com.example.type.employed-by:0.1.0",
204
235
  },
205
236
  },
206
237
  {
@@ -239,15 +270,17 @@ describe('QueryPlanner', () => {
239
270
  "steps": [
240
271
  {
241
272
  "_tag": "SelectStep",
273
+ "scope": {
274
+ "spaceIds": [
275
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
276
+ ],
277
+ },
242
278
  "selector": {
243
279
  "_tag": "IdSelector",
244
280
  "objectIds": [
245
281
  "01JVS9YYT7H6A6DXRN56RSHT6Z",
246
282
  ],
247
283
  },
248
- "spaces": [
249
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
250
- ],
251
284
  },
252
285
  {
253
286
  "_tag": "FilterDeletedStep",
@@ -259,7 +292,7 @@ describe('QueryPlanner', () => {
259
292
  "id": undefined,
260
293
  "props": {},
261
294
  "type": "object",
262
- "typename": "dxn:type:dxos.org/type/Person:0.1.0",
295
+ "typename": "dxn:type:com.example.type.person:0.1.0",
263
296
  },
264
297
  },
265
298
  {
@@ -279,7 +312,7 @@ describe('QueryPlanner', () => {
279
312
  "filter": {
280
313
  "props": {},
281
314
  "type": "object",
282
- "typename": "dxn:type:dxos.org/type/Task:0.1.0",
315
+ "typename": "dxn:type:com.example.type.task:0.1.0",
283
316
  },
284
317
  },
285
318
  {
@@ -297,7 +330,7 @@ describe('QueryPlanner', () => {
297
330
 
298
331
  test('get all tasks for employees of Cyberdyne', () => {
299
332
  const query = Query.select(Filter.type(TestSchema.Organization, { name: 'Cyberdyne' }))
300
- .targetOf(TestSchema.WorksFor)
333
+ .targetOf(TestSchema.EmployedBy)
301
334
  .source()
302
335
  .referencedBy(TestSchema.Task, 'assignee');
303
336
 
@@ -307,16 +340,18 @@ describe('QueryPlanner', () => {
307
340
  "steps": [
308
341
  {
309
342
  "_tag": "SelectStep",
343
+ "scope": {
344
+ "spaceIds": [
345
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
346
+ ],
347
+ },
310
348
  "selector": {
311
349
  "_tag": "TypeSelector",
312
350
  "inverted": false,
313
351
  "typename": [
314
- "dxn:type:dxos.org/type/Organization:0.1.0",
352
+ "dxn:type:com.example.type.organization:0.1.0",
315
353
  ],
316
354
  },
317
- "spaces": [
318
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
319
- ],
320
355
  },
321
356
  {
322
357
  "_tag": "FilterDeletedStep",
@@ -334,7 +369,7 @@ describe('QueryPlanner', () => {
334
369
  },
335
370
  },
336
371
  "type": "object",
337
- "typename": null,
372
+ "typename": "dxn:type:com.example.type.organization:0.1.0",
338
373
  },
339
374
  },
340
375
  {
@@ -354,7 +389,7 @@ describe('QueryPlanner', () => {
354
389
  "id": undefined,
355
390
  "props": {},
356
391
  "type": "object",
357
- "typename": "dxn:type:dxos.org/type/WorksFor:0.1.0",
392
+ "typename": "dxn:type:com.example.type.employed-by:0.1.0",
358
393
  },
359
394
  },
360
395
  {
@@ -385,7 +420,7 @@ describe('QueryPlanner', () => {
385
420
  "filter": {
386
421
  "props": {},
387
422
  "type": "object",
388
- "typename": "dxn:type:dxos.org/type/Task:0.1.0",
423
+ "typename": "dxn:type:com.example.type.task:0.1.0",
389
424
  },
390
425
  },
391
426
  {
@@ -418,42 +453,80 @@ describe('QueryPlanner', () => {
418
453
  "steps": [
419
454
  {
420
455
  "_tag": "SelectStep",
456
+ "scope": {
457
+ "spaceIds": [
458
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
459
+ ],
460
+ },
421
461
  "selector": {
422
462
  "_tag": "TypeSelector",
423
463
  "inverted": false,
424
464
  "typename": [
425
- "dxn:type:dxos.org/type/Person:0.1.0",
465
+ "dxn:type:com.example.type.person:0.1.0",
426
466
  ],
427
467
  },
428
- "spaces": [
429
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
430
- ],
431
468
  },
432
469
  {
433
470
  "_tag": "FilterDeletedStep",
434
471
  "mode": "only-non-deleted",
435
472
  },
473
+ {
474
+ "_tag": "FilterStep",
475
+ "filter": {
476
+ "id": undefined,
477
+ "props": {},
478
+ "type": "object",
479
+ "typename": "dxn:type:com.example.type.person:0.1.0",
480
+ },
481
+ },
482
+ {
483
+ "_tag": "OrderStep",
484
+ "order": [
485
+ {
486
+ "kind": "natural",
487
+ },
488
+ ],
489
+ },
436
490
  ],
437
491
  },
438
492
  {
439
493
  "steps": [
440
494
  {
441
495
  "_tag": "SelectStep",
496
+ "scope": {
497
+ "spaceIds": [
498
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
499
+ ],
500
+ },
442
501
  "selector": {
443
502
  "_tag": "TypeSelector",
444
503
  "inverted": false,
445
504
  "typename": [
446
- "dxn:type:dxos.org/type/Organization:0.1.0",
505
+ "dxn:type:com.example.type.organization:0.1.0",
447
506
  ],
448
507
  },
449
- "spaces": [
450
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
451
- ],
452
508
  },
453
509
  {
454
510
  "_tag": "FilterDeletedStep",
455
511
  "mode": "only-non-deleted",
456
512
  },
513
+ {
514
+ "_tag": "FilterStep",
515
+ "filter": {
516
+ "id": undefined,
517
+ "props": {},
518
+ "type": "object",
519
+ "typename": "dxn:type:com.example.type.organization:0.1.0",
520
+ },
521
+ },
522
+ {
523
+ "_tag": "OrderStep",
524
+ "order": [
525
+ {
526
+ "kind": "natural",
527
+ },
528
+ ],
529
+ },
457
530
  ],
458
531
  },
459
532
  ],
@@ -474,7 +547,7 @@ describe('QueryPlanner', () => {
474
547
  test('get all people not in orgs', () => {
475
548
  const query = Query.without(
476
549
  Query.select(Filter.type(TestSchema.Person)),
477
- Query.select(Filter.type(TestSchema.Person)).sourceOf(TestSchema.WorksFor).source(),
550
+ Query.select(Filter.type(TestSchema.Person)).sourceOf(TestSchema.EmployedBy).source(),
478
551
  );
479
552
 
480
553
  const plan = planner.createPlan(withSpaceIdOptions(query.ast));
@@ -487,16 +560,18 @@ describe('QueryPlanner', () => {
487
560
  "steps": [
488
561
  {
489
562
  "_tag": "SelectStep",
563
+ "scope": {
564
+ "spaceIds": [
565
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
566
+ ],
567
+ },
490
568
  "selector": {
491
569
  "_tag": "TypeSelector",
492
570
  "inverted": false,
493
571
  "typename": [
494
- "dxn:type:dxos.org/type/Person:0.1.0",
572
+ "dxn:type:com.example.type.person:0.1.0",
495
573
  ],
496
574
  },
497
- "spaces": [
498
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
499
- ],
500
575
  },
501
576
  {
502
577
  "_tag": "FilterDeletedStep",
@@ -508,7 +583,7 @@ describe('QueryPlanner', () => {
508
583
  "id": undefined,
509
584
  "props": {},
510
585
  "type": "object",
511
- "typename": null,
586
+ "typename": "dxn:type:com.example.type.person:0.1.0",
512
587
  },
513
588
  },
514
589
  {
@@ -528,7 +603,7 @@ describe('QueryPlanner', () => {
528
603
  "id": undefined,
529
604
  "props": {},
530
605
  "type": "object",
531
- "typename": "dxn:type:dxos.org/type/WorksFor:0.1.0",
606
+ "typename": "dxn:type:com.example.type.employed-by:0.1.0",
532
607
  },
533
608
  },
534
609
  {
@@ -542,22 +617,32 @@ describe('QueryPlanner', () => {
542
617
  "_tag": "FilterDeletedStep",
543
618
  "mode": "only-non-deleted",
544
619
  },
620
+ {
621
+ "_tag": "OrderStep",
622
+ "order": [
623
+ {
624
+ "kind": "natural",
625
+ },
626
+ ],
627
+ },
545
628
  ],
546
629
  },
547
630
  "source": {
548
631
  "steps": [
549
632
  {
550
633
  "_tag": "SelectStep",
634
+ "scope": {
635
+ "spaceIds": [
636
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
637
+ ],
638
+ },
551
639
  "selector": {
552
640
  "_tag": "TypeSelector",
553
641
  "inverted": false,
554
642
  "typename": [
555
- "dxn:type:dxos.org/type/Person:0.1.0",
643
+ "dxn:type:com.example.type.person:0.1.0",
556
644
  ],
557
645
  },
558
- "spaces": [
559
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
560
- ],
561
646
  },
562
647
  {
563
648
  "_tag": "FilterDeletedStep",
@@ -569,9 +654,17 @@ describe('QueryPlanner', () => {
569
654
  "id": undefined,
570
655
  "props": {},
571
656
  "type": "object",
572
- "typename": null,
657
+ "typename": "dxn:type:com.example.type.person:0.1.0",
573
658
  },
574
659
  },
660
+ {
661
+ "_tag": "OrderStep",
662
+ "order": [
663
+ {
664
+ "kind": "natural",
665
+ },
666
+ ],
667
+ },
575
668
  ],
576
669
  },
577
670
  },
@@ -589,7 +682,11 @@ describe('QueryPlanner', () => {
589
682
  });
590
683
 
591
684
  test('get assignees of all tasks created after 2020', () => {
592
- const query = Query.select(Filter.type(TestSchema.Task, { createdAt: Filter.gt('2020') })).reference('assignee');
685
+ const query = Query.select(
686
+ Filter.type(TestSchema.Task, {
687
+ deadline: Filter.gt<string | undefined>('2020'),
688
+ }),
689
+ ).reference('assignee');
593
690
 
594
691
  const plan = planner.createPlan(withSpaceIdOptions(query.ast));
595
692
  expect(plan).toMatchInlineSnapshot(`
@@ -597,16 +694,18 @@ describe('QueryPlanner', () => {
597
694
  "steps": [
598
695
  {
599
696
  "_tag": "SelectStep",
697
+ "scope": {
698
+ "spaceIds": [
699
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
700
+ ],
701
+ },
600
702
  "selector": {
601
703
  "_tag": "TypeSelector",
602
704
  "inverted": false,
603
705
  "typename": [
604
- "dxn:type:dxos.org/type/Task:0.1.0",
706
+ "dxn:type:com.example.type.task:0.1.0",
605
707
  ],
606
708
  },
607
- "spaces": [
608
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
609
- ],
610
709
  },
611
710
  {
612
711
  "_tag": "FilterDeletedStep",
@@ -617,14 +716,14 @@ describe('QueryPlanner', () => {
617
716
  "filter": {
618
717
  "id": undefined,
619
718
  "props": {
620
- "createdAt": {
719
+ "deadline": {
621
720
  "operator": "gt",
622
721
  "type": "compare",
623
722
  "value": "2020",
624
723
  },
625
724
  },
626
725
  "type": "object",
627
- "typename": null,
726
+ "typename": "dxn:type:com.example.type.task:0.1.0",
628
727
  },
629
728
  },
630
729
  {
@@ -661,14 +760,17 @@ describe('QueryPlanner', () => {
661
760
  "steps": [
662
761
  {
663
762
  "_tag": "SelectStep",
763
+ "scope": {
764
+ "spaceIds": [
765
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
766
+ ],
767
+ },
664
768
  "selector": {
665
769
  "_tag": "TextSelector",
666
770
  "searchKind": "full-text",
667
771
  "text": "Bill",
772
+ "typename": null,
668
773
  },
669
- "spaces": [
670
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
671
- ],
672
774
  },
673
775
  {
674
776
  "_tag": "FilterDeletedStep",
@@ -680,7 +782,7 @@ describe('QueryPlanner', () => {
680
782
  "id": undefined,
681
783
  "props": {},
682
784
  "type": "object",
683
- "typename": "dxn:type:dxos.org/type/Person:0.1.0",
785
+ "typename": "dxn:type:com.example.type.person:0.1.0",
684
786
  },
685
787
  },
686
788
  {
@@ -705,14 +807,17 @@ describe('QueryPlanner', () => {
705
807
  "steps": [
706
808
  {
707
809
  "_tag": "SelectStep",
810
+ "scope": {
811
+ "spaceIds": [
812
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
813
+ ],
814
+ },
708
815
  "selector": {
709
816
  "_tag": "TextSelector",
710
817
  "searchKind": "vector",
711
818
  "text": "Bill",
819
+ "typename": null,
712
820
  },
713
- "spaces": [
714
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
715
- ],
716
821
  },
717
822
  {
718
823
  "_tag": "FilterDeletedStep",
@@ -740,22 +845,44 @@ describe('QueryPlanner', () => {
740
845
  "steps": [
741
846
  {
742
847
  "_tag": "SelectStep",
848
+ "scope": {
849
+ "spaceIds": [
850
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
851
+ ],
852
+ },
743
853
  "selector": {
744
854
  "_tag": "TypeSelector",
745
855
  "inverted": false,
746
856
  "typename": [
747
- "dxn:type:dxos.org/type/Organization:0.1.0",
748
- "dxn:type:dxos.org/type/Person:0.1.0",
857
+ "dxn:type:com.example.type.organization:0.1.0",
858
+ "dxn:type:com.example.type.person:0.1.0",
749
859
  ],
750
860
  },
751
- "spaces": [
752
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
753
- ],
754
861
  },
755
862
  {
756
863
  "_tag": "FilterDeletedStep",
757
864
  "mode": "only-non-deleted",
758
865
  },
866
+ {
867
+ "_tag": "FilterStep",
868
+ "filter": {
869
+ "filters": [
870
+ {
871
+ "id": undefined,
872
+ "props": {},
873
+ "type": "object",
874
+ "typename": "dxn:type:com.example.type.organization:0.1.0",
875
+ },
876
+ {
877
+ "id": undefined,
878
+ "props": {},
879
+ "type": "object",
880
+ "typename": "dxn:type:com.example.type.person:0.1.0",
881
+ },
882
+ ],
883
+ "type": "or",
884
+ },
885
+ },
759
886
  {
760
887
  "_tag": "OrderStep",
761
888
  "order": [
@@ -788,22 +915,44 @@ describe('QueryPlanner', () => {
788
915
  "steps": [
789
916
  {
790
917
  "_tag": "SelectStep",
918
+ "scope": {
919
+ "spaceIds": [
920
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
921
+ ],
922
+ },
791
923
  "selector": {
792
924
  "_tag": "TypeSelector",
793
925
  "inverted": true,
794
926
  "typename": [
795
- "dxn:type:dxos.org/type/Organization:0.1.0",
796
- "dxn:type:dxos.org/type/Person:0.1.0",
927
+ "dxn:type:com.example.type.organization:0.1.0",
928
+ "dxn:type:com.example.type.person:0.1.0",
797
929
  ],
798
930
  },
799
- "spaces": [
800
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
801
- ],
802
931
  },
803
932
  {
804
933
  "_tag": "FilterDeletedStep",
805
934
  "mode": "only-non-deleted",
806
935
  },
936
+ {
937
+ "_tag": "FilterStep",
938
+ "filter": {
939
+ "filters": [
940
+ {
941
+ "id": undefined,
942
+ "props": {},
943
+ "type": "object",
944
+ "typename": "dxn:type:com.example.type.organization:0.1.0",
945
+ },
946
+ {
947
+ "id": undefined,
948
+ "props": {},
949
+ "type": "object",
950
+ "typename": "dxn:type:com.example.type.person:0.1.0",
951
+ },
952
+ ],
953
+ "type": "or",
954
+ },
955
+ },
807
956
  {
808
957
  "_tag": "OrderStep",
809
958
  "order": [
@@ -826,23 +975,184 @@ describe('QueryPlanner', () => {
826
975
  "steps": [
827
976
  {
828
977
  "_tag": "SelectStep",
978
+ "scope": {
979
+ "spaceIds": [
980
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
981
+ ],
982
+ },
829
983
  "selector": {
830
984
  "_tag": "TypeSelector",
831
985
  "inverted": false,
832
986
  "typename": [
833
- "dxn:type:dxos.org/type/Task:0.1.0",
987
+ "dxn:type:com.example.type.task:0.1.0",
834
988
  ],
835
989
  },
836
- "spaces": [
837
- "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
838
- ],
839
990
  },
840
991
  {
841
992
  "_tag": "FilterDeletedStep",
842
993
  "mode": "only-deleted",
843
994
  },
995
+ {
996
+ "_tag": "FilterStep",
997
+ "filter": {
998
+ "id": undefined,
999
+ "props": {},
1000
+ "type": "object",
1001
+ "typename": "dxn:type:com.example.type.task:0.1.0",
1002
+ },
1003
+ },
1004
+ {
1005
+ "_tag": "OrderStep",
1006
+ "order": [
1007
+ {
1008
+ "kind": "natural",
1009
+ },
1010
+ ],
1011
+ },
1012
+ ],
1013
+ }
1014
+ `);
1015
+ });
1016
+
1017
+ test('select items from a specific feed', () => {
1018
+ const query = Query.select(Filter.type(TestSchema.Task)).from({ feeds: [QUEUE_DXN] });
1019
+
1020
+ const plan = planner.createPlan(query.ast);
1021
+ expect(plan).toMatchInlineSnapshot(`
1022
+ {
1023
+ "steps": [
1024
+ {
1025
+ "_tag": "SelectStep",
1026
+ "scope": {
1027
+ "feeds": [
1028
+ "dxn:queue:data:B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO:01JJRA86VK4H1TEB6QQVSWXP0E",
1029
+ ],
1030
+ },
1031
+ "selector": {
1032
+ "_tag": "TypeSelector",
1033
+ "inverted": false,
1034
+ "typename": [
1035
+ "dxn:type:com.example.type.task:0.1.0",
1036
+ ],
1037
+ },
1038
+ },
1039
+ {
1040
+ "_tag": "FilterDeletedStep",
1041
+ "mode": "only-non-deleted",
1042
+ },
1043
+ {
1044
+ "_tag": "FilterStep",
1045
+ "filter": {
1046
+ "id": undefined,
1047
+ "props": {},
1048
+ "type": "object",
1049
+ "typename": "dxn:type:com.example.type.task:0.1.0",
1050
+ },
1051
+ },
1052
+ {
1053
+ "_tag": "OrderStep",
1054
+ "order": [
1055
+ {
1056
+ "kind": "natural",
1057
+ },
1058
+ ],
1059
+ },
1060
+ ],
1061
+ }
1062
+ `);
1063
+ });
1064
+
1065
+ test('select items from all feeds in a space', () => {
1066
+ const query = Query.select(Filter.type(TestSchema.Task)).from({
1067
+ spaceIds: [SPACE_ID],
1068
+ allFeedsFromSpaces: true,
1069
+ });
1070
+
1071
+ const plan = planner.createPlan(query.ast);
1072
+ expect(plan).toMatchInlineSnapshot(`
1073
+ {
1074
+ "steps": [
1075
+ {
1076
+ "_tag": "SelectStep",
1077
+ "scope": {
1078
+ "allFeedsFromSpaces": true,
1079
+ "spaceIds": [
1080
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
1081
+ ],
1082
+ },
1083
+ "selector": {
1084
+ "_tag": "TypeSelector",
1085
+ "inverted": false,
1086
+ "typename": [
1087
+ "dxn:type:com.example.type.task:0.1.0",
1088
+ ],
1089
+ },
1090
+ },
1091
+ {
1092
+ "_tag": "FilterDeletedStep",
1093
+ "mode": "only-non-deleted",
1094
+ },
1095
+ {
1096
+ "_tag": "FilterStep",
1097
+ "filter": {
1098
+ "id": undefined,
1099
+ "props": {},
1100
+ "type": "object",
1101
+ "typename": "dxn:type:com.example.type.task:0.1.0",
1102
+ },
1103
+ },
1104
+ {
1105
+ "_tag": "OrderStep",
1106
+ "order": [
1107
+ {
1108
+ "kind": "natural",
1109
+ },
1110
+ ],
1111
+ },
1112
+ ],
1113
+ }
1114
+ `);
1115
+ });
1116
+
1117
+ test('limit results', () => {
1118
+ const query = Query.select(Filter.type(TestSchema.Task)).limit(10);
1119
+
1120
+ const plan = planner.createPlan(withSpaceIdOptions(query.ast));
1121
+ expect(plan).toMatchInlineSnapshot(`
1122
+ {
1123
+ "steps": [
1124
+ {
1125
+ "_tag": "SelectStep",
1126
+ "limit": 10,
1127
+ "scope": {
1128
+ "spaceIds": [
1129
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
1130
+ ],
1131
+ },
1132
+ "selector": {
1133
+ "_tag": "TypeSelector",
1134
+ "inverted": false,
1135
+ "typename": [
1136
+ "dxn:type:com.example.type.task:0.1.0",
1137
+ ],
1138
+ },
1139
+ },
1140
+ {
1141
+ "_tag": "FilterDeletedStep",
1142
+ "mode": "only-non-deleted",
1143
+ },
1144
+ {
1145
+ "_tag": "FilterStep",
1146
+ "filter": {
1147
+ "id": undefined,
1148
+ "props": {},
1149
+ "type": "object",
1150
+ "typename": "dxn:type:com.example.type.task:0.1.0",
1151
+ },
1152
+ },
844
1153
  {
845
1154
  "_tag": "OrderStep",
1155
+ "limit": 10,
846
1156
  "order": [
847
1157
  {
848
1158
  "kind": "natural",
@@ -853,14 +1163,472 @@ describe('QueryPlanner', () => {
853
1163
  }
854
1164
  `);
855
1165
  });
1166
+
1167
+ test('ordered and limited results', () => {
1168
+ const query = Query.select(Filter.type(TestSchema.Task)).orderBy(Order.property('title', 'asc')).limit(10);
1169
+
1170
+ const plan = planner.createPlan(withSpaceIdOptions(query.ast));
1171
+ expect(plan).toMatchInlineSnapshot(`
1172
+ {
1173
+ "steps": [
1174
+ {
1175
+ "_tag": "SelectStep",
1176
+ "limit": 10,
1177
+ "scope": {
1178
+ "spaceIds": [
1179
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
1180
+ ],
1181
+ },
1182
+ "selector": {
1183
+ "_tag": "TypeSelector",
1184
+ "inverted": false,
1185
+ "typename": [
1186
+ "dxn:type:com.example.type.task:0.1.0",
1187
+ ],
1188
+ },
1189
+ },
1190
+ {
1191
+ "_tag": "FilterDeletedStep",
1192
+ "mode": "only-non-deleted",
1193
+ },
1194
+ {
1195
+ "_tag": "FilterStep",
1196
+ "filter": {
1197
+ "id": undefined,
1198
+ "props": {},
1199
+ "type": "object",
1200
+ "typename": "dxn:type:com.example.type.task:0.1.0",
1201
+ },
1202
+ },
1203
+ {
1204
+ "_tag": "OrderStep",
1205
+ "limit": 10,
1206
+ "order": [
1207
+ {
1208
+ "direction": "asc",
1209
+ "kind": "property",
1210
+ "property": "title",
1211
+ },
1212
+ ],
1213
+ },
1214
+ ],
1215
+ }
1216
+ `);
1217
+ });
1218
+
1219
+ test('union of limited queries', () => {
1220
+ const query = Query.all(
1221
+ Query.select(Filter.type(TestSchema.Person)).limit(5),
1222
+ Query.select(Filter.type(TestSchema.Organization)).limit(5),
1223
+ );
1224
+
1225
+ const plan = planner.createPlan(withSpaceIdOptions(query.ast));
1226
+ expect(plan).toMatchInlineSnapshot(`
1227
+ {
1228
+ "steps": [
1229
+ {
1230
+ "_tag": "UnionStep",
1231
+ "plans": [
1232
+ {
1233
+ "steps": [
1234
+ {
1235
+ "_tag": "SelectStep",
1236
+ "limit": 5,
1237
+ "scope": {
1238
+ "spaceIds": [
1239
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
1240
+ ],
1241
+ },
1242
+ "selector": {
1243
+ "_tag": "TypeSelector",
1244
+ "inverted": false,
1245
+ "typename": [
1246
+ "dxn:type:com.example.type.person:0.1.0",
1247
+ ],
1248
+ },
1249
+ },
1250
+ {
1251
+ "_tag": "FilterDeletedStep",
1252
+ "mode": "only-non-deleted",
1253
+ },
1254
+ {
1255
+ "_tag": "FilterStep",
1256
+ "filter": {
1257
+ "id": undefined,
1258
+ "props": {},
1259
+ "type": "object",
1260
+ "typename": "dxn:type:com.example.type.person:0.1.0",
1261
+ },
1262
+ },
1263
+ {
1264
+ "_tag": "OrderStep",
1265
+ "limit": 5,
1266
+ "order": [
1267
+ {
1268
+ "kind": "natural",
1269
+ },
1270
+ ],
1271
+ },
1272
+ ],
1273
+ },
1274
+ {
1275
+ "steps": [
1276
+ {
1277
+ "_tag": "SelectStep",
1278
+ "limit": 5,
1279
+ "scope": {
1280
+ "spaceIds": [
1281
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
1282
+ ],
1283
+ },
1284
+ "selector": {
1285
+ "_tag": "TypeSelector",
1286
+ "inverted": false,
1287
+ "typename": [
1288
+ "dxn:type:com.example.type.organization:0.1.0",
1289
+ ],
1290
+ },
1291
+ },
1292
+ {
1293
+ "_tag": "FilterDeletedStep",
1294
+ "mode": "only-non-deleted",
1295
+ },
1296
+ {
1297
+ "_tag": "FilterStep",
1298
+ "filter": {
1299
+ "id": undefined,
1300
+ "props": {},
1301
+ "type": "object",
1302
+ "typename": "dxn:type:com.example.type.organization:0.1.0",
1303
+ },
1304
+ },
1305
+ {
1306
+ "_tag": "OrderStep",
1307
+ "limit": 5,
1308
+ "order": [
1309
+ {
1310
+ "kind": "natural",
1311
+ },
1312
+ ],
1313
+ },
1314
+ ],
1315
+ },
1316
+ ],
1317
+ },
1318
+ {
1319
+ "_tag": "OrderStep",
1320
+ "order": [
1321
+ {
1322
+ "kind": "natural",
1323
+ },
1324
+ ],
1325
+ },
1326
+ ],
1327
+ }
1328
+ `);
1329
+ });
1330
+ test('throws when query has no from clause', () => {
1331
+ const query = Query.select(Filter.type(TestSchema.Person));
1332
+ expect(() => planner.createPlan(query.ast)).toThrow('Query must be scoped with a from() clause');
1333
+ });
1334
+
1335
+ test('from all accessible spaces', () => {
1336
+ const query = Query.select(Filter.type(TestSchema.Person)).from('all-accessible-spaces');
1337
+
1338
+ const plan = planner.createPlan(query.ast);
1339
+ expect(plan).toMatchInlineSnapshot(`
1340
+ {
1341
+ "steps": [
1342
+ {
1343
+ "_tag": "SelectStep",
1344
+ "scope": {},
1345
+ "selector": {
1346
+ "_tag": "TypeSelector",
1347
+ "inverted": false,
1348
+ "typename": [
1349
+ "dxn:type:com.example.type.person:0.1.0",
1350
+ ],
1351
+ },
1352
+ },
1353
+ {
1354
+ "_tag": "FilterDeletedStep",
1355
+ "mode": "only-non-deleted",
1356
+ },
1357
+ {
1358
+ "_tag": "FilterStep",
1359
+ "filter": {
1360
+ "id": undefined,
1361
+ "props": {},
1362
+ "type": "object",
1363
+ "typename": "dxn:type:com.example.type.person:0.1.0",
1364
+ },
1365
+ },
1366
+ {
1367
+ "_tag": "OrderStep",
1368
+ "order": [
1369
+ {
1370
+ "kind": "natural",
1371
+ },
1372
+ ],
1373
+ },
1374
+ ],
1375
+ }
1376
+ `);
1377
+ });
1378
+
1379
+ test('from all accessible spaces with feeds', () => {
1380
+ const query = Query.select(Filter.type(TestSchema.Person)).from('all-accessible-spaces', {
1381
+ includeFeeds: true,
1382
+ });
1383
+
1384
+ const plan = planner.createPlan(query.ast);
1385
+ expect(plan).toMatchInlineSnapshot(`
1386
+ {
1387
+ "steps": [
1388
+ {
1389
+ "_tag": "SelectStep",
1390
+ "scope": {
1391
+ "allFeedsFromSpaces": true,
1392
+ },
1393
+ "selector": {
1394
+ "_tag": "TypeSelector",
1395
+ "inverted": false,
1396
+ "typename": [
1397
+ "dxn:type:com.example.type.person:0.1.0",
1398
+ ],
1399
+ },
1400
+ },
1401
+ {
1402
+ "_tag": "FilterDeletedStep",
1403
+ "mode": "only-non-deleted",
1404
+ },
1405
+ {
1406
+ "_tag": "FilterStep",
1407
+ "filter": {
1408
+ "id": undefined,
1409
+ "props": {},
1410
+ "type": "object",
1411
+ "typename": "dxn:type:com.example.type.person:0.1.0",
1412
+ },
1413
+ },
1414
+ {
1415
+ "_tag": "OrderStep",
1416
+ "order": [
1417
+ {
1418
+ "kind": "natural",
1419
+ },
1420
+ ],
1421
+ },
1422
+ ],
1423
+ }
1424
+ `);
1425
+ });
1426
+
1427
+ test('from specific feed via feeds scope', () => {
1428
+ const query = Query.select(Filter.type(TestSchema.Task)).from({ feeds: [QUEUE_DXN] });
1429
+
1430
+ const plan = planner.createPlan(query.ast);
1431
+ expect(plan.steps[0]).toMatchObject({
1432
+ _tag: 'SelectStep',
1433
+ scope: { feeds: [QUEUE_DXN] },
1434
+ });
1435
+ });
1436
+
1437
+ test('from specific space with feeds', () => {
1438
+ const query = Query.select(Filter.type(TestSchema.Person)).from({
1439
+ spaceIds: [SPACE_ID],
1440
+ allFeedsFromSpaces: true,
1441
+ });
1442
+
1443
+ const plan = planner.createPlan(query.ast);
1444
+ expect(plan.steps[0]).toMatchObject({
1445
+ _tag: 'SelectStep',
1446
+ scope: { spaceIds: [SPACE_ID], allFeedsFromSpaces: true },
1447
+ });
1448
+ });
1449
+
1450
+ test('from subquery flattens into filter on subquery results', () => {
1451
+ // Query.select(Filter.props({ name: 'Alice' })).from(Query.select(Filter.type(Person)))
1452
+ // Should flatten to: select type Person -> filter props { name: 'Alice' }.
1453
+ const subquery = Query.select(Filter.type(TestSchema.Person)).from({ spaceIds: [SPACE_ID] });
1454
+ const query = Query.select(Filter.props<TestSchema.Person>({ name: 'Alice' })).from(subquery);
1455
+
1456
+ const plan = planner.createPlan(query.ast);
1457
+ expect(plan).toMatchInlineSnapshot(`
1458
+ {
1459
+ "steps": [
1460
+ {
1461
+ "_tag": "SelectStep",
1462
+ "scope": {
1463
+ "spaceIds": [
1464
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
1465
+ ],
1466
+ },
1467
+ "selector": {
1468
+ "_tag": "TypeSelector",
1469
+ "inverted": false,
1470
+ "typename": [
1471
+ "dxn:type:com.example.type.person:0.1.0",
1472
+ ],
1473
+ },
1474
+ },
1475
+ {
1476
+ "_tag": "FilterDeletedStep",
1477
+ "mode": "only-non-deleted",
1478
+ },
1479
+ {
1480
+ "_tag": "FilterStep",
1481
+ "filter": {
1482
+ "id": undefined,
1483
+ "props": {},
1484
+ "type": "object",
1485
+ "typename": "dxn:type:com.example.type.person:0.1.0",
1486
+ },
1487
+ },
1488
+ {
1489
+ "_tag": "FilterStep",
1490
+ "filter": {
1491
+ "id": undefined,
1492
+ "props": {
1493
+ "name": {
1494
+ "operator": "eq",
1495
+ "type": "compare",
1496
+ "value": "Alice",
1497
+ },
1498
+ },
1499
+ "type": "object",
1500
+ "typename": null,
1501
+ },
1502
+ },
1503
+ {
1504
+ "_tag": "OrderStep",
1505
+ "order": [
1506
+ {
1507
+ "kind": "natural",
1508
+ },
1509
+ ],
1510
+ },
1511
+ ],
1512
+ }
1513
+ `);
1514
+ });
1515
+
1516
+ test('from subquery with reference traversal', () => {
1517
+ // Query.select(Filter.type(Task)).reference('assignee').from(subquery)
1518
+ // The reference traversal wraps the outer select; flattening should still work.
1519
+ const subquery = Query.select(Filter.type(TestSchema.Person)).from({ spaceIds: [SPACE_ID] });
1520
+ const query = Query.select(Filter.type(TestSchema.Task)).reference('assignee').from(subquery);
1521
+
1522
+ const plan = planner.createPlan(query.ast);
1523
+ expect(plan).toMatchInlineSnapshot(`
1524
+ {
1525
+ "steps": [
1526
+ {
1527
+ "_tag": "SelectStep",
1528
+ "scope": {
1529
+ "spaceIds": [
1530
+ "B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO",
1531
+ ],
1532
+ },
1533
+ "selector": {
1534
+ "_tag": "TypeSelector",
1535
+ "inverted": false,
1536
+ "typename": [
1537
+ "dxn:type:com.example.type.person:0.1.0",
1538
+ ],
1539
+ },
1540
+ },
1541
+ {
1542
+ "_tag": "FilterDeletedStep",
1543
+ "mode": "only-non-deleted",
1544
+ },
1545
+ {
1546
+ "_tag": "FilterStep",
1547
+ "filter": {
1548
+ "id": undefined,
1549
+ "props": {},
1550
+ "type": "object",
1551
+ "typename": "dxn:type:com.example.type.person:0.1.0",
1552
+ },
1553
+ },
1554
+ {
1555
+ "_tag": "FilterStep",
1556
+ "filter": {
1557
+ "id": undefined,
1558
+ "props": {},
1559
+ "type": "object",
1560
+ "typename": "dxn:type:com.example.type.task:0.1.0",
1561
+ },
1562
+ },
1563
+ {
1564
+ "_tag": "TraverseStep",
1565
+ "traversal": {
1566
+ "_tag": "ReferenceTraversal",
1567
+ "direction": "outgoing",
1568
+ "property": "assignee",
1569
+ },
1570
+ },
1571
+ {
1572
+ "_tag": "FilterDeletedStep",
1573
+ "mode": "only-non-deleted",
1574
+ },
1575
+ {
1576
+ "_tag": "OrderStep",
1577
+ "order": [
1578
+ {
1579
+ "kind": "natural",
1580
+ },
1581
+ ],
1582
+ },
1583
+ ],
1584
+ }
1585
+ `);
1586
+ });
1587
+
1588
+ test('from subquery inherits scope from inner query', () => {
1589
+ // The outer query has no scope — the subquery carries the scope.
1590
+ const subquery = Query.select(Filter.type(TestSchema.Task)).from({ spaceIds: [SPACE_ID] });
1591
+ const query = Query.select(Filter.props<TestSchema.Task>({ title: 'Test' })).from(subquery);
1592
+
1593
+ const plan = planner.createPlan(query.ast);
1594
+ const selectStep = plan.steps.find((step) => step._tag === 'SelectStep');
1595
+ expect(selectStep).toMatchObject({
1596
+ _tag: 'SelectStep',
1597
+ scope: { spaceIds: [SPACE_ID] },
1598
+ });
1599
+ });
1600
+
1601
+ test('and(type, compare, timestamp) throws descriptive error about timestamp limitation', () => {
1602
+ const query = Query.select(
1603
+ Filter.and(
1604
+ Filter.type(TestSchema.Person),
1605
+ Filter.type(TestSchema.Person, { name: 'Alice' }),
1606
+ Filter.updated({ after: Date.now() }),
1607
+ ),
1608
+ );
1609
+ expect(() => planner.createPlan(withSpaceIdOptions(query.ast))).toThrow(/[Tt]imestamp/);
1610
+ });
1611
+
1612
+ test('and(type, timestamp) produces valid plan', () => {
1613
+ const query = Query.select(Filter.and(Filter.type(TestSchema.Person), Filter.updated({ after: Date.now() })));
1614
+ const plan = planner.createPlan(withSpaceIdOptions(query.ast));
1615
+ const hasTimestampFilter = plan.steps.some(
1616
+ (step) => step._tag === 'FilterStep' && JSON.stringify(step.filter).includes('timestamp'),
1617
+ );
1618
+ expect(hasTimestampFilter).toBe(true);
1619
+ });
856
1620
  });
857
1621
 
858
1622
  const SPACE_ID = SpaceId.make('B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO'); // Stable id for inline snapshots.
1623
+ const QUEUE_DXN = DXN.parse('dxn:queue:data:B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO:01JJRA86VK4H1TEB6QQVSWXP0E').toString(); // Stable queue DXN for inline snapshots.
859
1624
 
860
1625
  const withSpaceIdOptions = (query: QueryAST.Query): QueryAST.Query => ({
861
- type: 'options',
1626
+ type: 'from',
862
1627
  query,
863
- options: {
864
- spaceIds: [SPACE_ID],
1628
+ from: {
1629
+ _tag: 'scope',
1630
+ scope: {
1631
+ spaceIds: [SPACE_ID],
1632
+ },
865
1633
  },
866
1634
  });