@tldraw/store 4.1.0-canary.9f9255bd7a83 → 4.1.0-canary.a6e63b3bbde6
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-cjs/index.d.ts +1884 -153
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/AtomMap.js +241 -1
- package/dist-cjs/lib/AtomMap.js.map +2 -2
- package/dist-cjs/lib/BaseRecord.js.map +2 -2
- package/dist-cjs/lib/ImmutableMap.js +141 -0
- package/dist-cjs/lib/ImmutableMap.js.map +2 -2
- package/dist-cjs/lib/IncrementalSetConstructor.js +45 -5
- package/dist-cjs/lib/IncrementalSetConstructor.js.map +2 -2
- package/dist-cjs/lib/RecordType.js +116 -21
- package/dist-cjs/lib/RecordType.js.map +2 -2
- package/dist-cjs/lib/RecordsDiff.js.map +2 -2
- package/dist-cjs/lib/Store.js +233 -39
- package/dist-cjs/lib/Store.js.map +2 -2
- package/dist-cjs/lib/StoreQueries.js +135 -22
- package/dist-cjs/lib/StoreQueries.js.map +2 -2
- package/dist-cjs/lib/StoreSchema.js +207 -2
- package/dist-cjs/lib/StoreSchema.js.map +2 -2
- package/dist-cjs/lib/StoreSideEffects.js +102 -10
- package/dist-cjs/lib/StoreSideEffects.js.map +2 -2
- package/dist-cjs/lib/executeQuery.js.map +2 -2
- package/dist-cjs/lib/migrate.js.map +2 -2
- package/dist-cjs/lib/setUtils.js.map +2 -2
- package/dist-esm/index.d.mts +1884 -153
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/AtomMap.mjs +241 -1
- package/dist-esm/lib/AtomMap.mjs.map +2 -2
- package/dist-esm/lib/BaseRecord.mjs.map +2 -2
- package/dist-esm/lib/ImmutableMap.mjs +141 -0
- package/dist-esm/lib/ImmutableMap.mjs.map +2 -2
- package/dist-esm/lib/IncrementalSetConstructor.mjs +45 -5
- package/dist-esm/lib/IncrementalSetConstructor.mjs.map +2 -2
- package/dist-esm/lib/RecordType.mjs +116 -21
- package/dist-esm/lib/RecordType.mjs.map +2 -2
- package/dist-esm/lib/RecordsDiff.mjs.map +2 -2
- package/dist-esm/lib/Store.mjs +233 -39
- package/dist-esm/lib/Store.mjs.map +2 -2
- package/dist-esm/lib/StoreQueries.mjs +135 -22
- package/dist-esm/lib/StoreQueries.mjs.map +2 -2
- package/dist-esm/lib/StoreSchema.mjs +207 -2
- package/dist-esm/lib/StoreSchema.mjs.map +2 -2
- package/dist-esm/lib/StoreSideEffects.mjs +102 -10
- package/dist-esm/lib/StoreSideEffects.mjs.map +2 -2
- package/dist-esm/lib/executeQuery.mjs.map +2 -2
- package/dist-esm/lib/migrate.mjs.map +2 -2
- package/dist-esm/lib/setUtils.mjs.map +2 -2
- package/package.json +3 -3
- package/src/lib/AtomMap.ts +241 -1
- package/src/lib/BaseRecord.test.ts +44 -0
- package/src/lib/BaseRecord.ts +118 -4
- package/src/lib/ImmutableMap.test.ts +103 -0
- package/src/lib/ImmutableMap.ts +212 -0
- package/src/lib/IncrementalSetConstructor.test.ts +111 -0
- package/src/lib/IncrementalSetConstructor.ts +63 -6
- package/src/lib/RecordType.ts +149 -25
- package/src/lib/RecordsDiff.test.ts +144 -0
- package/src/lib/RecordsDiff.ts +145 -10
- package/src/lib/Store.test.ts +827 -0
- package/src/lib/Store.ts +533 -67
- package/src/lib/StoreQueries.test.ts +627 -0
- package/src/lib/StoreQueries.ts +194 -27
- package/src/lib/StoreSchema.test.ts +226 -0
- package/src/lib/StoreSchema.ts +386 -8
- package/src/lib/StoreSideEffects.test.ts +239 -19
- package/src/lib/StoreSideEffects.ts +266 -19
- package/src/lib/devFreeze.test.ts +137 -0
- package/src/lib/executeQuery.test.ts +481 -0
- package/src/lib/executeQuery.ts +80 -2
- package/src/lib/migrate.test.ts +400 -0
- package/src/lib/migrate.ts +187 -14
- package/src/lib/setUtils.test.ts +105 -0
- package/src/lib/setUtils.ts +44 -4
package/src/lib/StoreSchema.ts
CHANGED
|
@@ -19,7 +19,31 @@ import {
|
|
|
19
19
|
validateMigrations,
|
|
20
20
|
} from './migrate'
|
|
21
21
|
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Version 1 format for serialized store schema information.
|
|
24
|
+
*
|
|
25
|
+
* This is the legacy format used before schema version 2. Version 1 schemas
|
|
26
|
+
* separate store-level versioning from record-level versioning, and support
|
|
27
|
+
* subtypes for complex record types like shapes.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const schemaV1: SerializedSchemaV1 = {
|
|
32
|
+
* schemaVersion: 1,
|
|
33
|
+
* storeVersion: 2,
|
|
34
|
+
* recordVersions: {
|
|
35
|
+
* book: { version: 3 },
|
|
36
|
+
* shape: {
|
|
37
|
+
* version: 2,
|
|
38
|
+
* subTypeVersions: { rectangle: 1, circle: 2 },
|
|
39
|
+
* subTypeKey: 'type'
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
23
47
|
export interface SerializedSchemaV1 {
|
|
24
48
|
/** Schema version is the version for this type you're looking at right now */
|
|
25
49
|
schemaVersion: 1
|
|
@@ -43,7 +67,28 @@ export interface SerializedSchemaV1 {
|
|
|
43
67
|
>
|
|
44
68
|
}
|
|
45
69
|
|
|
46
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Version 2 format for serialized store schema information.
|
|
72
|
+
*
|
|
73
|
+
* This is the current format that uses a unified sequence-based approach
|
|
74
|
+
* for tracking versions across all migration sequences. Each sequence ID
|
|
75
|
+
* maps to the latest version number for that sequence.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const schemaV2: SerializedSchemaV2 = {
|
|
80
|
+
* schemaVersion: 2,
|
|
81
|
+
* sequences: {
|
|
82
|
+
* 'com.tldraw.store': 3,
|
|
83
|
+
* 'com.tldraw.book': 2,
|
|
84
|
+
* 'com.tldraw.shape': 4,
|
|
85
|
+
* 'com.tldraw.shape.rectangle': 1
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @public
|
|
91
|
+
*/
|
|
47
92
|
export interface SerializedSchemaV2 {
|
|
48
93
|
schemaVersion: 2
|
|
49
94
|
sequences: {
|
|
@@ -51,9 +96,58 @@ export interface SerializedSchemaV2 {
|
|
|
51
96
|
}
|
|
52
97
|
}
|
|
53
98
|
|
|
54
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* Union type representing all supported serialized schema formats.
|
|
101
|
+
*
|
|
102
|
+
* This type allows the store to handle both legacy (V1) and current (V2)
|
|
103
|
+
* schema formats during deserialization and migration.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* function handleSchema(schema: SerializedSchema) {
|
|
108
|
+
* if (schema.schemaVersion === 1) {
|
|
109
|
+
* // Handle V1 format
|
|
110
|
+
* console.log('Store version:', schema.storeVersion)
|
|
111
|
+
* } else {
|
|
112
|
+
* // Handle V2 format
|
|
113
|
+
* console.log('Sequences:', schema.sequences)
|
|
114
|
+
* }
|
|
115
|
+
* }
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* @public
|
|
119
|
+
*/
|
|
55
120
|
export type SerializedSchema = SerializedSchemaV1 | SerializedSchemaV2
|
|
56
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Upgrades a serialized schema from version 1 to version 2 format.
|
|
124
|
+
*
|
|
125
|
+
* Version 1 schemas use separate `storeVersion` and `recordVersions` fields,
|
|
126
|
+
* while version 2 schemas use a unified `sequences` object with sequence IDs.
|
|
127
|
+
*
|
|
128
|
+
* @param schema - The serialized schema to upgrade
|
|
129
|
+
* @returns A Result containing the upgraded schema or an error message
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* const v1Schema = {
|
|
134
|
+
* schemaVersion: 1,
|
|
135
|
+
* storeVersion: 1,
|
|
136
|
+
* recordVersions: {
|
|
137
|
+
* book: { version: 2 },
|
|
138
|
+
* author: { version: 1, subTypeVersions: { fiction: 1 }, subTypeKey: 'genre' }
|
|
139
|
+
* }
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* const result = upgradeSchema(v1Schema)
|
|
143
|
+
* if (result.ok) {
|
|
144
|
+
* console.log(result.value.sequences)
|
|
145
|
+
* // { 'com.tldraw.store': 1, 'com.tldraw.book': 2, 'com.tldraw.author': 1, 'com.tldraw.author.fiction': 1 }
|
|
146
|
+
* }
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* @public
|
|
150
|
+
*/
|
|
57
151
|
export function upgradeSchema(schema: SerializedSchema): Result<SerializedSchemaV2, string> {
|
|
58
152
|
if (schema.schemaVersion > 2 || schema.schemaVersion < 1) return Result.err('Bad schema version')
|
|
59
153
|
if (schema.schemaVersion === 2) return Result.ok(schema as SerializedSchemaV2)
|
|
@@ -75,7 +169,32 @@ export function upgradeSchema(schema: SerializedSchema): Result<SerializedSchema
|
|
|
75
169
|
return Result.ok(result)
|
|
76
170
|
}
|
|
77
171
|
|
|
78
|
-
/**
|
|
172
|
+
/**
|
|
173
|
+
* Information about a record validation failure that occurred in the store.
|
|
174
|
+
*
|
|
175
|
+
* This interface provides context about validation errors, including the failed
|
|
176
|
+
* record, the store state, and the operation phase where the failure occurred.
|
|
177
|
+
* It's used by validation failure handlers to implement recovery strategies.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* const schema = StoreSchema.create(
|
|
182
|
+
* { book: Book },
|
|
183
|
+
* {
|
|
184
|
+
* onValidationFailure: (failure: StoreValidationFailure<Book>) => {
|
|
185
|
+
* console.error(`Validation failed during ${failure.phase}:`, failure.error)
|
|
186
|
+
* console.log('Failed record:', failure.record)
|
|
187
|
+
* console.log('Previous record:', failure.recordBefore)
|
|
188
|
+
*
|
|
189
|
+
* // Return a corrected version of the record
|
|
190
|
+
* return { ...failure.record, title: failure.record.title || 'Untitled' }
|
|
191
|
+
* }
|
|
192
|
+
* }
|
|
193
|
+
* )
|
|
194
|
+
* ```
|
|
195
|
+
*
|
|
196
|
+
* @public
|
|
197
|
+
*/
|
|
79
198
|
export interface StoreValidationFailure<R extends UnknownRecord> {
|
|
80
199
|
error: unknown
|
|
81
200
|
store: Store<R>
|
|
@@ -84,7 +203,30 @@ export interface StoreValidationFailure<R extends UnknownRecord> {
|
|
|
84
203
|
recordBefore: R | null
|
|
85
204
|
}
|
|
86
205
|
|
|
87
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* Configuration options for creating a StoreSchema.
|
|
208
|
+
*
|
|
209
|
+
* These options control migration behavior, validation error handling,
|
|
210
|
+
* and integrity checking for the store schema.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* const options: StoreSchemaOptions<MyRecord, MyProps> = {
|
|
215
|
+
* migrations: [bookMigrations, authorMigrations],
|
|
216
|
+
* onValidationFailure: (failure) => {
|
|
217
|
+
* // Log the error and return a corrected record
|
|
218
|
+
* console.error('Validation failed:', failure.error)
|
|
219
|
+
* return sanitizeRecord(failure.record)
|
|
220
|
+
* },
|
|
221
|
+
* createIntegrityChecker: (store) => {
|
|
222
|
+
* // Set up integrity checking logic
|
|
223
|
+
* return setupIntegrityChecks(store)
|
|
224
|
+
* }
|
|
225
|
+
* }
|
|
226
|
+
* ```
|
|
227
|
+
*
|
|
228
|
+
* @public
|
|
229
|
+
*/
|
|
88
230
|
export interface StoreSchemaOptions<R extends UnknownRecord, P> {
|
|
89
231
|
migrations?: MigrationSequence[]
|
|
90
232
|
/** @public */
|
|
@@ -93,8 +235,68 @@ export interface StoreSchemaOptions<R extends UnknownRecord, P> {
|
|
|
93
235
|
createIntegrityChecker?(store: Store<R, P>): void
|
|
94
236
|
}
|
|
95
237
|
|
|
96
|
-
/**
|
|
238
|
+
/**
|
|
239
|
+
* Manages the schema definition, validation, and migration system for a Store.
|
|
240
|
+
*
|
|
241
|
+
* StoreSchema coordinates record types, handles data migrations between schema
|
|
242
|
+
* versions, validates records, and provides the foundational structure for
|
|
243
|
+
* reactive stores. It acts as the central authority for data consistency
|
|
244
|
+
* and evolution within the store system.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```ts
|
|
248
|
+
* // Define record types
|
|
249
|
+
* const Book = createRecordType<Book>('book', { scope: 'document' })
|
|
250
|
+
* const Author = createRecordType<Author>('author', { scope: 'document' })
|
|
251
|
+
*
|
|
252
|
+
* // Create schema with migrations
|
|
253
|
+
* const schema = StoreSchema.create(
|
|
254
|
+
* { book: Book, author: Author },
|
|
255
|
+
* {
|
|
256
|
+
* migrations: [bookMigrations, authorMigrations],
|
|
257
|
+
* onValidationFailure: (failure) => {
|
|
258
|
+
* console.warn('Validation failed, using default:', failure.error)
|
|
259
|
+
* return failure.record // or return a corrected version
|
|
260
|
+
* }
|
|
261
|
+
* }
|
|
262
|
+
* )
|
|
263
|
+
*
|
|
264
|
+
* // Use with store
|
|
265
|
+
* const store = new Store({ schema })
|
|
266
|
+
* ```
|
|
267
|
+
*
|
|
268
|
+
* @public
|
|
269
|
+
*/
|
|
97
270
|
export class StoreSchema<R extends UnknownRecord, P = unknown> {
|
|
271
|
+
/**
|
|
272
|
+
* Creates a new StoreSchema with the given record types and options.
|
|
273
|
+
*
|
|
274
|
+
* This static factory method is the recommended way to create a StoreSchema.
|
|
275
|
+
* It ensures type safety while providing a clean API for schema definition.
|
|
276
|
+
*
|
|
277
|
+
* @param types - Object mapping type names to their RecordType definitions
|
|
278
|
+
* @param options - Optional configuration for migrations, validation, and integrity checking
|
|
279
|
+
* @returns A new StoreSchema instance
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```ts
|
|
283
|
+
* const Book = createRecordType<Book>('book', { scope: 'document' })
|
|
284
|
+
* const Author = createRecordType<Author>('author', { scope: 'document' })
|
|
285
|
+
*
|
|
286
|
+
* const schema = StoreSchema.create(
|
|
287
|
+
* {
|
|
288
|
+
* book: Book,
|
|
289
|
+
* author: Author
|
|
290
|
+
* },
|
|
291
|
+
* {
|
|
292
|
+
* migrations: [bookMigrations],
|
|
293
|
+
* onValidationFailure: (failure) => failure.record
|
|
294
|
+
* }
|
|
295
|
+
* )
|
|
296
|
+
* ```
|
|
297
|
+
*
|
|
298
|
+
* @public
|
|
299
|
+
*/
|
|
98
300
|
static create<R extends UnknownRecord, P = unknown>(
|
|
99
301
|
// HACK: making this param work with RecordType is an enormous pain
|
|
100
302
|
// let's just settle for making sure each typeName has a corresponding RecordType
|
|
@@ -132,6 +334,35 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
|
|
|
132
334
|
}
|
|
133
335
|
}
|
|
134
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Validates a record using its corresponding RecordType validator.
|
|
339
|
+
*
|
|
340
|
+
* This method ensures that records conform to their type definitions before
|
|
341
|
+
* being stored. If validation fails and an onValidationFailure handler is
|
|
342
|
+
* provided, it will be called to potentially recover from the error.
|
|
343
|
+
*
|
|
344
|
+
* @param store - The store instance where validation is occurring
|
|
345
|
+
* @param record - The record to validate
|
|
346
|
+
* @param phase - The lifecycle phase where validation is happening
|
|
347
|
+
* @param recordBefore - The previous version of the record (for updates)
|
|
348
|
+
* @returns The validated record, potentially modified by validation failure handler
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```ts
|
|
352
|
+
* try {
|
|
353
|
+
* const validatedBook = schema.validateRecord(
|
|
354
|
+
* store,
|
|
355
|
+
* { id: 'book:1', typeName: 'book', title: '', author: 'Jane Doe' },
|
|
356
|
+
* 'createRecord',
|
|
357
|
+
* null
|
|
358
|
+
* )
|
|
359
|
+
* } catch (error) {
|
|
360
|
+
* console.error('Record validation failed:', error)
|
|
361
|
+
* }
|
|
362
|
+
* ```
|
|
363
|
+
*
|
|
364
|
+
* @public
|
|
365
|
+
*/
|
|
135
366
|
validateRecord(
|
|
136
367
|
store: Store<R>,
|
|
137
368
|
record: R,
|
|
@@ -159,6 +390,34 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
|
|
|
159
390
|
}
|
|
160
391
|
}
|
|
161
392
|
|
|
393
|
+
/**
|
|
394
|
+
* Gets all migrations that need to be applied to upgrade from a persisted schema
|
|
395
|
+
* to the current schema version.
|
|
396
|
+
*
|
|
397
|
+
* This method compares the persisted schema with the current schema and determines
|
|
398
|
+
* which migrations need to be applied to bring the data up to date. It handles
|
|
399
|
+
* both regular migrations and retroactive migrations, and caches results for
|
|
400
|
+
* performance.
|
|
401
|
+
*
|
|
402
|
+
* @param persistedSchema - The schema version that was previously persisted
|
|
403
|
+
* @returns A Result containing the list of migrations to apply, or an error message
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* ```ts
|
|
407
|
+
* const persistedSchema = {
|
|
408
|
+
* schemaVersion: 2,
|
|
409
|
+
* sequences: { 'com.tldraw.book': 1, 'com.tldraw.author': 0 }
|
|
410
|
+
* }
|
|
411
|
+
*
|
|
412
|
+
* const migrationsResult = schema.getMigrationsSince(persistedSchema)
|
|
413
|
+
* if (migrationsResult.ok) {
|
|
414
|
+
* console.log('Migrations to apply:', migrationsResult.value.length)
|
|
415
|
+
* // Apply each migration to bring data up to date
|
|
416
|
+
* }
|
|
417
|
+
* ```
|
|
418
|
+
*
|
|
419
|
+
* @public
|
|
420
|
+
*/
|
|
162
421
|
public getMigrationsSince(persistedSchema: SerializedSchema): Result<Migration[], string> {
|
|
163
422
|
// Check cache first
|
|
164
423
|
const cached = this.migrationCache.get(persistedSchema)
|
|
@@ -227,6 +486,34 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
|
|
|
227
486
|
return result
|
|
228
487
|
}
|
|
229
488
|
|
|
489
|
+
/**
|
|
490
|
+
* Migrates a single persisted record to match the current schema version.
|
|
491
|
+
*
|
|
492
|
+
* This method applies the necessary migrations to transform a record from an
|
|
493
|
+
* older (or newer) schema version to the current version. It supports both
|
|
494
|
+
* forward ('up') and backward ('down') migrations.
|
|
495
|
+
*
|
|
496
|
+
* @param record - The record to migrate
|
|
497
|
+
* @param persistedSchema - The schema version the record was persisted with
|
|
498
|
+
* @param direction - Direction to migrate ('up' for newer, 'down' for older)
|
|
499
|
+
* @returns A MigrationResult containing the migrated record or an error
|
|
500
|
+
*
|
|
501
|
+
* @example
|
|
502
|
+
* ```ts
|
|
503
|
+
* const oldRecord = { id: 'book:1', typeName: 'book', title: 'Old Title', publishDate: '2020-01-01' }
|
|
504
|
+
* const oldSchema = { schemaVersion: 2, sequences: { 'com.tldraw.book': 1 } }
|
|
505
|
+
*
|
|
506
|
+
* const result = schema.migratePersistedRecord(oldRecord, oldSchema, 'up')
|
|
507
|
+
* if (result.type === 'success') {
|
|
508
|
+
* console.log('Migrated record:', result.value)
|
|
509
|
+
* // Record now has publishedYear instead of publishDate
|
|
510
|
+
* } else {
|
|
511
|
+
* console.error('Migration failed:', result.reason)
|
|
512
|
+
* }
|
|
513
|
+
* ```
|
|
514
|
+
*
|
|
515
|
+
* @public
|
|
516
|
+
*/
|
|
230
517
|
migratePersistedRecord(
|
|
231
518
|
record: R,
|
|
232
519
|
persistedSchema: SerializedSchema,
|
|
@@ -282,6 +569,37 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
|
|
|
282
569
|
return { type: 'success', value: record }
|
|
283
570
|
}
|
|
284
571
|
|
|
572
|
+
/**
|
|
573
|
+
* Migrates an entire store snapshot to match the current schema version.
|
|
574
|
+
*
|
|
575
|
+
* This method applies all necessary migrations to bring a persisted store
|
|
576
|
+
* snapshot up to the current schema version. It handles both record-level
|
|
577
|
+
* and store-level migrations, and can optionally mutate the input store
|
|
578
|
+
* for performance.
|
|
579
|
+
*
|
|
580
|
+
* @param snapshot - The store snapshot containing data and schema information
|
|
581
|
+
* @param opts - Options controlling migration behavior
|
|
582
|
+
* - mutateInputStore - Whether to modify the input store directly (default: false)
|
|
583
|
+
* @returns A MigrationResult containing the migrated store or an error
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* ```ts
|
|
587
|
+
* const snapshot = {
|
|
588
|
+
* schema: { schemaVersion: 2, sequences: { 'com.tldraw.book': 1 } },
|
|
589
|
+
* store: {
|
|
590
|
+
* 'book:1': { id: 'book:1', typeName: 'book', title: 'Old Book', publishDate: '2020-01-01' }
|
|
591
|
+
* }
|
|
592
|
+
* }
|
|
593
|
+
*
|
|
594
|
+
* const result = schema.migrateStoreSnapshot(snapshot)
|
|
595
|
+
* if (result.type === 'success') {
|
|
596
|
+
* console.log('Migrated store:', result.value)
|
|
597
|
+
* // All records are now at current schema version
|
|
598
|
+
* }
|
|
599
|
+
* ```
|
|
600
|
+
*
|
|
601
|
+
* @public
|
|
602
|
+
*/
|
|
285
603
|
migrateStoreSnapshot(
|
|
286
604
|
snapshot: StoreSnapshot<R>,
|
|
287
605
|
opts?: { mutateInputStore?: boolean }
|
|
@@ -330,11 +648,50 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
|
|
|
330
648
|
return { type: 'success', value: store }
|
|
331
649
|
}
|
|
332
650
|
|
|
333
|
-
/**
|
|
651
|
+
/**
|
|
652
|
+
* Creates an integrity checker function for the given store.
|
|
653
|
+
*
|
|
654
|
+
* This method calls the createIntegrityChecker option if provided, allowing
|
|
655
|
+
* custom integrity checking logic to be set up for the store. The integrity
|
|
656
|
+
* checker is used to validate store consistency and catch data corruption.
|
|
657
|
+
*
|
|
658
|
+
* @param store - The store instance to create an integrity checker for
|
|
659
|
+
* @returns An integrity checker function, or undefined if none is configured
|
|
660
|
+
*
|
|
661
|
+
* @internal
|
|
662
|
+
*/
|
|
334
663
|
createIntegrityChecker(store: Store<R, P>): (() => void) | undefined {
|
|
335
664
|
return this.options.createIntegrityChecker?.(store) ?? undefined
|
|
336
665
|
}
|
|
337
666
|
|
|
667
|
+
/**
|
|
668
|
+
* Serializes the current schema to a SerializedSchemaV2 format.
|
|
669
|
+
*
|
|
670
|
+
* This method creates a serialized representation of the current schema,
|
|
671
|
+
* capturing the latest version number for each migration sequence.
|
|
672
|
+
* The result can be persisted and later used to determine what migrations
|
|
673
|
+
* need to be applied when loading data.
|
|
674
|
+
*
|
|
675
|
+
* @returns A SerializedSchemaV2 object representing the current schema state
|
|
676
|
+
*
|
|
677
|
+
* @example
|
|
678
|
+
* ```ts
|
|
679
|
+
* const serialized = schema.serialize()
|
|
680
|
+
* console.log(serialized)
|
|
681
|
+
* // {
|
|
682
|
+
* // schemaVersion: 2,
|
|
683
|
+
* // sequences: {
|
|
684
|
+
* // 'com.tldraw.book': 3,
|
|
685
|
+
* // 'com.tldraw.author': 2
|
|
686
|
+
* // }
|
|
687
|
+
* // }
|
|
688
|
+
*
|
|
689
|
+
* // Store this with your data for future migrations
|
|
690
|
+
* localStorage.setItem('schema', JSON.stringify(serialized))
|
|
691
|
+
* ```
|
|
692
|
+
*
|
|
693
|
+
* @public
|
|
694
|
+
*/
|
|
338
695
|
serialize(): SerializedSchemaV2 {
|
|
339
696
|
return {
|
|
340
697
|
schemaVersion: 2,
|
|
@@ -348,6 +705,14 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
|
|
|
348
705
|
}
|
|
349
706
|
|
|
350
707
|
/**
|
|
708
|
+
* Serializes a schema representing the earliest possible version.
|
|
709
|
+
*
|
|
710
|
+
* This method creates a serialized schema where all migration sequences
|
|
711
|
+
* are set to version 0, representing the state before any migrations
|
|
712
|
+
* have been applied. This is used in specific legacy scenarios.
|
|
713
|
+
*
|
|
714
|
+
* @returns A SerializedSchema with all sequences set to version 0
|
|
715
|
+
*
|
|
351
716
|
* @deprecated This is only here for legacy reasons, don't use it unless you have david's blessing!
|
|
352
717
|
* @internal
|
|
353
718
|
*/
|
|
@@ -360,7 +725,20 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
|
|
|
360
725
|
}
|
|
361
726
|
}
|
|
362
727
|
|
|
363
|
-
/**
|
|
728
|
+
/**
|
|
729
|
+
* Gets the RecordType definition for a given type name.
|
|
730
|
+
*
|
|
731
|
+
* This method retrieves the RecordType associated with the specified
|
|
732
|
+
* type name, which contains the record's validation, creation, and
|
|
733
|
+
* other behavioral logic.
|
|
734
|
+
*
|
|
735
|
+
* @param typeName - The name of the record type to retrieve
|
|
736
|
+
* @returns The RecordType definition for the specified type
|
|
737
|
+
*
|
|
738
|
+
* @throws Will throw an error if the record type does not exist
|
|
739
|
+
*
|
|
740
|
+
* @internal
|
|
741
|
+
*/
|
|
364
742
|
getType(typeName: string) {
|
|
365
743
|
const type = getOwnProperty(this.types, typeName)
|
|
366
744
|
assert(type, 'record type does not exists')
|