@dxos/echo-generator 0.8.2-staging.7ac8446 → 0.8.2
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 +83 -76
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +81 -74
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +83 -76
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/data.d.ts +13 -4
- package/dist/types/src/data.d.ts.map +1 -1
- package/dist/types/src/generator.d.ts +14 -12
- package/dist/types/src/generator.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +7 -6
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -12
- package/src/data.ts +56 -64
- package/src/generator.test.ts +35 -7
- package/src/generator.ts +27 -18
- package/src/types.ts +8 -6
package/src/data.ts
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { next as A } from '@
|
|
5
|
+
import { next as A } from '@automerge/automerge';
|
|
6
|
+
import { Schema } from 'effect';
|
|
7
|
+
|
|
6
8
|
import { createDocAccessor, type Space } from '@dxos/client/echo';
|
|
7
|
-
import {
|
|
8
|
-
import { createEchoSchema, makeRef } from '@dxos/live-object';
|
|
9
|
+
import { EchoObject, Ref } from '@dxos/echo-schema';
|
|
9
10
|
import { faker } from '@dxos/random';
|
|
10
11
|
|
|
11
12
|
import { SpaceObjectGenerator, TestObjectGenerator } from './generator';
|
|
@@ -19,67 +20,49 @@ import { randomText } from './util';
|
|
|
19
20
|
export const Status = ['pending', 'active', 'done'];
|
|
20
21
|
export const Priority = [1, 2, 3, 4, 5];
|
|
21
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated
|
|
25
|
+
*/
|
|
22
26
|
export enum TestSchemaType {
|
|
23
|
-
document = 'example.com/type/
|
|
24
|
-
organization = 'example.com/type/
|
|
25
|
-
contact = 'example.com/type/
|
|
26
|
-
project = 'example.com/type/
|
|
27
|
+
document = 'example.com/type/Document',
|
|
28
|
+
organization = 'example.com/type/Organization',
|
|
29
|
+
contact = 'example.com/type/Contact',
|
|
30
|
+
project = 'example.com/type/Project',
|
|
27
31
|
}
|
|
28
32
|
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated
|
|
35
|
+
*/
|
|
29
36
|
const testSchemas = (): TestSchemaMap<TestSchemaType> => {
|
|
30
|
-
const document =
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
},
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
name: S.String.annotations({ description: 'name of the person' }),
|
|
60
|
-
email: S.String,
|
|
61
|
-
org: Ref(organization),
|
|
62
|
-
lat: S.Number,
|
|
63
|
-
lng: S.Number,
|
|
64
|
-
},
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const project = createEchoSchema(
|
|
68
|
-
{
|
|
69
|
-
typename: TestSchemaType.project,
|
|
70
|
-
version: '0.1.0',
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
name: S.String.annotations({ description: 'name of the project' }),
|
|
74
|
-
description: S.String,
|
|
75
|
-
website: S.String,
|
|
76
|
-
repo: S.String,
|
|
77
|
-
status: S.String,
|
|
78
|
-
priority: S.Number,
|
|
79
|
-
active: S.Boolean,
|
|
80
|
-
org: Ref(organization),
|
|
81
|
-
},
|
|
82
|
-
);
|
|
37
|
+
const document = Schema.Struct({
|
|
38
|
+
title: Schema.String.annotations({ description: 'title of the document' }),
|
|
39
|
+
content: Schema.String,
|
|
40
|
+
}).pipe(EchoObject({ typename: TestSchemaType.document, version: '0.1.0' }));
|
|
41
|
+
|
|
42
|
+
const organization = Schema.Struct({
|
|
43
|
+
name: Schema.String.annotations({ description: 'name of the company or organization' }),
|
|
44
|
+
website: Schema.optional(Schema.String.annotations({ description: 'public website URL' })),
|
|
45
|
+
description: Schema.String.annotations({ description: 'short summary of the company' }),
|
|
46
|
+
}).pipe(EchoObject({ typename: TestSchemaType.organization, version: '0.1.0' }));
|
|
47
|
+
|
|
48
|
+
const contact = Schema.Struct({
|
|
49
|
+
name: Schema.String.annotations({ description: 'name of the person' }),
|
|
50
|
+
email: Schema.optional(Schema.String),
|
|
51
|
+
org: Schema.optional(Ref(organization)),
|
|
52
|
+
lat: Schema.optional(Schema.Number),
|
|
53
|
+
lng: Schema.optional(Schema.Number),
|
|
54
|
+
}).pipe(EchoObject({ typename: TestSchemaType.contact, version: '0.1.0' }));
|
|
55
|
+
|
|
56
|
+
const project = Schema.Struct({
|
|
57
|
+
name: Schema.String.annotations({ description: 'name of the project' }),
|
|
58
|
+
description: Schema.String,
|
|
59
|
+
website: Schema.String,
|
|
60
|
+
repo: Schema.String,
|
|
61
|
+
status: Schema.String,
|
|
62
|
+
priority: Schema.Number,
|
|
63
|
+
active: Schema.Boolean,
|
|
64
|
+
org: Schema.optional(Ref(organization)),
|
|
65
|
+
}).pipe(EchoObject({ typename: TestSchemaType.project, version: '0.1.0' }));
|
|
83
66
|
|
|
84
67
|
return {
|
|
85
68
|
[TestSchemaType.document]: document,
|
|
@@ -103,13 +86,14 @@ const testObjectGenerators: TestGeneratorMap<TestSchemaType> = {
|
|
|
103
86
|
|
|
104
87
|
[TestSchemaType.contact]: async (provider) => {
|
|
105
88
|
const organizations = await provider?.(TestSchemaType.organization);
|
|
106
|
-
const
|
|
89
|
+
const location = faker.datatype.boolean() ? faker.geo.airport() : {};
|
|
90
|
+
|
|
107
91
|
return {
|
|
108
92
|
name: faker.person.fullName(),
|
|
109
93
|
email: faker.datatype.boolean({ probability: 0.5 }) ? faker.internet.email() : undefined,
|
|
110
94
|
org:
|
|
111
|
-
organizations?.length && faker.datatype.boolean({ probability: 0.
|
|
112
|
-
?
|
|
95
|
+
organizations?.length && faker.datatype.boolean({ probability: 0.8 })
|
|
96
|
+
? Ref.make(faker.helpers.arrayElement(organizations))
|
|
113
97
|
: undefined,
|
|
114
98
|
...location,
|
|
115
99
|
};
|
|
@@ -117,8 +101,10 @@ const testObjectGenerators: TestGeneratorMap<TestSchemaType> = {
|
|
|
117
101
|
|
|
118
102
|
[TestSchemaType.project]: async () => ({
|
|
119
103
|
name: faker.commerce.productName(),
|
|
120
|
-
repo: faker.
|
|
104
|
+
repo: faker.internet.url(),
|
|
121
105
|
status: faker.helpers.arrayElement(Status),
|
|
106
|
+
description: faker.lorem.sentences(),
|
|
107
|
+
website: faker.internet.url(),
|
|
122
108
|
priority: faker.helpers.arrayElement(Priority),
|
|
123
109
|
active: faker.datatype.boolean(),
|
|
124
110
|
}),
|
|
@@ -151,7 +137,13 @@ const testObjectMutators: TestMutationsMap<TestSchemaType> = {
|
|
|
151
137
|
},
|
|
152
138
|
};
|
|
153
139
|
|
|
140
|
+
/**
|
|
141
|
+
* @deprecated Use generators in schema package.
|
|
142
|
+
*/
|
|
154
143
|
export const createTestObjectGenerator = () => new TestObjectGenerator(testSchemas(), testObjectGenerators);
|
|
155
144
|
|
|
145
|
+
/**
|
|
146
|
+
* @deprecated Use generators in schema package.
|
|
147
|
+
*/
|
|
156
148
|
export const createSpaceObjectGenerator = (space: Space) =>
|
|
157
149
|
new SpaceObjectGenerator(space, testSchemas(), testObjectGenerators, testObjectMutators);
|
package/src/generator.test.ts
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { next as A } from '@automerge/automerge';
|
|
6
|
+
import { Schema } from 'effect';
|
|
5
7
|
import { describe, expect, onTestFinished, test } from 'vitest';
|
|
6
8
|
|
|
7
|
-
import { next as A } from '@dxos/automerge/automerge';
|
|
8
9
|
import { Client } from '@dxos/client';
|
|
9
10
|
import { getObjectCore } from '@dxos/echo-db';
|
|
10
|
-
import {
|
|
11
|
+
import { TypedObject } from '@dxos/echo-schema';
|
|
11
12
|
import { getType } from '@dxos/live-object';
|
|
12
13
|
import { faker } from '@dxos/random';
|
|
13
14
|
|
|
@@ -59,14 +60,14 @@ describe('TestObjectGenerator', () => {
|
|
|
59
60
|
const generator = createSpaceObjectGenerator(space);
|
|
60
61
|
await generator.addSchemas();
|
|
61
62
|
const organization = await generator.createObject({ types: [TestSchemaType.organization] });
|
|
62
|
-
schemaId.push(getType(organization)!.
|
|
63
|
+
schemaId.push(getType(organization)!.toString());
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
{
|
|
66
67
|
const generator = createSpaceObjectGenerator(space);
|
|
67
68
|
await generator.addSchemas();
|
|
68
69
|
const organization = await generator.createObject({ types: [TestSchemaType.organization] });
|
|
69
|
-
schemaId.push(getType(organization)!.
|
|
70
|
+
schemaId.push(getType(organization)!.toString());
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
expect(schemaId[0]).not.to.be.undefined;
|
|
@@ -80,14 +81,14 @@ describe('TestObjectGenerator', () => {
|
|
|
80
81
|
const document = await generator.createObject({ types: [TestSchemaType.document] });
|
|
81
82
|
expect(getType(document)).to.exist;
|
|
82
83
|
|
|
83
|
-
const beforeChangesCount = A.getAllChanges(getObjectCore(document).docHandle!.
|
|
84
|
+
const beforeChangesCount = A.getAllChanges(getObjectCore(document).docHandle!.doc()).length;
|
|
84
85
|
|
|
85
86
|
// Mutate the document.
|
|
86
87
|
const mutationsCount = 10;
|
|
87
88
|
await generator.mutateObject(document, { count: mutationsCount, maxContentLength: 1000, mutationSize: 10 });
|
|
88
89
|
await space.db.flush();
|
|
89
90
|
|
|
90
|
-
const changesCount = A.getAllChanges(getObjectCore(document).docHandle!.
|
|
91
|
+
const changesCount = A.getAllChanges(getObjectCore(document).docHandle!.doc()).length;
|
|
91
92
|
expect(changesCount - beforeChangesCount).to.be.eq(mutationsCount);
|
|
92
93
|
});
|
|
93
94
|
|
|
@@ -96,7 +97,7 @@ describe('TestObjectGenerator', () => {
|
|
|
96
97
|
typename: 'example.org/type/Task',
|
|
97
98
|
version: '0.1.0',
|
|
98
99
|
})({
|
|
99
|
-
name:
|
|
100
|
+
name: Schema.optional(Schema.String),
|
|
100
101
|
}) {}
|
|
101
102
|
|
|
102
103
|
enum Types {
|
|
@@ -123,4 +124,31 @@ describe('TestObjectGenerator', () => {
|
|
|
123
124
|
const todo = await generator.createObject({ types: [Types.task] });
|
|
124
125
|
expect(getType(todo)).to.exist;
|
|
125
126
|
});
|
|
127
|
+
|
|
128
|
+
test('references', async () => {
|
|
129
|
+
const { space } = await setupTest();
|
|
130
|
+
const generator = createSpaceObjectGenerator(space);
|
|
131
|
+
await generator.addSchemas();
|
|
132
|
+
|
|
133
|
+
// Create raw object.
|
|
134
|
+
const objects = await generator.createObjects({
|
|
135
|
+
[TestSchemaType.organization]: 1,
|
|
136
|
+
[TestSchemaType.contact]: 1,
|
|
137
|
+
});
|
|
138
|
+
expect(objects).to.exist;
|
|
139
|
+
expect(objects.length).to.be.eq(2);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('create project', async () => {
|
|
143
|
+
const generator = createTestObjectGenerator();
|
|
144
|
+
const project = await generator.createObject({ types: [TestSchemaType.project] });
|
|
145
|
+
expect(getType(project)).to.exist;
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('create object with not type', async () => {
|
|
149
|
+
// TODO(burdon): Create Client/spaces.
|
|
150
|
+
const generator = createTestObjectGenerator();
|
|
151
|
+
|
|
152
|
+
await generator.createObject();
|
|
153
|
+
});
|
|
126
154
|
});
|
package/src/generator.ts
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Schema } from 'effect';
|
|
6
|
+
|
|
5
7
|
import { Filter, type Space } from '@dxos/client/echo';
|
|
6
|
-
import { type
|
|
7
|
-
import { getTypeAnnotation, EchoSchema,
|
|
8
|
+
import { type AnyLiveObject } from '@dxos/echo-db';
|
|
9
|
+
import { getTypeAnnotation, EchoSchema, getSchema } from '@dxos/echo-schema';
|
|
8
10
|
import { invariant } from '@dxos/invariant';
|
|
9
|
-
import {
|
|
11
|
+
import { live, isLiveObject, type Live } from '@dxos/live-object';
|
|
10
12
|
import { faker } from '@dxos/random';
|
|
11
|
-
import { range } from '@dxos/util';
|
|
13
|
+
import { entries, range } from '@dxos/util';
|
|
12
14
|
|
|
13
15
|
import { type TestSchemaType } from './data';
|
|
14
16
|
import {
|
|
@@ -21,6 +23,7 @@ import {
|
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Typed object generator.
|
|
26
|
+
* @deprecated
|
|
24
27
|
*/
|
|
25
28
|
export class TestObjectGenerator<T extends string = TestSchemaType> {
|
|
26
29
|
// prettier-ignore
|
|
@@ -30,31 +33,36 @@ export class TestObjectGenerator<T extends string = TestSchemaType> {
|
|
|
30
33
|
private readonly _provider?: TestObjectProvider<T>,
|
|
31
34
|
) {}
|
|
32
35
|
|
|
33
|
-
get schemas(): (EchoSchema |
|
|
36
|
+
get schemas(): (EchoSchema | Schema.Schema.AnyNoContext)[] {
|
|
34
37
|
return Object.values(this._schemas);
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
getSchema(type: T): EchoSchema |
|
|
40
|
+
getSchema(type: T): EchoSchema | Schema.Schema.AnyNoContext | undefined {
|
|
38
41
|
return this.schemas.find((schema) => getTypeAnnotation(schema)!.typename === type);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
protected setSchema(type: T, schema: EchoSchema |
|
|
44
|
+
protected setSchema(type: T, schema: EchoSchema | Schema.Schema.AnyNoContext): void {
|
|
42
45
|
this._schemas[type] = schema;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
async createObject({ types }: { types?: T[] } = {}): Promise<
|
|
48
|
+
async createObject({ types }: { types?: T[] } = {}): Promise<Live<any>> {
|
|
46
49
|
const type = faker.helpers.arrayElement(types ?? (Object.keys(this._schemas) as T[]));
|
|
47
50
|
const data = await this._generators[type](this._provider);
|
|
48
|
-
if (
|
|
51
|
+
if (isLiveObject(data)) {
|
|
49
52
|
return data;
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
const schema = this.getSchema(type);
|
|
53
|
-
return schema ?
|
|
56
|
+
return schema ? live(schema, data) : live(data);
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
// TODO(burdon): Based on dependencies (e.g., organization before contact).
|
|
57
60
|
async createObjects(map: Partial<Record<T, number>>) {
|
|
61
|
+
const results: Live<any>[] = [];
|
|
62
|
+
for (const [type, count] of entries(map)) {
|
|
63
|
+
results.push(...(await Promise.all(range(count ?? 0, () => this.createObject({ types: [type as T] })))));
|
|
64
|
+
}
|
|
65
|
+
|
|
58
66
|
const tasks = Object.entries<number>(map as any)
|
|
59
67
|
.map(([type, count]) => {
|
|
60
68
|
return range(count, () => this.createObject({ types: [type as T] }));
|
|
@@ -77,14 +85,15 @@ export class SpaceObjectGenerator<T extends string> extends TestObjectGenerator<
|
|
|
77
85
|
) {
|
|
78
86
|
super(schemaMap, generators, async (type: T) => {
|
|
79
87
|
const schema = this.getSchema(type);
|
|
80
|
-
|
|
88
|
+
const { objects } = await this._space.db.query(schema ? Filter.type(schema) : Filter.nothing()).run();
|
|
89
|
+
return objects;
|
|
81
90
|
});
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
async addSchemas() {
|
|
85
|
-
const result: (EchoSchema |
|
|
94
|
+
const result: (EchoSchema | Schema.Schema.AnyNoContext)[] = [];
|
|
86
95
|
for (const [typename, schema] of Object.entries(this._schemas)) {
|
|
87
|
-
const echoSchema = await this._maybeRegisterSchema(typename, schema as EchoSchema |
|
|
96
|
+
const echoSchema = await this._maybeRegisterSchema(typename, schema as EchoSchema | Schema.Schema.AnyNoContext);
|
|
88
97
|
this.setSchema(typename as T, echoSchema);
|
|
89
98
|
result.push(echoSchema);
|
|
90
99
|
}
|
|
@@ -92,14 +101,14 @@ export class SpaceObjectGenerator<T extends string> extends TestObjectGenerator<
|
|
|
92
101
|
return result;
|
|
93
102
|
}
|
|
94
103
|
|
|
95
|
-
override async createObject({ types }: { types?: T[] } = {}): Promise<
|
|
104
|
+
override async createObject({ types }: { types?: T[] } = {}): Promise<AnyLiveObject<any>> {
|
|
96
105
|
return this._space.db.add(await super.createObject({ types }));
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
private async _maybeRegisterSchema(
|
|
100
109
|
typename: string,
|
|
101
|
-
schema: EchoSchema |
|
|
102
|
-
): Promise<EchoSchema |
|
|
110
|
+
schema: EchoSchema | Schema.Schema.AnyNoContext,
|
|
111
|
+
): Promise<EchoSchema | Schema.Schema.AnyNoContext> {
|
|
103
112
|
if (schema instanceof EchoSchema) {
|
|
104
113
|
const existingSchema = this._space.db.schemaRegistry.getSchema(typename);
|
|
105
114
|
if (existingSchema != null) {
|
|
@@ -117,7 +126,7 @@ export class SpaceObjectGenerator<T extends string> extends TestObjectGenerator<
|
|
|
117
126
|
}
|
|
118
127
|
}
|
|
119
128
|
|
|
120
|
-
async mutateObject(object:
|
|
129
|
+
async mutateObject(object: AnyLiveObject<any>, params: MutationsProviderParams): Promise<void> {
|
|
121
130
|
invariant(this._mutations, 'Mutations not defined.');
|
|
122
131
|
const type = getTypeAnnotation(getSchema(object)!)!.typename as T;
|
|
123
132
|
invariant(type && this._mutations?.[type], 'Invalid object type.');
|
|
@@ -125,7 +134,7 @@ export class SpaceObjectGenerator<T extends string> extends TestObjectGenerator<
|
|
|
125
134
|
await this._mutations;
|
|
126
135
|
}
|
|
127
136
|
|
|
128
|
-
async mutateObjects(objects:
|
|
137
|
+
async mutateObjects(objects: AnyLiveObject<any>[], params: MutationsProviderParams): Promise<void> {
|
|
129
138
|
for (const object of objects) {
|
|
130
139
|
await this.mutateObject(object, params);
|
|
131
140
|
}
|
package/src/types.ts
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
6
|
-
|
|
7
|
-
import { type
|
|
5
|
+
import { type Schema } from 'effect';
|
|
6
|
+
|
|
7
|
+
import { type AnyLiveObject } from '@dxos/echo-db';
|
|
8
|
+
import { type EchoSchema } from '@dxos/echo-schema';
|
|
9
|
+
import { type Live } from '@dxos/live-object';
|
|
8
10
|
|
|
9
11
|
// TODO(burdon): Use echo-schema types.
|
|
10
12
|
export type TestObject = { id: string } & Record<string, any>;
|
|
11
13
|
|
|
12
|
-
export type TestSchemaMap<T extends string = string> = Record<T, EchoSchema |
|
|
14
|
+
export type TestSchemaMap<T extends string = string> = Record<T, EchoSchema | Schema.Schema.AnyNoContext>;
|
|
13
15
|
|
|
14
|
-
export type TestObjectProvider<T extends string = string> = (type: T) => Promise<
|
|
16
|
+
export type TestObjectProvider<T extends string = string> = (type: T) => Promise<Live<any>[]>;
|
|
15
17
|
|
|
16
18
|
export type TestGeneratorMap<T extends string = string> = Record<
|
|
17
19
|
T,
|
|
@@ -26,4 +28,4 @@ export type MutationsProviderParams = {
|
|
|
26
28
|
maxContentLength: number;
|
|
27
29
|
};
|
|
28
30
|
|
|
29
|
-
export type TestObjectMutators = (object:
|
|
31
|
+
export type TestObjectMutators = (object: AnyLiveObject<any>, params: MutationsProviderParams) => Promise<void>;
|