@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/src/data.ts CHANGED
@@ -2,10 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { next as A } from '@dxos/automerge/automerge';
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 { Ref, S } from '@dxos/echo-schema';
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/document',
24
- organization = 'example.com/type/organization',
25
- contact = 'example.com/type/contact',
26
- project = 'example.com/type/project',
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 = createEchoSchema(
31
- {
32
- typename: TestSchemaType.document,
33
- version: '0.1.0',
34
- },
35
- {
36
- title: S.String.annotations({ description: 'title of the document' }),
37
- content: S.String,
38
- },
39
- );
40
-
41
- const organization = createEchoSchema(
42
- {
43
- typename: TestSchemaType.organization,
44
- version: '0.1.0',
45
- },
46
- {
47
- name: S.String.annotations({ description: 'name of the company or organization' }),
48
- website: S.String.annotations({ description: 'public website URL' }),
49
- description: S.String.annotations({ description: 'short summary of the company' }),
50
- },
51
- );
52
-
53
- const contact = createEchoSchema(
54
- {
55
- typename: TestSchemaType.contact,
56
- version: '0.1.0',
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 { location } = faker.datatype.boolean() ? faker.geo.airport() : {};
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.3 })
112
- ? makeRef(faker.helpers.arrayElement(organizations))
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.datatype.boolean({ probability: 0.3 }) ? faker.internet.url() : undefined,
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);
@@ -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 { S, TypedObject } from '@dxos/echo-schema';
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)!.objectId);
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)!.objectId);
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!.docSync()).length;
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!.docSync()).length;
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: S.optional(S.String),
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 ReactiveEchoObject } from '@dxos/echo-db';
7
- import { getTypeAnnotation, EchoSchema, type S } from '@dxos/echo-schema';
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 { create, getSchema, isReactiveObject, type ReactiveObject } from '@dxos/live-object';
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 | S.Schema.AnyNoContext)[] {
36
+ get schemas(): (EchoSchema | Schema.Schema.AnyNoContext)[] {
34
37
  return Object.values(this._schemas);
35
38
  }
36
39
 
37
- getSchema(type: T): EchoSchema | S.Schema.AnyNoContext | undefined {
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 | S.Schema.AnyNoContext) {
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<ReactiveObject<any>> {
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 (isReactiveObject(data)) {
51
+ if (isLiveObject(data)) {
49
52
  return data;
50
53
  }
51
54
 
52
55
  const schema = this.getSchema(type);
53
- return schema ? create(schema, data) : create(data);
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
- return (schema && (await this._space.db.query(Filter.schema(schema)).run()).objects) ?? [];
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 | S.Schema.AnyNoContext)[] = [];
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 | S.Schema.AnyNoContext);
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<ReactiveEchoObject<any>> {
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 | S.Schema.AnyNoContext,
102
- ): Promise<EchoSchema | S.Schema.AnyNoContext> {
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: ReactiveEchoObject<any>, params: MutationsProviderParams) {
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![type](object, params);
126
135
  }
127
136
 
128
- async mutateObjects(objects: ReactiveEchoObject<any>[], params: MutationsProviderParams) {
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 ReactiveEchoObject } from '@dxos/echo-db';
6
- import { type EchoSchema, type S } from '@dxos/echo-schema';
7
- import { type ReactiveObject } from '@dxos/live-object';
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 | S.Schema.AnyNoContext>;
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<ReactiveObject<any>[]>;
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: ReactiveEchoObject<any>, params: MutationsProviderParams) => Promise<void>;
31
+ export type TestObjectMutators = (object: AnyLiveObject<any>, params: MutationsProviderParams) => Promise<void>;