muya 2.3.2 → 2.3.3

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.
@@ -1 +1 @@
1
- import{STATE_SCHEDULER as y}from"../create";import{getId as P}from"../utils/id";import{shallow as v}from"../utils/shallow";import{selectSql as O}from"./select-sql";import{createTable as R,DEFAULT_STEP_SIZE as M}from"./table/table";function K(g){const k=P();function m(e){return`state-${k}-search-${e}`}let h;async function o(){if(!h){const{backend:e,...n}=g,t=e instanceof Promise?await e:e;h=await R({backend:t,...n})}return h}const c=new Map,i=new Map,S=new Map;async function p(e,n){const t=S.get(e),{options:a={}}=n,{stepSize:s=M}=a;if(!t)return!1;const r=[];for(let u=0;u<s;u++){const l=await t.next();if(l.done){S.delete(e);break}n.keys.has(String(l.value.rowId))||(r.push(l.value.document),n.keys.add(String(l.value.rowId)))}return r.length===0||v(n.items,r)?!1:(n.items=[...n.items,...r],!0)}function b(e){const n=i.get(e);n&&n()}async function x(e){const n=await o(),t=c.get(e);if(!t)return;const{options:a}=t,s=n.search({...a,select:(r,{rowId:u})=>({document:r,rowId:u})});S.set(e,s),t.keys=new Set,t.items=[],await p(e,t)}async function f(e){await x(e),b(e)}function T(e){const{key:n,op:t}=e,a=new Set;for(const[s,{keys:r}]of c)switch(t){case"delete":case"update":{r.has(String(n))&&a.add(s);break}case"insert":{a.add(s);break}}return a}async function d(e){const n=new Set;for(const t of e){const a=T(t);for(const s of a)n.add(s)}for(const t of n){const a=m(t);y.schedule(a,{searchId:t})}}const w=new Set;function D(e,n){c.has(e)||(c.set(e,{items:[],options:n,keys:new Set}),n&&f(e));const t=c.get(e);return n&&(t.options=n),t}const I={async set(e){const t=await(await o()).set(e);return await d([t]),t},async batchSet(e){const t=await(await o()).batchSet(e);return await d(t),t},async delete(e){const t=await(await o()).delete(e);return t&&await d([t]),t},async deleteBy(e){const t=await(await o()).deleteBy(e);return await d(t),t},async get(e,n){return(await o()).get(e,n)},async*search(e={}){const n=await o();for await(const t of n.search(e))yield t},async count(e){return await(await o()).count(e)},updateSearchOptions(e,n){const t=D(e,n);t.options=n;const a=m(e);y.schedule(a,{searchId:e})},subscribe(e,n){const t=m(e),a=y.add(t,{onScheduleDone(){f(e)}});return w.add(a),i.has(e)||i.set(e,n),()=>{i.delete(e),a(),c.delete(e)}},getSnapshot(e){return D(e).items},refresh:f,destroy(){for(const e of w)e();c.clear(),i.clear()},async next(e){const n=c.get(e);if(n){const t=await p(e,n);return t&&b(e),t}return!1},select(e){return O(I,e)}};return I}export{K as createSqliteState};
1
+ import{STATE_SCHEDULER as f}from"../create";import{getId as P}from"../utils/id";import{shallow as v}from"../utils/shallow";import{selectSql as O}from"./select-sql";import{createTable as R,DEFAULT_STEP_SIZE as M}from"./table/table";function K(g){const k=P();function m(e){return`state-${k}-search-${e}`}let h;async function o(){if(!h){const{backend:e,...n}=g,t=e instanceof Promise?await e:e;h=await R({backend:t,...n})}return h}const c=new Map,i=new Map,S=new Map;async function p(e,n){const t=S.get(e),{options:a={}}=n,{stepSize:s=M}=a;if(!t)return!1;const r=[];for(let l=0;l<s;l++){const u=await t.next();if(u.done){S.delete(e);break}n.keys.has(String(u.value.rowId))||(r.push(u.value.document),n.keys.add(String(u.value.rowId)))}return r.length===0||v(n.items,r)?!1:(n.items=[...n.items,...r],!0)}function b(e){const n=i.get(e);n&&n()}async function x(e){const n=await o(),t=c.get(e);if(!t)return;const{options:a}=t,s=n.search({...a,select:(r,{rowId:l})=>({document:r,rowId:l})});S.set(e,s),t.keys=new Set,t.items=[],await p(e,t)}async function y(e){await x(e),b(e)}function T(e){const{key:n,op:t}=e,a=new Set;for(const[s,{keys:r}]of c)switch(t){case"delete":case"update":{r.has(String(n))&&a.add(s);break}case"insert":{a.add(s);break}}return a}async function d(e){const n=new Set;for(const t of e){const a=T(t);for(const s of a)n.add(s)}for(const t of n){const a=m(t);f.schedule(a,{searchId:t})}}const w=new Set;function D(e,n){c.has(e)||(c.set(e,{items:[],options:n,keys:new Set}),n&&y(e));const t=c.get(e);return n&&(t.options=n),t}const I={clear(e){c.delete(e)},async set(e){const t=await(await o()).set(e);return await d([t]),t},async batchSet(e){const t=await(await o()).batchSet(e);return await d(t),t},async delete(e){const t=await(await o()).delete(e);return t&&await d([t]),t},async deleteBy(e){const t=await(await o()).deleteBy(e);return await d(t),t},async get(e,n){return(await o()).get(e,n)},async*search(e={}){const n=await o();for await(const t of n.search(e))yield t},async count(e){return await(await o()).count(e)},updateSearchOptions(e,n){const t=D(e,n);t.options=n;const a=m(e);f.schedule(a,{searchId:e})},subscribe(e,n){const t=m(e),a=f.add(t,{onScheduleDone(){y(e)}});return w.add(a),i.has(e)||i.set(e,n),()=>{i.delete(e),a()}},getSnapshot(e){return D(e).items},refresh:y,destroy(){for(const e of w)e();c.clear(),i.clear()},async next(e){const n=c.get(e);if(n){const t=await p(e,n);return t&&b(e),t}return!1},select(e){return O(I,e)}};return I}export{K as createSqliteState};
@@ -1 +1 @@
1
- import{useCallback as r,useDebugValue as S,useId as p,useLayoutEffect as a,useMemo as D}from"react";import{isError as f,isPromise as y}from"../utils/is";import{useSyncExternalStoreWithSelector as x}from"use-sync-external-store/shim/with-selector";function L(e,s={},u=[]){const{select:c}=s,t=p();a(()=>{e.updateSearchOptions(t,{...s,select:void 0})},u);const l=r(o=>c?o.map(c):o,[c]),d=r(o=>e.subscribe(t,o),[e,t]),i=r(()=>e.getSnapshot(t),[e,t]),n=x(d,i,i,l);if(S(n),y(n)||f(n))throw n;const m=D(()=>({next:()=>e.next(t),reset:()=>e.refresh(t)}),[t,e]);return[n,m]}export{L as useSqliteValue};
1
+ import{useCallback as r,useDebugValue as S,useEffect as p,useId as a,useLayoutEffect as f,useMemo as D}from"react";import{isError as y,isPromise as x}from"../utils/is";import{useSyncExternalStoreWithSelector as b}from"use-sync-external-store/shim/with-selector";function O(e,s={},u=[]){const{select:c}=s,t=a();f(()=>{e.updateSearchOptions(t,{...s,select:void 0})},u),p(()=>()=>{e.clear(t)},[]);const l=r(o=>c?o.map(c):o,[c]),d=r(o=>e.subscribe(t,o),[e,t]),i=r(()=>e.getSnapshot(t),[e,t]),n=b(d,i,i,l);if(S(n),x(n)||y(n))throw n;const m=D(()=>({next:()=>e.next(t),reset:()=>e.refresh(t)}),[t,e]);return[n,m]}export{O as useSqliteValue};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muya",
3
- "version": "2.3.2",
3
+ "version": "2.3.3",
4
4
  "author": "samuel.gjabel@gmail.com",
