[tweak] migrate store snapshot arguments (#1659)

This PR updates the `migrateStoreSnapshot` method in @tldraw/store

### Change Type

- [x] `major` — Breaking change

### Test Plan

- [x] Unit Tests
This commit is contained in:
Steve Ruiz 2023-06-27 14:59:07 +01:00 committed by GitHub
parent ed8d4d9e05
commit 2d5b2bdc94
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 23 additions and 23 deletions

View file

@ -181,10 +181,10 @@ export class TLLocalSyncClient {
const documentSnapshot = Object.fromEntries(data.records.map((r) => [r.id, r])) const documentSnapshot = Object.fromEntries(data.records.map((r) => [r.id, r]))
const sessionStateSnapshot = const sessionStateSnapshot =
data.sessionStateSnapshot ?? extractSessionStateFromLegacySnapshot(documentSnapshot) data.sessionStateSnapshot ?? extractSessionStateFromLegacySnapshot(documentSnapshot)
const migrationResult = this.store.schema.migrateStoreSnapshot( const migrationResult = this.store.schema.migrateStoreSnapshot({
documentSnapshot, store: documentSnapshot,
data.schema ?? this.store.schema.serializeEarliestVersion() schema: data.schema ?? this.store.schema.serializeEarliestVersion(),
) })
if (migrationResult.type === 'error') { if (migrationResult.type === 'error') {
console.error('failed to migrate store', migrationResult) console.error('failed to migrate store', migrationResult)

View file

@ -122,7 +122,7 @@ export function parseTldrawJsonFile({
let migrationResult: MigrationResult<SerializedStore<TLRecord>> let migrationResult: MigrationResult<SerializedStore<TLRecord>>
try { try {
const storeSnapshot = Object.fromEntries(data.records.map((r) => [r.id, r as TLRecord])) const storeSnapshot = Object.fromEntries(data.records.map((r) => [r.id, r as TLRecord]))
migrationResult = schema.migrateStoreSnapshot(storeSnapshot, data.schema) migrationResult = schema.migrateStoreSnapshot({ store: storeSnapshot, schema: data.schema })
} catch (e) { } catch (e) {
// junk data in the migration // junk data in the migration
return Result.err({ type: 'invalidRecords', cause: e }) return Result.err({ type: 'invalidRecords', cause: e })

View file

@ -304,7 +304,7 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
// (undocumented) // (undocumented)
migratePersistedRecord(record: R, persistedSchema: SerializedSchema, direction?: 'down' | 'up'): MigrationResult<R>; migratePersistedRecord(record: R, persistedSchema: SerializedSchema, direction?: 'down' | 'up'): MigrationResult<R>;
// (undocumented) // (undocumented)
migrateStoreSnapshot(storeSnapshot: SerializedStore<R>, persistedSchema: SerializedSchema): MigrationResult<SerializedStore<R>>; migrateStoreSnapshot(snapshot: StoreSnapshot<R>): MigrationResult<SerializedStore<R>>;
// (undocumented) // (undocumented)
serialize(): SerializedSchema; serialize(): SerializedSchema;
// (undocumented) // (undocumented)

View file

@ -551,7 +551,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
* @public * @public
*/ */
loadSnapshot(snapshot: StoreSnapshot<R>): void { loadSnapshot(snapshot: StoreSnapshot<R>): void {
const migrationResult = this.schema.migrateStoreSnapshot(snapshot.store, snapshot.schema) const migrationResult = this.schema.migrateStoreSnapshot(snapshot)
if (migrationResult.type === 'error') { if (migrationResult.type === 'error') {
throw new Error(`Failed to migrate snapshot: ${migrationResult.reason}`) throw new Error(`Failed to migrate snapshot: ${migrationResult.reason}`)

View file

@ -1,7 +1,7 @@
import { getOwnProperty, objectMapValues } from '@tldraw/utils' import { getOwnProperty, objectMapValues } from '@tldraw/utils'
import { IdOf, UnknownRecord } from './BaseRecord' import { IdOf, UnknownRecord } from './BaseRecord'
import { RecordType } from './RecordType' import { RecordType } from './RecordType'
import { SerializedStore, Store } from './Store' import { SerializedStore, Store, StoreSnapshot } from './Store'
import { import {
MigrationFailureReason, MigrationFailureReason,
MigrationResult, MigrationResult,
@ -188,17 +188,14 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
return { type: 'success', value: result.value } return { type: 'success', value: result.value }
} }
migrateStoreSnapshot( migrateStoreSnapshot(snapshot: StoreSnapshot<R>): MigrationResult<SerializedStore<R>> {
storeSnapshot: SerializedStore<R>,
persistedSchema: SerializedSchema
): MigrationResult<SerializedStore<R>> {
const migrations = this.options.snapshotMigrations const migrations = this.options.snapshotMigrations
if (!migrations) { if (!migrations) {
return { type: 'success', value: storeSnapshot } return { type: 'success', value: snapshot.store }
} }
// apply store migrations first // apply store migrations first
const ourStoreVersion = migrations.currentVersion const ourStoreVersion = migrations.currentVersion
const persistedStoreVersion = persistedSchema.storeVersion ?? 0 const persistedStoreVersion = snapshot.schema.storeVersion ?? 0
if (ourStoreVersion < persistedStoreVersion) { if (ourStoreVersion < persistedStoreVersion) {
return { type: 'error', reason: MigrationFailureReason.TargetVersionTooOld } return { type: 'error', reason: MigrationFailureReason.TargetVersionTooOld }
@ -206,7 +203,7 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
if (ourStoreVersion > persistedStoreVersion) { if (ourStoreVersion > persistedStoreVersion) {
const result = migrate<SerializedStore<R>>({ const result = migrate<SerializedStore<R>>({
value: storeSnapshot, value: snapshot.store,
migrations, migrations,
fromVersion: persistedStoreVersion, fromVersion: persistedStoreVersion,
toVersion: ourStoreVersion, toVersion: ourStoreVersion,
@ -215,12 +212,12 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
if (result.type === 'error') { if (result.type === 'error') {
return result return result
} }
storeSnapshot = result.value snapshot.store = result.value
} }
const updated: R[] = [] const updated: R[] = []
for (const r of objectMapValues(storeSnapshot)) { for (const r of objectMapValues(snapshot.store)) {
const result = this.migratePersistedRecord(r, persistedSchema) const result = this.migratePersistedRecord(r, snapshot.schema)
if (result.type === 'error') { if (result.type === 'error') {
return result return result
} else if (result.value && result.value !== r) { } else if (result.value && result.value !== r) {
@ -228,12 +225,12 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
} }
} }
if (updated.length) { if (updated.length) {
storeSnapshot = { ...storeSnapshot } snapshot.store = { ...snapshot.store }
for (const r of updated) { for (const r of updated) {
storeSnapshot[r.id as IdOf<R>] = r snapshot.store[r.id as IdOf<R>] = r
} }
} }
return { type: 'success', value: storeSnapshot } return { type: 'success', value: snapshot.store }
} }
/** @internal */ /** @internal */

View file

@ -305,7 +305,7 @@ test('subtype versions in the future fail', () => {
}) })
test('migrating a whole store snapshot works', () => { test('migrating a whole store snapshot works', () => {
const snapshot: SerializedStore<any> = { const serializedStore: SerializedStore<any> = {
'user-1': { 'user-1': {
id: 'user-1', id: 'user-1',
typeName: 'user', typeName: 'user',
@ -329,7 +329,10 @@ test('migrating a whole store snapshot works', () => {
}, },
} }
const result = testSchemaV1.migrateStoreSnapshot(snapshot, serializedV0Schenma) const result = testSchemaV1.migrateStoreSnapshot({
store: serializedStore,
schema: serializedV0Schenma,
})
if (result.type !== 'success') { if (result.type !== 'success') {
console.error(result) console.error(result)