@ontrails/store 1.0.0-beta.14 → 1.0.0-beta.15
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/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +7 -0
- package/README.md +126 -61
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/signal-identity.d.ts +17 -0
- package/dist/internal/signal-identity.d.ts.map +1 -0
- package/dist/internal/signal-identity.js +81 -0
- package/dist/internal/signal-identity.js.map +1 -0
- package/dist/jsonfile/index.d.ts +3 -0
- package/dist/jsonfile/index.d.ts.map +1 -0
- package/dist/jsonfile/index.js +2 -0
- package/dist/jsonfile/index.js.map +1 -0
- package/dist/jsonfile/runtime.d.ts +19 -0
- package/dist/jsonfile/runtime.d.ts.map +1 -0
- package/dist/jsonfile/runtime.js +403 -0
- package/dist/jsonfile/runtime.js.map +1 -0
- package/dist/jsonfile/types.d.ts +40 -0
- package/dist/jsonfile/types.d.ts.map +1 -0
- package/dist/{drizzle → jsonfile}/types.js.map +1 -1
- package/dist/store.d.ts +8 -18
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +152 -94
- package/dist/store.js.map +1 -1
- package/dist/testing.d.ts +28 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +90 -0
- package/dist/testing.js.map +1 -0
- package/dist/trails/crud.d.ts +38 -0
- package/dist/trails/crud.d.ts.map +1 -0
- package/dist/trails/crud.js +112 -0
- package/dist/trails/crud.js.map +1 -0
- package/dist/trails/index.d.ts +7 -0
- package/dist/trails/index.d.ts.map +1 -0
- package/dist/trails/index.js +4 -0
- package/dist/trails/index.js.map +1 -0
- package/dist/trails/reconcile.d.ts +36 -0
- package/dist/trails/reconcile.d.ts.map +1 -0
- package/dist/trails/reconcile.js +142 -0
- package/dist/trails/reconcile.js.map +1 -0
- package/dist/trails/sync.d.ts +25 -0
- package/dist/trails/sync.d.ts.map +1 -0
- package/dist/trails/sync.js +96 -0
- package/dist/trails/sync.js.map +1 -0
- package/dist/trails/utils.d.ts +51 -0
- package/dist/trails/utils.d.ts.map +1 -0
- package/dist/trails/utils.js +65 -0
- package/dist/trails/utils.js.map +1 -0
- package/dist/types.d.ts +205 -35
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -9
- package/src/__tests__/crud.test.ts +346 -0
- package/src/__tests__/jsonfile.test.ts +502 -0
- package/src/__tests__/store.test.ts +239 -33
- package/src/__tests__/sync-reconcile.test.ts +646 -0
- package/src/index.ts +12 -8
- package/src/internal/signal-identity.ts +162 -0
- package/src/jsonfile/index.ts +6 -0
- package/src/jsonfile/runtime.ts +702 -0
- package/src/jsonfile/types.ts +50 -0
- package/src/store.ts +296 -134
- package/src/testing.ts +175 -0
- package/src/trails/crud.ts +355 -0
- package/src/trails/index.ts +10 -0
- package/src/trails/reconcile.ts +281 -0
- package/src/trails/sync.ts +251 -0
- package/src/trails/utils.ts +96 -0
- package/src/types.ts +355 -63
- package/tsconfig.tests.json +10 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/drizzle/index.d.ts +0 -3
- package/dist/drizzle/index.d.ts.map +0 -1
- package/dist/drizzle/index.js +0 -2
- package/dist/drizzle/index.js.map +0 -1
- package/dist/drizzle/runtime.d.ts +0 -21
- package/dist/drizzle/runtime.d.ts.map +0 -1
- package/dist/drizzle/runtime.js +0 -458
- package/dist/drizzle/runtime.js.map +0 -1
- package/dist/drizzle/schema.d.ts +0 -15
- package/dist/drizzle/schema.d.ts.map +0 -1
- package/dist/drizzle/schema.js +0 -322
- package/dist/drizzle/schema.js.map +0 -1
- package/dist/drizzle/types.d.ts +0 -40
- package/dist/drizzle/types.d.ts.map +0 -1
- package/src/drizzle/__tests__/drizzle.test.ts +0 -469
- package/src/drizzle/index.ts +0 -17
- package/src/drizzle/runtime.ts +0 -853
- package/src/drizzle/schema.ts +0 -577
- package/src/drizzle/types.ts +0 -70
- /package/dist/{drizzle → jsonfile}/types.js +0 -0
|
@@ -3,19 +3,15 @@ import { ValidationError } from '@ontrails/core';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
|
+
AnyStoreTable,
|
|
6
7
|
EntityOf,
|
|
7
8
|
FixtureInputOf,
|
|
8
9
|
FixtureOf,
|
|
9
10
|
InsertOf,
|
|
10
11
|
UpdateOf,
|
|
11
12
|
} from '../index.js';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
fixtureSchemaOf,
|
|
15
|
-
insertSchemaOf,
|
|
16
|
-
store,
|
|
17
|
-
updateSchemaOf,
|
|
18
|
-
} from '../index.js';
|
|
13
|
+
import { store } from '../index.js';
|
|
14
|
+
import { bindStoreDefinition } from '../internal/signal-identity.js';
|
|
19
15
|
|
|
20
16
|
const userSchema = z.object({
|
|
21
17
|
email: z.string().email(),
|
|
@@ -36,37 +32,64 @@ const createStoreDefinition = () =>
|
|
|
36
32
|
store({
|
|
37
33
|
gists: {
|
|
38
34
|
generated: ['id', 'createdAt', 'updatedAt'],
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
identity: 'id',
|
|
36
|
+
indexed: ['ownerId'],
|
|
41
37
|
references: { ownerId: 'users' },
|
|
42
38
|
schema: gistSchema,
|
|
43
39
|
search: { fts: true },
|
|
44
40
|
},
|
|
45
41
|
users: {
|
|
46
42
|
generated: ['id'],
|
|
47
|
-
|
|
43
|
+
identity: 'id',
|
|
48
44
|
schema: userSchema,
|
|
49
45
|
},
|
|
50
46
|
});
|
|
51
47
|
|
|
48
|
+
const expectGistSignals = (
|
|
49
|
+
table: ReturnType<typeof createStoreDefinition>['tables']['gists']
|
|
50
|
+
) => {
|
|
51
|
+
expect(table.signals.created.id).toBe('gists.created');
|
|
52
|
+
expect(table.signals.updated.id).toBe('gists.updated');
|
|
53
|
+
expect(table.signals.removed.id).toBe('gists.removed');
|
|
54
|
+
expect(
|
|
55
|
+
table.signals.created.payload.parse({
|
|
56
|
+
createdAt: '2026-04-03T12:00:00.000Z',
|
|
57
|
+
id: 'gist-1',
|
|
58
|
+
ownerId: 'user-1',
|
|
59
|
+
updatedAt: '2026-04-03T12:00:00.000Z',
|
|
60
|
+
})
|
|
61
|
+
).toEqual({
|
|
62
|
+
createdAt: '2026-04-03T12:00:00.000Z',
|
|
63
|
+
description: null,
|
|
64
|
+
id: 'gist-1',
|
|
65
|
+
isPublic: true,
|
|
66
|
+
ownerId: 'user-1',
|
|
67
|
+
tags: [],
|
|
68
|
+
updatedAt: '2026-04-03T12:00:00.000Z',
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
52
72
|
const expectNormalizedGistTable = (
|
|
53
73
|
table: ReturnType<typeof createStoreDefinition>['tables']['gists']
|
|
54
74
|
) => {
|
|
55
75
|
expect(table.name).toBe('gists');
|
|
76
|
+
expect(table.identity).toBe('id');
|
|
56
77
|
expect(table.primaryKey).toBe('id');
|
|
57
78
|
expect(table.generated).toEqual(['id', 'createdAt', 'updatedAt']);
|
|
79
|
+
expect(table.indexed).toEqual(['ownerId']);
|
|
58
80
|
expect(table.indexes).toEqual(['ownerId']);
|
|
59
81
|
expect(table.references).toEqual({ ownerId: 'users' });
|
|
60
82
|
expect(table.search).toEqual({ fts: true });
|
|
83
|
+
expectGistSignals(table);
|
|
61
84
|
};
|
|
62
85
|
|
|
63
86
|
const expectDerivedSchemas = (
|
|
64
87
|
table: ReturnType<typeof createStoreDefinition>['tables']['gists']
|
|
65
88
|
) => {
|
|
66
|
-
expect(
|
|
67
|
-
expect(
|
|
68
|
-
expect(
|
|
69
|
-
expect(
|
|
89
|
+
expect(table.schema).toBeDefined();
|
|
90
|
+
expect(table.fixtureSchema).toBeDefined();
|
|
91
|
+
expect(table.insertSchema).toBeDefined();
|
|
92
|
+
expect(table.updateSchema).toBeDefined();
|
|
70
93
|
|
|
71
94
|
expect(
|
|
72
95
|
table.insertSchema.parse({
|
|
@@ -92,14 +115,26 @@ const createTypeTestStore = () =>
|
|
|
92
115
|
store({
|
|
93
116
|
gists: {
|
|
94
117
|
generated: ['id', 'createdAt', 'updatedAt'],
|
|
95
|
-
|
|
118
|
+
identity: 'id',
|
|
119
|
+
schema: gistSchema,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const createVersionedStoreDefinition = () =>
|
|
124
|
+
store({
|
|
125
|
+
gists: {
|
|
126
|
+
generated: ['id', 'createdAt', 'updatedAt'],
|
|
127
|
+
identity: 'id',
|
|
96
128
|
schema: gistSchema,
|
|
129
|
+
versioned: true,
|
|
97
130
|
},
|
|
98
131
|
});
|
|
99
132
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
>
|
|
133
|
+
type VersionedGistTable = ReturnType<
|
|
134
|
+
typeof createVersionedStoreDefinition
|
|
135
|
+
>['tables']['gists'];
|
|
136
|
+
|
|
137
|
+
const createGistEntity = <TTable extends AnyStoreTable>() =>
|
|
103
138
|
({
|
|
104
139
|
createdAt: '2026-04-03T12:00:00.000Z',
|
|
105
140
|
description: null,
|
|
@@ -118,12 +153,66 @@ const requireFixture = <T>(fixture: T | undefined): T => {
|
|
|
118
153
|
return fixture;
|
|
119
154
|
};
|
|
120
155
|
|
|
156
|
+
const createVersionedGistTypeSamples = (): {
|
|
157
|
+
readonly entity: EntityOf<VersionedGistTable>;
|
|
158
|
+
readonly fixtureInput: FixtureInputOf<VersionedGistTable>;
|
|
159
|
+
readonly insertInput: InsertOf<VersionedGistTable>;
|
|
160
|
+
} => ({
|
|
161
|
+
entity: {
|
|
162
|
+
createdAt: '2026-04-03T12:00:00.000Z',
|
|
163
|
+
description: null,
|
|
164
|
+
id: 'gist-1',
|
|
165
|
+
isPublic: true,
|
|
166
|
+
ownerId: 'user-1',
|
|
167
|
+
tags: ['core'],
|
|
168
|
+
updatedAt: '2026-04-03T12:00:00.000Z',
|
|
169
|
+
version: 1,
|
|
170
|
+
},
|
|
171
|
+
fixtureInput: {
|
|
172
|
+
ownerId: 'user-2',
|
|
173
|
+
version: 2,
|
|
174
|
+
},
|
|
175
|
+
insertInput: {
|
|
176
|
+
ownerId: 'user-3',
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const expectVersionedGistTypeSamples = ({
|
|
181
|
+
entity,
|
|
182
|
+
fixtureInput,
|
|
183
|
+
insertInput,
|
|
184
|
+
}: ReturnType<typeof createVersionedGistTypeSamples>): void => {
|
|
185
|
+
expect(entity.version).toBe(1);
|
|
186
|
+
expect(fixtureInput.version).toBe(2);
|
|
187
|
+
expect(insertInput.ownerId).toBe('user-3');
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const expectVersionedFixtureDefaults = (
|
|
191
|
+
db: ReturnType<typeof createVersionedStoreDefinition>
|
|
192
|
+
): void => {
|
|
193
|
+
expect(db.tables.gists.fixtureSchema.parse({ ownerId: 'user-4' })).toEqual({
|
|
194
|
+
description: null,
|
|
195
|
+
isPublic: true,
|
|
196
|
+
ownerId: 'user-4',
|
|
197
|
+
tags: [],
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
|
|
121
201
|
describe('@ontrails/store', () => {
|
|
122
202
|
test('normalizes tables and derives insert/update schemas', () => {
|
|
123
203
|
const db = createStoreDefinition();
|
|
124
204
|
|
|
125
|
-
expect(db.kind).toBe('
|
|
205
|
+
expect(db.kind).toBe('tabular');
|
|
206
|
+
expect(db.signals.map((candidate) => candidate.id)).toEqual([
|
|
207
|
+
'gists.created',
|
|
208
|
+
'gists.updated',
|
|
209
|
+
'gists.removed',
|
|
210
|
+
'users.created',
|
|
211
|
+
'users.updated',
|
|
212
|
+
'users.removed',
|
|
213
|
+
]);
|
|
126
214
|
expect(db.tableNames).toEqual(['gists', 'users']);
|
|
215
|
+
expect(db.type).toBe('store');
|
|
127
216
|
|
|
128
217
|
const table = db.tables.gists;
|
|
129
218
|
expectNormalizedGistTable(table);
|
|
@@ -131,6 +220,21 @@ describe('@ontrails/store', () => {
|
|
|
131
220
|
expectDerivedSchemas(table);
|
|
132
221
|
});
|
|
133
222
|
|
|
223
|
+
test('accepts an explicit backend-agnostic kind', () => {
|
|
224
|
+
const db = store(
|
|
225
|
+
{
|
|
226
|
+
gists: {
|
|
227
|
+
identity: 'id',
|
|
228
|
+
schema: gistSchema,
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
{ kind: 'document' }
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
expect(db.kind).toBe('document');
|
|
235
|
+
expect(db.tables.gists.identity).toBe('id');
|
|
236
|
+
});
|
|
237
|
+
|
|
134
238
|
test('normalizes fixtures through the derived fixture schema', () => {
|
|
135
239
|
const db = store({
|
|
136
240
|
gists: {
|
|
@@ -141,7 +245,7 @@ describe('@ontrails/store', () => {
|
|
|
141
245
|
},
|
|
142
246
|
],
|
|
143
247
|
generated: ['id', 'createdAt', 'updatedAt'],
|
|
144
|
-
|
|
248
|
+
identity: 'id',
|
|
145
249
|
schema: gistSchema,
|
|
146
250
|
},
|
|
147
251
|
});
|
|
@@ -174,6 +278,42 @@ describe('@ontrails/store', () => {
|
|
|
174
278
|
});
|
|
175
279
|
});
|
|
176
280
|
|
|
281
|
+
test('normalizes versioned tables with a framework-managed version field', () => {
|
|
282
|
+
const db = createVersionedStoreDefinition();
|
|
283
|
+
const samples = createVersionedGistTypeSamples();
|
|
284
|
+
|
|
285
|
+
expect(db.tables.gists.versioned).toBe(true);
|
|
286
|
+
expect(db.tables.gists.generated).toEqual([
|
|
287
|
+
'id',
|
|
288
|
+
'createdAt',
|
|
289
|
+
'updatedAt',
|
|
290
|
+
'version',
|
|
291
|
+
]);
|
|
292
|
+
expectVersionedGistTypeSamples(samples);
|
|
293
|
+
expect(db.tables.gists.schema.parse(samples.entity)).toEqual(
|
|
294
|
+
samples.entity
|
|
295
|
+
);
|
|
296
|
+
expect(
|
|
297
|
+
db.tables.gists.signals.updated.payload.parse({
|
|
298
|
+
createdAt: '2026-04-03T12:00:00.000Z',
|
|
299
|
+
id: 'gist-1',
|
|
300
|
+
ownerId: 'user-1',
|
|
301
|
+
updatedAt: '2026-04-03T12:00:00.000Z',
|
|
302
|
+
version: 2,
|
|
303
|
+
})
|
|
304
|
+
).toEqual({
|
|
305
|
+
createdAt: '2026-04-03T12:00:00.000Z',
|
|
306
|
+
description: null,
|
|
307
|
+
id: 'gist-1',
|
|
308
|
+
isPublic: true,
|
|
309
|
+
ownerId: 'user-1',
|
|
310
|
+
tags: [],
|
|
311
|
+
updatedAt: '2026-04-03T12:00:00.000Z',
|
|
312
|
+
version: 2,
|
|
313
|
+
});
|
|
314
|
+
expectVersionedFixtureDefaults(db);
|
|
315
|
+
});
|
|
316
|
+
|
|
177
317
|
test('rejects duplicate fixture primary keys when they are explicitly provided', () => {
|
|
178
318
|
expect(() =>
|
|
179
319
|
store({
|
|
@@ -189,7 +329,7 @@ describe('@ontrails/store', () => {
|
|
|
189
329
|
},
|
|
190
330
|
],
|
|
191
331
|
generated: ['id', 'createdAt', 'updatedAt'],
|
|
192
|
-
|
|
332
|
+
identity: 'id',
|
|
193
333
|
schema: gistSchema,
|
|
194
334
|
},
|
|
195
335
|
})
|
|
@@ -204,7 +344,7 @@ describe('@ontrails/store', () => {
|
|
|
204
344
|
expect(() =>
|
|
205
345
|
store({
|
|
206
346
|
broken: {
|
|
207
|
-
|
|
347
|
+
identity: 'id' as never,
|
|
208
348
|
schema: z.string() as never,
|
|
209
349
|
},
|
|
210
350
|
})
|
|
@@ -215,13 +355,13 @@ describe('@ontrails/store', () => {
|
|
|
215
355
|
expect(() =>
|
|
216
356
|
store({
|
|
217
357
|
gists: {
|
|
218
|
-
|
|
358
|
+
identity: 'slug' as never,
|
|
219
359
|
schema: gistSchema,
|
|
220
360
|
},
|
|
221
361
|
})
|
|
222
362
|
).toThrow(
|
|
223
363
|
new ValidationError(
|
|
224
|
-
'Store table "gists" declares
|
|
364
|
+
'Store table "gists" declares identity "slug" that is not present on the schema'
|
|
225
365
|
)
|
|
226
366
|
);
|
|
227
367
|
|
|
@@ -229,7 +369,7 @@ describe('@ontrails/store', () => {
|
|
|
229
369
|
store({
|
|
230
370
|
gists: {
|
|
231
371
|
generated: ['missing'] as const as never,
|
|
232
|
-
|
|
372
|
+
identity: 'id',
|
|
233
373
|
schema: gistSchema,
|
|
234
374
|
},
|
|
235
375
|
})
|
|
@@ -242,14 +382,28 @@ describe('@ontrails/store', () => {
|
|
|
242
382
|
expect(() =>
|
|
243
383
|
store({
|
|
244
384
|
gists: {
|
|
245
|
-
|
|
246
|
-
|
|
385
|
+
identity: 'id',
|
|
386
|
+
schema: gistSchema.extend({ version: z.number().int() }),
|
|
387
|
+
versioned: true,
|
|
388
|
+
},
|
|
389
|
+
})
|
|
390
|
+
).toThrow(
|
|
391
|
+
new ValidationError(
|
|
392
|
+
'Store table "gists" cannot declare a "version" field when versioned storage is enabled because the framework manages that field.'
|
|
393
|
+
)
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
expect(() =>
|
|
397
|
+
store({
|
|
398
|
+
gists: {
|
|
399
|
+
identity: 'id',
|
|
400
|
+
indexed: ['missing'] as const as never,
|
|
247
401
|
schema: gistSchema,
|
|
248
402
|
},
|
|
249
403
|
})
|
|
250
404
|
).toThrow(
|
|
251
405
|
new ValidationError(
|
|
252
|
-
'Store table "gists" declares
|
|
406
|
+
'Store table "gists" declares indexed field "missing" that is not present on the schema'
|
|
253
407
|
)
|
|
254
408
|
);
|
|
255
409
|
|
|
@@ -258,7 +412,7 @@ describe('@ontrails/store', () => {
|
|
|
258
412
|
gists: {
|
|
259
413
|
fixtures: [{ id: 'gist-seed' } as never],
|
|
260
414
|
generated: ['id', 'createdAt', 'updatedAt'],
|
|
261
|
-
|
|
415
|
+
identity: 'id',
|
|
262
416
|
schema: gistSchema,
|
|
263
417
|
},
|
|
264
418
|
})
|
|
@@ -273,12 +427,12 @@ describe('@ontrails/store', () => {
|
|
|
273
427
|
expect(() =>
|
|
274
428
|
store({
|
|
275
429
|
gists: {
|
|
276
|
-
|
|
430
|
+
identity: 'id',
|
|
277
431
|
references: { missing: 'users' } as never,
|
|
278
432
|
schema: gistSchema,
|
|
279
433
|
},
|
|
280
434
|
users: {
|
|
281
|
-
|
|
435
|
+
identity: 'id',
|
|
282
436
|
schema: userSchema,
|
|
283
437
|
},
|
|
284
438
|
})
|
|
@@ -291,12 +445,12 @@ describe('@ontrails/store', () => {
|
|
|
291
445
|
expect(() =>
|
|
292
446
|
store({
|
|
293
447
|
gists: {
|
|
294
|
-
|
|
448
|
+
identity: 'id',
|
|
295
449
|
references: { ownerId: 'accounts' },
|
|
296
450
|
schema: gistSchema,
|
|
297
451
|
},
|
|
298
452
|
users: {
|
|
299
|
-
|
|
453
|
+
identity: 'id',
|
|
300
454
|
schema: userSchema,
|
|
301
455
|
},
|
|
302
456
|
})
|
|
@@ -307,6 +461,23 @@ describe('@ontrails/store', () => {
|
|
|
307
461
|
);
|
|
308
462
|
});
|
|
309
463
|
|
|
464
|
+
test('keeps tabular aliases working for existing stores', () => {
|
|
465
|
+
const db = store({
|
|
466
|
+
gists: {
|
|
467
|
+
generated: ['id'],
|
|
468
|
+
indexes: ['ownerId'],
|
|
469
|
+
primaryKey: 'id',
|
|
470
|
+
schema: gistSchema,
|
|
471
|
+
},
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
expect(db.kind).toBe('tabular');
|
|
475
|
+
expect(db.tables.gists.identity).toBe('id');
|
|
476
|
+
expect(db.tables.gists.primaryKey).toBe('id');
|
|
477
|
+
expect(db.tables.gists.indexed).toEqual(['ownerId']);
|
|
478
|
+
expect(db.tables.gists.indexes).toEqual(['ownerId']);
|
|
479
|
+
});
|
|
480
|
+
|
|
310
481
|
test('type-level helpers expose connector-facing contracts', () => {
|
|
311
482
|
const db = createTypeTestStore();
|
|
312
483
|
|
|
@@ -331,3 +502,38 @@ describe('@ontrails/store', () => {
|
|
|
331
502
|
expect(db.tables.gists.name).toBe('gists');
|
|
332
503
|
});
|
|
333
504
|
});
|
|
505
|
+
|
|
506
|
+
describe('bindStoreDefinition', () => {
|
|
507
|
+
const definition = store({
|
|
508
|
+
gists: {
|
|
509
|
+
generated: ['id'],
|
|
510
|
+
identity: 'id',
|
|
511
|
+
schema: gistSchema,
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
test('rejects scopes containing ":"', () => {
|
|
516
|
+
expect(() => bindStoreDefinition(definition, 'bad:scope')).toThrow(
|
|
517
|
+
new ValidationError(
|
|
518
|
+
'Store resource id "bad:scope" is invalid: must be a non-empty string with no ":" characters and no whitespace.'
|
|
519
|
+
)
|
|
520
|
+
);
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
test('rejects scopes containing whitespace', () => {
|
|
524
|
+
expect(() => bindStoreDefinition(definition, 'bad scope')).toThrow(
|
|
525
|
+
ValidationError
|
|
526
|
+
);
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
test('rejects empty scopes', () => {
|
|
530
|
+
expect(() => bindStoreDefinition(definition, '')).toThrow(ValidationError);
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
test('accepts valid scopes and scopes store signal ids', () => {
|
|
534
|
+
const bound = bindStoreDefinition(definition, 'primary');
|
|
535
|
+
expect(bound.tables.gists.signals.created.id).toBe('primary:gists.created');
|
|
536
|
+
expect(bound.tables.gists.signals.updated.id).toBe('primary:gists.updated');
|
|
537
|
+
expect(bound.tables.gists.signals.removed.id).toBe('primary:gists.removed');
|
|
538
|
+
});
|
|
539
|
+
});
|