Skip to content

Commit

Permalink
feat(app-state): by default PersistentStore now resets to the defau…
Browse files Browse the repository at this point in the history
…lt state when `_version` changes

BREAKING CHANGE: If you rely on the old behavior of `PersistentStore` throwing an exception when `_version` changes, you should pass an empty migration manager: `new PersistentStore('myKey', myDefaultState, { migrationManager: new MigrationManager() })`
  • Loading branch information
ersimont committed Oct 3, 2023
1 parent 6887bef commit 770330c
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 3 deletions.
9 changes: 9 additions & 0 deletions projects/app-state/src/lib/utils/persistent-store.spec.ts
Expand Up @@ -24,6 +24,15 @@ describe('PersistentStore', () => {
expect(store.state()).toBe(defaultState);
});

it('overwrites the store with `defaultState` on a version change', () => {
localStorage.setItem('thekey', '{"_version": 0, "myKey": "saved"}');
const defaultState = { _version: 1, source: 'default' };

const store = new PersistentStore('thekey', defaultState);

expect(store.state()).toBe(defaultState);
});

describe('documentation', () => {
it('is working for the simple example', () => {
/* eslint-disable camelcase */
Expand Down
19 changes: 16 additions & 3 deletions projects/app-state/src/lib/utils/persistent-store.ts
Expand Up @@ -44,7 +44,7 @@ export interface PersistenceCodec<State, Persisted> {
* expect(store.state().my_state_key).toBe('my new value');
* ```
*
* Later when you want to change the schema of the state, it's time to take advantage of the `{@link MigrationManager}:
* At this point, if you change `_version` the store will be reset to the default state. This is a convenience during initial development of your app. Once it is released to real users, you will want to use a {@link MigrationManager} to avoid wiping out your users' data:
*
* ```ts
* class MyState implements VersionedObject {
Expand Down Expand Up @@ -128,8 +128,8 @@ export class PersistentStore<
persistenceKey: string,
defaultState: State,
{
migrator = new MigrationManager<Persisted>(),
codec = new IdentityCodec() as PersistenceCodec<State, Persisted>,
migrator = new NonMigrationManager() as MigrationManager<Persisted>,
codec = new IdentityCodec<any>() as PersistenceCodec<State, Persisted>,
} = {},
) {
const persistence = new Persistence<Persisted>(persistenceKey);
Expand All @@ -150,3 +150,16 @@ class IdentityCodec<T> implements PersistenceCodec<T, T> {
decode = identity;
encode = identity;
}

class NonMigrationManager<
T extends VersionedObject,
> extends MigrationManager<T> {
override run(persistence: Persistence<T>, defaultValue: T): T {
let persisted = persistence.get() ?? defaultValue;
if (persisted._version !== defaultValue._version) {
persisted = defaultValue;
}
persistence.put(persisted);
return persisted;
}
}

0 comments on commit 770330c

Please sign in to comment.