Skip to content

Commit 0e13e23

Browse files
committed
Add tests to static-store
1 parent e9a516d commit 0e13e23

File tree

8 files changed

+170
-147
lines changed

8 files changed

+170
-147
lines changed

packages/map/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"ReactiveMap",
2020
"ReactiveWeakMap"
2121
],
22-
"category": "Utilities"
22+
"category": "Reactivity"
2323
},
2424
"keywords": [
2525
"map",

packages/set/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"ReactiveSet",
2020
"ReactiveWeakSet"
2121
],
22-
"category": "Utilities"
22+
"category": "Reactivity"
2323
},
2424
"keywords": [
2525
"solid",

packages/static-store/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
"name": "static-store",
1818
"stage": 0,
1919
"list": [
20-
"createPrimitiveTemplate"
20+
"createStaticStore",
21+
"createDerivedStaticStore"
2122
],
22-
"category": "Display & Media"
23+
"category": "Reactivity"
2324
},
2425
"keywords": [
2526
"solid",

packages/static-store/src/index.ts

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -46,44 +46,44 @@ export type StaticStoreSetter<T extends object> = {
4646
export function createStaticStore<T extends object>(
4747
init: T,
4848
): [access: T, write: StaticStoreSetter<T>] {
49-
const copy = { ...init };
50-
const store = { ...init };
51-
const cache = new Map<PropertyKey, Signal<any>>();
49+
const copy = { ...init },
50+
store = { ...init },
51+
cache: Partial<Record<PropertyKey, Signal<T[keyof T]>>> = {};
5252

53-
const getValue = <K extends keyof T>(key: K): T[K] => {
54-
const saved = cache.get(key);
55-
if (saved) return saved[0]();
56-
const signal = createSignal<any>(copy[key], {
57-
internal: true,
58-
});
59-
cache.set(key, signal);
60-
delete copy[key];
53+
const getValue = (key: keyof T): T[keyof T] => {
54+
let signal = cache[key];
55+
if (!signal) {
56+
if (!getListener()) return copy[key];
57+
cache[key] = signal = createSignal(copy[key], { internal: true });
58+
delete copy[key];
59+
}
6160
return signal[0]();
6261
};
6362

64-
const setValue = <K extends keyof T>(key: K, value: SetterParam<any>): void => {
65-
const saved = cache.get(key);
66-
if (saved) return saved[1](value);
67-
if (key in copy) copy[key] = accessWith(value, [copy[key]]);
68-
};
69-
7063
for (const key in init) {
71-
Object.defineProperty(store, key, { get: getValue.bind(void 0, key) });
64+
Object.defineProperty(store, key, { get: () => getValue(key), enumerable: true });
7265
}
7366

74-
const setter = (a: ((prev: T) => Partial<T>) | Partial<T> | keyof T, b?: SetterParam<any>) => {
75-
if (isObject(a)) {
76-
const entries = untrack(
77-
() => Object.entries(accessWith(a, store) as Partial<T>) as [any, any][],
78-
);
79-
batch(() => {
80-
for (const [key, value] of entries) setValue(key, () => value);
81-
});
82-
} else setValue(a, b);
83-
return store;
67+
const setValue = (key: keyof T, value: SetterParam<any>): void => {
68+
const signal = cache[key];
69+
if (signal) return signal[1](value);
70+
if (key in copy) copy[key] = accessWith(value, [copy[key]]);
8471
};
8572

86-
return [store, setter];
73+
return [
74+
store,
75+
(a: ((prev: T) => Partial<T>) | Partial<T> | keyof T, b?: SetterParam<any>) => {
76+
if (isObject(a)) {
77+
const entries = untrack(
78+
() => Object.entries(accessWith(a, store) as Partial<T>) as [any, any][],
79+
);
80+
batch(() => {
81+
for (const [key, value] of entries) setValue(key, () => value);
82+
});
83+
} else setValue(a, b);
84+
return store;
85+
},
86+
];
8787
}
8888

8989
/**
@@ -143,20 +143,20 @@ export function createDerivedStaticStore<T extends object>(
143143
value?: T,
144144
options?: MemoOptions<T>,
145145
): T {
146-
const cache = new Map<keyof T, Accessor<T[keyof T]>>(),
147-
o = getOwner(),
146+
const o = getOwner(),
148147
fnMemo = createMemo(fn, value, options),
149-
store = { ...untrack(fnMemo) };
148+
store = { ...untrack(fnMemo) },
149+
cache: Partial<Record<keyof T, Accessor<T[keyof T]>>> = {};
150150

151151
for (const key in store)
152152
Object.defineProperty(store, key, {
153153
get() {
154-
let propMemo = cache.get(key);
155-
if (!propMemo) {
154+
let keyMemo = cache[key];
155+
if (!keyMemo) {
156156
if (!getListener()) return fnMemo()[key];
157-
runWithOwner(o, () => cache.set(key, (propMemo = createMemo(() => fnMemo()[key]))));
157+
runWithOwner(o, () => (cache[key] = keyMemo = createMemo(() => fnMemo()[key])));
158158
}
159-
return propMemo!();
159+
return keyMemo!();
160160
},
161161
enumerable: true,
162162
});
Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,106 @@
1-
import { describe, test, expect } from "vitest";
2-
import { createRoot } from "solid-js";
3-
import { createPrimitiveTemplate } from "../src";
4-
5-
describe("createPrimitiveTemplate", () => {
6-
test("createPrimitiveTemplate return values", () =>
7-
createRoot(dispose => {
8-
const [value, setValue] = createPrimitiveTemplate(true);
9-
expect(value(), "initial value should be true").toBe(true);
10-
setValue(false);
11-
expect(value(), "value after change should be false").toBe(false);
12-
dispose();
1+
import { createEffect, createRoot, createSignal } from "solid-js";
2+
import { describe, expect, test } from "vitest";
3+
import { createDerivedStaticStore, createHydratableStaticStore, createStaticStore } from "../src";
4+
5+
describe("createStaticStore", () => {
6+
test("individual keys only update when changed", () => {
7+
let aUpdates = -1;
8+
9+
const { dispose, setState } = createRoot(dispose => {
10+
const _shape = { a: 1, b: 2, c: 3, d: [0, 1, 2] };
11+
const [state, setState] = createStaticStore(_shape);
12+
13+
expect(state).toEqual(_shape);
14+
expect(_shape, "original input shouldn't be mutated").toEqual({
15+
a: 1,
16+
b: 2,
17+
c: 3,
18+
d: [0, 1, 2],
19+
});
20+
21+
setState({ a: 9, d: [3, 2, 1] });
22+
23+
expect(state).toEqual({ a: 9, b: 2, c: 3, d: [3, 2, 1] });
24+
expect(_shape, "original input shouldn't be mutated").toEqual({
25+
a: 1,
26+
b: 2,
27+
c: 3,
28+
d: [0, 1, 2],
29+
});
30+
31+
createEffect(() => {
32+
state.a;
33+
aUpdates++;
34+
});
35+
36+
return { dispose, setState };
37+
});
38+
39+
expect(aUpdates).toBe(0);
40+
41+
setState({
42+
b: 3,
43+
});
44+
expect(aUpdates).toBe(0);
45+
setState("a", 4);
46+
expect(aUpdates).toBe(1);
47+
48+
dispose();
49+
});
50+
});
51+
52+
describe("createHydratableStaticStore", () => {
53+
test("createHydratableStaticStore() - CSR", () => {
54+
const [state, setState] = createHydratableStaticStore({ foo: "server" }, () => ({
55+
foo: "client",
1356
}));
57+
expect(state).toEqual({ foo: "client" });
58+
expect(setState).toBeInstanceOf(Function);
59+
});
60+
});
61+
62+
describe("createDerivedStaticStore", () => {
63+
test("individual keys only update when changed", () => {
64+
let aUpdates = -1;
65+
66+
const { dispose, set } = createRoot(dispose => {
67+
const _shape = { a: 1, b: 2, c: 3, d: [0, 1, 2] };
68+
const [s, set] = createSignal(_shape);
69+
const state = createDerivedStaticStore(s);
70+
71+
expect(state).toEqual(_shape);
72+
expect(_shape, "original input shouldn't be mutated").toEqual({
73+
a: 1,
74+
b: 2,
75+
c: 3,
76+
d: [0, 1, 2],
77+
});
78+
79+
set(p => ({ ...p, a: 9, d: [3, 2, 1] }));
80+
81+
expect(state).toEqual({ a: 9, b: 2, c: 3, d: [3, 2, 1] });
82+
expect(_shape, "original input shouldn't be mutated").toEqual({
83+
a: 1,
84+
b: 2,
85+
c: 3,
86+
d: [0, 1, 2],
87+
});
88+
89+
createEffect(() => {
90+
state.a;
91+
aUpdates++;
92+
});
93+
94+
return { dispose, set };
95+
});
96+
97+
expect(aUpdates).toBe(0);
98+
99+
set(p => ({ ...p, b: 3 }));
100+
expect(aUpdates).toBe(0);
101+
set(p => ({ ...p, a: 4 }));
102+
expect(aUpdates).toBe(1);
103+
104+
dispose();
105+
});
14106
});
Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
1-
import { describe, test, expect } from "vitest";
2-
import { createPrimitiveTemplate } from "../src";
1+
import { describe, expect, test } from "vitest";
2+
import { createHydratableStaticStore, createStaticStore, createDerivedStaticStore } from "../src";
33

4-
describe("createPrimitiveTemplate", () => {
4+
describe("createStaticStore", () => {
55
test("doesn't break in SSR", () => {
6-
const [value, setValue] = createPrimitiveTemplate(true);
7-
expect(value(), "initial value should be true").toBe(true);
6+
const [state, setState] = createStaticStore({ foo: "server" });
7+
expect(state).toEqual({ foo: "server" });
8+
expect(setState).toBeInstanceOf(Function);
9+
});
10+
});
11+
12+
describe("createHydratableStaticStore", () => {
13+
test("createHydratableStaticStore() - SSR", () => {
14+
const [state, setState] = createHydratableStaticStore({ foo: "server" }, () => ({
15+
foo: "client",
16+
}));
17+
expect(state).toEqual({ foo: "server" });
18+
expect(setState).toBeInstanceOf(Function);
19+
});
20+
});
21+
22+
describe("createDerivedStaticStore", () => {
23+
test("createDerivedStaticStore() - SSR", () => {
24+
const state = createDerivedStaticStore(() => ({ foo: "server" }));
25+
expect(state).toEqual({ foo: "server" });
826
});
927
});

packages/utils/test/index.test.ts

Lines changed: 1 addition & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,5 @@
11
import { describe, test, expect, assert } from "vitest";
2-
import { createComputed, createRoot } from "solid-js";
3-
import {
4-
createStaticStore,
5-
handleDiffArray,
6-
arrayEquals,
7-
createHydratableSignal,
8-
createHydratableStaticStore,
9-
} from "../src";
10-
11-
describe("createStaticStore", () => {
12-
test("individual keys only update when changed", () => {
13-
createRoot(dispose => {
14-
const _shape = { a: 1, b: 2, c: 3, d: [0, 1, 2] };
15-
const [state, setState] = createStaticStore(_shape);
16-
17-
expect(state).toEqual(_shape);
18-
expect(_shape, "original input shouldn't be mutated").toEqual({
19-
a: 1,
20-
b: 2,
21-
c: 3,
22-
d: [0, 1, 2],
23-
});
24-
25-
setState({ a: 9, d: [3, 2, 1] });
26-
27-
expect(state).toEqual({ a: 9, b: 2, c: 3, d: [3, 2, 1] });
28-
expect(_shape, "original input shouldn't be mutated").toEqual({
29-
a: 1,
30-
b: 2,
31-
c: 3,
32-
d: [0, 1, 2],
33-
});
34-
35-
let aUpdates = -1;
36-
createComputed(() => {
37-
state.a;
38-
aUpdates++;
39-
});
40-
expect(aUpdates).toBe(0);
41-
42-
setState({
43-
b: 3,
44-
});
45-
expect(aUpdates).toBe(0);
46-
setState("a", 4);
47-
expect(aUpdates).toBe(1);
48-
49-
dispose();
50-
});
51-
});
52-
53-
// tss("able to listen to key, not yet added", () =>
54-
// createRoot(dispose => {
55-
// const _shape = {};
56-
// const [state, setState] = createShallowStore<{ a?: number }>(_shape);
57-
58-
// let captured: any[] = [];
59-
// createComputed(() => captured.push(state.a));
60-
61-
// assert.equal(captured, [undefined]);
62-
63-
// setState("a", 1);
64-
65-
// assert.equal(captured, [undefined, 1]);
66-
67-
// dispose();
68-
// })
69-
// );
70-
});
2+
import { handleDiffArray, arrayEquals, createHydratableSignal } from "../src";
713

724
describe("handleDiffArray", () => {
735
test("handleAdded called for new array", () => {
@@ -170,13 +102,3 @@ describe("createHydratableSignal", () => {
170102
expect(setState).toBeInstanceOf(Function);
171103
});
172104
});
173-
174-
describe("createHydratableStaticStore", () => {
175-
test("createHydratableStaticStore() - CSR", () => {
176-
const [state, setState] = createHydratableStaticStore({ foo: "server" }, () => ({
177-
foo: "client",
178-
}));
179-
expect(state).toEqual({ foo: "client" });
180-
expect(setState).toBeInstanceOf(Function);
181-
});
182-
});

packages/utils/test/server.test.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createHydratableSignal, createHydratableStaticStore } from "../src";
1+
import { createHydratableSignal } from "../src";
22
import { describe, expect, test } from "vitest";
33

44
describe("API doesn't break in SSR", () => {
@@ -8,13 +8,3 @@ describe("API doesn't break in SSR", () => {
88
expect(setState).toBeInstanceOf(Function);
99
});
1010
});
11-
12-
describe("createHydratableStaticStore", () => {
13-
test("createHydratableStaticStore() - SSR", () => {
14-
const [state, setState] = createHydratableStaticStore({ foo: "server" }, () => ({
15-
foo: "client",
16-
}));
17-
expect(state).toEqual({ foo: "server" });
18-
expect(setState).toBeInstanceOf(Function);
19-
});
20-
});

0 commit comments

Comments
 (0)