muya 2.4.3 → 2.4.5

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.
package/cjs/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var V=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var Y=Object.prototype.hasOwnProperty;var W=(e,r)=>{for(var o in r)V(e,o,{get:r[o],enumerable:!0})},J=(e,r,o,i)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of K(r))!Y.call(e,s)&&s!==o&&V(e,s,{get:()=>r[s],enumerable:!(i=N(r,s))||i.enumerable});return e};var Q=e=>J(V({},"__esModule",{value:!0}),e);var $={};W($,{EMPTY_SELECTOR:()=>v,create:()=>F,isAbortError:()=>I,isArray:()=>g,isEqualBase:()=>m,isError:()=>D,isFunction:()=>h,isMap:()=>x,isPromise:()=>f,isSet:()=>E,isSetValueFunction:()=>O,isState:()=>Z,isUndefined:()=>d,select:()=>P,shallow:()=>M,useValue:()=>C});module.exports=Q($);var p=class extends Error{static Error="AbortError"};function X(e,r){r&&r.abort();let o=new AbortController,{signal:i}=o;return{promise:new Promise((n,a)=>{i.addEventListener("abort",()=>{a(new p)}),e.then(n).catch(a)}),controller:o}}function y(e,r=m){if(!d(e.current)){if(!d(e.previous)&&r(e.current,e.previous))return!1;e.previous=e.current}return!0}function T(e,r){let{cache:o,emitter:{emit:i}}=e;if(!f(r))return r;o.abortController&&o.abortController.abort();let{promise:s,controller:n}=X(r,o.abortController);return o.abortController=n,s.then(a=>{o.current=a,i()}).catch(a=>{I(a)||(o.current=a,i())})}function f(e){return e instanceof Promise}function h(e){return typeof e=="function"}function x(e){return e instanceof Map}function E(e){return e instanceof Set}function g(e){return Array.isArray(e)}function m(e,r){return e===r?!0:!!Object.is(e,r)}function O(e){return typeof e=="function"}function I(e){return e instanceof p}function D(e){return e instanceof Error}function d(e){return e===void 0}function Z(e){return h(e)&&"get"in e&&"set"in e&&"isSet"in e&&e.isSet===!0}var v=e=>e;function U(){let e=new Map,r=new Set,o=performance.now(),i=!1;function s(){let a=performance.now(),t=a-o,{size:c}=r;if(t<.2&&c>0&&c<10){o=a,n();return}i||(i=!0,Promise.resolve().then(()=>{i=!1,o=performance.now(),n()}))}function n(){if(r.size===0)return;let a=new Set;for(let t of r){if(e.has(t.id)){a.add(t.id);let{onResolveItem:c}=e.get(t.id);c&&c(t.value)}r.delete(t)}if(r.size>0){s();return}for(let t of a)e.get(t)?.onScheduleDone()}return{add(a,t){return e.set(a,t),()=>{e.delete(a)}},schedule(a,t){r.add({value:t,id:a}),s()}}}function P(e,r,o){function i(){let u=!1,l=e.map(A=>{let w=A.get();return f(w)&&(u=!0),w});return u?new Promise((A,w)=>{Promise.all(l).then(G=>{if(G.some(_=>d(_)))return w(new p);let j=r(...G);A(j)})}):r(...l)}function s(){if(d(t.cache.current)){let u=i();t.cache.current=T(t,u)}return t.cache.current}function n(){if(d(t.cache.current)){let l=i();t.cache.current=T(t,l)}let{current:u}=t.cache;return f(u)?new Promise(l=>{u.then(S=>{if(d(S)){l(n());return}l(S)})}):t.cache.current}let a=[];for(let u of e){let l=u.emitter.subscribe(()=>{b.schedule(t.id,null)});a.push(l)}let t=k({destroy(){for(let u of a)u();c(),t.emitter.clear(),t.cache.current=void 0},get:n,getSnapshot:s}),c=b.add(t.id,{onScheduleDone(){let u=i();t.cache.current=T(t,u),y(t.cache,o)&&t.emitter.emit()}});return t}var R=require("react");var L=require("use-sync-external-store/shim/with-selector");function C(e,r=v){let{emitter:o}=e,i=(0,L.useSyncExternalStoreWithSelector)(e.emitter.subscribe,o.getSnapshot,o.getInitialSnapshot,r);if((0,R.useDebugValue)(i),f(i)||D(i))throw i;return i}function q(e,r){let o=new Set,i=[];return{clear:()=>{for(let s of i)s();o.clear()},subscribe:s=>(o.add(s),()=>{o.delete(s)}),emit:(...s)=>{for(let n of o)n(...s)},contains:s=>o.has(s),getSnapshot:e,getInitialSnapshot:r,getSize:()=>o.size,subscribeToOtherEmitter(s){let n=s.subscribe(()=>{this.emit()});i.push(n)}}}var H=0;function z(){return H++,H.toString(36)}function k(e){let{get:r,destroy:o,set:i,getSnapshot:s}=e,n=!!i,a={},t=function(c){return C(t,c)};return t.isSet=n,t.id=z(),t.emitter=q(s),t.destroy=o,t.listen=function(c){return this.emitter.subscribe(()=>{let u=r();f(u)||c(r())})},t.withName=function(c){return this.stateName=c,this},t.select=function(c,u=m){return P([t],c,u)},t.get=r,t.set=i,t.cache=a,t}var b=U();function F(e,r=m){function o(){try{if(d(n.cache.current)){let t=h(e)?e():e,c=T(n,t);return n.cache.current=c,n.cache.current}return n.cache.current}catch(t){n.cache.current=t}return n.cache.current}async function i(t,c){await t;let u=c(n.cache.current),l=T(n,u);n.cache.current=l}function s(t){let c=o(),u=O(t);if(u&&f(c)){i(c,t);return}n.cache.abortController&&n.cache.abortController.abort();let l=u?t(c):t,S=T(n,l);n.cache.current=S}let n=k({get:o,destroy(){o(),a(),n.emitter.clear(),n.cache.current=void 0},set(t){b.schedule(n.id,t)},getSnapshot:o}),a=b.add(n.id,{onScheduleDone(){n.cache.current=o(),y(n.cache,r)&&n.emitter.emit()},onResolveItem:s});return h(e)||o(),n}function M(e,r){if(e==r)return!0;if(typeof e!="object"||e==null||typeof r!="object"||r==null)return!1;if(x(e)&&x(r)){if(e.size!==r.size)return!1;for(let[s,n]of e)if(!Object.is(n,r.get(s)))return!1;return!0}if(E(e)&&E(r)){if(e.size!==r.size)return!1;for(let s of e)if(!r.has(s))return!1;return!0}if(g(e)&&g(r)){if(e.length!==r.length)return!1;for(let[s,n]of e.entries())if(!Object.is(n,r[s]))return!1;return!0}let o=Object.keys(e),i=Object.keys(r);if(o.length!==i.length)return!1;for(let s of o)if(!Object.prototype.hasOwnProperty.call(r,s)||!Object.is(e[s],r[s]))return!1;return!0}
1
+ "use strict";var V=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var Y=Object.prototype.hasOwnProperty;var W=(e,t)=>{for(var o in t)V(e,o,{get:t[o],enumerable:!0})},J=(e,t,o,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of K(t))!Y.call(e,s)&&s!==o&&V(e,s,{get:()=>t[s],enumerable:!(a=N(t,s))||a.enumerable});return e};var Q=e=>J(V({},"__esModule",{value:!0}),e);var $={};W($,{EMPTY_SELECTOR:()=>D,create:()=>z,isAbortError:()=>I,isArray:()=>g,isEqualBase:()=>m,isError:()=>v,isFunction:()=>h,isMap:()=>x,isPromise:()=>f,isSet:()=>E,isSetValueFunction:()=>O,isState:()=>Z,isUndefined:()=>d,select:()=>k,shallow:()=>F,useValue:()=>C});module.exports=Q($);var T=class extends Error{static Error="AbortError"};function X(e,t){t&&t.abort();let o=new AbortController,{signal:a}=o;return{promise:new Promise((n,u)=>{a.addEventListener("abort",()=>{u(new T)}),e.then(n).catch(u)}),controller:o}}function y(e,t=m){if(!d(e.current)){if(!d(e.previous)&&t(e.current,e.previous))return!1;e.previous=e.current}return!0}function p(e,t){let{cache:o,emitter:{emit:a}}=e;if(!f(t))return t;o.abortController&&o.abortController.abort();let{promise:s,controller:n}=X(t,o.abortController);return o.abortController=n,s.then(u=>{o.current=u,a()}).catch(u=>{I(u)||(o.current=u,a())})}function f(e){return e instanceof Promise}function h(e){return typeof e=="function"}function x(e){return e instanceof Map}function E(e){return e instanceof Set}function g(e){return Array.isArray(e)}function m(e,t){return e===t?!0:!!Object.is(e,t)}function O(e){return typeof e=="function"}function I(e){return e instanceof T}function v(e){return e instanceof Error}function d(e){return e===void 0}function Z(e){return h(e)&&"get"in e&&"set"in e&&"isSet"in e&&e.isSet===!0}var D=e=>e;function U(){let e=new Map,t=new Set,o=performance.now(),a=!1;function s(){let u=performance.now(),r=u-o,{size:i}=t;if(r<.2&&i>0&&i<10){o=u,n();return}a||(a=!0,Promise.resolve().then(()=>{a=!1,o=performance.now(),n()}))}function n(){if(t.size===0)return;let u=new Set,r=new Map;for(let i of t){if(e.has(i.id)){u.add(i.id);let{onResolveItem:c}=e.get(i.id);c&&c(i.value),r.has(i.id)||r.set(i.id,[]),r.get(i.id).push(i.value)}t.delete(i)}if(t.size>0){s();return}for(let i of u){let c=r.get(i);e.get(i)?.onScheduleDone(c)}}return{add(u,r){return e.set(u,r),()=>{e.delete(u)}},schedule(u,r){t.add({value:r,id:u}),s()}}}function k(e,t,o){function a(){let c=!1,l=e.map(A=>{let w=A.get();return f(w)&&(c=!0),w});return c?new Promise((A,w)=>{Promise.all(l).then(G=>{if(G.some(_=>d(_)))return w(new T);let j=t(...G);A(j)})}):t(...l)}function s(){if(d(r.cache.current)){let c=a();r.cache.current=p(r,c)}return r.cache.current}function n(){if(d(r.cache.current)){let l=a();r.cache.current=p(r,l)}let{current:c}=r.cache;return f(c)?new Promise(l=>{c.then(S=>{if(d(S)){l(n());return}l(S)})}):r.cache.current}let u=[];for(let c of e){let l=c.emitter.subscribe(()=>{b.schedule(r.id,null)});u.push(l)}let r=P({destroy(){for(let c of u)c();i(),r.emitter.clear(),r.cache.current=void 0},get:n,getSnapshot:s}),i=b.add(r.id,{onScheduleDone(){let c=a();r.cache.current=p(r,c),y(r.cache,o)&&r.emitter.emit()}});return r}var R=require("react");var L=require("use-sync-external-store/shim/with-selector");function C(e,t=D){let{emitter:o}=e,a=(0,L.useSyncExternalStoreWithSelector)(e.emitter.subscribe,o.getSnapshot,o.getInitialSnapshot,t);if((0,R.useDebugValue)(a),f(a)||v(a))throw a;return a}function q(e,t){let o=new Set,a=[];return{clear:()=>{for(let s of a)s();o.clear()},subscribe:s=>(o.add(s),()=>{o.delete(s)}),emit:(...s)=>{for(let n of o)n(...s)},contains:s=>o.has(s),getSnapshot:e,getInitialSnapshot:t,getSize:()=>o.size,subscribeToOtherEmitter(s){let n=s.subscribe(()=>{this.emit()});a.push(n)}}}var M=0;function H(){return M++,M.toString(36)}function P(e){let{get:t,destroy:o,set:a,getSnapshot:s}=e,n=!!a,u={},r=function(i){return C(r,i)};return r.isSet=n,r.id=H(),r.emitter=q(s),r.destroy=o,r.listen=function(i){return this.emitter.subscribe(()=>{let c=t();f(c)||i(t())})},r.withName=function(i){return this.stateName=i,this},r.select=function(i,c=m){return k([r],i,c)},r.get=t,r.set=a,r.cache=u,r}var b=U();function z(e,t=m){function o(){try{if(d(n.cache.current)){let r=h(e)?e():e,i=p(n,r);return n.cache.current=i,n.cache.current}return n.cache.current}catch(r){n.cache.current=r}return n.cache.current}async function a(r,i){await r;let c=i(n.cache.current),l=p(n,c);n.cache.current=l}function s(r){let i=o(),c=O(r);if(c&&f(i)){a(i,r);return}n.cache.abortController&&n.cache.abortController.abort();let l=c?r(i):r,S=p(n,l);n.cache.current=S}let n=P({get:o,destroy(){o(),u(),n.emitter.clear(),n.cache.current=void 0},set(r){b.schedule(n.id,r)},getSnapshot:o}),u=b.add(n.id,{onScheduleDone(){n.cache.current=o(),y(n.cache,t)&&n.emitter.emit()},onResolveItem:s});return h(e)||o(),n}function F(e,t){if(e==t)return!0;if(typeof e!="object"||e==null||typeof t!="object"||t==null)return!1;if(x(e)&&x(t)){if(e.size!==t.size)return!1;for(let[s,n]of e)if(!Object.is(n,t.get(s)))return!1;return!0}if(E(e)&&E(t)){if(e.size!==t.size)return!1;for(let s of e)if(!t.has(s))return!1;return!0}if(g(e)&&g(t)){if(e.length!==t.length)return!1;for(let[s,n]of e.entries())if(!Object.is(n,t[s]))return!1;return!0}let o=Object.keys(e),a=Object.keys(t);if(o.length!==a.length)return!1;for(let s of o)if(!Object.prototype.hasOwnProperty.call(t,s)||!Object.is(e[s],t[s]))return!1;return!0}
package/esm/scheduler.js CHANGED
@@ -1 +1 @@
1
- const u=.2,i=10,f=0;function a(){const t=new Map,o=new Set;let d=performance.now(),c=!1;function s(){const n=performance.now(),e=n-d,{size:r}=o;if(e<.2&&r>0&&r<10){d=n,l();return}c||(c=!0,Promise.resolve().then(()=>{c=!1,d=performance.now(),l()}))}function l(){if(o.size===0)return;const n=new Set;for(const e of o){if(t.has(e.id)){n.add(e.id);const{onResolveItem:r}=t.get(e.id);r&&r(e.value)}o.delete(e)}if(o.size>0){s();return}for(const e of n)t.get(e)?.onScheduleDone()}return{add(n,e){return t.set(n,e),()=>{t.delete(n)}},schedule(n,e){o.add({value:e,id:n}),s()}}}export{f as RESCHEDULE_COUNT,u as THRESHOLD,i as THRESHOLD_ITEMS,a as createScheduler};
1
+ const i=.2,a=10,f=0;function S(){const s=new Map,o=new Set;let r=performance.now(),c=!1;function l(){const n=performance.now(),t=n-r,{size:e}=o;if(t<.2&&e>0&&e<10){r=n,u();return}c||(c=!0,Promise.resolve().then(()=>{c=!1,r=performance.now(),u()}))}function u(){if(o.size===0)return;const n=new Set,t=new Map;for(const e of o){if(s.has(e.id)){n.add(e.id);const{onResolveItem:d}=s.get(e.id);d&&d(e.value),t.has(e.id)||t.set(e.id,[]),t.get(e.id).push(e.value)}o.delete(e)}if(o.size>0){l();return}for(const e of n){const d=t.get(e);s.get(e)?.onScheduleDone(d)}}return{add(n,t){return s.set(n,t),()=>{s.delete(n)}},schedule(n,t){o.add({value:t,id:n}),l()}}}export{f as RESCHEDULE_COUNT,i as THRESHOLD,a as THRESHOLD_ITEMS,S as createScheduler};
@@ -1 +1 @@
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 M}from"./select-sql";import{createTable as O,DEFAULT_STEP_SIZE as R}from"./table/table";function q(g){const k=P();function m(e){return`state-${k}-search-${e}`}let h;async function s(){if(!h){const{backend:e,...n}=g,t=e instanceof Promise?await e:e;h=await O({backend:t,...n})}return h}const r=new Map,i=new Map,y=new Map;async function p(e,n){const t=y.get(e),{options:a={}}=n,{stepSize:c=R}=a;if(!t)return!1;const o=[];for(let u=0;u<c;u++){const d=await t.next();if(d.done){y.delete(e);break}n.keys.has(String(d.value.key))||(o.push(d.value.document),n.keys.add(String(d.value.key)))}return o.length===0||v(n.items,o)?!1:(n.items=[...n.items,...o],!0)}function b(e){const n=i.get(e);if(n)for(const[,t]of n)t()}async function x(e){const n=await s(),t=r.get(e);if(!t)return;const{options:a}=t,c=n.search({...a,select:(o,{rowId:u,key:d})=>({document:o,rowId:u,key:d})});y.set(e,c),t.keys=new Set,t.items=[],await p(e,t)}async function S(e){await x(e),b(e)}function T(e){const{key:n,op:t}=e,a=new Set;for(const[c,{keys:o}]of r)switch(t){case"delete":case"update":{o.has(String(n))&&a.add(c);break}case"insert":{a.add(c);break}}return a}async function l(e){const n=new Set;for(const t of e){const a=T(t);for(const c of a)n.add(c)}for(const t of n){const a=m(t);f.schedule(a,{searchId:t})}}const w=new Set;function D(e,n){r.has(e)||(r.set(e,{items:[],options:n,keys:new Set}),n&&S(e));const t=r.get(e);return n&&(t.options=n),t}const I={clear(e){r.delete(e)},async set(e){const t=await(await s()).set(e);return await l([t]),t},async batchSet(e){const t=await(await s()).batchSet(e);return await l(t),t},async delete(e){const t=await(await s()).delete(e);return t&&await l([t]),t},async deleteBy(e){const t=await(await s()).deleteBy(e);return await l(t),t},async get(e,n){return(await s()).get(e,n)},async*search(e={}){const n=await s();for await(const t of n.search(e))yield t},async count(e){return await(await s()).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,t){const a=m(e),c=f.add(a,{onScheduleDone(){S(e)}});w.add(c),i.has(e)||i.set(e,new Map);const o=i.get(e);return o.set(n,t),()=>{o.delete(n),o.size===0&&i.delete(e),c()}},getSnapshot(e){return D(e).items},refresh:S,destroy(){for(const e of w)e();r.clear(),i.clear()},async next(e){const n=r.get(e);if(n){const t=await p(e,n);return t&&b(e),t}return!1},select(e){return M(I,e)}};return I}export{q as createSqliteState};
1
+ import{STATE_SCHEDULER as l}from"../create";import{getId as m}from"../utils/id";import{createTable as d}from"./table/table";function D(u){let s;async function a(){if(!s){const{backend:e,...n}=u,t=e instanceof Promise?await e:e;s=await d({backend:t,...n})}return s}const i=m();l.add(i,{onScheduleDone(e){if(!e)return;const n=e,t={};for(const c of n)c.removedAll&&(t.removedAll=!0),c.mutations&&(t.mutations||(t.mutations=[]),t.mutations.push(...c.mutations));for(const c of r)c(t)}});function o(e){l.schedule(i,e)}const r=new Set;return{subscribe(e){return r.add(e),()=>r.delete(e)},clear(){s?.clear(),o({removedAll:!0})},async set(e){const t=await(await a()).set(e);return o({mutations:[t]}),t},async batchSet(e){const t=await(await a()).batchSet(e);return o({mutations:t}),t},async delete(e){const t=await(await a()).delete(e);return t&&o({mutations:[t]}),t},async deleteBy(e){const t=await(await a()).deleteBy(e);return o({mutations:t}),t},async get(e,n){return(await a()).get(e,n)},async*search(e={}){const n=await a();for await(const t of n.search(e))yield t},async count(e){return await(await a()).count(e)}}}export{D as createSqliteState};
@@ -1 +1 @@
1
- export*from"./create-sqlite";export*from"./table";export*from"./select-sql";export*from"./use-sqlite";
1
+ export*from"./create-sqlite";export*from"./table";export*from"./use-sqlite-count";export*from"./use-sqlite";
@@ -1,4 +1,4 @@
1
- import{unicodeTokenizer as C}from"./tokenizer";import{getWhereQuery as k}from"./where";const L=500,M=100;function R(l){return"$."+l}function U(l,a){if(!(!l||!a))return a.split(".").reduce((t,y)=>{if(typeof t=="object"&&t!==null&&y in t)return t[y]},l)}async function z(l){const{backend:a,tableName:t,indexes:y,key:$,disablePragmaOptimization:x}=l,u=$!==void 0;x||(await a.execute("PRAGMA journal_mode=WAL;"),await a.execute("PRAGMA synchronous=NORMAL;"),await a.execute("PRAGMA temp_store=MEMORY;"),await a.execute("PRAGMA cache_size=-20000;")),u?await a.execute(`
1
+ import{unicodeTokenizer as C}from"./tokenizer";import{getWhereQuery as k}from"./where";const L=500,M=100;function R(l){return"$."+l}function U(l,a){if(!(!l||!a))return a.split(".").reduce((t,y)=>{if(typeof t=="object"&&t!==null&&y in t)return t[y]},l)}async function P(l){const{backend:a,tableName:t,indexes:y,key:A,disablePragmaOptimization:x}=l,u=A!==void 0;x||(await a.execute("PRAGMA journal_mode=WAL;"),await a.execute("PRAGMA synchronous=NORMAL;"),await a.execute("PRAGMA temp_store=MEMORY;"),await a.execute("PRAGMA cache_size=-20000;")),u?await a.execute(`
2
2
  CREATE TABLE IF NOT EXISTS ${t} (
3
3
  key TEXT PRIMARY KEY,
4
4
  data TEXT NOT NULL
@@ -35,4 +35,4 @@ import{unicodeTokenizer as C}from"./tokenizer";import{getWhereQuery as k}from"./
35
35
  SET ${T.map(o=>`${f[o]}=json_extract(new.data, '${R(o)}')`).join(", ")}
36
36
  WHERE rowid = old.rowid;
37
37
  END;
38
- `)}function A(e){if(u)return U(e,String($))}async function b(e){return(await e.select("SELECT changes() AS c"))[0]?.c??0}const g={backend:a,async set(e,n){const r=n??a,o=JSON.stringify(e);if(u){const s=A(e);if(s==null)throw new Error(`Document is missing the configured key "${String($)}".`);if(await r.execute(`UPDATE ${t} SET data = ? WHERE key = ?`,[o,s]),await b(r)===1)return{key:s,op:"update"};try{return await r.execute(`INSERT INTO ${t} (key, data) VALUES (?, ?)`,[s,o]),{key:s,op:"insert"}}catch{return await r.execute(`UPDATE ${t} SET data = ? WHERE key = ?`,[o,s]),{key:s,op:"update"}}}await r.execute(`INSERT INTO ${t} (data) VALUES (?)`,[o]);const c=(await r.select("SELECT last_insert_rowid() AS id"))[0]?.id;if(typeof c!="number")throw new Error("Failed to retrieve last_insert_rowid()");return{key:c,op:"insert"}},async get(e,n=r=>r){const r=u?"key = ?":"rowid = ?",o=await a.select(`SELECT rowid, data FROM ${t} WHERE ${r}`,[e]);if(o.length===0)return;const{data:E,rowid:c}=o[0],s=JSON.parse(E),i=u?A(s)??c:c;return n(s,{rowId:c,key:i})},async delete(e){const n=u?"key = ?":"rowid = ?";if(await a.execute(`DELETE FROM ${t} WHERE ${n}`,[e]),((await a.select("SELECT changes() AS c"))[0]?.c??0)>0)return{key:e,op:"delete"}},async*search(e={}){const{sortBy:n,order:r="asc",limit:o,offset:E=0,where:c,select:s=w=>w,stepSize:i=M}=e,p=k(c,t),h=`SELECT rowid, data FROM ${t} ${p}`;let S=0,D=E;for(;;){let w=h;n?w+=` ORDER BY json_extract(data, '${R(String(n))}') COLLATE NOCASE ${r.toUpperCase()}`:w+=u?` ORDER BY key COLLATE NOCASE ${r.toUpperCase()}`:` ORDER BY rowid ${r.toUpperCase()}`;const I=o?Math.min(i,o-S):i;w+=` LIMIT ${I} OFFSET ${D}`;const m=await a.select(w);if(m.length===0)break;for(const{rowid:O,data:F}of m){if(o&&S>=o)return;const N=JSON.parse(F),_=u?A(N)??O:O;yield s(N,{rowId:O,key:_}),S++}if(m.length<I||o&&S>=o)break;D+=m.length}},async count(e={}){const n=k(e.where,t),r=`SELECT COUNT(*) as count FROM ${t} ${n}`;return(await a.select(r))[0]?.count??0},async deleteBy(e){const n=k(e,t),r=u?"key":"rowid",o=[];return await a.transaction(async E=>{const c=await E.select(`SELECT ${r} AS k FROM ${t} ${n}`);if(c.length===0)return;const s=c.map(i=>i.k);for(let i=0;i<s.length;i+=L){const p=s.slice(i,i+L),h=p.map(()=>"?").join(",");await E.execute(`DELETE FROM ${t} WHERE ${r} IN (${h})`,p)}for(const i of s)o.push({key:i,op:"delete"})}),o},async clear(){await a.execute(`DELETE FROM ${t}`)},async batchSet(e){const n=[];return await a.transaction(async r=>{for(const o of e){const E=await g.set(o,r);n.push(E)}}),n}};return g}export{M as DEFAULT_STEP_SIZE,z as createTable,U as getByPath,R as toJsonPath};
38
+ `)}function $(e){if(u)return U(e,String(A))}async function b(e){return(await e.select("SELECT changes() AS c"))[0]?.c??0}const g={backend:a,async set(e,n){const r=n??a,o=JSON.stringify(e);if(u){const s=$(e);if(s==null)throw new Error(`Document is missing the configured key "${String(A)}".`);if(await r.execute(`UPDATE ${t} SET data = ? WHERE key = ?`,[o,s]),await b(r)===1)return{key:s,op:"update"};try{return await r.execute(`INSERT INTO ${t} (key, data) VALUES (?, ?)`,[s,o]),{key:s,op:"insert"}}catch{return await r.execute(`UPDATE ${t} SET data = ? WHERE key = ?`,[o,s]),{key:s,op:"update"}}}await r.execute(`INSERT INTO ${t} (data) VALUES (?)`,[o]);const c=(await r.select("SELECT last_insert_rowid() AS id"))[0]?.id;if(typeof c!="number")throw new Error("Failed to retrieve last_insert_rowid()");return{key:c,op:"insert"}},async get(e,n=r=>r){const r=u?"key = ?":"rowid = ?",o=await a.select(`SELECT rowid, data FROM ${t} WHERE ${r}`,[e]);if(o.length===0)return;const{data:E,rowid:c}=o[0],s=JSON.parse(E),i=u?$(s)??c:c;return n(s,{rowId:c,key:i})},async delete(e){const n=u?"key = ?":"rowid = ?";if(await a.execute(`DELETE FROM ${t} WHERE ${n}`,[e]),((await a.select("SELECT changes() AS c"))[0]?.c??0)>0)return{key:e,op:"delete"}},async*search(e={}){const{sortBy:n,order:r="asc",limit:o,offset:E=0,where:c,select:s=w=>w,pageSize:i=M}=e,p=k(c,t),h=`SELECT rowid, data FROM ${t} ${p}`;let S=0,D=E;for(;;){let w=h;n?w+=` ORDER BY json_extract(data, '${R(String(n))}') COLLATE NOCASE ${r.toUpperCase()}`:w+=u?` ORDER BY key COLLATE NOCASE ${r.toUpperCase()}`:` ORDER BY rowid ${r.toUpperCase()}`;const I=o?Math.min(i,o-S):i;w+=` LIMIT ${I} OFFSET ${D}`;const m=await a.select(w);if(m.length===0)break;for(const{rowid:O,data:F}of m){if(o&&S>=o)return;const N=JSON.parse(F),_=u?$(N)??O:O;yield s(N,{rowId:O,key:_}),S++}if(m.length<I||o&&S>=o)break;D+=m.length}},async count(e={}){const n=k(e.where,t),r=`SELECT COUNT(*) as count FROM ${t} ${n}`;return(await a.select(r))[0]?.count??0},async deleteBy(e){const n=k(e,t),r=u?"key":"rowid",o=[];return await a.transaction(async E=>{const c=await E.select(`SELECT ${r} AS k FROM ${t} ${n}`);if(c.length===0)return;const s=c.map(i=>i.k);for(let i=0;i<s.length;i+=L){const p=s.slice(i,i+L),h=p.map(()=>"?").join(",");await E.execute(`DELETE FROM ${t} WHERE ${r} IN (${h})`,p)}for(const i of s)o.push({key:i,op:"delete"})}),o},async clear(){await a.execute(`DELETE FROM ${t}`)},async batchSet(e){const n=[];return await a.transaction(async r=>{for(const o of e){const E=await g.set(o,r);n.push(E)}}),n}};return g}export{M as DEFAULT_PAGE_SIZE,P as createTable,U as getByPath,R as toJsonPath};
@@ -0,0 +1 @@
1
+ import{useCallback as l,useEffect as b,useLayoutEffect as y,useReducer as d,useRef as D}from"react";function w(t,f={},r=[]){const n=D(0),[,o]=d(e=>e+1,0),u=l(async()=>{const e=await t.count(f);n.current=e,o()},r);return b(()=>{u()},r),y(()=>{const e=t.subscribe(a=>{const{mutations:c,removedAll:m}=a;if(m){n.current=0,o();return}if(!c)return;let s=!1;for(const p of c){const{op:i}=p;if(i==="insert"||i==="delete"){s=!0;break}}s&&u()});return()=>{e()}},[t]),n.current}export{w as useSqliteCount};
@@ -1 +1 @@
1
- import{useCallback as f,useDebugValue as p,useEffect as a,useId as y,useLayoutEffect as D,useMemo as S}from"react";import{isError as h,isPromise as x}from"../utils/is";import{useSyncExternalStoreWithSelector as b}from"use-sync-external-store/shim/with-selector";function q(t){const{limit:o,offset:s,order:c,sortBy:e,where:i,stepSize:u,select:d}=t;let n="";return o!==void 0&&(n+=`l${o}`),s!==void 0&&(n+=`o${s}`),c!==void 0&&(n+=`r${c}`),e!==void 0&&(n+=`s${e}`),i!==void 0&&(n+=`w${JSON.stringify(i)}`),u!==void 0&&(n+=`t${u}`),d!==void 0&&(n+=`f${d.toString()}`),n}function w(t,o={},s=[]){const{select:c}=o,e=S(()=>q({...o,select:void 0}),[o]),i=y();D(()=>{t.updateSearchOptions(e,{...o,select:void 0})},s),a(()=>()=>{t.clear(e)},[]);const u=f(l=>c?l.map(c):l,[c]),d=f(l=>t.subscribe(e,i,l),[t,e,i]),n=f(()=>t.getSnapshot(e),[t,e]),r=b(d,n,n,u);if(p(r),x(r)||h(r))throw r;const m=S(()=>({next:()=>t.next(e),reset:()=>t.refresh(e)}),[e,t]);return[r,m]}export{w as useSqliteValue};
1
+ import{useCallback as l,useLayoutEffect as A,useReducer as v,useRef as D}from"react";import{DEFAULT_PAGE_SIZE as O}from"./table";const I=1e4;function _(u,g={},k=[]){const{select:p,pageSize:P=O}=g,e=D(),[,w]=v(n=>n+1,0),t=D(new Map),S=D(),b=l(()=>{const{select:n,...o}=g;S.current=u.search({select:(c,s)=>({doc:c,meta:s}),...o})},[u,...k]),f=l(()=>{e.current=[],t.current.clear(),b()},[b]),m=l(async n=>{e.current===void 0&&(e.current=[]),n===!0&&f();const{current:o}=S;if(!o)return!0;let c=!1;for(let s=0;s<P;s++){const r=await o.next();if(r.done){S.current=void 0,c=!0;break}if(t.current.has(r.value.meta.key)){s+=-1;continue}e.current.push(p?p(r.value.doc):r.value.doc),t.current.set(r.value.meta.key,e.current.length-1)}return c},[]),y=l(async()=>{const n=await m(!1);return w(),n},[m]);A(()=>{const n=u.subscribe(async o=>{const{mutations:c,removedAll:s}=o;if(s&&f(),!c)return;const r=e.current?.length??0;let h=r,x=!1;for(const i of c){const{key:a,op:q}=i;switch(q){case"insert":{h+=1;break}case"delete":{if(e.current&&t.current.has(a)){const d=t.current.get(a);if(d===void 0)break;e.current.splice(d,1),t.current.delete(a),x=!0}break}case"update":{if(e.current&&t.current.has(a)){const d=t.current.get(a);if(d===void 0)break;e.current[d]=await u.get(a,p),x=!0}break}}}const L=r!==h;if(L||x){if(L){await m(!0);let i=0;for(;(e.current?.length??0)<h&&i<I;)await m(!1),i++;i===I&&console.warn("Reached maximum iterations in fillNextPage loop. Possible duplicate or data issue.")}w()}});return()=>{n()}},[u]),A(()=>{b(),e.current=void 0,t.current.clear(),y()},k);const T=l(async()=>{f(),await y()},[y,f]);return[e.current,{nextPage:y,reset:T,keysIndex:t.current}]}export{_ as useSqliteValue};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muya",
3
- "version": "2.4.3",
3
+ "version": "2.4.5",
4
4
  "author": "samuel.gjabel@gmail.com",
