@dxos/echo-generator 0.4.10-main.0302e13 → 0.4.10-main.05dbd64
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 +66 -137
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +67 -140
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/data.d.ts +0 -3
- package/dist/types/src/data.d.ts.map +1 -1
- package/dist/types/src/generator.d.ts +9 -8
- package/dist/types/src/generator.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +3 -3
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/data.ts +43 -107
- package/src/generator.test.ts +24 -28
- package/src/generator.ts +33 -30
- package/src/types.ts +3 -3
package/src/data.ts
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// TODO(burdon): Reconcile with @dxos/plugin-debug, @dxos/aurora/testing.
|
|
6
6
|
// TODO(burdon): Bug when adding stale objects to space (e.g., static objects already added in previous story invocation).
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { type Space } from '@dxos/client/echo';
|
|
9
|
+
import { S, DynamicEchoSchema, effectToJsonSchema, StoredEchoSchema, create, ref, echoObject } from '@dxos/echo-schema';
|
|
9
10
|
import { faker } from '@dxos/random';
|
|
10
11
|
|
|
11
12
|
import { SpaceObjectGenerator, TestObjectGenerator } from './generator';
|
|
@@ -22,111 +23,46 @@ export enum TestSchemaType {
|
|
|
22
23
|
project = 'example.com/schema/project',
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
const createDynamicSchema = (typename: string, fields: S.Struct.Fields): DynamicEchoSchema => {
|
|
27
|
+
const typeSchema = S.partial(S.struct(fields)).pipe(echoObject(typename, '1.0.0'));
|
|
28
|
+
return new DynamicEchoSchema(
|
|
29
|
+
create(StoredEchoSchema, {
|
|
30
|
+
typename,
|
|
31
|
+
version: '1.0.0',
|
|
32
|
+
jsonSchema: effectToJsonSchema(typeSchema),
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const testSchemas = (): TestSchemaMap<TestSchemaType> => {
|
|
38
|
+
const document = createDynamicSchema(TestSchemaType.document, {
|
|
39
|
+
title: S.string.pipe(S.description('title of the document')),
|
|
40
|
+
content: S.string,
|
|
39
41
|
});
|
|
40
42
|
|
|
41
|
-
const organization =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
id: 'name',
|
|
46
|
-
type: Schema.PropType.STRING,
|
|
47
|
-
description: 'name of the company or organization',
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
id: 'website',
|
|
51
|
-
type: Schema.PropType.STRING,
|
|
52
|
-
description: 'public website URL',
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
id: 'description',
|
|
56
|
-
type: Schema.PropType.STRING,
|
|
57
|
-
description: 'short summary of the company',
|
|
58
|
-
},
|
|
59
|
-
],
|
|
43
|
+
const organization = createDynamicSchema(TestSchemaType.organization, {
|
|
44
|
+
name: S.string.pipe(S.description('name of the company or organization')),
|
|
45
|
+
website: S.string.pipe(S.description('public website URL')),
|
|
46
|
+
description: S.string.pipe(S.description('short summary of the company')),
|
|
60
47
|
});
|
|
61
48
|
|
|
62
|
-
const contact =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
description: 'name of the person',
|
|
69
|
-
},
|
|
70
|
-
// TODO(burdon): Support multiple tagged properties.
|
|
71
|
-
{
|
|
72
|
-
id: 'email',
|
|
73
|
-
type: Schema.PropType.STRING,
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
id: 'org',
|
|
77
|
-
type: Schema.PropType.REF,
|
|
78
|
-
ref: organization,
|
|
79
|
-
},
|
|
80
|
-
// TODO(burdon): Convert to object with nested props.
|
|
81
|
-
{
|
|
82
|
-
id: 'lat',
|
|
83
|
-
type: Schema.PropType.NUMBER,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
id: 'lng',
|
|
87
|
-
type: Schema.PropType.NUMBER,
|
|
88
|
-
},
|
|
89
|
-
],
|
|
49
|
+
const contact = createDynamicSchema(TestSchemaType.contact, {
|
|
50
|
+
name: S.string.pipe(S.description('name of the person')),
|
|
51
|
+
email: S.string,
|
|
52
|
+
org: ref(organization),
|
|
53
|
+
lat: S.number,
|
|
54
|
+
lng: S.number,
|
|
90
55
|
});
|
|
91
56
|
|
|
92
|
-
const project =
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
id: 'description',
|
|
102
|
-
type: Schema.PropType.STRING, // TODO(burdon): Text.
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
id: 'website',
|
|
106
|
-
type: Schema.PropType.STRING,
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
id: 'repo',
|
|
110
|
-
type: Schema.PropType.STRING,
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
id: 'status',
|
|
114
|
-
type: Schema.PropType.STRING,
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
id: 'priority',
|
|
118
|
-
type: Schema.PropType.NUMBER,
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
id: 'active',
|
|
122
|
-
type: Schema.PropType.BOOLEAN,
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
id: 'org',
|
|
126
|
-
type: Schema.PropType.REF,
|
|
127
|
-
ref: organization,
|
|
128
|
-
},
|
|
129
|
-
],
|
|
57
|
+
const project = createDynamicSchema(TestSchemaType.project, {
|
|
58
|
+
name: S.string.pipe(S.description('name of the project')),
|
|
59
|
+
description: S.string,
|
|
60
|
+
website: S.string,
|
|
61
|
+
repo: S.string,
|
|
62
|
+
status: S.string,
|
|
63
|
+
priority: S.number,
|
|
64
|
+
active: S.boolean,
|
|
65
|
+
org: ref(organization),
|
|
130
66
|
});
|
|
131
67
|
|
|
132
68
|
return {
|
|
@@ -137,20 +73,20 @@ export const testSchemas = (): TestSchemaMap<TestSchemaType> => {
|
|
|
137
73
|
};
|
|
138
74
|
};
|
|
139
75
|
|
|
140
|
-
|
|
141
|
-
[TestSchemaType.document]: () => ({
|
|
76
|
+
const testObjectGenerators: TestGeneratorMap<TestSchemaType> = {
|
|
77
|
+
[TestSchemaType.document]: async () => ({
|
|
142
78
|
title: faker.lorem.sentence(3),
|
|
143
79
|
content: faker.lorem.sentences({ min: 1, max: faker.number.int({ min: 1, max: 3 }) }),
|
|
144
80
|
}),
|
|
145
81
|
|
|
146
|
-
[TestSchemaType.organization]: () => ({
|
|
82
|
+
[TestSchemaType.organization]: async () => ({
|
|
147
83
|
name: faker.company.name(),
|
|
148
84
|
website: faker.datatype.boolean({ probability: 0.3 }) ? faker.internet.url() : undefined,
|
|
149
|
-
description:
|
|
85
|
+
description: faker.lorem.sentences(),
|
|
150
86
|
}),
|
|
151
87
|
|
|
152
|
-
[TestSchemaType.contact]: (provider) => {
|
|
153
|
-
const organizations = provider?.(TestSchemaType.organization);
|
|
88
|
+
[TestSchemaType.contact]: async (provider) => {
|
|
89
|
+
const organizations = await provider?.(TestSchemaType.organization);
|
|
154
90
|
const location = faker.datatype.boolean() ? faker.helpers.arrayElement(locations) : undefined;
|
|
155
91
|
return {
|
|
156
92
|
name: faker.person.fullName(),
|
|
@@ -163,7 +99,7 @@ export const testObjectGenerators: TestGeneratorMap<TestSchemaType> = {
|
|
|
163
99
|
};
|
|
164
100
|
},
|
|
165
101
|
|
|
166
|
-
[TestSchemaType.project]: () => ({
|
|
102
|
+
[TestSchemaType.project]: async () => ({
|
|
167
103
|
name: faker.commerce.productName(),
|
|
168
104
|
repo: faker.datatype.boolean({ probability: 0.3 }) ? faker.internet.url() : undefined,
|
|
169
105
|
status: faker.helpers.arrayElement(Status),
|
package/src/generator.test.ts
CHANGED
|
@@ -5,71 +5,67 @@
|
|
|
5
5
|
import { expect } from 'chai';
|
|
6
6
|
|
|
7
7
|
import { Client } from '@dxos/client';
|
|
8
|
-
import {
|
|
8
|
+
import { getType } from '@dxos/echo-schema';
|
|
9
9
|
import { faker } from '@dxos/random';
|
|
10
|
-
import { describe, test } from '@dxos/test';
|
|
10
|
+
import { afterTest, describe, test } from '@dxos/test';
|
|
11
11
|
|
|
12
12
|
import { createSpaceObjectGenerator, createTestObjectGenerator, TestSchemaType } from './data';
|
|
13
13
|
|
|
14
14
|
faker.seed(3);
|
|
15
15
|
|
|
16
16
|
describe('TestObjectGenerator', () => {
|
|
17
|
-
test('basic', () => {
|
|
17
|
+
test('basic', async () => {
|
|
18
18
|
const generator = createTestObjectGenerator();
|
|
19
19
|
|
|
20
20
|
// Create raw object.
|
|
21
|
-
const object = generator.createObject({ types: [TestSchemaType.contact] });
|
|
21
|
+
const object = await generator.createObject({ types: [TestSchemaType.contact] });
|
|
22
22
|
expect(object).to.exist;
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
test('with space', async () => {
|
|
26
|
-
const
|
|
27
|
-
await client.initialize();
|
|
28
|
-
await client.halo.createIdentity();
|
|
29
|
-
const space = await client.spaces.create();
|
|
26
|
+
const { space } = await setupTest();
|
|
30
27
|
|
|
31
28
|
const generator = createSpaceObjectGenerator(space);
|
|
32
29
|
generator.addSchemas();
|
|
33
30
|
|
|
34
31
|
// Create org object.
|
|
35
|
-
const organization = generator.createObject({ types: [TestSchemaType.organization] });
|
|
36
|
-
expect(organization
|
|
32
|
+
const organization = await generator.createObject({ types: [TestSchemaType.organization] });
|
|
33
|
+
expect(getType(organization)).to.exist;
|
|
37
34
|
|
|
38
35
|
// Expect at least one person object with a linked org reference.
|
|
39
|
-
const objects = generator.createObjects({ [TestSchemaType.contact]: 10 });
|
|
36
|
+
const objects = await generator.createObjects({ [TestSchemaType.contact]: 10 });
|
|
40
37
|
expect(objects.some((object) => object.org === organization)).to.be.true;
|
|
41
|
-
|
|
42
|
-
await client.destroy();
|
|
43
38
|
});
|
|
44
39
|
|
|
45
|
-
test
|
|
46
|
-
const
|
|
47
|
-
await client.initialize();
|
|
48
|
-
await client.halo.createIdentity();
|
|
49
|
-
const space = await client.spaces.create();
|
|
40
|
+
test('idempotence', async () => {
|
|
41
|
+
const { space } = await setupTest();
|
|
50
42
|
|
|
51
43
|
const schemaId: string[] = [];
|
|
52
44
|
|
|
53
45
|
{
|
|
54
46
|
const generator = createSpaceObjectGenerator(space);
|
|
55
47
|
generator.addSchemas();
|
|
56
|
-
const organization = generator.createObject({ types: [TestSchemaType.organization] });
|
|
57
|
-
schemaId.push(organization
|
|
48
|
+
const organization = await generator.createObject({ types: [TestSchemaType.organization] });
|
|
49
|
+
schemaId.push(getType(organization)!.itemId);
|
|
58
50
|
}
|
|
59
51
|
|
|
60
52
|
{
|
|
61
53
|
const generator = createSpaceObjectGenerator(space);
|
|
62
54
|
generator.addSchemas();
|
|
63
|
-
const organization = generator.createObject({ types: [TestSchemaType.organization] });
|
|
64
|
-
schemaId.push(organization
|
|
55
|
+
const organization = await generator.createObject({ types: [TestSchemaType.organization] });
|
|
56
|
+
schemaId.push(getType(organization)!.itemId);
|
|
65
57
|
}
|
|
66
58
|
|
|
59
|
+
expect(schemaId[0]).not.to.be.undefined;
|
|
67
60
|
expect(schemaId[0]).to.eq(schemaId[1]);
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
console.log(space.db.objects.map((object) => object[debug]));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
await client.destroy();
|
|
74
61
|
});
|
|
62
|
+
|
|
63
|
+
const setupTest = async () => {
|
|
64
|
+
const client = new Client();
|
|
65
|
+
await client.initialize();
|
|
66
|
+
afterTest(async () => await client.destroy());
|
|
67
|
+
await client.halo.createIdentity();
|
|
68
|
+
const space = await client.spaces.create();
|
|
69
|
+
return { client, space };
|
|
70
|
+
};
|
|
75
71
|
});
|
package/src/generator.ts
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { type Space, Filter } from '@dxos/client/echo';
|
|
6
|
+
import { type DynamicEchoSchema, type ReactiveObject } from '@dxos/echo-schema';
|
|
7
|
+
import { create } from '@dxos/echo-schema';
|
|
6
8
|
import { faker } from '@dxos/random';
|
|
7
9
|
|
|
8
10
|
import { type TestSchemaType } from './data';
|
|
@@ -20,35 +22,36 @@ export class TestObjectGenerator<T extends string = TestSchemaType> {
|
|
|
20
22
|
private readonly _provider?: TestObjectProvider<T>
|
|
21
23
|
) {}
|
|
22
24
|
|
|
23
|
-
get schemas():
|
|
25
|
+
get schemas(): DynamicEchoSchema[] {
|
|
24
26
|
return Object.values(this._schemas);
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
getSchema(type: T) {
|
|
29
|
+
getSchema(type: T): DynamicEchoSchema | undefined {
|
|
28
30
|
return this.schemas.find((schema) => schema.typename === type);
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
protected setSchema(type: T, schema:
|
|
33
|
+
protected setSchema(type: T, schema: DynamicEchoSchema) {
|
|
32
34
|
this._schemas[type] = schema;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
// TODO(burdon): Runtime type check via: https://github.com/Effect-TS/schema (or zod).
|
|
36
|
-
createObject({ types }: { types?: T[] } = {}):
|
|
38
|
+
async createObject({ types }: { types?: T[] } = {}): Promise<ReactiveObject<any>> {
|
|
37
39
|
const type = faker.helpers.arrayElement(types ?? (Object.keys(this._schemas) as T[]));
|
|
38
|
-
const data = this._generators[type](this._provider);
|
|
40
|
+
const data = await this._generators[type](this._provider);
|
|
39
41
|
const schema = this.getSchema(type);
|
|
40
|
-
return
|
|
42
|
+
return schema ? create(schema, data) : create(data);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
// TODO(burdon): Create batch.
|
|
44
46
|
// TODO(burdon): Based on dependencies (e.g., organization before contact).
|
|
45
|
-
createObjects(map: Partial<Record<T, number>>):
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
async createObjects(map: Partial<Record<T, number>>): Promise<ReactiveObject<any>[]> {
|
|
48
|
+
const tasks = Object.entries<number>(map as any)
|
|
49
|
+
.map(([type, count]) => {
|
|
50
|
+
return range(() => this.createObject({ types: [type as T] }), count);
|
|
51
|
+
})
|
|
52
|
+
.flatMap((t) => t);
|
|
50
53
|
|
|
51
|
-
return
|
|
54
|
+
return Promise.all(tasks);
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
57
|
|
|
@@ -61,37 +64,37 @@ export class SpaceObjectGenerator<T extends string> extends TestObjectGenerator<
|
|
|
61
64
|
schemaMap: TestSchemaMap<T>,
|
|
62
65
|
generators: TestGeneratorMap<T>,
|
|
63
66
|
) {
|
|
64
|
-
super(schemaMap, generators, (type: T) => {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
return objects;
|
|
67
|
+
super(schemaMap, generators, async (type: T) => {
|
|
68
|
+
const schema = this.getSchema(type);
|
|
69
|
+
return (schema && (await this._space.db.query(Filter.schema(schema)).run()).objects) ?? [];
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
// TODO(burdon): Map initially are objects that have not been added to the space.
|
|
73
73
|
// Merge existing schema in space with defaults.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this.setSchema(type as T, schema);
|
|
74
|
+
Object.entries<DynamicEchoSchema>(schemaMap).forEach(([type, dynamicSchema]) => {
|
|
75
|
+
let schema = this._space.db.schemaRegistry.getRegisteredByTypename(type);
|
|
76
|
+
if (schema == null) {
|
|
77
|
+
schema = this._space.db.schemaRegistry.add(dynamicSchema.schema);
|
|
79
78
|
}
|
|
79
|
+
this.setSchema(type as T, schema);
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
addSchemas() {
|
|
84
|
-
const
|
|
84
|
+
const result: DynamicEchoSchema[] = [];
|
|
85
85
|
this.schemas.forEach((schema) => {
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
const existing = this._space.db.schemaRegistry.getRegisteredByTypename(schema.typename);
|
|
87
|
+
if (existing == null) {
|
|
88
|
+
result.push(this._space.db.schemaRegistry.add(schema.schema));
|
|
89
|
+
} else {
|
|
90
|
+
result.push(existing);
|
|
88
91
|
}
|
|
89
92
|
});
|
|
90
93
|
|
|
91
|
-
return
|
|
94
|
+
return result;
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
override createObject({ types }: { types?: T[] } = {}):
|
|
95
|
-
return this._space.db.add(super.createObject({ types }));
|
|
97
|
+
override async createObject({ types }: { types?: T[] } = {}): Promise<ReactiveObject<any>> {
|
|
98
|
+
return this._space.db.add(await super.createObject({ types }));
|
|
96
99
|
}
|
|
97
100
|
}
|
package/src/types.ts
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type DynamicEchoSchema, type ReactiveObject } from '@dxos/echo-schema';
|
|
6
6
|
|
|
7
7
|
export type TestObject = { id: string } & Record<string, any>;
|
|
8
8
|
|
|
9
|
-
export type TestSchemaMap<T extends string> = Record<T,
|
|
9
|
+
export type TestSchemaMap<T extends string> = Record<T, DynamicEchoSchema>;
|
|
10
10
|
|
|
11
11
|
export type TestGeneratorMap<T extends string> = Record<T, (provider: TestObjectProvider<T> | undefined) => any>;
|
|
12
12
|
|
|
13
|
-
export type TestObjectProvider<T extends string> = (type: T) =>
|
|
13
|
+
export type TestObjectProvider<T extends string> = (type: T) => Promise<ReactiveObject<any>[]>;
|