@dxos/echo 0.8.3-main.672df60 → 0.8.3-staging.0fa589b

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 (57) hide show
  1. package/README.md +25 -23
  2. package/dist/lib/browser/chunk-UYPR62ZB.mjs +624 -0
  3. package/dist/lib/browser/chunk-UYPR62ZB.mjs.map +7 -0
  4. package/dist/lib/browser/index.mjs +11 -280
  5. package/dist/lib/browser/index.mjs.map +4 -4
  6. package/dist/lib/browser/meta.json +1 -1
  7. package/dist/lib/browser/testing/index.mjs +70 -0
  8. package/dist/lib/browser/testing/index.mjs.map +7 -0
  9. package/dist/lib/node/chunk-4HQE2F3L.cjs +644 -0
  10. package/dist/lib/node/chunk-4HQE2F3L.cjs.map +7 -0
  11. package/dist/lib/node/index.cjs +11 -282
  12. package/dist/lib/node/index.cjs.map +4 -4
  13. package/dist/lib/node/meta.json +1 -1
  14. package/dist/lib/node/testing/index.cjs +89 -0
  15. package/dist/lib/node/testing/index.cjs.map +7 -0
  16. package/dist/lib/node-esm/chunk-BYBICDIO.mjs +624 -0
  17. package/dist/lib/node-esm/chunk-BYBICDIO.mjs.map +7 -0
  18. package/dist/lib/node-esm/index.mjs +11 -280
  19. package/dist/lib/node-esm/index.mjs.map +4 -4
  20. package/dist/lib/node-esm/meta.json +1 -1
  21. package/dist/lib/node-esm/testing/index.mjs +70 -0
  22. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  23. package/dist/types/src/Key.d.ts +2 -0
  24. package/dist/types/src/Key.d.ts.map +1 -0
  25. package/dist/types/src/Obj.d.ts +37 -18
  26. package/dist/types/src/Obj.d.ts.map +1 -1
  27. package/dist/types/src/Ref.d.ts +9 -3
  28. package/dist/types/src/Ref.d.ts.map +1 -1
  29. package/dist/types/src/Relation.d.ts +36 -10
  30. package/dist/types/src/Relation.d.ts.map +1 -1
  31. package/dist/types/src/Type.d.ts +82 -17
  32. package/dist/types/src/Type.d.ts.map +1 -1
  33. package/dist/types/src/index.d.ts +5 -3
  34. package/dist/types/src/index.d.ts.map +1 -1
  35. package/dist/types/src/query/dsl.d.ts +218 -0
  36. package/dist/types/src/query/dsl.d.ts.map +1 -0
  37. package/dist/types/src/query/dsl.test.d.ts +2 -0
  38. package/dist/types/src/query/dsl.test.d.ts.map +1 -0
  39. package/dist/types/src/query/index.d.ts +2 -0
  40. package/dist/types/src/query/index.d.ts.map +1 -0
  41. package/dist/types/src/testing/index.d.ts +2 -0
  42. package/dist/types/src/testing/index.d.ts.map +1 -0
  43. package/dist/types/src/testing/types.d.ts +113 -0
  44. package/dist/types/src/testing/types.d.ts.map +1 -0
  45. package/package.json +56 -12
  46. package/src/Key.ts +5 -0
  47. package/src/Obj.ts +66 -25
  48. package/src/Ref.ts +9 -6
  49. package/src/Relation.ts +75 -13
  50. package/src/Type.ts +122 -18
  51. package/src/index.ts +5 -3
  52. package/src/query/dsl.test.ts +323 -0
  53. package/src/query/dsl.ts +646 -0
  54. package/src/query/index.ts +5 -0
  55. package/src/test/api.test.ts +54 -9
  56. package/src/testing/index.ts +5 -0
  57. package/src/testing/types.ts +91 -0
package/src/Type.ts CHANGED
@@ -3,32 +3,75 @@
3
3
  //
4
4
 
5
5
  import { type Schema } from 'effect';
6
+ import type { Simplify } from 'effect/Schema';
6
7
 
7
8
  import type { EncodedReference } from '@dxos/echo-protocol';
8
9
  import * as EchoSchema from '@dxos/echo-schema';
10
+ import type { ToMutable } from '@dxos/echo-schema';
9
11
  import { invariant } from '@dxos/invariant';
10
12
  import type * as Keys from '@dxos/keys';
11
13
 
