Skip to content

Commit

Permalink
fix: prefix persitance paths
Browse files Browse the repository at this point in the history
  • Loading branch information
schummar committed Feb 16, 2024
1 parent 92a3972 commit 7a2538e
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 34 deletions.
34 changes: 28 additions & 6 deletions src/persist/persist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,15 @@ export class Persist<T> {

private updateInProgress?: [any, any];

constructor(public readonly store: Store<T>, public readonly options: PersistOptions<T>) {
private prefix;

constructor(
public readonly store: Store<T>,
public readonly options: PersistOptions<T>,
) {
this.storage = normalizeStorage(options.storage);
this.channel = new BroadcastChannel(`cross-state-persist_${options.id}`);
this.prefix = `${options.id}:`;

this.paths = (options.paths ?? [])
.map<{
Expand Down Expand Up @@ -126,7 +132,11 @@ export class Persist<T> {
}

for (const key of keys) {
const path = JSON.parse(key);
const path = this.parseKey(key);
if (!path) {
continue;
}

this.queue(() => this.load(path));
}

Expand All @@ -140,6 +150,18 @@ export class Persist<T> {
this.handles.add(() => this.channel.removeEventListener('message', listener));
}

private buildKey(path: KeyType[]) {
return `${this.prefix}${JSON.stringify(path)}`;
}

private parseKey(key: string) {
if (!key.startsWith(this.prefix)) {
return;
}

return JSON.parse(key.slice(this.prefix.length)) as KeyType[];
}

private load(path: KeyType[]) {
const matchingPath = this.paths.find(
(p) => p.path.length === path.length && isAncestor(p.path, path),
Expand All @@ -148,7 +170,7 @@ export class Persist<T> {
return;
}

const key = JSON.stringify(path);
const key = this.buildKey(path);

return maybeAsync(this.storage.getItem(key), (value) => {
if (this.stopped || !value) {
Expand All @@ -171,7 +193,7 @@ export class Persist<T> {
}

private save(path: KeyType[]) {
const key = JSON.stringify(path);
const key = this.buildKey(path);
const value = get(this.store.get(), path as any);
const serializedValue = value === undefined ? 'undefined' : JSON.stringify(value);

Expand All @@ -180,9 +202,9 @@ export class Persist<T> {

return maybeAsync(this.storage.keys(), (keys) => {
const toRemove = keys.filter((k) => {
const parsedKey = JSON.parse(k);
const parsedKey = this.parseKey(k);
return (
parsedKey.length > path.length && isAncestor(path, parsedKey)
parsedKey && parsedKey.length > path.length && isAncestor(path, parsedKey)
// !this.queue.getRefs().find((ref) => isAncestor(ref, parsedKey))
);
});
Expand Down
56 changes: 28 additions & 28 deletions test/persist/persist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ describe('persist', () => {
test('wait initialized', async () => {
vi.useRealTimers();
const storage = new MockStorage({ keys: 1, get: 1 });
storage.items.set('["a"]', '1');
storage.items.set('test:["a"]', '1');
const s1 = createStore({ a: 0 });
const p = persist(s1, {
id: 'test',
Expand All @@ -118,7 +118,7 @@ describe('persist', () => {

s1.set({ a: { b: 2 } });

expect(storage.items).toStrictEqual(new Map([['["a"]', '{"b":2}']]));
expect(storage.items).toStrictEqual(new Map([['test:["a"]', '{"b":2}']]));
});

test('save path', async () => {
Expand All @@ -134,8 +134,8 @@ describe('persist', () => {

expect(storage.items).toStrictEqual(
new Map([
['["a"]', '4'],
['["c"]', '6'],
['test:["a"]', '4'],
['test:["c"]', '6'],
]),
);
});
Expand All @@ -153,8 +153,8 @@ describe('persist', () => {

expect(storage.items).toStrictEqual(
new Map([
['["a","x"]', '4'],
['["a","z"]', '5'],
['test:["a","x"]', '4'],
['test:["a","z"]', '5'],
]),
);
});
Expand All @@ -170,7 +170,7 @@ describe('persist', () => {

s1.set({ a: [1, 4, 3] });

expect(storage.items).toStrictEqual(new Map([['["a",1]', '4']]));
expect(storage.items).toStrictEqual(new Map([['test:["a",1]', '4']]));
});

test('save wildcard path with map', async () => {
Expand Down Expand Up @@ -198,8 +198,8 @@ describe('persist', () => {

expect(storage.items).toStrictEqual(
new Map([
['["a","x"]', '4'],
['["a","z"]', '5'],
['test:["a","x"]', '4'],
['test:["a","z"]', '5'],
]),
);
});
Expand All @@ -219,7 +219,7 @@ describe('persist', () => {
a: new Set([1, 4, 3]),
});

expect(storage.items).toStrictEqual(new Map([['["a",1]', '4']]));
expect(storage.items).toStrictEqual(new Map([['test:["a",1]', '4']]));
});

test('save removal', async () => {
Expand All @@ -232,14 +232,14 @@ describe('persist', () => {

s1.set({});

expect(storage.items).toStrictEqual(new Map([['["a"]', 'undefined']]));
expect(storage.items).toStrictEqual(new Map([['test:["a"]', 'undefined']]));
});
});

describe('load', () => {
test('load all', async () => {
const storage = new MockStorage();
storage.items.set('["a"]', '{"b":2}');
storage.items.set('test:["a"]', '{"b":2}');

const s1 = createStore({ a: { b: 1 } });
persist(s1, {
Expand All @@ -252,8 +252,8 @@ describe('persist', () => {

test('load path', async () => {
const storage = new MockStorage();
storage.items.set('["a"]', '4');
storage.items.set('["c"]', '6');
storage.items.set('test:["a"]', '4');
storage.items.set('test:["c"]', '6');

const s1 = createStore({ a: 1, b: 2, c: 3 });
persist(s1, {
Expand All @@ -267,8 +267,8 @@ describe('persist', () => {

test('load wildcard path', async () => {
const storage = new MockStorage();
storage.items.set('["a","x"]', '4');
storage.items.set('["a","z"]', '5');
storage.items.set('test:["a","x"]', '4');
storage.items.set('test:["a","z"]', '5');

const s1 = createStore({ a: { x: 1, y: 2, z: 3 } });
persist(s1, {
Expand All @@ -282,8 +282,8 @@ describe('persist', () => {

test(`doesn't load item whose path is not persisted anymore`, () => {
const storage = new MockStorage();
storage.items.set('["a"]', '3');
storage.items.set('["b"]', '4');
storage.items.set('test:["a"]', '3');
storage.items.set('test:["b"]', '4');

const s1 = createStore({ a: 1, b: 2 });
persist(s1, {
Expand All @@ -297,7 +297,7 @@ describe('persist', () => {

test('load removal', async () => {
const storage = new MockStorage();
storage.items.set('["a"]', 'undefined');
storage.items.set('test:["a"]', 'undefined');

const s1 = createStore<any>({ a: { b: 1 } });
persist(s1, {
Expand All @@ -312,7 +312,7 @@ describe('persist', () => {
describe('change something wile loading', () => {
test('changed same path', async () => {
const storage = new MockStorage({ get: 1 });
storage.items.set('["a"]', '2');
storage.items.set('test:["a"]', '2');

const s1 = createStore({ a: 1 });
persist(s1, {
Expand All @@ -324,13 +324,13 @@ describe('persist', () => {
vi.runAllTimers();
await flushPromises();

expect(storage.items).toStrictEqual(new Map([['["a"]', '3']]));
expect(storage.items).toStrictEqual(new Map([['test:["a"]', '3']]));
expect(s1.get()).toStrictEqual({ a: 3 });
});

test('changed ancestor path', async () => {
const storage = new MockStorage({ get: 1 });
storage.items.set('["a"]', '2');
storage.items.set('test:["a"]', '2');

const s1 = createStore<any>({ a: 1 });
persist(s1, {
Expand All @@ -343,13 +343,13 @@ describe('persist', () => {
vi.runAllTimers();
await flushPromises();

expect(storage.items).toStrictEqual(new Map([['[]', '{"b":3}']]));
expect(storage.items).toStrictEqual(new Map([['test:[]', '{"b":3}']]));
expect(s1.get()).toStrictEqual({ b: 3 });
});

test('changed descendant path', async () => {
const storage = new MockStorage({ get: 1 });
storage.items.set('[]', '{"a":2}');
storage.items.set('test:[]', '{"a":2}');

const s1 = createStore({ a: 1 });
persist(s1, {
Expand All @@ -364,8 +364,8 @@ describe('persist', () => {

expect(storage.items).toStrictEqual(
new Map([
['[]', '{"a":2}'],
['["a"]', '3'],
['test:[]', '{"a":2}'],
['test:["a"]', '3'],
]),
);
expect(s1.get()).toStrictEqual({ a: 3 });
Expand Down Expand Up @@ -425,7 +425,7 @@ describe('persist', () => {

expect(s1.get()).toStrictEqual({ a: 2 });
expect(s2.get()).toStrictEqual({ a: 3 });
expect(storage.items).toStrictEqual(new Map([[`["a"]`, '3']]));
expect(storage.items).toStrictEqual(new Map([[`test:["a"]`, '3']]));

vi.runAllTimers();
await flushPromises();
Expand All @@ -434,7 +434,7 @@ describe('persist', () => {

expect(s1.get()).toStrictEqual({ a: 3 });
expect(s2.get()).toStrictEqual({ a: 3 });
expect(storage.items).toStrictEqual(new Map([[`["a"]`, '3']]));
expect(storage.items).toStrictEqual(new Map([[`test:["a"]`, '3']]));
});

test.skip('sync avoids conflicts when updating ancestors or descendants', async () => {
Expand Down

0 comments on commit 7a2538e

Please sign in to comment.