@dxos/echo 0.8.2-main.2f9c567 → 0.8.2-main.30e4dbb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +19 -4
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +16 -1
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +19 -4
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/experimental/database.d.ts.map +1 -0
- package/dist/types/src/experimental/index.d.ts +1 -0
- package/dist/types/src/experimental/index.d.ts.map +1 -0
- package/dist/types/src/experimental/queue.d.ts.map +1 -0
- package/dist/types/src/experimental/space.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +3 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/query/api.d.ts +183 -0
- package/dist/types/src/query/api.d.ts.map +1 -0
- package/dist/types/src/query/ast.d.ts +146 -0
- package/dist/types/src/query/ast.d.ts.map +1 -0
- package/dist/types/src/query/query.test.d.ts +2 -0
- package/dist/types/src/query/query.test.d.ts.map +1 -0
- package/dist/types/src/type/Relation.d.ts +16 -0
- package/dist/types/src/type/Relation.d.ts.map +1 -0
- package/dist/types/src/{api/type.d.ts → type/Type.d.ts} +1 -1
- package/dist/types/src/type/Type.d.ts.map +1 -0
- package/dist/types/src/type/Type.test.d.ts +2 -0
- package/dist/types/src/type/Type.test.d.ts.map +1 -0
- package/dist/types/src/type/index.d.ts +3 -0
- package/dist/types/src/type/index.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/src/{api → experimental}/index.ts +0 -5
- package/src/index.ts +4 -1
- package/src/query/api.ts +498 -0
- package/src/query/ast.ts +179 -0
- package/src/query/query.test.ts +146 -0
- package/src/type/Relation.ts +17 -0
- package/src/{api.test.ts → type/Type.test.ts} +38 -19
- package/src/{api/type.ts → type/Type.ts} +1 -1
- package/src/type/index.ts +6 -0
- package/dist/types/src/api/database.d.ts.map +0 -1
- package/dist/types/src/api/index.d.ts +0 -4
- package/dist/types/src/api/index.d.ts.map +0 -1
- package/dist/types/src/api/queue.d.ts.map +0 -1
- package/dist/types/src/api/space.d.ts.map +0 -1
- package/dist/types/src/api/type.d.ts.map +0 -1
- package/dist/types/src/api.test.d.ts +0 -2
- package/dist/types/src/api.test.d.ts.map +0 -1
- /package/dist/types/src/{api → experimental}/database.d.ts +0 -0
- /package/dist/types/src/{api → experimental}/queue.d.ts +0 -0
- /package/dist/types/src/{api → experimental}/space.d.ts +0 -0
- /package/src/{api → experimental}/database.ts +0 -0
- /package/src/{api → experimental}/queue.ts +0 -0
- /package/src/{api → experimental}/space.ts +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Schema } from 'effect';
|
|
6
|
+
import { describe, test } from 'vitest';
|
|
7
|
+
|
|
8
|
+
import { create } from '@dxos/echo-schema';
|
|
9
|
+
import { log } from '@dxos/log';
|
|
10
|
+
|
|
11
|
+
import { Filter, Query } from './api';
|
|
12
|
+
import * as QueryAST from './ast';
|
|
13
|
+
import { Type, Relation } from '..';
|
|
14
|
+
|
|
15
|
+
//
|
|
16
|
+
// Example schema
|
|
17
|
+
//
|
|
18
|
+
|
|
19
|
+
const Person = Schema.Struct({
|
|
20
|
+
name: Schema.String,
|
|
21
|
+
email: Schema.optional(Schema.String),
|
|
22
|
+
age: Schema.optional(Schema.Number),
|
|
23
|
+
}).pipe(Type.def({ typename: 'dxos.org/type/Person', version: '0.1.0' }));
|
|
24
|
+
interface Person extends Schema.Schema.Type<typeof Person> {}
|
|
25
|
+
|
|
26
|
+
const Org = Schema.Struct({
|
|
27
|
+
name: Schema.String,
|
|
28
|
+
}).pipe(Type.def({ typename: 'dxos.org/type/Org', version: '0.1.0' }));
|
|
29
|
+
interface Org extends Schema.Schema.Type<typeof Org> {}
|
|
30
|
+
|
|
31
|
+
const WorksFor = Schema.Struct({
|
|
32
|
+
since: Schema.String,
|
|
33
|
+
}).pipe(Relation.def({ typename: 'dxos.org/type/WorksFor', version: '0.1.0', source: Person, target: Org }));
|
|
34
|
+
interface WorksFor extends Schema.Schema.Type<typeof WorksFor> {}
|
|
35
|
+
|
|
36
|
+
const Task = Schema.Struct({
|
|
37
|
+
title: Schema.String,
|
|
38
|
+
createdAt: Schema.String,
|
|
39
|
+
assignee: Type.Ref(Person),
|
|
40
|
+
}).pipe(Type.def({ typename: 'dxos.org/type/Task', version: '0.1.0' }));
|
|
41
|
+
interface Task extends Schema.Schema.Type<typeof Task> {}
|
|
42
|
+
|
|
43
|
+
//
|
|
44
|
+
// Example queries
|
|
45
|
+
//
|
|
46
|
+
|
|
47
|
+
describe('query api', () => {
|
|
48
|
+
test('get all people', () => {
|
|
49
|
+
// Query<Person>
|
|
50
|
+
const getAllPeople = Query.type(Person);
|
|
51
|
+
|
|
52
|
+
log.info('query', { ast: getAllPeople.ast });
|
|
53
|
+
Schema.validateSync(QueryAST.Query)(getAllPeople.ast);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('get all people named Fred', () => {
|
|
57
|
+
// Query<Person>
|
|
58
|
+
const getAllPeopleNamedFred = Query.select(Filter.type(Person, { name: 'Fred' }));
|
|
59
|
+
|
|
60
|
+
log.info('query', { ast: getAllPeopleNamedFred.ast });
|
|
61
|
+
Schema.validateSync(QueryAST.Query)(getAllPeopleNamedFred.ast);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('get all orgs Fred worked for since 2020', () => {
|
|
65
|
+
// Query<Org>
|
|
66
|
+
const fred = create(Person, { name: 'Fred' });
|
|
67
|
+
const getAllOrgsFredWorkedForSince2020 = Query.select(Filter.type(Person, { id: fred.id }))
|
|
68
|
+
.sourceOf(WorksFor, { since: Filter.gt('2020') })
|
|
69
|
+
.target();
|
|
70
|
+
|
|
71
|
+
log.info('query', { ast: getAllOrgsFredWorkedForSince2020.ast });
|
|
72
|
+
Schema.validateSync(QueryAST.Query)(getAllOrgsFredWorkedForSince2020.ast);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('get all tasks for Fred', () => {
|
|
76
|
+
// Query<Task>
|
|
77
|
+
const fred = create(Person, { name: 'Fred' });
|
|
78
|
+
const getAllTasksForFred = Query.select(Filter.type(Person, { id: fred.id })).referencedBy(Task, 'assignee');
|
|
79
|
+
|
|
80
|
+
log.info('query', { ast: getAllTasksForFred.ast });
|
|
81
|
+
Schema.validateSync(QueryAST.Query)(getAllTasksForFred.ast);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('get all tasks for employees of Cyberdyne', () => {
|
|
85
|
+
// Query<Task>
|
|
86
|
+
const allTasksForEmployeesOfCyberdyne = Query.select(Filter.type(Org, { name: 'Cyberdyne' }))
|
|
87
|
+
.targetOf(WorksFor)
|
|
88
|
+
.source()
|
|
89
|
+
.referencedBy(Task, 'assignee');
|
|
90
|
+
|
|
91
|
+
log.info('query', { ast: allTasksForEmployeesOfCyberdyne.ast });
|
|
92
|
+
Schema.validateSync(QueryAST.Query)(allTasksForEmployeesOfCyberdyne.ast);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('get all people or orgs', () => {
|
|
96
|
+
// Query<Person | Org>
|
|
97
|
+
const allPeopleOrOrgs = Query.all(Query.select(Filter.type(Person)), Query.select(Filter.type(Org)));
|
|
98
|
+
|
|
99
|
+
log.info('query', { ast: allPeopleOrOrgs.ast });
|
|
100
|
+
Schema.validateSync(QueryAST.Query)(allPeopleOrOrgs.ast);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('get assignees of all tasks created after 2020', () => {
|
|
104
|
+
// Query<Person>
|
|
105
|
+
const assigneesOfAllTasksCreatedAfter2020 = Query.select(
|
|
106
|
+
Filter.type(Task, { createdAt: Filter.gt('2020') }),
|
|
107
|
+
).reference('assignee');
|
|
108
|
+
|
|
109
|
+
log.info('query', { ast: assigneesOfAllTasksCreatedAfter2020.ast });
|
|
110
|
+
Schema.validateSync(QueryAST.Query)(assigneesOfAllTasksCreatedAfter2020.ast);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('contact full-text search', () => {
|
|
114
|
+
// Query<Person>
|
|
115
|
+
const contactFullTextSearch = Query.select(Filter.text(Person, 'Bill'));
|
|
116
|
+
|
|
117
|
+
log.info('query', { ast: contactFullTextSearch.ast });
|
|
118
|
+
Schema.validateSync(QueryAST.Query)(contactFullTextSearch.ast);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test.skip('chain', () => {
|
|
122
|
+
// NOTE: Can't support props without type since they can't be inferred.
|
|
123
|
+
// const f1: Filter<Person> = Filter.props({ name: 'Fred' });
|
|
124
|
+
|
|
125
|
+
// const x = Query.select(Filter.props({ id: '123' }));
|
|
126
|
+
const y = Query.select(Filter.type(Person));
|
|
127
|
+
|
|
128
|
+
const fOr = Filter.or(Filter.type(Person, { id: Filter.in('1', '2', '3') }), Filter.type(Org));
|
|
129
|
+
|
|
130
|
+
const fAnd = Filter.and(
|
|
131
|
+
Filter.type(Person, { id: Filter.in('1', '2', '3') }),
|
|
132
|
+
Filter.type(Person, { name: 'Fred' }),
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const q = Query
|
|
136
|
+
//
|
|
137
|
+
// NOTE: Can't support functions since they can't be serialized (to server).
|
|
138
|
+
// .filter((object) => Math.random() > 0.5)
|
|
139
|
+
.select(Filter.type(Person))
|
|
140
|
+
.select(Filter.type(Person, { name: 'Fred' }))
|
|
141
|
+
.select({ age: Filter.between(20, 40) })
|
|
142
|
+
.select(Filter.and(Filter.type(Person), Filter.type(Person, { name: Filter.in('bob', 'bill') })));
|
|
143
|
+
|
|
144
|
+
log.info('stuff', { fOr, fAnd, q, y });
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { EchoRelation, type RelationSourceTargetRefs } from '@dxos/echo-schema';
|
|
6
|
+
|
|
7
|
+
export const def = EchoRelation;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get relation target type.
|
|
11
|
+
*/
|
|
12
|
+
export type Target<A> = A extends RelationSourceTargetRefs<infer T, infer _S> ? T : never;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get relation source type.
|
|
16
|
+
*/
|
|
17
|
+
export type Source<A> = A extends RelationSourceTargetRefs<infer _T, infer S> ? S : never;
|
|
@@ -8,7 +8,7 @@ import { describe, test } from 'vitest';
|
|
|
8
8
|
import { raise } from '@dxos/debug';
|
|
9
9
|
import { FormatEnum, FormatAnnotation } from '@dxos/echo-schema';
|
|
10
10
|
|
|
11
|
-
import { Type } from './
|
|
11
|
+
import { Type } from './Type';
|
|
12
12
|
|
|
13
13
|
namespace Testing {
|
|
14
14
|
export const Organization = Schema.Struct({
|
|
@@ -37,14 +37,25 @@ namespace Testing {
|
|
|
37
37
|
|
|
38
38
|
export interface Person extends Schema.Schema.Type<typeof Person> {}
|
|
39
39
|
|
|
40
|
-
export const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
})
|
|
40
|
+
// export const WorksFor = S.Struct({
|
|
41
|
+
// id: Type.ObjectId,
|
|
42
|
+
// since: S.String,
|
|
43
|
+
// jobTitle: S.String,
|
|
44
|
+
// ...Range({ from, to }),
|
|
45
|
+
// ...Provenance({ source: 'duckduckgo.com', confidence: 0.9 }), // keys
|
|
46
|
+
// ...Relation.make({ source: Contact, target: Organization }),
|
|
47
|
+
// }).pipe(
|
|
48
|
+
// Relation.def({
|
|
49
|
+
// typename: 'example.com/relation/WorksFor',
|
|
50
|
+
// version: '0.1.0',
|
|
51
|
+
// }),
|
|
52
|
+
// );
|
|
53
|
+
|
|
54
|
+
// {
|
|
55
|
+
// const contact = db.add(create(Contact, { name: 'Test' }));
|
|
56
|
+
// const organization = db.add(create(Organization, { name: 'DXOS' }));
|
|
57
|
+
// db.add(create(WorksFor, { source: contact, target: organization }));
|
|
58
|
+
// }
|
|
48
59
|
|
|
49
60
|
export const WorksFor = Schema.Struct({
|
|
50
61
|
// id: Type.ObjectId,
|
|
@@ -61,13 +72,23 @@ namespace Testing {
|
|
|
61
72
|
|
|
62
73
|
export interface WorksFor extends Schema.Schema.Type<typeof WorksFor> {}
|
|
63
74
|
|
|
64
|
-
// TODO(burdon): Fix (Type.def currently removes TypeLiteral that implements the `make` function)
|
|
65
|
-
// }
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
// TODO(burdon): Fix (Type.def currently removes TypeLiteral that implements the `make` function).
|
|
76
|
+
// Property 'make' does not exist on type 'EchoObjectSchema<Struct<{ timestamp: PropertySignature<":", string, never, ":", string, true, never>; }>>'.ts(2339)
|
|
77
|
+
export const MessageStruct = Schema.Struct({
|
|
78
|
+
// TODO(burdon): Support S.Date; Custom Timestamp (with defaults).
|
|
79
|
+
// TODO(burdon): Support defaults (update create and create).
|
|
80
|
+
timestamp: Schema.String.pipe(
|
|
81
|
+
Schema.propertySignature,
|
|
82
|
+
Schema.withConstructorDefault(() => new Date().toISOString()),
|
|
83
|
+
),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export const Message = MessageStruct.pipe(
|
|
87
|
+
Type.def({
|
|
88
|
+
typename: 'example.com/type/Message',
|
|
89
|
+
version: '0.1.0',
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
71
92
|
|
|
72
93
|
export interface Message extends Schema.Schema.Type<typeof Message> {}
|
|
73
94
|
}
|
|
@@ -98,9 +119,7 @@ describe('Experimental API review', () => {
|
|
|
98
119
|
});
|
|
99
120
|
|
|
100
121
|
test('default props', ({ expect }) => {
|
|
101
|
-
|
|
102
|
-
// Property 'make' does not exist on type 'EchoObjectSchema<Struct<{ timestamp: PropertySignature<":", string, never, ":", string, true, never>; }>>'.ts(2339)
|
|
103
|
-
const message = Type.create(Testing.Message, Testing.Message.make({}));
|
|
122
|
+
const message = Type.create(Testing.Message, Testing.MessageStruct.make({}));
|
|
104
123
|
expect(message.timestamp).to.exist;
|
|
105
124
|
});
|
|
106
125
|
});
|
|
@@ -32,7 +32,7 @@ import { invariant } from '@dxos/invariant';
|
|
|
32
32
|
import { SpaceId as SpaceId$ } from '@dxos/keys';
|
|
33
33
|
import { live as live$ } from '@dxos/live-object';
|
|
34
34
|
|
|
35
|
-
// TODO(burdon): Type vs. Relation vs. Object.
|
|
35
|
+
// TODO(burdon): Type vs. Ref vs. Relation vs. Object.
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Type System API.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../../src/api/database.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,yBAAiB,QAAQ,CAAC,GAAE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAMjC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../../../src/api/queue.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,yBAAiB,KAAK,CAAC,GAAE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"space.d.ts","sourceRoot":"","sources":["../../../../src/api/space.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,MAAM,CAAC,OAAO,WAAW,KAAK,CAAC,GAAE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../../src/api/type.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,EAAE,KAAK,aAAa,IAAI,cAAc,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,UAAU,EAEf,UAAU,EACV,OAAO,IAAI,QAAQ,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,QAAQ,IAAI,SAAS,EACrB,GAAG,IAAI,IAAI,EAEX,KAAK,YAAY,EACjB,KAAK,QAAQ,EAQd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKjD;;;;;GAKG;AACH,yBAAiB,IAAI,CAAC;IAKb,MAAM,aAAa,wCAAiB,CAAC;IACrC,MAAM,OAAO;;;;;;MAAW,CAAC;IAChC,KAAY,OAAO,GAAG,QAAQ,CAAC;IAExB,MAAM,QAAQ,2CAAY,CAAC;IAClC,KAAY,QAAQ,GAAG,SAAS,CAAC;IAM1B,MAAM,IAAI,mBAAa,CAAC;IAC/B,KAAY,SAAS,GAAG,cAAc,CAAC;IACvC,KAAY,aAAa,CAAC,CAAC,SAAS,UAAU,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC;IAMpE,KAAY,UAAU,GAAG,cAAc,CAAC;IAExC;;OAEG;IACI,MAAM,OAAO,0CAAW,CAAC;IAChC,KAAY,OAAO,GAAG,QAAQ,CAAC;IAG/B,KAAY,QAAQ,CAAC,CAAC,GAAG,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC9C,KAAY,aAAa,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC;IAClD,KAAY,WAAW,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAY,UAAU,GAAG,YAAY,CAAC;IAE/B,MAAM,MAAM;;uCA7DX,OAAS,MAAK;KA6DK,CAAC;IAE5B;;;;;;;;;;;;;OAaG;IACI,MAAM,GAAG,SAAU,QAAQ,mBAqBuD,OAAQ,MAAM,CAEvG,GAAD,iEAvBwD,CAAC;IAMxD;;;;;;;;;;;;;;OAcG;IACI,MAAM,GAAG,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,YAAY,QAAQ,CAAC,4DAAsC,CAAC;IAEjG,MAAM,GAAG,sEAAY,CAAC;IAMtB,MAAM,OAAO,WApCD,OAClB,MAAI,CAAC,GAAG,2DAmC+B,CAAC;IAClC,MAAM,SAAS,gCA/GV,OAAQ,MAClB,CAAC,YAAY,YA8GoB,CAAC;IAC7B,MAAM,UAAU,kBAfL,OAAQ,MAAM,CAAC,YAChC,4CAGA,OACC,MAAM,CAAC,IAAI,QAUyB,CAAC;IAOhC,MAAM,MAAM,WA9Gb,OACN,MAAI,CAAC,GAAG,yCA6G0B,CAAC;IAC5B,MAAM,WAAW,WAAY,MAAM,CAAC,MAAM,CAAC,YAAY,KAAG,MAIhE,CAAC;IACK,MAAM,UAAU,WA5BtB,OAAI,MAAM,CAAC,GAAG,uBA4B2B,CAAC;IACpC,MAAM,YAAY,WAlHvB,OAAQ,MACV,CAAC,GAAG,mBAiHqC,CAAC;CAC3C"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api.test.d.ts","sourceRoot":"","sources":["../../../src/api.test.ts"],"names":[],"mappings":""}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|