14
+ import type * as RelationModule from './Relation';
15
+
16
+ export const KindId: unique symbol = EchoSchema.EntityKindId as any;
17
+ export type KindId = typeof KindId;
18
+
19
+ export { EntityKind as Kind } from '@dxos/echo-schema';
20
+
12
21
  /**
13
- * ECHO schema.
22
+ * Assigns a kind to an Object or Relation instance.
14
23
  */
15
- export type Schema = EchoSchema.EchoSchema;
24
+ // NOTE: Needed to make `isRelation` and `isObject` checks work.
25
+ export interface OfKind<Kind extends EchoSchema.EntityKind> {
26
+ readonly id: Keys.ObjectId;
27
+ readonly [KindId]: Kind;
28
+ }
29
+
30
+ interface ObjJsonProps {
31
+ id: string;
32
+ }
33
+
34
+ interface RelationJsonProps {
35
+ id: string;
36
+ [EchoSchema.ATTR_RELATION_SOURCE]: string;
37
+ [EchoSchema.ATTR_RELATION_TARGET]: string;
38
+ }
39
+
40
+ /**
41
+ * Returns all properties of an object or relation except for the id and kind.
42
+ */
43
+ export type Properties<T> = Omit<T, 'id' | KindId | RelationModule.Source | RelationModule.Target>;
16
44
 
17
45
  /**
18
- * EchoObject schema.
46
+ * Base ECHO schema type.
19
47
  */
20
- export const Obj = EchoSchema.EchoObject;
48
+ export type Schema = EchoSchema.EchoSchema;
21
49
 
22
50
  /**
23
- * EchoRelation schema.
51
+ * Return type of the `Obj` schema constructor.
52
+ *
53
+ * This typedef avoids `TS4023` error (name from external module cannot be used named).
54
+ * See Effect's note on interface types.
24
55
  */
25
- export const Relation = EchoSchema.EchoRelation;
56
+ export interface obj<Self extends Schema.Schema.Any>
57
+ extends Schema.AnnotableClass<
58
+ obj<Self>,
59
+ OfKind<EchoSchema.EntityKind.Object> & ToMutable<Schema.Schema.Type<Self>>,
60
+ Simplify<ObjJsonProps & ToMutable<Schema.Schema.Encoded<Self>>>,
61
+ Schema.Schema.Context<Self>
62
+ >,
63
+ EchoSchema.TypeMeta {}
26
64
 
27
65
  /**
28
- * Ref schema.
66
+ * Object schema.
29
67
  */
30
- export const Ref: <S extends Obj.Any>(schema: S) => EchoSchema.Ref$<Schema.Schema.Type<S>> = EchoSchema.Ref;
68
+ export const Obj: {
69
+ (opts: EchoSchema.TypeMeta): <Self extends Schema.Schema.Any>(self: Self) => obj<Self>;
70
+ } = EchoSchema.EchoObject as any;
31
71
 
