@dxos/echo 0.8.3 → 0.8.4-main.1f223c7
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/README.md +1 -1
- package/dist/lib/browser/{chunk-UYPR62ZB.mjs → chunk-EIXXFUN5.mjs} +271 -56
- package/dist/lib/browser/chunk-EIXXFUN5.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +9 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +2 -2
- package/dist/lib/node-esm/{chunk-BYBICDIO.mjs → chunk-TCY7IVTS.mjs} +271 -56
- package/dist/lib/node-esm/chunk-TCY7IVTS.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +9 -1
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +2 -2
- package/dist/types/src/Obj.d.ts +102 -12
- package/dist/types/src/Obj.d.ts.map +1 -1
- package/dist/types/src/Ref.d.ts +2 -2
- package/dist/types/src/Relation.d.ts +6 -4
- package/dist/types/src/Relation.d.ts.map +1 -1
- package/dist/types/src/Type.d.ts +34 -33
- package/dist/types/src/Type.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +72 -0
- package/dist/types/src/errors.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/dsl.d.ts +27 -2
- package/dist/types/src/query/dsl.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +20 -13
- package/src/Obj.ts +206 -20
- package/src/Relation.ts +10 -8
- package/src/Type.ts +65 -50
- package/src/errors.ts +18 -0
- package/src/index.ts +4 -1
- package/src/query/dsl.test.ts +40 -1
- package/src/query/dsl.ts +112 -6
- package/src/test/api.test.ts +9 -2
- package/dist/lib/browser/chunk-UYPR62ZB.mjs.map +0 -7
- package/dist/lib/node/chunk-4HQE2F3L.cjs +0 -644
- package/dist/lib/node/chunk-4HQE2F3L.cjs.map +0 -7
- package/dist/lib/node/index.cjs +0 -43
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node/testing/index.cjs +0 -89
- package/dist/lib/node/testing/index.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-BYBICDIO.mjs.map +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/echo",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4-main.1f223c7",
|
|
4
4
|
"description": "ECHO API",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -10,31 +10,37 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
+
"source": "./src/index.ts",
|
|
13
14
|
"types": "./dist/types/src/index.d.ts",
|
|
14
15
|
"browser": "./dist/lib/browser/index.mjs",
|
|
15
16
|
"node": "./dist/lib/node-esm/index.mjs"
|
|
16
17
|
},
|
|
17
18
|
"./Type": {
|
|
19
|
+
"source": "./src/Type.ts",
|
|
18
20
|
"types": "./dist/types/src/Type.d.ts",
|
|
19
21
|
"browser": "./dist/lib/browser/Type.mjs",
|
|
20
22
|
"node": "./dist/lib/node-esm/Type.mjs"
|
|
21
23
|
},
|
|
22
24
|
"./Obj": {
|
|
25
|
+
"source": "./src/Obj.ts",
|
|
23
26
|
"types": "./dist/types/src/Obj.d.ts",
|
|
24
27
|
"browser": "./dist/lib/browser/Obj.mjs",
|
|
25
28
|
"node": "./dist/lib/node-esm/Obj.mjs"
|
|
26
29
|
},
|
|
27
30
|
"./Relation": {
|
|
31
|
+
"source": "./src/Relation.ts",
|
|
28
32
|
"types": "./dist/types/src/Relation.d.ts",
|
|
29
33
|
"browser": "./dist/lib/browser/Relation.mjs",
|
|
30
34
|
"node": "./dist/lib/node-esm/Relation.mjs"
|
|
31
35
|
},
|
|
32
36
|
"./Ref": {
|
|
37
|
+
"source": "./src/Ref.ts",
|
|
33
38
|
"types": "./dist/types/src/Ref.d.ts",
|
|
34
39
|
"browser": "./dist/lib/browser/Ref.mjs",
|
|
35
40
|
"node": "./dist/lib/node-esm/Ref.mjs"
|
|
36
41
|
},
|
|
37
42
|
"./testing": {
|
|
43
|
+
"source": "./src/testing/types.ts",
|
|
38
44
|
"types": "./dist/types/src/testing/types.d.ts",
|
|
39
45
|
"browser": "./dist/lib/browser/testing/index.mjs",
|
|
40
46
|
"node": "./dist/lib/node-esm/testing/index.mjs"
|
|
@@ -66,18 +72,19 @@
|
|
|
66
72
|
],
|
|
67
73
|
"dependencies": {
|
|
68
74
|
"@preact/signals-core": "^1.9.0",
|
|
69
|
-
"effect": "3.
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/echo-
|
|
73
|
-
"@dxos/echo-signals": "0.8.
|
|
74
|
-
"@dxos/effect": "0.8.
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/keys": "0.8.
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/
|
|
75
|
+
"effect": "3.17.7",
|
|
76
|
+
"@dxos/echo-protocol": "0.8.4-main.1f223c7",
|
|
77
|
+
"@dxos/debug": "0.8.4-main.1f223c7",
|
|
78
|
+
"@dxos/echo-schema": "0.8.4-main.1f223c7",
|
|
79
|
+
"@dxos/echo-signals": "0.8.4-main.1f223c7",
|
|
80
|
+
"@dxos/effect": "0.8.4-main.1f223c7",
|
|
81
|
+
"@dxos/errors": "0.8.4-main.1f223c7",
|
|
82
|
+
"@dxos/invariant": "0.8.4-main.1f223c7",
|
|
83
|
+
"@dxos/keys": "0.8.4-main.1f223c7",
|
|
84
|
+
"@dxos/live-object": "0.8.4-main.1f223c7",
|
|
85
|
+
"@dxos/log": "0.8.4-main.1f223c7",
|
|
86
|
+
"@dxos/node-std": "0.8.4-main.1f223c7",
|
|
87
|
+
"@dxos/util": "0.8.4-main.1f223c7"
|
|
81
88
|
},
|
|
82
89
|
"publishConfig": {
|
|
83
90
|
"access": "public"
|
package/src/Obj.ts
CHANGED
|
@@ -3,48 +3,65 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Schema } from 'effect';
|
|
6
|
+
import { dual } from 'effect/Function';
|
|
6
7
|
|
|
7
8
|
import * as EchoSchema from '@dxos/echo-schema';
|
|
8
9
|
import { assertArgument, invariant } from '@dxos/invariant';
|
|
9
10
|
import { type DXN } from '@dxos/keys';
|
|
10
|
-
import
|
|
11
|
+
import * as LiveObject from '@dxos/live-object';
|
|
11
12
|
import { live } from '@dxos/live-object';
|
|
12
|
-
import { assumeType } from '@dxos/util';
|
|
13
|
+
import { assumeType, deepMapValues } from '@dxos/util';
|
|
13
14
|
|
|
14
15
|
import type * as Ref from './Ref';
|
|
15
16
|
import type * as Relation from './Relation';
|
|
16
17
|
import type * as Type from './Type';
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
19
|
+
/**
|
|
20
|
+
* NOTE: Don't export: Obj.Any and Obj.Obj form the public API.
|
|
21
|
+
*/
|
|
22
|
+
interface BaseObj extends EchoSchema.HasId, Type.OfKind<EchoSchema.EntityKind.Object> {}
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Object type with specific properties.
|
|
25
26
|
*/
|
|
26
|
-
export type Obj<Props> =
|
|
27
|
+
export type Obj<Props> = BaseObj & Props;
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Base type for all ECHO objects.
|
|
30
31
|
*/
|
|
31
|
-
export interface Any extends
|
|
32
|
+
export interface Any extends BaseObj {}
|
|
33
|
+
|
|
34
|
+
type Props<T = any> = { id?: EchoSchema.ObjectId } & Type.Properties<T>;
|
|
35
|
+
|
|
36
|
+
export type MakeProps<T extends Type.Obj.Any> = NoInfer<Props<Schema.Schema.Type<T>>> & {
|
|
37
|
+
[Meta]?: Partial<EchoSchema.ObjectMeta>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const Meta: unique symbol = EchoSchema.MetaId as any;
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
id?: EchoSchema.ObjectId;
|
|
35
|
-
} & Type.Properties<T>;
|
|
42
|
+
// TODO(dmaretskyi): Expose Meta = EchoSchema.MetaId.
|
|
36
43
|
|
|
37
44
|
/**
|
|
38
45
|
* Creates new object.
|
|
46
|
+
* @param schema - Object schema.
|
|
47
|
+
* @param props - Object properties.
|
|
48
|
+
* @param meta - Object metadata (deprecated) -- pass with Obj.Meta.
|
|
49
|
+
*
|
|
50
|
+
* Meta can be passed as a symbol in `props`.
|
|
51
|
+
*
|
|
52
|
+
* Example:
|
|
53
|
+
* ```ts
|
|
54
|
+
* const obj = Obj.make(Person, { [Obj.Meta]: { keys: [...] }, name: 'John' });
|
|
55
|
+
* ```
|
|
39
56
|
*/
|
|
40
|
-
// TODO(dmaretskyi): Move meta into props.
|
|
41
57
|
export const make = <S extends Type.Obj.Any>(
|
|
42
58
|
schema: S,
|
|
43
|
-
props:
|
|
59
|
+
props: MakeProps<S>,
|
|
44
60
|
meta?: EchoSchema.ObjectMeta,
|
|
45
61
|
): LiveObject.Live<Schema.Schema.Type<S>> => {
|
|
46
62
|
assertArgument(
|
|
47
63
|
EchoSchema.getTypeAnnotation(schema)?.kind === EchoSchema.EntityKind.Object,
|
|
64
|
+
'schema',
|
|
48
65
|
'Expected an object schema',
|
|
49
66
|
);
|
|
50
67
|
|
|
@@ -90,8 +107,8 @@ export const instanceOf: {
|
|
|
90
107
|
export const getSchema = EchoSchema.getSchema;
|
|
91
108
|
|
|
92
109
|
// TODO(dmaretskyi): Allow returning undefined.
|
|
93
|
-
export const getDXN = (obj: Any): DXN => {
|
|
94
|
-
assertArgument(!Schema.isSchema(obj), 'Object should not be a schema.');
|
|
110
|
+
export const getDXN = (obj: Any | Relation.Any): DXN => {
|
|
111
|
+
assertArgument(!Schema.isSchema(obj), 'obj', 'Object should not be a schema.');
|
|
95
112
|
const dxn = EchoSchema.getObjectDXN(obj);
|
|
96
113
|
invariant(dxn != null, 'Invalid object.');
|
|
97
114
|
return dxn;
|
|
@@ -108,7 +125,7 @@ export const getTypeDXN = EchoSchema.getType;
|
|
|
108
125
|
* @returns The typename of the object's type.
|
|
109
126
|
* @example `example.com/type/Contact`
|
|
110
127
|
*/
|
|
111
|
-
export const getTypename = (obj: Any): string | undefined => {
|
|
128
|
+
export const getTypename = (obj: Any | Relation.Any): string | undefined => {
|
|
112
129
|
const schema = getSchema(obj);
|
|
113
130
|
if (schema == null) {
|
|
114
131
|
// Try to extract typename from DXN.
|
|
@@ -119,26 +136,61 @@ export const getTypename = (obj: Any): string | undefined => {
|
|
|
119
136
|
};
|
|
120
137
|
|
|
121
138
|
// TODO(dmaretskyi): Allow returning undefined.
|
|
122
|
-
export const getMeta = (obj: Any): EchoSchema.ObjectMeta => {
|
|
139
|
+
export const getMeta = (obj: Any | Relation.Any): EchoSchema.ObjectMeta => {
|
|
123
140
|
const meta = EchoSchema.getMeta(obj);
|
|
124
141
|
invariant(meta != null, 'Invalid object.');
|
|
125
142
|
return meta;
|
|
126
143
|
};
|
|
127
144
|
|
|
145
|
+
/**
|
|
146
|
+
* @returns Foreign keys for the object from the specified source.
|
|
147
|
+
*/
|
|
148
|
+
export const getKeys: {
|
|
149
|
+
(obj: Any | Relation.Any, source: string): EchoSchema.ForeignKey[];
|
|
150
|
+
(source: string): (obj: Any | Relation.Any) => EchoSchema.ForeignKey[];
|
|
151
|
+
} = dual(2, (obj: Any | Relation.Any, source?: string): EchoSchema.ForeignKey[] => {
|
|
152
|
+
const meta = EchoSchema.getMeta(obj);
|
|
153
|
+
invariant(meta != null, 'Invalid object.');
|
|
154
|
+
return meta.keys.filter((key) => key.source === source);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Delete all keys from the object for the specified source.
|
|
159
|
+
* @param obj
|
|
160
|
+
* @param source
|
|
161
|
+
*/
|
|
162
|
+
export const deleteKeys = (obj: Any | Relation.Any, source: string) => {
|
|
163
|
+
const meta = EchoSchema.getMeta(obj);
|
|
164
|
+
for (let i = 0; i < meta.keys.length; i++) {
|
|
165
|
+
if (meta.keys[i].source === source) {
|
|
166
|
+
meta.keys.splice(i, 1);
|
|
167
|
+
i--;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
128
172
|
// TODO(dmaretskyi): Default to `false`.
|
|
129
|
-
export const isDeleted = (obj: Any): boolean => {
|
|
173
|
+
export const isDeleted = (obj: Any | Relation.Any): boolean => {
|
|
130
174
|
const deleted = EchoSchema.isDeleted(obj);
|
|
131
175
|
invariant(typeof deleted === 'boolean', 'Invalid object.');
|
|
132
176
|
return deleted;
|
|
133
177
|
};
|
|
134
178
|
|
|
135
|
-
|
|
179
|
+
// TODO(burdon): Rename "label"
|
|
180
|
+
export const getLabel = (obj: Any | Relation.Any): string | undefined => {
|
|
136
181
|
const schema = getSchema(obj);
|
|
137
182
|
if (schema != null) {
|
|
138
183
|
return EchoSchema.getLabel(schema, obj);
|
|
139
184
|
}
|
|
140
185
|
};
|
|
141
186
|
|
|
187
|
+
export const setLabel = (obj: Any | Relation.Any, label: string) => {
|
|
188
|
+
const schema = getSchema(obj);
|
|
189
|
+
if (schema != null) {
|
|
190
|
+
EchoSchema.setLabel(schema, obj, label);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
142
194
|
/**
|
|
143
195
|
* JSON representation of an object.
|
|
144
196
|
*/
|
|
@@ -149,6 +201,7 @@ export type JSON = EchoSchema.ObjectJSON;
|
|
|
149
201
|
*
|
|
150
202
|
* The same algorithm is used when calling the standard `JSON.stringify(obj)` function.
|
|
151
203
|
*/
|
|
204
|
+
// TODO(burdon): Base util type for Obj/Relation?
|
|
152
205
|
export const toJSON = (obj: Any | Relation.Any): JSON => EchoSchema.objectToJSON(obj);
|
|
153
206
|
|
|
154
207
|
/**
|
|
@@ -156,6 +209,139 @@ export const toJSON = (obj: Any | Relation.Any): JSON => EchoSchema.objectToJSON
|
|
|
156
209
|
* References and schemas will be resolvable if the `refResolver` is provided.
|
|
157
210
|
*
|
|
158
211
|
* The function need to be async to support resolving the schema as well as the relation endpoints.
|
|
212
|
+
*
|
|
213
|
+
* @param options.refResolver - Resolver for references. Produces hydrated references that can be resolved.
|
|
214
|
+
* @param options.dxn - Override object DXN. Changes the result of `Obj.getDXN`.
|
|
159
215
|
*/
|
|
160
|
-
export const fromJSON: (json: unknown, options?: { refResolver?: Ref.Resolver }) => Promise<Any> =
|
|
216
|
+
export const fromJSON: (json: unknown, options?: { refResolver?: Ref.Resolver; dxn?: DXN }) => Promise<Any> =
|
|
161
217
|
EchoSchema.objectFromJSON as any;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Returns an immutable snapshot of an object.
|
|
221
|
+
*/
|
|
222
|
+
export const getSnapshot: <T extends Any>(obj: Obj<T>) => T = LiveObject.getSnapshot;
|
|
223
|
+
|
|
224
|
+
export type CloneOptions = {
|
|
225
|
+
/**
|
|
226
|
+
* Retain the original object's ID.
|
|
227
|
+
* @default false
|
|
228
|
+
*/
|
|
229
|
+
retainId?: boolean;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Clones an object or relation.
|
|
234
|
+
* This does not clone referenced objects, only the properties in the object.
|
|
235
|
+
* @returns A new object with the same schema and properties.
|
|
236
|
+
*/
|
|
237
|
+
export const clone = <T extends Any | Relation.Any>(obj: T, opts?: CloneOptions): T => {
|
|
238
|
+
const { id, ...data } = obj;
|
|
239
|
+
const schema = getSchema(obj);
|
|
240
|
+
invariant(schema != null, 'Object should have a schema');
|
|
241
|
+
const props: any = deepMapValues(data, (value, recurse) => {
|
|
242
|
+
if (EchoSchema.Ref.isRef(value)) {
|
|
243
|
+
return value;
|
|
244
|
+
}
|
|
245
|
+
return recurse(value);
|
|
246
|
+
});
|
|
247
|
+
if (opts?.retainId) {
|
|
248
|
+
props.id = id;
|
|
249
|
+
}
|
|
250
|
+
const meta = getMeta(obj);
|
|
251
|
+
props[EchoSchema.MetaId] = deepMapValues(meta, (value, recurse) => {
|
|
252
|
+
if (EchoSchema.Ref.isRef(value)) {
|
|
253
|
+
return value;
|
|
254
|
+
}
|
|
255
|
+
return recurse(value);
|
|
256
|
+
});
|
|
257
|
+
return make(schema, props);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
export const VersionTypeId = EchoSchema.VersionTypeId;
|
|
261
|
+
export type VersionType = typeof VersionTypeId;
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Represent object version.
|
|
265
|
+
* May be backed by Automerge.
|
|
266
|
+
* Objects with no history are not versioned.
|
|
267
|
+
*/
|
|
268
|
+
export interface Version {
|
|
269
|
+
[VersionTypeId]: {};
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Whether the object is versioned.
|
|
273
|
+
*/
|
|
274
|
+
versioned: boolean;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Automerge heads.
|
|
278
|
+
*/
|
|
279
|
+
automergeHeads?: string[];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const unversioned: Version = {
|
|
283
|
+
[VersionTypeId]: {},
|
|
284
|
+
versioned: false,
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Checks that `obj` is a version object.
|
|
289
|
+
*/
|
|
290
|
+
export const isVersion = (obj: unknown): obj is Version => {
|
|
291
|
+
return obj != null && typeof obj === 'object' && VersionTypeId in obj;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Returns the version of the object.
|
|
296
|
+
*/
|
|
297
|
+
export const version = (obj: Any | Relation.Any): Version => {
|
|
298
|
+
const version = (obj as any)[EchoSchema.ObjectVersionId];
|
|
299
|
+
if (version === undefined) {
|
|
300
|
+
return unversioned;
|
|
301
|
+
}
|
|
302
|
+
return version;
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Checks that `version` is a valid version object.
|
|
307
|
+
*/
|
|
308
|
+
export const versionValid = (version: Version): boolean => {
|
|
309
|
+
assertArgument(isVersion(version), 'version', 'Invalid version object');
|
|
310
|
+
return !!version.versioned;
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
export type VersionCompareResult = 'unversioned' | 'equal' | 'different';
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Compares two versions.
|
|
317
|
+
* @param version1
|
|
318
|
+
* @param version2
|
|
319
|
+
* @returns 'unversioned' if either object is unversioned, 'equal' if the versions are equal, 'different' if the versions are different.
|
|
320
|
+
*/
|
|
321
|
+
export const compareVersions = (version1: Version, version2: Version): VersionCompareResult => {
|
|
322
|
+
assertArgument(isVersion(version1), 'version1', 'Invalid version object');
|
|
323
|
+
assertArgument(isVersion(version2), 'version2', 'Invalid version object');
|
|
324
|
+
|
|
325
|
+
if (!versionValid(version1) || !versionValid(version2)) {
|
|
326
|
+
return 'unversioned';
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (version1.automergeHeads?.length !== version2.automergeHeads?.length) {
|
|
330
|
+
return 'different';
|
|
331
|
+
}
|
|
332
|
+
if (version1.automergeHeads?.some((head) => !version2.automergeHeads?.includes(head))) {
|
|
333
|
+
return 'different';
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return 'equal';
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
export const encodeVersion = (version: Version): string => {
|
|
340
|
+
return JSON.stringify(version);
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
export const decodeVersion = (version: string): Version => {
|
|
344
|
+
const parsed = JSON.parse(version);
|
|
345
|
+
parsed[VersionTypeId] = {};
|
|
346
|
+
return parsed;
|
|
347
|
+
};
|
package/src/Relation.ts
CHANGED
|
@@ -14,22 +14,23 @@ import { assumeType } from '@dxos/util';
|
|
|
14
14
|
import type * as Obj from './Obj';
|
|
15
15
|
import type * as Type from './Type';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
/**
|
|
18
|
+
* NOTE: Don't export: Relation.Relation and Relation.Any form the public API.
|
|
19
|
+
*/
|
|
20
|
+
interface BaseRelation<Source, Target>
|
|
21
|
+
extends EchoSchema.HasId,
|
|
22
|
+
Type.Relation.Endpoints<Source, Target>,
|
|
23
|
+
Type.OfKind<EchoSchema.EntityKind.Relation> {}
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Relation type with specific properties.
|
|
26
27
|
*/
|
|
27
|
-
export type Relation<Source extends Obj.Any, Target extends Obj.Any, Props> =
|
|
28
|
+
export type Relation<Source extends Obj.Any, Target extends Obj.Any, Props> = BaseRelation<Source, Target> & Props;
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Base type for all ECHO relations.
|
|
31
32
|
*/
|
|
32
|
-
export interface Any extends
|
|
33
|
+
export interface Any extends BaseRelation<Obj.Any, Obj.Any> {}
|
|
33
34
|
|
|
34
35
|
// TODO(dmaretskyi): Has to be `unique symbol`.
|
|
35
36
|
export const Source: unique symbol = EchoSchema.RelationSourceId as any;
|
|
@@ -59,6 +60,7 @@ export const make = <S extends Type.Relation.Any>(
|
|
|
59
60
|
): Live<Schema.Schema.Type<S> & Type.OfKind<EchoSchema.EntityKind.Relation>> => {
|
|
60
61
|
assertArgument(
|
|
61
62
|
EchoSchema.getTypeAnnotation(schema)?.kind === EchoSchema.EntityKind.Relation,
|
|
63
|
+
'schema',
|
|
62
64
|
'Expected a relation schema',
|
|
63
65
|
);
|
|
64
66
|
|
package/src/Type.ts
CHANGED
|
@@ -3,20 +3,24 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Schema } from 'effect';
|
|
6
|
-
import type
|
|
6
|
+
import { type Simplify } from 'effect/Schema';
|
|
7
7
|
|
|
8
|
-
import type
|
|
8
|
+
import { type EncodedReference } from '@dxos/echo-protocol';
|
|
9
9
|
import * as EchoSchema from '@dxos/echo-schema';
|
|
10
|
-
import type
|
|
10
|
+
import { type ToMutable } from '@dxos/echo-schema';
|
|
11
11
|
import { invariant } from '@dxos/invariant';
|
|
12
12
|
import type * as Keys from '@dxos/keys';
|
|
13
13
|
|
|
14
14
|
import type * as RelationModule from './Relation';
|
|
15
15
|
|
|
16
|
+
//
|
|
17
|
+
// Kind
|
|
18
|
+
//
|
|
19
|
+
|
|
16
20
|
export const KindId: unique symbol = EchoSchema.EntityKindId as any;
|
|
17
21
|
export type KindId = typeof KindId;
|
|
18
22
|
|
|
19
|
-
export
|
|
23
|
+
export const Kind = EchoSchema.EntityKind;
|
|
20
24
|
|
|
21
25
|
/**
|
|
22
26
|
* Assigns a kind to an Object or Relation instance.
|
|
@@ -27,25 +31,23 @@ export interface OfKind<Kind extends EchoSchema.EntityKind> {
|
|
|
27
31
|
readonly [KindId]: Kind;
|
|
28
32
|
}
|
|
29
33
|
|
|
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
34
|
/**
|
|
41
|
-
*
|
|
35
|
+
* Base ECHO schema type.
|
|
42
36
|
*/
|
|
43
|
-
export type
|
|
37
|
+
export type Schema = EchoSchema.EchoSchema;
|
|
44
38
|
|
|
45
39
|
/**
|
|
46
|
-
*
|
|
40
|
+
* Returns all properties of an object or relation except for the id and kind.
|
|
47
41
|
*/
|
|
48
|
-
export type
|
|
42
|
+
export type Properties<T = any> = Omit<T, 'id' | KindId | RelationModule.Source | RelationModule.Target>;
|
|
43
|
+
|
|
44
|
+
//
|
|
45
|
+
// Obj
|
|
46
|
+
//
|
|
47
|
+
|
|
48
|
+
interface ObjJsonProps {
|
|
49
|
+
id: string;
|
|
50
|
+
}
|
|
49
51
|
|
|
50
52
|
/**
|
|
51
53
|
* Return type of the `Obj` schema constructor.
|
|
@@ -54,13 +56,13 @@ export type Schema = EchoSchema.EchoSchema;
|
|
|
54
56
|
* See Effect's note on interface types.
|
|
55
57
|
*/
|
|
56
58
|
export interface obj<Self extends Schema.Schema.Any>
|
|
57
|
-
extends
|
|
59
|
+
extends EchoSchema.TypeMeta,
|
|
60
|
+
Schema.AnnotableClass<
|
|
58
61
|
obj<Self>,
|
|
59
62
|
OfKind<EchoSchema.EntityKind.Object> & ToMutable<Schema.Schema.Type<Self>>,
|
|
60
63
|
Simplify<ObjJsonProps & ToMutable<Schema.Schema.Encoded<Self>>>,
|
|
61
64
|
Schema.Schema.Context<Self>
|
|
62
|
-
|
|
63
|
-
EchoSchema.TypeMeta {}
|
|
65
|
+
> {}
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
68
|
* Object schema.
|
|
@@ -78,9 +80,33 @@ export namespace Obj {
|
|
|
78
80
|
* NOTE: This is not an instance type.
|
|
79
81
|
*/
|
|
80
82
|
// TODO(dmaretskyi): If schema was covariant, we could specify props in here, like `id: ObjectId`.
|
|
83
|
+
// TODO(burdon): This erases the ECHO type info (e.g., id, typename).
|
|
81
84
|
export type Any = Schema.Schema.AnyNoContext;
|
|
82
85
|
}
|
|
83
86
|
|
|
87
|
+
//
|
|
88
|
+
// Expando
|
|
89
|
+
//
|
|
90
|
+
|
|
91
|
+
// TODO(burdon): We're using Expando in many places as a base type.
|
|
92
|
+
export interface Expando extends OfKind<EchoSchema.EntityKind.Object> {
|
|
93
|
+
[key: string]: any;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
type ExpandoEncoded = Simplify<ObjJsonProps & { [key: string]: any }>;
|
|
97
|
+
|
|
98
|
+
export const Expando: Schema.Schema<Expando, ExpandoEncoded, never> = EchoSchema.Expando as any;
|
|
99
|
+
|
|
100
|
+
//
|
|
101
|
+
// Relation
|
|
102
|
+
//
|
|
103
|
+
|
|
104
|
+
interface RelationJsonProps {
|
|
105
|
+
id: string;
|
|
106
|
+
[EchoSchema.ATTR_RELATION_SOURCE]: string;
|
|
107
|
+
[EchoSchema.ATTR_RELATION_TARGET]: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
84
110
|
/**
|
|
85
111
|
* Return type of the `Relation` schema constructor.
|
|
86
112
|
*
|
|
@@ -91,15 +117,15 @@ export interface relation<
|
|
|
91
117
|
Self extends Schema.Schema.Any,
|
|
92
118
|
SourceSchema extends Schema.Schema.Any,
|
|
93
119
|
TargetSchema extends Schema.Schema.Any,
|
|
94
|
-
> extends
|
|
120
|
+
> extends EchoSchema.TypeMeta,
|
|
121
|
+
Schema.AnnotableClass<
|
|
95
122
|
relation<Self, SourceSchema, TargetSchema>,
|
|
96
123
|
OfKind<EchoSchema.EntityKind.Relation> &
|
|
97
124
|
Relation.Endpoints<Schema.Schema.Type<SourceSchema>, Schema.Schema.Type<TargetSchema>> &
|
|
98
125
|
ToMutable<Schema.Schema.Type<Self>>,
|
|
99
126
|
Simplify<RelationJsonProps & ToMutable<Schema.Schema.Encoded<Self>>>,
|
|
100
127
|
Schema.Schema.Context<Self>
|
|
101
|
-
|
|
102
|
-
EchoSchema.TypeMeta {}
|
|
128
|
+
> {}
|
|
103
129
|
|
|
104
130
|
/**
|
|
105
131
|
* Relation schema.
|
|
@@ -123,14 +149,14 @@ export namespace Relation {
|
|
|
123
149
|
export type Any = Schema.Schema.AnyNoContext;
|
|
124
150
|
|
|
125
151
|
/**
|
|
126
|
-
* Get relation
|
|
152
|
+
* Get relation source type.
|
|
127
153
|
*/
|
|
128
|
-
export type
|
|
154
|
+
export type Source<A> = A extends Relation.Endpoints<infer S, infer _T> ? S : never;
|
|
129
155
|
|
|
130
156
|
/**
|
|
131
|
-
* Get relation
|
|
157
|
+
* Get relation target type.
|
|
132
158
|
*/
|
|
133
|
-
export type
|
|
159
|
+
export type Target<A> = A extends Relation.Endpoints<infer _S, infer T> ? T : never;
|
|
134
160
|
|
|
135
161
|
export type Endpoints<Source, Target> = {
|
|
136
162
|
[RelationModule.Source]: Source;
|
|
@@ -138,6 +164,10 @@ export namespace Relation {
|
|
|
138
164
|
};
|
|
139
165
|
}
|
|
140
166
|
|
|
167
|
+
//
|
|
168
|
+
// Ref
|
|
169
|
+
//
|
|
170
|
+
|
|
141
171
|
/**
|
|
142
172
|
* Return type of the `Ref` schema constructor.
|
|
143
173
|
*
|
|
@@ -193,6 +223,11 @@ export const getVersion = (schema: Obj.Any | Relation.Any): string => {
|
|
|
193
223
|
return version;
|
|
194
224
|
};
|
|
195
225
|
|
|
226
|
+
/**
|
|
227
|
+
* @returns True if the schema is mutable.
|
|
228
|
+
*/
|
|
229
|
+
export const isMutable = EchoSchema.isMutable;
|
|
230
|
+
|
|
196
231
|
/**
|
|
197
232
|
* ECHO type metadata.
|
|
198
233
|
*/
|
|
@@ -205,27 +240,7 @@ export const getMeta = (schema: Obj.Any | Relation.Any): Meta | undefined => {
|
|
|
205
240
|
return EchoSchema.getTypeAnnotation(schema);
|
|
206
241
|
};
|
|
207
242
|
|
|
208
|
-
|
|
209
|
-
* @returns True if the schema is mutable.
|
|
210
|
-
*/
|
|
211
|
-
export const isMutable = EchoSchema.isMutable;
|
|
212
|
-
|
|
243
|
+
// TODO(dmaretskyi): Remove re-exports.
|
|
213
244
|
export { SpaceId, ObjectId, DXN } from '@dxos/keys';
|
|
214
245
|
|
|
215
|
-
export
|
|
216
|
-
[key: string]: any;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export const Expando: Schema.Schema<
|
|
220
|
-
Expando,
|
|
221
|
-
Simplify<ObjJsonProps & { [key: string]: any }>,
|
|
222
|
-
never
|
|
223
|
-
> = EchoSchema.Expando as any;
|
|
224
|
-
|
|
225
|
-
export {
|
|
226
|
-
// TODO(burdon): Standardize.
|
|
227
|
-
Format,
|
|
228
|
-
JsonSchemaType as JsonSchema,
|
|
229
|
-
toEffectSchema,
|
|
230
|
-
toJsonSchema,
|
|
231
|
-
} from '@dxos/echo-schema';
|
|
246
|
+
export { Format, JsonSchemaType as JsonSchema, toEffectSchema, toJsonSchema } from '@dxos/echo-schema';
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { BaseError, type BaseErrorOptions } from '@dxos/errors';
|
|
6
|
+
import { type DXN } from '@dxos/keys';
|
|
7
|
+
|
|
8
|
+
export class SchemaNotFoundError extends BaseError.extend('SCHEMA_NOT_FOUND', 'Schema not found') {
|
|
9
|
+
constructor(schema: string, options?: BaseErrorOptions) {
|
|
10
|
+
super({ context: { schema }, ...options });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class ObjectNotFoundError extends BaseError.extend('OBJECT_NOT_FOUND', 'Object not found') {
|
|
15
|
+
constructor(dxn: DXN, options?: BaseErrorOptions) {
|
|
16
|
+
super({ context: { dxn }, ...options });
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
export * from './errors';
|
|
6
|
+
|
|
5
7
|
export * as Key from './Key';
|
|
6
8
|
export * as Obj from './Obj';
|
|
7
9
|
export * as Ref from './Ref';
|
|
@@ -9,5 +11,6 @@ export * as Relation from './Relation';
|
|
|
9
11
|
export * as Type from './Type';
|
|
10
12
|
|
|
11
13
|
export { DXN } from '@dxos/keys';
|
|
12
|
-
export { Filter, Query } from './query';
|
|
14
|
+
export { Filter, Order, Query } from './query';
|
|
15
|
+
export { QueryAST } from '@dxos/echo-protocol';
|
|
13
16
|
export { type Live } from '@dxos/live-object';
|