5
5
  "repository": "https://github.com/samuelgjabel/muya",
6
6
  "main": "cjs/index.js",
package/src/scheduler.ts CHANGED
@@ -10,7 +10,7 @@ interface GlobalSchedulerItem<T> {
10
10
 
11
11
  export interface SchedulerOptions<T> {
12
12
  readonly onResolveItem?: (item: T) => void
13
- readonly onScheduleDone: () => void | Promise<void>
13
+ readonly onScheduleDone: (values?: unknown[]) => void | Promise<void>
14
14
  }
15
15
 
16
16
  /**
@@ -59,6 +59,7 @@ export function createScheduler() {
59
59
  }
60
60
 
61
61
  const effectedListeners = new Set<ScheduleId>()
62
+ const valuesMap = new Map<ScheduleId, unknown[]>()
62
63
  for (const value of batches) {
63
64
  if (listeners.has(value.id)) {
64
65
  effectedListeners.add(value.id)
@@ -66,6 +67,10 @@ export function createScheduler() {
66
67
  if (onResolveItem) {
67
68
  onResolveItem(value.value)
68
69
  }
70
+ if (!valuesMap.has(value.id)) {
71
+ valuesMap.set(value.id, [])
72
+ }
73
+ valuesMap.get(value.id)!.push(value.value)
69
74
  }
70
75
  batches.delete(value)
71
76
  }
@@ -76,7 +81,8 @@ export function createScheduler() {
76
81
  }
77
82
 
78
83
  for (const id of effectedListeners) {
79
- listeners.get(id)?.onScheduleDone()
84
+ const values = valuesMap.get(id)
85
+ listeners.get(id)?.onScheduleDone(values)
80
86
  }
81
87
  }
82
88
 
@@ -0,0 +1,96 @@
1
+ import { act, renderHook } from '@testing-library/react-hooks'
2
+ import { createSqliteState } from '../create-sqlite'
3
+ import { useSqliteCount } from '../use-sqlite-count'
4
+ import { bunMemoryBackend } from '../table/bun-backend'
5
+ import { waitFor } from '@testing-library/react'
6
+
7
+ const backend = bunMemoryBackend()
8
+ interface Person {
9
+ id: string
10
+ name: string
11
+ age: number
12
+ }
13
+
14
+ describe('useSqliteCount', () => {
15
+ it('should count items in the table', async () => {
16
+ const sql = createSqliteState<Person>({ backend, tableName: 'CountTest1', key: 'id' })
17
+ const { result } = renderHook(() => useSqliteCount(sql))
18
+
19
+ await waitFor(() => {
20
+ expect(result.current).toBe(0)
21
+ })
22
+
23
+ act(() => {
24
+ sql.set({ id: '1', name: 'Alice', age: 30 })
25
+ sql.set({ id: '2', name: 'Bob', age: 25 })
26
+ })
27
+
28
+ await waitFor(() => {
29
+ expect(result.current).toBe(2)
30
+ })
31
+
32
+ act(() => {
33
+ sql.delete('1')
34
+ })
35
+
36
+ await waitFor(() => {
37
+ expect(result.current).toBe(1)
38
+ })
39
+ })
40
+
41
+ it('should support filtering with where clause', async () => {
42
+ const sql = createSqliteState<Person>({ backend, tableName: 'CountTest2', key: 'id' })
43
+ await sql.batchSet([
44
+ { id: '1', name: 'Alice', age: 30 },
45
+ { id: '2', name: 'Bob', age: 25 },
46
+ { id: '3', name: 'Carol', age: 40 },
47
+ ])
48
+
49
+ const { result } = renderHook(() => useSqliteCount(sql, { where: { age: { gt: 30 } } }))
50
+
51
+ await waitFor(() => {
52
+ expect(result.current).toBe(1)
53
+ })
54
+
55
+ act(() => {
56
+ sql.set({ id: '4', name: 'Dave', age: 35 })
57
+ })
58
+
59
+ await waitFor(() => {
60
+ expect(result.current).toBe(2)
61
+ })
62
+
63
+ act(() => {
64
+ sql.delete('3')
65
+ })
66
+
67
+ await waitFor(() => {
68
+ expect(result.current).toBe(1)
69
+ })
70
+ })
71
+
72
+ it('should react to dependency changes', async () => {
73
+ const sql = createSqliteState<Person>({ backend, tableName: 'CountTest3', key: 'id' })
74
+ await sql.batchSet([
75
+ { id: '1', name: 'Alice', age: 30 },
76
+ { id: '2', name: 'Bob', age: 25 },
77
+ { id: '3', name: 'Carol', age: 40 },
78
+ ])
79
+
80
+ const { result, rerender } = renderHook(({ minAge }) => useSqliteCount(sql, { where: { age: { gt: minAge } } }, [minAge]), {
81
+ initialProps: { minAge: 20 },
82
+ })
83
+
84
+ await waitFor(() => {
85
+ expect(result.current).toBe(3)
86
+ })
87
+
88
+ act(() => {
89
+ rerender({ minAge: 30 })
90
+ })
91
+
92
+ await waitFor(() => {
93
+ expect(result.current).toBe(1)
94
+ })
95
+ })
96
+ })
@@ -5,7 +5,7 @@ import { useSqliteValue } from '../use-sqlite'
5
5
  import { waitFor } from '@testing-library/react'
6
6
  import { bunMemoryBackend } from '../table/bun-backend'
7
7
  import { StrictMode, Suspense, useState } from 'react'
8
- import { DEFAULT_STEP_SIZE } from '../table/table'
8
+ import { DEFAULT_PAGE_SIZE } from '../table/table'
9
9
 
10
10
  const backend = bunMemoryBackend()
11
11
  interface Person {
@@ -28,7 +28,7 @@ describe('use-sqlite-state', () => {
28
28
  const { result, rerender } = renderHook(
29
29
  () => {
30
30
  reRenders++
31
- const aha = useSqliteValue(sql, {}, [])
31
+ const aha = useSqliteValue(sql)
32
32
  return aha
33
33
  },
34
34
  { wrapper: Wrapper },
@@ -67,7 +67,7 @@ describe('use-sqlite-state', () => {
67
67
  sql.set({ id: '2', name: 'Bob', age: 25 })
68
68
  })
69
69
  await waitFor(() => {
70
- expect(result.current[0].length).toBe(2)
70
+ expect(result.current[0]?.length).toBe(2)
71
71
  expect(reRenders).toBe(6)
72
72
  })
73
73
 
@@ -76,7 +76,7 @@ describe('use-sqlite-state', () => {
76
76
  })
77
77
  await waitFor(() => {
78
78
  expect(reRenders).toBe(7)
79
- expect(result.current[0].length).toBe(2)
79
+ expect(result.current[0]?.length).toBe(2)
80
80
  })
81
81
  })
82
82
 
@@ -95,7 +95,8 @@ describe('use-sqlite-state', () => {
95
95
  })
96
96
 
97
97
  await waitFor(() => {
98
- expect(result.current[0][0].map((p) => p.name)).toEqual(['Bob', 'Alice', 'Carol'])
98
+ const names = result.current?.[0][0]?.map((p) => p.name)
99
+ expect(names).toEqual(['Bob', 'Alice', 'Carol'])
99
100
  expect(reRenders).toBe(2)
100
101
  })
101
102
 
@@ -104,7 +105,8 @@ describe('use-sqlite-state', () => {
104
105
  result.current[1](29)
105
106
  })
106
107
  await waitFor(() => {
107
- expect(result.current[0][0].map((p) => p.name)).toEqual(['Alice', 'Carol'])
108
+ const names = result.current?.[0][0]?.map((p) => p.name)
109
+ expect(names).toEqual(['Alice', 'Carol'])
108
110
  expect(reRenders).toBe(4)
109
111
  })
110
112
  })
@@ -125,13 +127,13 @@ describe('use-sqlite-state', () => {
125
127
  { initialProps: { like: '%Ali%' } },
126
128
  )
127
129
  await waitFor(() => {
128
- expect(result.current[0].map((p) => p.name)).toEqual(['Alice', 'Alicia'])
130
+ expect(result.current?.[0]?.map((p) => p.name)).toEqual(['Alice', 'Alicia'])
129
131
  })
130
132
  act(() => {
131
133
  rerender({ like: '%Bob%' })
132
134
  })
133
135
  await waitFor(() => {
134
- expect(result.current[0].map((p) => p.name)).toEqual(['Bob'])
136
+ expect(result.current?.[0]?.map((p) => p.name)).toEqual(['Bob'])
135
137
  })
136
138
  expect(reRenders).toBeGreaterThanOrEqual(2)
137
139
  })
@@ -148,19 +150,19 @@ describe('use-sqlite-state', () => {
148
150
  { initialProps: { order: 'asc' as 'asc' | 'desc', limit: 2 } },
149
151
  )
150
152
  await waitFor(() => {
151
- expect(result.current[0].map((p) => p.name)).toEqual(['Bob', 'Alice'])
153
+ expect(result.current?.[0]?.map((p) => p.name)).toEqual(['Bob', 'Alice'])
152
154
  })
153
155
  act(() => {
154
156
  rerender({ order: 'desc', limit: 2 })
155
157
  })
156
158
  await waitFor(() => {
157
- expect(result.current[0].map((p) => p.name)).toEqual(['Carol', 'Alice'])
159
+ expect(result.current?.[0]?.map((p) => p.name)).toEqual(['Carol', 'Alice'])
158
160
  })
159
161
  act(() => {
160
162
  rerender({ order: 'desc', limit: 1 })
161
163
  })
162
164
  await waitFor(() => {
163
- expect(result.current[0].map((p) => p.name)).toEqual(['Carol'])
165
+ expect(result.current?.[0]?.map((p) => p.name)).toEqual(['Carol'])
164
166
  })
165
167
  })
166
168
 
@@ -173,13 +175,11 @@ describe('use-sqlite-state', () => {
173
175
  const { result } = renderHook(() => useSqliteValue(sql, {}, []))
174
176
  // actions.next and actions.refresh should be functions
175
177
  await waitFor(() => {
176
- expect(typeof result.current[1].next).toBe('function')
178
+ expect(typeof result.current[1].nextPage).toBe('function')
177
179
  expect(typeof result.current[1].reset).toBe('function')
178
- expect(result.current[1].reset()).resolves.toBeUndefined()
179
- expect(result.current[1].next()).resolves.toBeFalsy()
180
180
  })
181
181
  })
182
- it('should handle thousands of records', async () => {
182
+ it('should handle thousands of records Here', async () => {
183
183
  const sql = createSqliteState<Person>({ backend, tableName: 'State6Hook', key: 'id' })
184
184
  const people: Person[] = []
185
185
  const ITEMS_COUNT = 1000
@@ -189,16 +189,16 @@ describe('use-sqlite-state', () => {
189
189
  await sql.batchSet(people)
190
190
  const { result } = renderHook(() => useSqliteValue(sql, {}, []))
191
191
  await waitFor(() => {
192
- expect(result.current[0].length).toBe(DEFAULT_STEP_SIZE)
192
+ expect(result.current?.[0]?.length ?? 0).toBe(DEFAULT_PAGE_SIZE)
193
193
  })
194
194
 
195
- // loop until we have all ITEMS_COUNT items
196
- for (let index = 0; index < ITEMS_COUNT / DEFAULT_STEP_SIZE; index++) {
195
+ // // loop until we have all ITEMS_COUNT items
196
+ for (let index = 0; index < ITEMS_COUNT / DEFAULT_PAGE_SIZE; index++) {
197
197
  act(() => {
198
- result.current[1].next()
198
+ result.current[1].nextPage()
199
199
  })
200
200
  await waitFor(() => {
201
- expect(result.current[0].length).toBe(Math.min(DEFAULT_STEP_SIZE * (index + 2), ITEMS_COUNT))
201
+ expect(result.current?.[0]?.length).toBe(Math.min(DEFAULT_PAGE_SIZE * (index + 2), ITEMS_COUNT))
202
202
  })
203
203
  }
204
204
 
@@ -206,7 +206,7 @@ describe('use-sqlite-state', () => {
206
206
  result.current[1].reset()
207
207
  })
208
208
  await waitFor(() => {
209
- expect(result.current[0].length).toBe(DEFAULT_STEP_SIZE)
209
+ expect(result.current?.[0]?.length).toBe(DEFAULT_PAGE_SIZE)
210
210
  })
211
211
  })
212
212
 
@@ -214,7 +214,7 @@ describe('use-sqlite-state', () => {
214
214
  const sql = createSqliteState<Person>({ backend, tableName: 'State6Hook', key: 'id' })
215
215
  const people: Person[] = []
216
216
  const ITEMS_COUNT = 10_000
217
- const stepSize = 5000
217
+ const pageSize = 500
218
218
  for (let index = 1; index <= ITEMS_COUNT; index++) {
219
219
  people.push({ id: index.toString(), name: `Person${index}`, age: 20 + (index % 50) })
220
220
  }
@@ -222,30 +222,30 @@ describe('use-sqlite-state', () => {
222
222
  let reRenders = 0
223
223
  const { result } = renderHook(() => {
224
224
  reRenders++
225
- return useSqliteValue(sql, { stepSize }, [])
225
+ return useSqliteValue(sql, { pageSize }, [])
226
226
  })
227
227
  await waitFor(() => {
228
228
  expect(reRenders).toBe(2)
229
- expect(result.current[0].length).toBe(stepSize)
229
+ expect(result.current?.[0]?.length).toBe(pageSize)
230
230
  })
231
231
 
232
232
  act(() => {
233
- for (let index = 0; index < ITEMS_COUNT / stepSize; index++) {
234
- result.current[1].next()
233
+ for (let index = 0; index < (ITEMS_COUNT - pageSize) / pageSize; index++) {
234
+ result.current[1].nextPage()
235
235
  }
236
236
  })
237
237
 
238
238
  await waitFor(() => {
239
- expect(reRenders).toBe(4)
240
- expect(result.current[0].length).toBe(ITEMS_COUNT)
239
+ expect(reRenders).toBe(21)
240
+ expect(result.current?.[0]?.length).toBe(ITEMS_COUNT)
241
241
  })
242
242
 
243
243
  act(() => {
244
244
  result.current[1].reset()
245
245
  })
246
246
  await waitFor(() => {
247
- expect(reRenders).toBe(5)
248
- expect(result.current[0].length).toBe(stepSize)
247
+ expect(reRenders).toBe(22)
248
+ expect(result.current?.[0]?.length).toBe(pageSize)
249
249
  })
250
250
  })
251
251
  it('should change ordering', async () => {
@@ -259,13 +259,13 @@ describe('use-sqlite-state', () => {
259
259
  initialProps: { order: 'asc' as 'asc' | 'desc' },
260
260
  })
261
261
  await waitFor(() => {
262
- expect(result.current[0][0].age).toBe(20)
262
+ expect(result.current?.[0]?.[0]?.age).toBe(20)
263
263
  })
264
264
  act(() => {
265
265
  rerender({ order: 'desc' })
266
266
  })
267
267
  await waitFor(() => {
268
- expect(result.current[0][0].age).toBe(69)
268
+ expect(result.current?.[0]?.[0]?.age).toBe(69)
269
269
  })
270
270
  })
271
271
 
@@ -305,8 +305,8 @@ describe('use-sqlite-state', () => {
305
305
  )
306
306
  })
307
307
  await waitFor(() => {
308
- expect(reRenders).toBe(2)
309
- expect(result1.current[0].length).toBe(0)
308
+ expect(reRenders).toBe(1)
309
+ expect(result1.current?.[0]?.length).toBe(undefined)
310
310
  })
311
311
 
312
312
  const people: Person[] = []
@@ -316,12 +316,12 @@ describe('use-sqlite-state', () => {
316
316
  await sql.batchSet(people)
317
317
  await waitFor(() => {
318
318
  expect(reRenders).toBe(3)
319
- expect(result1.current[0].length).toBe(50)
319
+ expect(result1.current?.[0]?.length).toBe(50)
320
320
  })
321
321
 
322
322
  const { result: result2 } = renderHook(() => useSqliteValue(sql, {}, []))
323
323
  await waitFor(() => {
324
- expect(result2.current[0].length).toBe(50)
324
+ expect(result2.current?.[0]?.length).toBe(50)
325
325
  })
326
326
  })
327
327
 
@@ -342,7 +342,7 @@ describe('use-sqlite-state', () => {
342
342
 
343
343
  await waitFor(() => {
344
344
  expect(reRenders).toBe(2)
345
- expect(result.current[0].length).toBe(0)
345
+ expect(result.current?.[0]?.length).toBe(0)
346
346
  })
347
347
 
348
348
  act(() => {
@@ -358,7 +358,7 @@ describe('use-sqlite-state', () => {
358
358
  sql.set({ person: { id: 'some_id', name: 'Alice', age: 31 } })
359
359
  })
360
360
  await waitFor(() => {
361
- // expect(reRenders).toBe(4)
361
+ expect(reRenders).toBe(4)
362
362
  expect(result.current[0]).toEqual([{ person: { id: 'some_id', name: 'Alice', age: 31 } }])
363
363
  })
364
364
 
@@ -387,7 +387,7 @@ describe('use-sqlite-state', () => {
387
387
 
388
388
  await waitFor(() => {
389
389
  expect(reRenders).toBe(2)
390
- expect(result.current[0].length).toBe(1)
390
+ expect(result.current?.[0]?.length).toBe(1)
391
391
  })
392
392
 
393
393
  act(() => {
@@ -395,15 +395,98 @@ describe('use-sqlite-state', () => {
395
395
  })
396
396
  await waitFor(() => {
397
397
  expect(reRenders).toBe(3)
398
- expect(result.current[0].length).toBe(2)
398
+ expect(result.current?.[0]?.length).toBe(2)
399
399
  })
400
400
 
401
401
  act(() => {
402
402
  result.current[1].reset()
403
403
  })
404
404
  await waitFor(() => {
405
- expect(result.current[0].length).toBe(2)
405
+ expect(result.current?.[0]?.length).toBe(2)
406
406
  expect(reRenders).toBe(4)
407
407
  })
408
408
  })
409
+
410
+ it('should handle no items in the database', async () => {
411
+ const sql = createSqliteState<Person>({ backend, tableName: 'EmptyState', key: 'id' })
412
+ const { result } = renderHook(() => useSqliteValue(sql, {}, []))
413
+
414
+ await waitFor(() => {
415
+ expect(result.current[0]).toEqual([])
416
+ })
417
+ })
418
+
419
+ it('should handle fewer items than page size', async () => {
420
+ const sql = createSqliteState<Person>({ backend, tableName: 'FewItemsState', key: 'id' })
421
+ await sql.batchSet([
422
+ { id: '1', name: 'Alice', age: 30 },
423
+ { id: '2', name: 'Bob', age: 25 },
424
+ ])
425
+
426
+ const { result } = renderHook(() => useSqliteValue(sql, {}, []))
427
+
428
+ await waitFor(() => {
429
+ expect(result.current[0]).toEqual([
430
+ { id: '1', name: 'Alice', age: 30 },
431
+ { id: '2', name: 'Bob', age: 25 },
432
+ ])
433
+ })
434
+ })
435
+
436
+ it('should handle exactly page size items', async () => {
437
+ const sql = createSqliteState<Person>({ backend, tableName: 'ExactPageSizeState', key: 'id' })
438
+ const items = Array.from({ length: DEFAULT_PAGE_SIZE }, (_, index) => ({
439
+ id: `${index + 1}`,
440
+ name: `Person${index + 1}`,
441
+ age: 20 + (index % 50),
442
+ }))
443
+ await sql.batchSet(items)
444
+
445
+ const { result } = renderHook(() => useSqliteValue(sql, {}, []))
446
+
447
+ await waitFor(() => {
448
+ expect(result.current[0]?.length).toBe(DEFAULT_PAGE_SIZE)
449
+ })
450
+ })
451
+
452
+ it('should have thousands items, and update in middle check', async () => {
453
+ let reRenders = 0
454
+ const sql = createSqliteState<Person>({ backend, tableName: 'ManyItemsState', key: 'id' })
455
+ const ITEMS_COUNT = 1000
456
+ const people: Person[] = []
457
+ for (let index = 1; index <= ITEMS_COUNT; index++) {
458
+ people.push({ id: index.toString(), name: `Person${index}`, age: 20 + (index % 50) })
459
+ }
460
+ await sql.batchSet(people)
461
+
462
+ const { result } = renderHook(() => {
463
+ reRenders++
464
+ return useSqliteValue(sql, { pageSize: 100 }, [])
465
+ })
466
+
467
+ await waitFor(() => {
468
+ expect(result.current[0]?.length).toBe(100)
469
+ expect(reRenders).toBe(2)
470
+ })
471
+ act(() => {
472
+ for (let index = 0; index < (ITEMS_COUNT - 100) / 100; index++) {
473
+ result.current[1].nextPage()
474
+ }
475
+ })
476
+ await waitFor(() => {
477
+ expect(result.current[0]?.length).toBe(ITEMS_COUNT)
478
+ expect(reRenders).toBe(11)
479
+ })
480
+
481
+ act(() => {
482
+ sql.set({ id: '500', name: 'UpdatedPerson500', age: 99 })
483
+ })
484
+
485
+ await waitFor(() => {
486
+ const updated = result.current[0]?.find((p) => p.id === '500')
487
+ expect(updated).toEqual({ id: '500', name: 'UpdatedPerson500', age: 99 })
488
+ expect(reRenders).toBe(12)
489
+ expect(result.current[0]?.length).toBe(ITEMS_COUNT)
490
+ })
491
+ })
409
492
  })