72
+ /**
73
+ * Object schema type definitions.
74
+ */
32
75
  export namespace Obj {
33
76
  /**
34
77
  * Type that represents an arbitrary schema type of an object.
@@ -38,6 +81,39 @@ export namespace Obj {
38
81
  export type Any = Schema.Schema.AnyNoContext;
39
82
  }
40
83
 
84
+ /**
85
+ * Return type of the `Relation` schema constructor.
86
+ *
87
+ * This typedef avoids `TS4023` error (name from external module cannot be used named).
88
+ * See Effect's note on interface types.
89
+ */
90
+ export interface relation<
91
+ Self extends Schema.Schema.Any,
92
+ SourceSchema extends Schema.Schema.Any,
93
+ TargetSchema extends Schema.Schema.Any,
94
+ > extends Schema.AnnotableClass<
95
+ relation<Self, SourceSchema, TargetSchema>,
96
+ OfKind<EchoSchema.EntityKind.Relation> &
97
+ Relation.Endpoints<Schema.Schema.Type<SourceSchema>, Schema.Schema.Type<TargetSchema>> &
98
+ ToMutable<Schema.Schema.Type<Self>>,
99
+ Simplify<RelationJsonProps & ToMutable<Schema.Schema.Encoded<Self>>>,
100
+ Schema.Schema.Context<Self>
101
+ >,
102
+ EchoSchema.TypeMeta {}
103
+
104
+ /**
105
+ * Relation schema.
106
+ */
107
+ // TODO(dmaretskyi): I have to redefine the type here so that the definition uses symbols from @dxos/echo/Relation.
108
+ export const Relation: {
109
+ <Source extends Schema.Schema.AnyNoContext, Target extends Schema.Schema.AnyNoContext>(
110
+ opts: EchoSchema.EchoRelationOptions<Source, Target>,
111
+ ): <Self extends Schema.Schema.Any>(self: Self) => relation<Self, Source, Target>;
112
+ } = EchoSchema.EchoRelation as any;
113
+
114
+ /**
115
+ * Relation schema type definitions.
116
+ */
41
117
  export namespace Relation {
42
118
  /**
43
119
  * Type that represents an arbitrary schema type of a relation.
@@ -49,14 +125,36 @@ export namespace Relation {
49
125
  /**
50
126
  * Get relation target type.
51
127
  */
52
- export type Target<A> = A extends EchoSchema.RelationSourceTargetRefs<infer T, infer _S> ? T : never;
128
+ export type Target<A> = A extends Relation.Endpoints<infer _S, infer T> ? T : never;
53
129
 
54
130
  /**
55
131
  * Get relation source type.
56
132
  */
57
- export type Source<A> = A extends EchoSchema.RelationSourceTargetRefs<infer _T, infer S> ? S : never;
133
+ export type Source<A> = A extends Relation.Endpoints<infer S, infer _T> ? S : never;
134
+
135
+ export type Endpoints<Source, Target> = {
136
+ [RelationModule.Source]: Source;
137
+ [RelationModule.Target]: Target;
138
+ };
58
139
  }
59
140
 
141
+ /**
142
+ * Return type of the `Ref` schema constructor.
143
+ *
144
+ * This typedef avoids `TS4023` error (name from external module cannot be used named).
145
+ * See Effect's note on interface types.
146
+ */
147
+ export interface ref<TargetSchema extends Schema.Schema.Any>
148
+ extends EchoSchema.Ref$<Schema.Schema.Type<TargetSchema>> {}
149
+
150
+ /**
151
+ * Ref schema.
152
+ */
153
+ export const Ref: <S extends Obj.Any>(schema: S) => ref<S> = EchoSchema.Ref;
154
+
155
+ export interface Ref<T> extends Schema.SchemaClass<EchoSchema.Ref<T>, EncodedReference> {}
156
+
157
+ // TODO(buurdon): Move to Ref?
60
158
  export namespace Ref {
61
159
  /**
62
160
  * Type that represents an arbitrary schema type of a reference.
@@ -107,21 +205,27 @@ export const getMeta = (schema: Obj.Any | Relation.Any): Meta | undefined => {
107
205
  return EchoSchema.getTypeAnnotation(schema);
108
206
  };
109
207
 
110
- export { EntityKind as Kind } from '@dxos/echo-schema';
111
-
112
208
  /**
113
209
  * @returns True if the schema is mutable.
114
210
  */
115
- export const isMutable = (schema: Obj.Any | Relation.Any): boolean => {
116
- return EchoSchema.isMutable(schema);
117
- };
211
+ export const isMutable = EchoSchema.isMutable;
118
212
 
119
213
  export { SpaceId, ObjectId, DXN } from '@dxos/keys';
120
214
 
121
- export {
122
- //
215
+ export interface Expando extends OfKind<EchoSchema.EntityKind.Object> {
216
+ [key: string]: any;
217
+ }
218
+
219
+ export const Expando: Schema.Schema<
123
220
  Expando,
221
+ Simplify<ObjJsonProps & { [key: string]: any }>,
222
+ never
223
+ > = EchoSchema.Expando as any;
224
+
225
+ export {
226
+ // TODO(burdon): Standardize.
227
+ Format,
124
228
  JsonSchemaType as JsonSchema,
229
+ toEffectSchema,
125
230
  toJsonSchema,
126
- Format,
127
231
  } from '@dxos/echo-schema';
package/src/index.ts CHANGED
@@ -2,10 +2,12 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * as Type from './Type';
5
+ export * as Key from './Key';
6
6
  export * as Obj from './Obj';
7
- export * as Relation from './Relation';
8
7
  export * as Ref from './Ref';
8
+ export * as Relation from './Relation';
9
+ export * as Type from './Type';
9
10
 
11
+ export { DXN } from '@dxos/keys';
12
+ export { Filter, Query } from './query';
10
13
  export { type Live } from '@dxos/live-object';
11
- export { Filter, Query } from '@dxos/echo-schema';
@@ -0,0 +1,323 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Schema } from 'effect';
6
+ import { describe, expect, test } from 'vitest';
7
+
8
+ import { QueryAST } from '@dxos/echo-protocol';
9
+ import { DXN } from '@dxos/keys';
10
+ import { log } from '@dxos/log';
11
+
12
+ import { Filter, Query } from './dsl';
13
+ import * as Obj from '../Obj';
14
+ import * as Ref from '../Ref';
15
+ import * as Type from '../Type';
16
+
17
+ //
18
+ // Example schema
19
+ //
20
+
21
+ // TODO(dmaretskyi): Need common set of test types.
22
+ const Person = Schema.Struct({
23
+ name: Schema.String,
24
+ email: Schema.optional(Schema.String),
25
+ age: Schema.optional(Schema.Number),
26
+ }).pipe(
27
+ Type.Obj({
28
+ typename: 'dxos.org/type/Person',
29
+ version: '0.1.0',
30
+ }),
31
+ );
32
+ interface Person extends Schema.Schema.Type<typeof Person> {}
33
+
34
+ const Organization = Schema.Struct({
35
+ name: Schema.String,
36
+ }).pipe(
37
+ Type.Obj({
38
+ typename: 'dxos.org/type/Organization',
39
+ version: '0.1.0',
40
+ }),
41
+ );
42
+ interface Organization extends Schema.Schema.Type<typeof Organization> {}
43
+
44
+ const WorksFor = Schema.Struct({
45
+ since: Schema.String,
46
+ }).pipe(
47
+ Type.Relation({
48
+ typename: 'dxos.org/type/WorksFor',
49
+ version: '0.1.0',
50
+ source: Person,
51
+ target: Organization,
52
+ }),
53
+ );
54
+ interface WorksFor extends Schema.Schema.Type<typeof WorksFor> {}
55
+
56
+ const Task = Schema.Struct({
57
+ title: Schema.String,
58
+ createdAt: Schema.String,
59
+ assignee: Schema.optional(Type.Ref(Person)),
60
+ }).pipe(Type.Obj({ typename: 'dxos.org/type/Task', version: '0.1.0' }));
61
+ interface Task extends Schema.Schema.Type<typeof Task> {}
62
+
63
+ //
64
+ // Example queries
65
+ //
66
+
67
+ describe('query api', () => {
68
+ test('get all people', () => {
69
+ const getAllPeople = Query.type(Person);
70
+
71
+ log('query', { ast: getAllPeople.ast });
72
+ Schema.validateSync(QueryAST.Query)(getAllPeople.ast);
73
+ console.log('getAllPeople', JSON.stringify(getAllPeople.ast, null, 2));
74
+ });
75
+
76
+ test('get all people named Fred', () => {
77
+ const PeopleNamedFred = Query.select(Filter.type(Person, { name: 'Fred' }));
78
+
79
+ log('query', { ast: PeopleNamedFred.ast });
80
+ Schema.validateSync(QueryAST.Query)(PeopleNamedFred.ast);
81
+ console.log('PeopleNamedFred', JSON.stringify(PeopleNamedFred.ast, null, 2));
82
+ });
83
+
84
+ test('get all orgs Fred worked for since 2020', () => {
85
+ const fred = Obj.make(Person, { name: 'Fred' });
86
+ const OrganizationsFredWorkedForSince2020 = Query.select(Filter.type(Person, { id: fred.id }))
87
+ .sourceOf(WorksFor, { since: Filter.gt('2020') })
88
+ .target();
89
+
90
+ log('query', { ast: OrganizationsFredWorkedForSince2020.ast });
91
+ Schema.validateSync(QueryAST.Query)(OrganizationsFredWorkedForSince2020.ast);
92
+ console.log(
93
+ 'OrganizationsFredWorkedForSince2020',
94
+ JSON.stringify(OrganizationsFredWorkedForSince2020.ast, null, 2),
95
+ );
96
+ });
97
+
98
+ test('get all tasks for Fred', () => {
99
+ const fred = Obj.make(Person, { name: 'Fred' });
100
+ const TasksForFred = Query.select(Filter.type(Person, { id: fred.id })).referencedBy(Task, 'assignee');
101
+
102
+ log('query', { ast: TasksForFred.ast });
103
+ Schema.validateSync(QueryAST.Query)(TasksForFred.ast);
104
+ console.log('TasksForFred', JSON.stringify(TasksForFred.ast, null, 2));
105
+ });
106
+
107
+ test('get all tasks for employees of Cyberdyne', () => {
108
+ const TasksForEmployeesOfCyberdyne = Query.select(Filter.type(Organization, { name: 'Cyberdyne' }))
109
+ .targetOf(WorksFor)
110
+ .source()
111
+ .referencedBy(Task, 'assignee');
112
+
113
+ log('query', { ast: TasksForEmployeesOfCyberdyne.ast });
114
+ Schema.validateSync(QueryAST.Query)(TasksForEmployeesOfCyberdyne.ast);
115
+ console.log('TasksForEmployeesOfCyberdyne', JSON.stringify(TasksForEmployeesOfCyberdyne.ast, null, 2));
116
+ });
117
+
118
+ test('get all people or orgs', () => {
119
+ const PeopleOrOrganizations = Query.all(Query.select(Filter.type(Person)), Query.select(Filter.type(Organization)));
120
+
121
+ log('query', { ast: PeopleOrOrganizations.ast });
122
+ Schema.validateSync(QueryAST.Query)(PeopleOrOrganizations.ast);
123
+ console.log('PeopleOrOrganizations', JSON.stringify(PeopleOrOrganizations.ast, null, 2));
124
+ });
125
+
126
+ test('get all people not in orgs', () => {
127
+ const PeopleNotInOrganizations = Query.without(
128
+ Query.select(Filter.type(Person)),
129
+ Query.select(Filter.type(Person)).sourceOf(WorksFor).source(),
130
+ );
131
+
132
+ log('query', { ast: PeopleNotInOrganizations.ast });
133
+ Schema.validateSync(QueryAST.Query)(PeopleNotInOrganizations.ast);
134
+ console.log('PeopleNotInOrganizations', JSON.stringify(PeopleNotInOrganizations.ast, null, 2));
135
+ });
136
+
137
+ test('get assignees of all tasks created after 2020', () => {
138
+ const AssigneesOfAllTasksCreatedAfter2020 = Query.select(
139
+ Filter.type(Task, { createdAt: Filter.gt('2020') }),
140
+ ).reference('assignee');
141
+
142
+ log('query', { ast: AssigneesOfAllTasksCreatedAfter2020.ast });
143
+ Schema.validateSync(QueryAST.Query)(AssigneesOfAllTasksCreatedAfter2020.ast);
144
+ console.log(
145
+ 'AssigneesOfAllTasksCreatedAfter2020',
146
+ JSON.stringify(AssigneesOfAllTasksCreatedAfter2020.ast, null, 2),
147
+ );
148
+ });
149
+
150
+ test('untyped full-text search', () => {
151
+ const contactFullTextSearch = Query.select(Filter.text('Bill'));
152
+
153
+ log('query', { ast: contactFullTextSearch.ast });
154
+ Schema.validateSync(QueryAST.Query)(contactFullTextSearch.ast);
155
+ expect(contactFullTextSearch.ast).toMatchInlineSnapshot(`
156
+ {
157
+ "filter": {
158
+ "searchKind": undefined,
159
+ "text": "Bill",
160
+ "type": "text-search",
161
+ },
162
+ "type": "select",
163
+ }
164
+ `);
165
+ });
166
+
167
+ test('typed full-text search', () => {
168
+ const contactFullTextSearch = Query.select(Filter.type(Person)).select(Filter.text('Bill'));
169
+
170
+ log('query', { ast: contactFullTextSearch.ast });
171
+ Schema.validateSync(QueryAST.Query)(contactFullTextSearch.ast);
172
+ expect(contactFullTextSearch.ast).toMatchInlineSnapshot(`
173
+ {
174
+ "filter": {
175
+ "searchKind": undefined,
176
+ "text": "Bill",
177
+ "type": "text-search",
178
+ },
179
+ "selection": {
180
+ "filter": {
181
+ "id": undefined,
182
+ "props": {},
183
+ "type": "object",
184
+ "typename": "dxn:type:dxos.org/type/Person:0.1.0",
185
+ },
186
+ "type": "select",
187
+ },
188
+ "type": "filter",
189
+ }
190
+ `);
191
+ });
192
+
193
+ test('filter by ref', () => {
194
+ const fred = Obj.make(Person, { name: 'Fred' });
195
+ const tasksByFred = Filter.type(Task, { assignee: Ref.make(fred) });
196
+ expect(tasksByFred.ast).toEqual({
197
+ props: {
198
+ assignee: {
199
+ operator: 'eq',
200
+ type: 'compare',
201
+ value: {
202
+ '/': DXN.fromLocalObjectId(fred.id).toString(),
203
+ },
204
+ },
205
+ },
206
+ type: 'object',
207
+ typename: 'dxn:type:dxos.org/type/Task:0.1.0',
208
+ });
209
+ console.log('tasksByFred', JSON.stringify(tasksByFred.ast, null, 2));
210
+ });
211
+
212
+ test('select orgs and people', () => {
213
+ const orgsAndPeople = Query.select(Filter.or(Filter.type(Organization), Filter.type(Person)));
214
+
215
+ Schema.validateSync(QueryAST.Query)(orgsAndPeople.ast);
216
+ expect(orgsAndPeople.ast).toMatchInlineSnapshot(`
217
+ {
218
+ "filter": {
219
+ "filters": [
220
+ {
221
+ "id": undefined,
222
+ "props": {},
223
+ "type": "object",
224
+ "typename": "dxn:type:dxos.org/type/Organization:0.1.0",
225
+ },
226
+ {
227
+ "id": undefined,
228
+ "props": {},
229
+ "type": "object",
230
+ "typename": "dxn:type:dxos.org/type/Person:0.1.0",
231
+ },
232
+ ],
233
+ "type": "or",
234
+ },
235
+ "type": "select",
236
+ }
237
+ `);
238
+ });
239
+
240
+ test('select everything but orgs and people', () => {
241
+ const everythingButOrgsAndPeople = Query.select(
242
+ Filter.not(Filter.or(Filter.type(Organization), Filter.type(Person))),
243
+ );
244
+
245
+ Schema.validateSync(QueryAST.Query)(everythingButOrgsAndPeople.ast);
246
+ expect(everythingButOrgsAndPeople.ast).toMatchInlineSnapshot(`
247
+ {
248
+ "filter": {
249
+ "filter": {
250
+ "filters": [
251
+ {
252
+ "id": undefined,
253
+ "props": {},
254
+ "type": "object",
255
+ "typename": "dxn:type:dxos.org/type/Organization:0.1.0",
256
+ },
257
+ {
258
+ "id": undefined,
259
+ "props": {},
260
+ "type": "object",
261
+ "typename": "dxn:type:dxos.org/type/Person:0.1.0",
262
+ },
263
+ ],
264
+ "type": "or",
265
+ },
266
+ "type": "not",
267
+ },
268
+ "type": "select",
269
+ }
270
+ `);
271
+ });
272
+
273
+ test('select deleted tasks', () => {
274
+ const deletedTasks = Query.select(Filter.type(Task)).options({
275
+ deleted: 'only',
276
+ });
277
+
278
+ Schema.validateSync(QueryAST.Query)(deletedTasks.ast);
279
+ expect(deletedTasks.ast).toMatchInlineSnapshot(`
280
+ {
281
+ "options": {
282
+ "deleted": "only",
283
+ },
284
+ "query": {
285
+ "filter": {
286
+ "id": undefined,
287
+ "props": {},
288
+ "type": "object",
289
+ "typename": "dxn:type:dxos.org/type/Task:0.1.0",
290
+ },
291
+ "type": "select",
292
+ },
293
+ "type": "options",
294
+ }
295
+ `);
296
+ });
297
+
298
+ test.skip('chain', () => {
299
+ // NOTE: Can't support props without type since they can't be inferred.
300
+ // const f1: Filter<Person> = Filter.props({ name: 'Fred' });
301
+
302
+ // const x = Query.select(Filter.props({ id: '123' }));
303
+ const y = Query.select(Filter.type(Person));
304
+
305
+ const or = Filter.or(Filter.type(Person, { id: Filter.in('1', '2', '3') }), Filter.type(Organization));
306
+
307
+ const and = Filter.and(
308
+ Filter.type(Person, { id: Filter.in('1', '2', '3') }),
309
+ Filter.type(Person, { name: 'Fred' }),
310
+ );
311
+
312
+ const q = Query
313
+ //
314
+ // NOTE: Can't support functions since they can't be serialized (to server).
315
+ // .filter((object) => Math.random() > 0.5)
316
+ .select(Filter.type(Person))
317
+ .select(Filter.type(Person, { name: 'Fred' }))
318
+ .select({ age: Filter.between(20, 40) })
319
+ .select(Filter.and(Filter.type(Person), Filter.type(Person, { name: Filter.in('bob', 'bill') })));
320
+
321
+ log('stuff', { fOr: or, fAnd: and, q, y });
322
+ });
323
+ });