5
5
  "repository": "https://github.com/samuelgjabel/muya",
6
6
  "main": "cjs/index.js",
@@ -4,7 +4,7 @@ import { createSqliteState } from '../create-sqlite'
4
4
  import { useSqliteValue } from '../use-sqlite'
5
5
  import { waitFor } from '@testing-library/react'
6
6
  import { bunMemoryBackend } from '../table/bun-backend'
7
- import { Suspense, useState } from 'react'
7
+ import { StrictMode, Suspense, useState } from 'react'
8
8
  import { DEFAULT_STEP_SIZE } from '../table/table'
9
9
 
10
10
  const backend = bunMemoryBackend()
@@ -15,13 +15,17 @@ interface Person {
15
15
  }
16
16
 
17
17
  function Wrapper({ children }: Readonly<{ children: React.ReactNode }>) {
18
- return <Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
18
+ return (
19
+ <StrictMode>
20
+ <Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
21
+ </StrictMode>
22
+ )
19
23
  }
20
24
  describe('use-sqlite-state', () => {
21
25
  it('should get basic value states', async () => {
22
26
  const sql = createSqliteState<Person>({ backend, tableName: 'State1', key: 'id' })
23
27
  let reRenders = 0
24
- const { result } = renderHook(
28
+ const { result, rerender } = renderHook(
25
29
  () => {
26
30
  reRenders++
27
31
  const aha = useSqliteValue(sql, {}, [])
@@ -66,6 +70,14 @@ describe('use-sqlite-state', () => {
66
70
  expect(result.current[0].length).toBe(2)
67
71
  expect(reRenders).toBe(6)
68
72
  })
73
+
74
+ act(() => {
75
+ rerender()
76
+ })
77
+ await waitFor(() => {
78
+ expect(reRenders).toBe(7)
79
+ expect(result.current[0].length).toBe(2)
80
+ })
69
81
  })
70
82
 
71
83
  it('should use where clause changed via state', async () => {
@@ -31,6 +31,7 @@ export interface SyncTable<Document extends DocType> {
31
31
  readonly deleteBy: (where: Where<Document>) => Promise<MutationResult[]>
32
32
  readonly destroy: () => void
33
33
  readonly next: (searchId: SearchId) => Promise<boolean>
34
+ readonly clear: (searchId: SearchId) => void
34
35
 
35
36
  readonly select: <Params extends unknown[]>(
36
37
  compute: (...args: Params) => SearchOptions<Document>,
@@ -221,6 +222,9 @@ export function createSqliteState<Document extends DocType>(options: CreateSqlit
221
222
  }
222
223
 
223
224
  const state: SyncTable<Document> = {
225
+ clear(searchId: SearchId) {
226
+ cachedData.delete(searchId)
227
+ },
224
228
  async set(document) {
225
229
  const table = await getTable()
226
230
  const changes = await table.set(document)
@@ -271,20 +275,19 @@ export function createSqliteState<Document extends DocType>(options: CreateSqlit
271
275
 
272
276
  subscribe(searchId, listener) {
273
277
  const scheduleId = getScheduleId(searchId)
274
- const clear = STATE_SCHEDULER.add(scheduleId, {
278
+ const clearScheduler = STATE_SCHEDULER.add(scheduleId, {
275
279
  onScheduleDone() {
276
280
  refresh(searchId)
277
281
  },
278
282
  })
279
- clearSchedulers.add(clear)
283
+ clearSchedulers.add(clearScheduler)
280
284
 
281
285
  if (!listeners.has(searchId)) {
282
286
  listeners.set(searchId, listener)
283
287
  }
284
288
  return () => {
285
289
  listeners.delete(searchId)
286
- clear()
287
- cachedData.delete(searchId)
290
+ clearScheduler()
288
291
  }
289
292
  },
290
293
  getSnapshot(searchId) {
@@ -1,4 +1,4 @@
1
- import { useCallback, useDebugValue, useId, useLayoutEffect, useMemo, type DependencyList } from 'react'
1
+ import { useCallback, useDebugValue, useEffect, useId, useLayoutEffect, useMemo, type DependencyList } from 'react'
2
2
  import type { SyncTable } from './create-sqlite'
3
3
  import type { DocType } from './table/table.types'
4
4
  import { isError, isPromise } from '../utils/is'
@@ -39,6 +39,13 @@ export function useSqliteValue<Document extends DocType, Selected = Document>(
39
39
  // eslint-disable-next-line react-hooks/exhaustive-deps
40
40
  }, deps)
41
41
 
42
+ useEffect(() => {
43
+ return () => {
44
+ state.clear(id)
45
+ }
46
+ // eslint-disable-next-line react-hooks/exhaustive-deps
47
+ }, [])
48
+
42
49
  const selector = useCallback(
43
50
  (documents: Document[]) => {
44
51
  // eslint-disable-next-line unicorn/no-array-callback-reference
@@ -22,6 +22,7 @@ export interface SyncTable<Document extends DocType> {
22
22
  readonly deleteBy: (where: Where<Document>) => Promise<MutationResult[]>;
23
23
  readonly destroy: () => void;
24
24
  readonly next: (searchId: SearchId) => Promise<boolean>;
25
+ readonly clear: (searchId: SearchId) => void;
25
26
  readonly select: <Params extends unknown[]>(compute: (...args: Params) => SearchOptions<Document>) => CreateState<Document, Params>;
26
27
  }
27
28
  /**