muya 2.1.1 → 2.1.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.
Files changed (53) hide show
  1. package/cjs/index.js +1 -1
  2. package/esm/create-state.js +1 -1
  3. package/esm/create.js +1 -1
  4. package/esm/scheduler.js +1 -1
  5. package/esm/select.js +1 -1
  6. package/esm/sqlite/__tests__/create-sqlite.test.js +1 -0
  7. package/esm/sqlite/__tests__/map-deque.test.js +1 -0
  8. package/esm/sqlite/__tests__/table.test.js +1 -0
  9. package/esm/sqlite/__tests__/use-sqlite.test.js +1 -0
  10. package/esm/sqlite/create-sqlite.js +1 -0
  11. package/esm/sqlite/select-sql.js +1 -0
  12. package/esm/sqlite/table/backend.js +1 -0
  13. package/esm/sqlite/table/bun-backend.js +1 -0
  14. package/esm/sqlite/table/map-deque.js +1 -0
  15. package/esm/sqlite/table/table.js +10 -0
  16. package/esm/sqlite/table/table.types.js +0 -0
  17. package/esm/sqlite/table/where.js +1 -0
  18. package/esm/sqlite/use-sqlite.js +1 -0
  19. package/esm/utils/common.js +1 -1
  20. package/package.json +1 -1
  21. package/src/__tests__/scheduler.test.tsx +2 -2
  22. package/src/create-state.ts +3 -2
  23. package/src/create.ts +22 -24
  24. package/src/scheduler.ts +15 -7
  25. package/src/select.ts +15 -17
  26. package/src/sqlite/__tests__/create-sqlite.test.ts +81 -0
  27. package/src/sqlite/__tests__/map-deque.test.ts +61 -0
  28. package/src/sqlite/__tests__/table.test.ts +142 -0
  29. package/src/sqlite/__tests__/use-sqlite.test.ts +274 -0
  30. package/src/sqlite/create-sqlite.ts +273 -0
  31. package/src/sqlite/select-sql.ts +55 -0
  32. package/src/sqlite/table/backend.ts +21 -0
  33. package/src/sqlite/table/bun-backend.ts +38 -0
  34. package/src/sqlite/table/map-deque.ts +29 -0
  35. package/src/sqlite/table/table.ts +200 -0
  36. package/src/sqlite/table/table.types.ts +55 -0
  37. package/src/sqlite/table/where.ts +267 -0
  38. package/src/sqlite/use-sqlite.ts +70 -0
  39. package/src/types.ts +1 -0
  40. package/src/utils/common.ts +6 -2
  41. package/types/create.d.ts +3 -3
  42. package/types/scheduler.d.ts +12 -3
  43. package/types/sqlite/create-sqlite.d.ts +28 -0
  44. package/types/sqlite/select-sql.d.ts +14 -0
  45. package/types/sqlite/table/backend.d.ts +20 -0
  46. package/types/sqlite/table/bun-backend.d.ts +2 -0
  47. package/types/sqlite/table/map-deque.d.ts +5 -0
  48. package/types/sqlite/table/table.d.ts +3 -0
  49. package/types/sqlite/table/table.types.d.ts +52 -0
  50. package/types/sqlite/table/where.d.ts +32 -0
  51. package/types/sqlite/use-sqlite.d.ts +15 -0
  52. package/types/types.d.ts +1 -0
  53. package/types/utils/common.d.ts +2 -2
package/cjs/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var O=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var K=Object.prototype.hasOwnProperty;var Y=(e,t)=>{for(var r in t)O(e,r,{get:t[r],enumerable:!0})},W=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of _(t))!K.call(e,o)&&o!==r&&O(e,o,{get:()=>t[o],enumerable:!(n=N(t,o))||n.enumerable});return e};var J=e=>W(O({},"__esModule",{value:!0}),e);var B={};Y(B,{EMPTY_SELECTOR:()=>D,create:()=>z,isAbortError:()=>I,isArray:()=>P,isEqualBase:()=>S,isError:()=>G,isFunction:()=>w,isMap:()=>E,isPromise:()=>f,isSet:()=>k,isSetValueFunction:()=>v,isState:()=>X,isUndefined:()=>m,select:()=>g,shallow:()=>M,useValue:()=>V});module.exports=J(B);var T=class extends Error{static Error="AbortError"};function Q(e,t){t&&t.abort();let r=new AbortController,{signal:n}=r;return{promise:new Promise((u,s)=>{n.addEventListener("abort",()=>{s(new T)}),e.then(u).catch(s)}),controller:r}}function x(e,t=S){if(!m(e.current)){if(!m(e.previous)&&t(e.current,e.previous))return!1;e.previous=e.current}return!0}function p(e,t,r){if(!f(r))return r;e.abortController&&e.abortController.abort();let{promise:n,controller:o}=Q(r,e.abortController);return e.abortController=o,n.then(u=>{e.current=u,t()}).catch(u=>{I(u)||(e.current=u,t())})}function f(e){return e instanceof Promise}function w(e){return typeof e=="function"}function E(e){return e instanceof Map}function k(e){return e instanceof Set}function P(e){return Array.isArray(e)}function S(e,t){return e===t?!0:!!Object.is(e,t)}function v(e){return typeof e=="function"}function I(e){return e instanceof T}function G(e){return e instanceof Error}function m(e){return e===void 0}function X(e){return w(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,r=performance.now(),n=!1;function o(){let s=performance.now(),a=s-r,{size:i}=t;if(a<.2&&i>0&&i<10){r=s,u();return}n||(n=!0,Promise.resolve().then(()=>{n=!1,r=performance.now(),u()}))}function u(){if(t.size===0)return;let s=new Set;for(let a of t){if(e.has(a.id)){s.add(a.id);let{onResolveItem:i}=e.get(a.id);i&&i(a.value)}t.delete(a)}if(t.size>0){o();return}for(let a of s)e.get(a)?.onFinish()}return{add(s,a){return e.set(s,a),()=>{e.delete(s)}},schedule(s,a){t.add({value:a,id:s}),o()}}}function g(e,t,r){let n={};function o(){let c=!1,l=e.map(A=>{let y=A.get();return f(y)&&(c=!0),y});return c?new Promise((A,y)=>{Promise.all(l).then(F=>{if(F.some(j=>m(j)))return y(new T);let H=t(...F);A(H)})}):t(...l)}function u(){if(m(n.current)){let c=o();n.current=p(n,i.emitter.emit,c)}return n.current}function s(){if(m(n.current)){let l=o();n.current=p(n,i.emitter.emit,l)}let{current:c}=n;return f(c)?new Promise(l=>{c.then(b=>{if(m(b)){l(s());return}l(b)})}):n.current}let a=[];for(let c of e){let l=c.emitter.subscribe(()=>{h.schedule(i.id,null)});a.push(l)}let i=C({destroy(){for(let c of a)c();d(),i.emitter.clear(),n.current=void 0},get:s,getSnapshot:u}),d=h.add(i.id,{onFinish(){let c=o();n.current=p(n,i.emitter.emit,c),x(n,r)&&i.emitter.emit()}});return i}var q=require("react");var R=require("use-sync-external-store/shim/with-selector");function V(e,t=D){let{emitter:r}=e,n=(0,R.useSyncExternalStoreWithSelector)(e.emitter.subscribe,r.getSnapshot,r.getInitialSnapshot,t);if((0,q.useDebugValue)(n),f(n)||G(n))throw n;return n}function L(e,t){let r=new Set,n=[];return{clear:()=>{for(let o of n)o();r.clear()},subscribe:o=>(r.add(o),()=>{r.delete(o)}),emit:(...o)=>{for(let u of r)u(...o)},contains:o=>r.has(o),getSnapshot:e,getInitialSnapshot:t,getSize:()=>r.size,subscribeToOtherEmitter(o){let u=o.subscribe(()=>{this.emit()});n.push(u)}}}var Z=0;function $(){return Z++}function C(e){let{get:t,destroy:r,set:n,getSnapshot:o}=e,u=!!n,s=function(a){return V(s,a)};return s.isSet=u,s.id=$(),s.emitter=L(o),s.destroy=r,s.listen=function(a){return this.emitter.subscribe(()=>{let i=t();f(i)||a(t())})},s.withName=function(a){return this.stateName=a,this},s.select=function(a,i=S){return g([s],a,i)},s.get=t,s.set=n,s}var h=U();function z(e,t=S){let r={};function n(){try{if(m(r.current)){let i=w(e)?e():e,d=p(r,s.emitter.emit,i);return r.current=d,r.current}return r.current}catch(i){r.current=i}return r.current}async function o(i,d){await i;let c=d(r.current),l=p(r,s.emitter.emit,c);r.current=l}function u(i){let d=n(),c=v(i);if(c&&f(d)){o(d,i);return}r.abortController&&r.abortController.abort();let l=c?i(d):i,b=p(r,s.emitter.emit,l);r.current=b}let s=C({get:n,destroy(){n(),a(),s.emitter.clear(),r.current=void 0},set(i){h.schedule(s.id,i)},getSnapshot:n}),a=h.add(s.id,{onFinish(){r.current=n(),x(r,t)&&s.emitter.emit()},onResolveItem:u});return w(e)||n(),s}function M(e,t){if(e==t)return!0;if(typeof e!="object"||e==null||typeof t!="object"||t==null)return!1;if(E(e)&&E(t)){if(e.size!==t.size)return!1;for(let[o,u]of e)if(!Object.is(u,t.get(o)))return!1;return!0}if(k(e)&&k(t)){if(e.size!==t.size)return!1;for(let o of e)if(!t.has(o))return!1;return!0}if(P(e)&&P(t)){if(e.length!==t.length)return!1;for(let[o,u]of e.entries())if(!Object.is(u,t[o]))return!1;return!0}let r=Object.keys(e),n=Object.keys(t);if(r.length!==n.length)return!1;for(let o of r)if(!Object.prototype.hasOwnProperty.call(t,o)||!Object.is(e[o],t[o]))return!1;return!0}
1
+ "use strict";var V=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var K=(e,r)=>{for(var o in r)V(e,o,{get:r[o],enumerable:!0})},Y=(e,r,o,i)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of _(r))!N.call(e,s)&&s!==o&&V(e,s,{get:()=>r[s],enumerable:!(i=j(r,s))||i.enumerable});return e};var W=e=>Y(V({},"__esModule",{value:!0}),e);var $={};K($,{EMPTY_SELECTOR:()=>v,create:()=>H,isAbortError:()=>I,isArray:()=>P,isEqualBase:()=>p,isError:()=>D,isFunction:()=>h,isMap:()=>E,isPromise:()=>f,isSet:()=>x,isSetValueFunction:()=>O,isState:()=>Q,isUndefined:()=>d,select:()=>g,shallow:()=>z,useValue:()=>C});module.exports=W($);var m=class extends Error{static Error="AbortError"};function J(e,r){r&&r.abort();let o=new AbortController,{signal:i}=o;return{promise:new Promise((n,a)=>{i.addEventListener("abort",()=>{a(new m)}),e.then(n).catch(a)}),controller:o}}function y(e,r=p){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}=J(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 E(e){return e instanceof Map}function x(e){return e instanceof Set}function P(e){return Array.isArray(e)}function p(e,r){return e===r?!0:!!Object.is(e,r)}function O(e){return typeof e=="function"}function I(e){return e instanceof m}function D(e){return e instanceof Error}function d(e){return e===void 0}function Q(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 g(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(M=>d(M)))return w(new m);let F=r(...G);A(F)})}):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 X=0;function Z(){return X++}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=p){return g([t],c,u)},t.get=r,t.set=i,t.cache=a,t}var b=U();function H(e,r=p){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 z(e,r){if(e==r)return!0;if(typeof e!="object"||e==null||typeof r!="object"||r==null)return!1;if(E(e)&&E(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(x(e)&&x(r)){if(e.size!==r.size)return!1;for(let s of e)if(!r.has(s))return!1;return!0}if(P(e)&&P(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 +1 @@
1
- import{select as l}from"./select";import{useValue as S}from"./use-value";import{createEmitter as c}from"./utils/create-emitter";import{isEqualBase as d,isPromise as m}from"./utils/is";let T=0;function f(){return T++}function h(n){const{get:r,destroy:o,set:a,getSnapshot:i}=n,u=!!a,t=function(e){return S(t,e)};return t.isSet=u,t.id=f(),t.emitter=c(i),t.destroy=o,t.listen=function(e){return this.emitter.subscribe(()=>{const s=r();m(s)||e(r())})},t.withName=function(e){return this.stateName=e,this},t.select=function(e,s=d){return l([t],e,s)},t.get=r,t.set=a,t}export{h as createState};
1
+ import{select as l}from"./select";import{useValue as S}from"./use-value";import{createEmitter as d}from"./utils/create-emitter";import{isEqualBase as m,isPromise as T}from"./utils/is";let f=0;function p(){return f++}function G(n){const{get:a,destroy:o,set:s,getSnapshot:i}=n,u=!!s,c={},t=function(e){return S(t,e)};return t.isSet=u,t.id=p(),t.emitter=d(i),t.destroy=o,t.listen=function(e){return this.emitter.subscribe(()=>{const r=a();T(r)||e(a())})},t.withName=function(e){return this.stateName=e,this},t.select=function(e,r=m){return l([t],e,r)},t.get=a,t.set=s,t.cache=c,t}export{G as createState};
package/esm/create.js CHANGED
@@ -1 +1 @@
1
- import{canUpdate as p,handleAsyncUpdate as u}from"./utils/common";import{isEqualBase as h,isFunction as i,isPromise as V,isSetValueFunction as b,isUndefined as y}from"./utils/is";import{createScheduler as C}from"./scheduler";import{subscribeToDevelopmentTools as w}from"./debug/development-tools";import{createState as v}from"./create-state";const l=C();function E(c,m=h){const e={};function o(){try{if(y(e.current)){const t=i(c)?c():c,n=u(e,r.emitter.emit,t);return e.current=n,e.current}return e.current}catch(t){e.current=t}return e.current}async function d(t,n){await t;const a=n(e.current),s=u(e,r.emitter.emit,a);e.current=s}function f(t){const n=o(),a=b(t);if(a&&V(n)){d(n,t);return}e.abortController&&e.abortController.abort();const s=a?t(n):t,S=u(e,r.emitter.emit,s);e.current=S}const r=v({get:o,destroy(){o(),T(),r.emitter.clear(),e.current=void 0},set(t){l.schedule(r.id,t)},getSnapshot:o}),T=l.add(r.id,{onFinish(){e.current=o(),p(e,m)&&r.emitter.emit()},onResolveItem:f});return i(c)||o(),w(r),r}export{E as create,l as stateScheduler};
1
+ import{canUpdate as S,handleAsyncUpdate as u}from"./utils/common";import{isEqualBase as T,isFunction as s,isPromise as p,isSetValueFunction as V,isUndefined as b}from"./utils/is";import{createScheduler as y}from"./scheduler";import{subscribeToDevelopmentTools as E}from"./debug/development-tools";import{createState as w}from"./create-state";const i=y();function g(a,l=T){function c(){try{if(b(e.cache.current)){const t=s(a)?a():a,r=u(e,t);return e.cache.current=r,e.cache.current}return e.cache.current}catch(t){e.cache.current=t}return e.cache.current}async function d(t,r){await t;const n=r(e.cache.current),o=u(e,n);e.cache.current=o}function h(t){const r=c(),n=V(t);if(n&&p(r)){d(r,t);return}e.cache.abortController&&e.cache.abortController.abort();const o=n?t(r):t,f=u(e,o);e.cache.current=f}const e=w({get:c,destroy(){c(),m(),e.emitter.clear(),e.cache.current=void 0},set(t){i.schedule(e.id,t)},getSnapshot:c}),m=i.add(e.id,{onScheduleDone(){e.cache.current=c(),S(e.cache,l)&&e.emitter.emit()},onResolveItem:h});return s(a)||c(),E(e),e}export{i as STATE_SCHEDULER,g as create};
package/esm/scheduler.js CHANGED
@@ -1 +1 @@
1
- const l=.2,d=10,f=0;function a(){const o=new Map,t=new Set;let s=performance.now(),i=!1;function c(){const n=performance.now(),e=n-s,{size:r}=t;if(e<.2&&r>0&&r<10){s=n,u();return}i||(i=!0,Promise.resolve().then(()=>{i=!1,s=performance.now(),u()}))}function u(){if(t.size===0)return;const n=new Set;for(const e of t){if(o.has(e.id)){n.add(e.id);const{onResolveItem:r}=o.get(e.id);r&&r(e.value)}t.delete(e)}if(t.size>0){c();return}for(const e of n)o.get(e)?.onFinish()}return{add(n,e){return o.set(n,e),()=>{o.delete(n)}},schedule(n,e){t.add({value:e,id:n}),c()}}}export{f as RESCHEDULE_COUNT,l as THRESHOLD,d as THRESHOLD_ITEMS,a as createScheduler};
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};
package/esm/select.js CHANGED
@@ -1 +1 @@
1
- import{stateScheduler as T}from"./create";import{createState as b}from"./create-state";import{subscribeToDevelopmentTools as P}from"./debug/development-tools";import{AbortError as V,canUpdate as g,handleAsyncUpdate as c}from"./utils/common";import{isPromise as y,isUndefined as i}from"./utils/is";function U(m,d,w){const e={};function s(){let t=!1;const r=m.map(u=>{const o=u.get();return y(o)&&(t=!0),o});return t?new Promise((u,o)=>{Promise.all(r).then(p=>{if(p.some(k=>i(k)))return o(new V);const A=d(...p);u(A)})}):d(...r)}function S(){if(i(e.current)){const t=s();e.current=c(e,n.emitter.emit,t)}return e.current}function f(){if(i(e.current)){const r=s();e.current=c(e,n.emitter.emit,r)}const{current:t}=e;return y(t)?new Promise(r=>{t.then(a=>{if(i(a)){r(f());return}r(a)})}):e.current}const l=[];for(const t of m){const r=t.emitter.subscribe(()=>{T.schedule(n.id,null)});l.push(r)}const n=b({destroy(){for(const t of l)t();h(),n.emitter.clear(),e.current=void 0},get:f,getSnapshot:S}),h=T.add(n.id,{onFinish(){const t=s();e.current=c(e,n.emitter.emit,t),g(e,w)&&n.emitter.emit()}});return P(n),n}export{U as select};
1
+ import{STATE_SCHEDULER as p}from"./create";import{createState as k}from"./create-state";import{subscribeToDevelopmentTools as E}from"./debug/development-tools";import{AbortError as b,canUpdate as D,handleAsyncUpdate as s}from"./utils/common";import{isPromise as T,isUndefined as c}from"./utils/is";function U(i,d,h){function o(){let t=!1;const n=i.map(u=>{const r=u.get();return T(r)&&(t=!0),r});return t?new Promise((u,r)=>{Promise.all(n).then(m=>{if(m.some(A=>c(A)))return r(new b);const w=d(...m);u(w)})}):d(...n)}function S(){if(c(e.cache.current)){const t=o();e.cache.current=s(e,t)}return e.cache.current}function f(){if(c(e.cache.current)){const n=o();e.cache.current=s(e,n)}const{current:t}=e.cache;return T(t)?new Promise(n=>{t.then(a=>{if(c(a)){n(f());return}n(a)})}):e.cache.current}const l=[];for(const t of i){const n=t.emitter.subscribe(()=>{p.schedule(e.id,null)});l.push(n)}const e=k({destroy(){for(const t of l)t();y(),e.emitter.clear(),e.cache.current=void 0},get:f,getSnapshot:S}),y=p.add(e.id,{onScheduleDone(){const t=o();e.cache.current=s(e,t),D(e.cache,h)&&e.emitter.emit()}});return E(e),e}export{U as select};
@@ -0,0 +1 @@
1
+ import{createSqliteState as o}from"../create-sqlite";import{bunMemoryBackend as s}from"../table/bun-backend";const n=s();describe("create-sqlite-state",()=>{it("should batchSet and update multiple documents",async()=>{const e=o({backend:n,tableName:"State2",key:"id"});await e.batchSet([{id:"1",name:"Alice",age:30},{id:"2",name:"Bob",age:25}]);const a=[];for await(const i of e.search())a.push(i);expect(a).toHaveLength(2),await e.batchSet([{id:"1",name:"Alice2",age:31},{id:"2",name:"Bob2",age:26}]);const t=[];for await(const i of e.search())t.push(i);expect(t).toEqual([{id:"1",name:"Alice2",age:31},{id:"2",name:"Bob2",age:26}])}),it("should deleteBy condition",async()=>{const e=o({backend:n,tableName:"State3",key:"id"});await e.batchSet([{id:"1",name:"Alice",age:30},{id:"2",name:"Bob",age:25},{id:"3",name:"Carol",age:40}]);const a=await e.deleteBy({age:{gt:30}});expect(a.length).toBe(1);const t=[];for await(const i of e.search())t.push(i);expect(t.map(i=>i.id)).toEqual(["1","2"])}),it("should get by key and with selector",async()=>{const e=o({backend:n,tableName:"State4",key:"id"});await e.set({id:"1",name:"Alice",age:30});const a=await e.get("1");expect(a).toEqual({id:"1",name:"Alice",age:30});const t=await e.get("1",c=>c.name);expect(t).toBe("Alice");const i=await e.get("999");expect(i).toBeUndefined()}),it("should count documents with and without where",async()=>{const e=o({backend:n,tableName:"State5",key:"id"});await e.batchSet([{id:"1",name:"Alice",age:30},{id:"2",name:"Bob",age:25},{id:"3",name:"Carol",age:40}]),expect(await e.count()).toBe(3),expect(await e.count({where:{age:{gt:30}}})).toBe(1)}),it("should support search with options",async()=>{const e=o({backend:n,tableName:"State6",key:"id"});await e.batchSet([{id:"1",name:"Alice",age:30},{id:"2",name:"Bob",age:25},{id:"3",name:"Carol",age:40}]);const a=[];for await(const t of e.search({where:{age:{lt:35}}}))a.push(t);expect(a.map(t=>t.id)).toEqual(["1","2"])})});
@@ -0,0 +1 @@
1
+ import{MapDeque as t}from"../table/map-deque";describe("MapDeque",()=>{it("should throw if maxSize <= 0",()=>{expect(()=>new t(0)).toThrow(RangeError),expect(()=>new t(-1)).toThrow(RangeError)}),it("should add items up to maxSize",()=>{const e=new t(2);e.set("a",1),e.set("b",2),expect(e.size).toBe(2),expect(e.get("a")).toBe(1),expect(e.get("b")).toBe(2)}),it("should evict the oldest item when maxSize is exceeded",()=>{const e=new t(2);e.set("a",1),e.set("b",2),e.set("c",3),expect(e.size).toBe(2),expect(e.has("a")).toBe(!1),expect(e.get("b")).toBe(2),expect(e.get("c")).toBe(3)}),it("should update value if key already exists and not evict",()=>{const e=new t(2);e.set("a",1),e.set("b",2),e.set("a",42),expect(e.size).toBe(2),expect(e.get("a")).toBe(42),expect(e.get("b")).toBe(2)}),it("should work with initial entries",()=>{const e=[["x",10],["y",20]],s=new t(3,e);expect(s.size).toBe(2),expect(s.get("x")).toBe(10),expect(s.get("y")).toBe(20)}),it("should evict in insertion order, not key order",()=>{const e=new t(2);e.set("b",1),e.set("a",2),e.set("c",3),expect(e.size).toBe(2),expect(e.has("b")).toBe(!1),expect(e.has("a")).toBe(!0),expect(e.has("c")).toBe(!0)})});
@@ -0,0 +1 @@
1
+ import{bunMemoryBackend as c}from"../table/bun-backend";import{createTable as r}from"../table/table";describe("table",()=>{let n=c(),e;beforeEach(async()=>{n=c(),e=await r({backend:n,tableName:"TestTable",key:"name"})}),it("should set and get items",async()=>{const a=await e.set({name:"Alice",age:30,city:"Paris"});expect(a.key).toBe("Alice"),expect(a.op).toBe("insert");const i=await e.get("Alice");expect(i).toEqual({name:"Alice",age:30,city:"Paris"});const t=await e.set({name:"Alice",age:31,city:"Paris"});expect(t.key).toBe("Alice"),expect(t.op).toBe("update");const s=await e.get("Alice");expect(s).toEqual({name:"Alice",age:31,city:"Paris"})}),it("should count items and count with where",async()=>{await e.set({name:"Alice",age:30,city:"Paris"}),await e.set({name:"Bob",age:25,city:"London"}),expect(await e.count()).toBe(2),expect(await e.count({where:{city:"Paris"}})).toBe(1)}),it("should search with ordering, limit and offset",async()=>{const a=[{name:"Alice",age:30,city:"Paris"},{name:"Bob",age:25,city:"London"},{name:"Carol",age:35,city:"Berlin"}];for(const o of a)await e.set(o);const i=[];for await(const o of e.search({sorBy:"age",order:"asc"}))i.push(o);expect(i.map(o=>o.name)).toEqual(["Bob","Alice","Carol"]);const t=[];for await(const o of e.search({sorBy:"age",order:"asc",limit:2}))t.push(o);expect(t.map(o=>o.name)).toEqual(["Bob","Alice"]);const s=[];for await(const o of e.search({sorBy:"age",order:"asc",offset:1,limit:2}))s.push(o);expect(s.map(o=>o.name)).toEqual(["Alice","Carol"])}),it("should deleteBy where clause",async()=>{await e.set({name:"Dave",age:40,city:"NY"}),await e.set({name:"Eve",age:45,city:"NY"}),await e.set({name:"Frank",age:50,city:"LA"}),expect(await e.count()).toBe(3),await e.deleteBy({city:"NY"}),expect(await e.count()).toBe(1),expect(await e.get("Frank")).toEqual({name:"Frank",age:50,city:"LA"}),expect(await e.get("Dave")).toBeUndefined()}),it("should use selector in get and search",async()=>{await e.set({name:"Gary",age:60,city:"SF"});const a=await e.get("Gary",({age:t})=>t);expect(a).toBe(60);const i=[];for await(const t of e.search({select:({city:s})=>s}))i.push(t);expect(i).toEqual(["SF"])}),it("should delete items by key",async()=>{await e.set({name:"Helen",age:28,city:"Rome"}),expect(await e.get("Helen")).toBeDefined(),await e.delete("Helen"),expect(await e.get("Helen")).toBeUndefined()}),it("should test search with 1000 items",async()=>{const a=[];for(let t=0;t<1e3;t++)a.push({name:`Person${t}`,age:Math.floor(Math.random()*100),city:"City"+t%10});for(const t of a)await e.set(t);const i=[];for await(const t of e.search({sorBy:"age",order:"asc",limit:100}))i.push(t);expect(i.length).toBe(100)}),it("should handle operations on an empty table",async()=>{expect(await e.count()).toBe(0),expect(await e.get("NonExistent")).toBeUndefined();const a=[];for await(const i of e.search({sorBy:"age",order:"asc"}))a.push(i);expect(a.length).toBe(0)}),it("should handle duplicate keys gracefully",async()=>{await e.set({name:"Alice",age:30,city:"Paris"}),await e.set({name:"Alice",age:35,city:"Berlin"});const a=await e.get("Alice");expect(a).toEqual({name:"Alice",age:35,city:"Berlin"})}),it("should handle edge cases in selectors",async()=>{await e.set({name:"Charlie",age:40,city:"NY"});const a=await e.get("Charlie",()=>null);expect(a).toBeNull();const i=await e.get("Charlie",()=>{});expect(i).toBeUndefined()})});
@@ -0,0 +1 @@
1
+ import{act as s,renderHook as c}from"@testing-library/react-hooks";import{createSqliteState as i}from"../create-sqlite";import{useSqliteValue as l}from"../use-sqlite";import{waitFor as o}from"@testing-library/react";import{bunMemoryBackend as g}from"../table/bun-backend";import{useState as x}from"react";import{DEFAULT_STEP_SIZE as m}from"../table/table";const u=g();describe("use-sqlite-state",()=>{it("should get basic value states",async()=>{const a=i({backend:u,tableName:"State1",key:"id"});let t=0;const{result:n}=c(()=>(t++,l(a,{},[])));expect(t).toBe(1),s(()=>{a.set({id:"1",name:"Alice",age:30})}),await o(()=>{expect(n.current[0]).toEqual([{id:"1",name:"Alice",age:30}]),expect(t).toBe(3)}),s(()=>{a.set({id:"1",name:"Alice2",age:30})}),await o(()=>{expect(n.current[0]).toEqual([{id:"1",name:"Alice2",age:30}]),expect(t).toBe(4)}),s(()=>{a.delete("1")}),await o(()=>{expect(n.current[0]).toEqual([]),expect(t).toBe(5)}),s(()=>{a.set({id:"1",name:"Alice",age:30}),a.set({id:"2",name:"Bob",age:25})}),await o(()=>{expect(n.current[0].length).toBe(2),expect(t).toBe(6)})}),it("should use where clause changed via state",async()=>{const a=i({backend:u,tableName:"State2",key:"id"});await a.batchSet([{id:"1",name:"Alice",age:30},{id:"2",name:"Bob",age:25},{id:"3",name:"Carol",age:40}]);let t=0;const{result:n}=c(()=>{t++;const[r,e]=x(20);return[l(a,{where:{age:{gt:r}},sorBy:"age"},[r]),e]});await o(()=>{expect(n.current[0][0].map(r=>r.name)).toEqual(["Bob","Alice","Carol"]),expect(t).toBe(2)}),s(()=>{n.current[1](29)}),await o(()=>{expect(n.current[0][0].map(r=>r.name)).toEqual(["Alice","Carol"]),expect(t).toBe(4)})}),it("should support like in where clause and update results",async()=>{const a=i({backend:u,tableName:"State3",key:"id"});await a.batchSet([{id:"1",name:"Alice",age:30},{id:"2",name:"Alicia",age:25},{id:"3",name:"Bob",age:40}]);let t=0;const{result:n,rerender:r}=c(({like:e})=>(t++,l(a,{where:{name:{like:e}}},[e])),{initialProps:{like:"%Ali%"}});await o(()=>{expect(n.current[0].map(e=>e.name)).toEqual(["Alice","Alicia"])}),s(()=>{r({like:"%Bob%"})}),await o(()=>{expect(n.current[0].map(e=>e.name)).toEqual(["Bob"])}),expect(t).toBeGreaterThanOrEqual(2)}),it("should update results when changing order and limit options",async()=>{const a=i({backend:u,tableName:"State4",key:"id"});await a.batchSet([{id:"1",name:"Alice",age:30},{id:"2",name:"Bob",age:25},{id:"3",name:"Carol",age:40}]);const{result:t,rerender:n}=c(({order:r,limit:e})=>l(a,{sorBy:"age",order:r,limit:e},[r,e]),{initialProps:{order:"asc",limit:2}});await o(()=>{expect(t.current[0].map(r=>r.name)).toEqual(["Bob","Alice"])}),s(()=>{n({order:"desc",limit:2})}),await o(()=>{expect(t.current[0].map(r=>r.name)).toEqual(["Carol","Alice"])}),s(()=>{n({order:"desc",limit:1})}),await o(()=>{expect(t.current[0].map(r=>r.name)).toEqual(["Carol"])})}),it("should support actions.next and actions.refresh",async()=>{const a=i({backend:u,tableName:"State5",key:"id"});await a.batchSet([{id:"1",name:"Alice",age:30},{id:"2",name:"Bob",age:25}]);const{result:t}=c(()=>l(a,{},[]));await o(()=>{expect(typeof t.current[1].next).toBe("function"),expect(typeof t.current[1].reset).toBe("function"),expect(t.current[1].reset()).resolves.toBeUndefined(),expect(t.current[1].next()).resolves.toBeFalsy()})}),it("should handle thousands of records",async()=>{const a=i({backend:u,tableName:"State6",key:"id"}),t=[],n=1e3;for(let e=1;e<=n;e++)t.push({id:e.toString(),name:`Person${e}`,age:20+e%50});await a.batchSet(t);const{result:r}=c(()=>l(a,{},[]));await o(()=>{expect(r.current[0].length).toBe(m)});for(let e=0;e<n/m;e++)s(()=>{r.current[1].next()}),await o(()=>{expect(r.current[0].length).toBe(Math.min(m*(e+2),n))});s(()=>{r.current[1].reset()}),await o(()=>{expect(r.current[0].length).toBe(m)})}),it("should handle thousands of records with single update",async()=>{const a=i({backend:u,tableName:"State6",key:"id"}),t=[],n=1e4,r=5e3;for(let d=1;d<=n;d++)t.push({id:d.toString(),name:`Person${d}`,age:20+d%50});await a.batchSet(t);let e=0;const{result:p}=c(()=>(e++,l(a,{stepSize:r},[])));await o(()=>{expect(e).toBe(2),expect(p.current[0].length).toBe(r)}),s(()=>{for(let d=0;d<n/r;d++)p.current[1].next()}),await o(()=>{expect(e).toBe(4),expect(p.current[0].length).toBe(n)}),s(()=>{p.current[1].reset()}),await o(()=>{expect(e).toBe(5),expect(p.current[0].length).toBe(r)})}),it("should change ordering",async()=>{const a=i({backend:u,tableName:"State7",key:"id",indexes:["age"]}),t=[];for(let e=1;e<=100;e++)t.push({id:e.toString(),name:`Person${e}`,age:20+e%50});await a.batchSet(t);const{result:n,rerender:r}=c(({order:e})=>l(a,{sorBy:"age",order:e},[e]),{initialProps:{order:"asc"}});await o(()=>{expect(n.current[0][0].age).toBe(20)}),s(()=>{r({order:"desc"})}),await o(()=>{expect(n.current[0][0].age).toBe(69)})}),it("should support selector in options",async()=>{const a=i({backend:u,tableName:"State8",key:"id"});await a.batchSet([{id:"1",name:"Alice",age:30},{id:"2",name:"Bob",age:25},{id:"3",name:"Carol",age:40}]);const{result:t}=c(()=>l(a,{sorBy:"age",select:n=>n.name},[]));await o(()=>{expect(t.current[0]).toEqual(["Bob","Alice","Carol"])})})});
@@ -0,0 +1 @@
1
+ import{createScheduler as k}from"../scheduler";import{shallow as R}from"../utils/shallow";import{selectSql as v}from"./select-sql";import{createTable as M,DEFAULT_STEP_SIZE as O}from"./table/table";const f=k();let C=0;function E(){return C++}function B(g){const x=E();function l(e){return`state-${x}-search-${e}`}let m;async function o(){return m||(m=await M(g)),m}const c=new Map,i=new Map,h=new Map;async function p(e,n){const t=h.get(e),{options:a={}}=n,{stepSize:s=O}=a;if(!t)return!1;const r=[];for(let d=0;d<s;d++){const y=await t.next();if(y.done){h.delete(e);break}r.push(y.value.document),n.keys.add(String(y.value.rowId))}return r.length===0||R(n.items,r)?!1:(n.items=[...n.items,...r],!0)}function b(e){const n=i.get(e);n&&n()}async function T(e){const n=await o(),t=c.get(e);if(!t)return;const{options:a}=t,s=n.search({...a,select:(r,{rowId:d})=>({document:r,rowId:d})});h.set(e,s),t.keys=new Set,t.items=[],await p(e,t)}async function S(e){await T(e),b(e)}function P(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 u(e){const n=new Set;for(const t of e){const a=P(t);for(const s of a)n.add(s)}for(const t of n){const a=l(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&&S(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 u([t]),t},async batchSet(e){const t=await(await o()).batchSet(e);return await u(t),t},async delete(e){const t=await(await o()).delete(e);return t&&await u([t]),t},async deleteBy(e){const t=await(await o()).deleteBy(e);return await u(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=l(e);f.schedule(a,{searchId:e})},subscribe(e,n){const t=l(e),a=f.add(t,{onScheduleDone(){S(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:S,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 v(I,e)}};return I}export{B as createSqliteState};
@@ -0,0 +1 @@
1
+ import{createState as p}from"../create-state";let n=0;function i(){return n++,`${n.toString(36)}-sql`}function S(r,o){const{subscribe:a,updateSearchOptions:s}=r;return(...c)=>{const e=i(),m=a(e,()=>{t.emitter.emit()}),u=o(...c),t=p({destroy(){m(),t.emitter.clear(),t.cache.current=void 0},get(){return r.getSnapshot(e)},getSnapshot(){return r.getSnapshot(e)}});return s(e,u),t}}export{S as selectSql};
@@ -0,0 +1 @@
1
+ const e=":memory:";export{e as IN_MEMORY_DB};
@@ -0,0 +1 @@
1
+ import{Database as m}from"bun:sqlite";import{MapDeque as p}from"./map-deque";function d(){const n=m.open(":memory:"),r=new p(100);function s(e){if(r.has(e))return r.get(e);const t=n.prepare(e);return r.set(e,t),t}const c={execute:async(e,t=[])=>{const a=s(e).run(...t);return{rowsAffected:a.changes,changes:a.changes}},transaction:async e=>n.transaction(()=>e(c))(),path:n.filename,select:async(e,t=[])=>s(e).all(...t)};return c}export{d as bunMemoryBackend};
@@ -0,0 +1 @@
1
+ class a extends Map{constructor(e,t){super(t);this.maxSize=e;if(this.maxSize<=0)throw new RangeError("maxSize must be greater than 0")}set(e,t){if(this.has(e))return super.set(e,t),this;if(this.size>=this.maxSize){const s=this.keys().next().value;s!==void 0&&this.delete(s)}return super.set(e,t),this}}export{a as MapDeque};
@@ -0,0 +1,10 @@
1
+ import{getWhereQuery as S}from"./where";const p=500,L=100;async function N(k){const{backend:s,tableName:o,indexes:D,key:T}=k,d=T!==void 0;d?await s.execute(`
2
+ CREATE TABLE IF NOT EXISTS ${o} (
3
+ key TEXT PRIMARY KEY,
4
+ data TEXT NOT NULL
5
+ );
6
+ `):await s.execute(`
7
+ CREATE TABLE IF NOT EXISTS ${o} (
8
+ data TEXT NOT NULL
9
+ );
10
+ `);for(const n of D??[]){const a=String(n);await s.execute(`CREATE INDEX IF NOT EXISTS idx_${o}_${a} ON ${o} (json_extract(data, '$.${a}'));`)}function O(n){return d?n[T]:void 0}async function $(n){return(await n.select("SELECT changes() AS c"))[0]?.c??0}const f={backend:s,async set(n,a){const e=a??s,r=JSON.stringify(n);if(d){const t=O(n);if(t==null)throw new Error(`Document is missing the configured key "${String(T)}". Provide it or create the table without "key".`);if(await e.execute(`UPDATE ${o} SET data = ? WHERE key = ?`,[r,t]),await $(e)===1)return{key:t,op:"update"};try{return await e.execute(`INSERT INTO ${o} (key, data) VALUES (?, ?)`,[t,r]),{key:t,op:"insert"}}catch{return await e.execute(`UPDATE ${o} SET data = ? WHERE key = ?`,[r,t]),{key:t,op:"update"}}}await e.execute(`INSERT INTO ${o} (data) VALUES (?)`,[r]);const c=(await e.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(n,a=(e,r)=>e){const e=d?"key = ?":"rowid = ?",r=await s.select(`SELECT rowid, data FROM ${o} WHERE ${e}`,[n]);if(r.length===0)return;const[i]=r,{data:c,rowid:u}=i,t=JSON.parse(c);return a(t,{rowid:u})},async delete(n){const a=d?"key = ?":"rowid = ?";if(await s.execute(`DELETE FROM ${o} WHERE ${a}`,[n]),((await s.select("SELECT changes() AS c"))[0]?.c??0)>0)return{key:n,op:"delete"}},async*search(n={}){const{sorBy:a,order:e="asc",limit:r,offset:i=0,where:c,select:u=(y,m)=>y,stepSize:t=L}=n;let E=`SELECT rowid, data FROM ${o}`;c&&(E+=" "+S(c));let l=0,h=i;for(;;){let y=E;a?y+=` ORDER BY json_extract(data, '$.${String(a)}') COLLATE NOCASE ${e.toUpperCase()}`:y+=d?` ORDER BY key COLLATE NOCASE ${e.toUpperCase()}`:` ORDER BY rowid ${e.toUpperCase()}`;const m=r?Math.min(t,r-l):t;y+=` LIMIT ${m} OFFSET ${h}`;const w=await s.select(y);if(w.length===0)break;for(const{rowid:b,data:R}of w){if(r&&l>=r)return;const A=JSON.parse(R);yield u(A,{rowId:b}),l++}if(w.length<m||r&&l>=r)break;h+=w.length}},async count(n={}){const{where:a}=n;let e=`SELECT COUNT(*) as count FROM ${o}`;return a&&(e+=" "+S(a)),(await s.select(e))[0]?.count??0},async deleteBy(n){const a=S(n),e=d?"key":"rowid",r=[];return await s.transaction(async i=>{const c=await i.select(`SELECT ${e} AS k, rowid FROM ${o} ${a}`);if(c.length===0)return;const u=c.map(t=>t.k);for(let t=0;t<u.length;t+=p){const E=u.slice(t,t+p),l=E.map(()=>"?").join(",");await i.execute(`DELETE FROM ${o} WHERE ${e} IN (${l})`,E)}for(const t of u)r.push({key:t,op:"delete"})}),r},async batchSet(n){const a=[];return await s.transaction(async e=>{for(const r of n){const i=await f.set(r,e);a.push(i)}}),a}};return f}export{L as DEFAULT_STEP_SIZE,N as createTable};
File without changes
@@ -0,0 +1 @@
1
+ function y(n){return typeof n=="string"?`'${n.split("'").join("''")}'`:typeof n=="number"?n.toString():typeof n=="boolean"?n?"1":"0":`'${String(n).split("'").join("''")}'`}function $(n,c,i){const e=i?`${i}.`:"";return n==="KEY"?`"${e}key"`:typeof c=="string"?`CAST(json_extract(${e}data, '$.${n}') AS TEXT)`:typeof c=="boolean"?`CAST(json_extract(${e}data, '$.${n}') AS INTEGER)`:typeof c=="number"?`CAST(json_extract(${e}data, '$.${n}') AS NUMERIC)`:`json_extract(${e}data, '$.${n}')`}const N=new Set(["is","isNot","gt","gte","lt","lte","in","notIn","like"]);function m(n){return n===void 0}function l(n,c){if(!n||typeof n!="object")return"";if(!m(n.AND)){const t=n.AND;if(Array.isArray(t)&&t.length>0){let o="",u=!1;for(const a of t){const f=l(a,c);f&&(u&&(o+=" AND "),o+=f,u=!0)}return u?`(${o})`:""}return""}if(!m(n.OR)){const t=n.OR;if(Array.isArray(t)&&t.length>0){let o="",u=!1;for(const a of t){const f=l(a,c);f&&(u&&(o+=" OR "),o+=f,u=!0)}return u?`(${o})`:""}return""}if(!m(n.NOT)){const t=n.NOT;if(t&&typeof t=="object"){const o=l(t,c);return o?`(NOT ${o})`:""}return""}let i="",e=!1;for(const t in n){if(t==="AND"||t==="OR"||t==="NOT")continue;const o=n[t];if(o==null)continue;let u;typeof o!="object"||Array.isArray(o)?u=Array.isArray(o)?{in:o}:{is:o}:u=o;for(const a of Object.keys(u)){if(!N.has(a))continue;const f=u[a];if(f==null)continue;const s=Array.isArray(f)?f:[f];if(s.length!==0){if(a==="is"||a==="isNot"||a==="in"||a==="notIn"){const[D]=s,r=$(t,D,c);let d="";if(s.length>1)for(const[A,g]of s.entries())A>0&&(d+=","),d+=y(g);switch(a){case"is":{i+=s.length>1?(e?" AND ":"")+`${r} IN (${d})`:(e?" AND ":"")+`${r} = ${y(s[0])}`;break}case"isNot":{i+=s.length>1?(e?" AND ":"")+`${r} NOT IN (${d})`:(e?" AND ":"")+`${r} <> ${y(s[0])}`;break}case"in":{i+=s.length>1?(e?" AND ":"")+`${r} IN (${d})`:(e?" AND ":"")+`${r} IN (${y(s[0])})`;break}case"notIn":{i+=s.length>1?(e?" AND ":"")+`${r} NOT IN (${d})`:(e?" AND ":"")+`${r} NOT IN (${y(s[0])})`;break}}e=!0;continue}for(const D of s){const r=$(t,D,c);switch(a){case"gt":{i+=(e?" AND ":"")+`${r} > ${y(D)}`;break}case"gte":{i+=(e?" AND ":"")+`${r} >= ${y(D)}`;break}case"lt":{i+=(e?" AND ":"")+`${r} < ${y(D)}`;break}case"lte":{i+=(e?" AND ":"")+`${r} <= ${y(D)}`;break}case"like":{i+=(e?" AND ":"")+`${r} LIKE ${y(D)}`;break}}e=!0}}}}return e?`(${i})`:""}function k(n){const c=l(n);return c?`WHERE ${c}`:""}export{l as getWhere,k as getWhereQuery};
@@ -0,0 +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 +1 @@
1
- import{isAbortError as a,isEqualBase as b,isPromise as u,isUndefined as i}from"./is";class p extends Error{static Error="AbortError"}function T(r,o){o&&o.abort();const t=new AbortController,{signal:n}=t;return{promise:new Promise((e,s)=>{n.addEventListener("abort",()=>{s(new p)}),r.then(e).catch(s)}),controller:t}}function f(r,o=b){if(!i(r.current)){if(!i(r.previous)&&o(r.current,r.previous))return!1;r.previous=r.current}return!0}function m(r,o,t){if(!u(t))return t;r.abortController&&r.abortController.abort();const{promise:n,controller:l}=T(t,r.abortController);return r.abortController=l,n.then(e=>{r.current=e,o()}).catch(e=>{a(e)||(r.current=e,o())})}export{p as AbortError,f as canUpdate,T as cancelablePromise,m as handleAsyncUpdate};
1
+ import{isAbortError as i,isEqualBase as c,isPromise as b,isUndefined as l}from"./is";class u extends Error{static Error="AbortError"}function m(r,t){t&&t.abort();const e=new AbortController,{signal:n}=e;return{promise:new Promise((a,o)=>{n.addEventListener("abort",()=>{o(new u)}),r.then(a).catch(o)}),controller:e}}function T(r,t=c){if(!l(r.current)){if(!l(r.previous)&&t(r.current,r.previous))return!1;r.previous=r.current}return!0}function f(r,t){const{cache:e,emitter:{emit:n}}=r;if(!b(t))return t;e.abortController&&e.abortController.abort();const{promise:s,controller:a}=m(t,e.abortController);return e.abortController=a,s.then(o=>{e.current=o,n()}).catch(o=>{i(o)||(e.current=o,n())})}export{u as AbortError,T as canUpdate,m as cancelablePromise,f as handleAsyncUpdate};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muya",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "author": "samuel.gjabel@gmail.com",
5
5
  "repository": "https://github.com/samuelgjabel/muya",
6
6
  "main": "cjs/index.js",
@@ -9,7 +9,7 @@ describe('scheduler', () => {
9
9
  const value = 2
10
10
  const callback = jest.fn()
11
11
  scheduler.add(id, {
12
- onFinish: callback,
12
+ onScheduleDone: callback,
13
13
  })
14
14
  scheduler.schedule(id, value)
15
15
  await waitFor(() => {
@@ -23,7 +23,7 @@ describe('scheduler', () => {
23
23
  for (const id of ids) {
24
24
  const callback = jest.fn()
25
25
  scheduler.add(id, {
26
- onFinish: callback,
26
+ onScheduleDone: callback,
27
27
  })
28
28
  callbacks.push(callback)
29
29
  }
@@ -1,5 +1,5 @@
1
1
  import { select } from './select'
2
- import type { GetState, SetValue, State } from './types'
2
+ import type { GetState, SetValue, State, Cache } from './types'
3
3
  import { useValue } from './use-value'
4
4
  import { createEmitter } from './utils/create-emitter'
5
5
  import { isEqualBase, isPromise } from './utils/is'
@@ -23,7 +23,7 @@ type FullState<T> = GetStateOptions<T>['set'] extends undefined ? GetState<T> :
23
23
  export function createState<T>(options: GetStateOptions<T>): FullState<T> {
24
24
  const { get, destroy, set, getSnapshot } = options
25
25
  const isSet = !!set
26
-
26
+ const cache: Cache<T> = {}
27
27
  const state: FullState<T> = function (selector) {
28
28
  // eslint-disable-next-line react-hooks/rules-of-hooks
29
29
  return useValue(state, selector)
@@ -50,6 +50,7 @@ export function createState<T>(options: GetStateOptions<T>): FullState<T> {
50
50
  } as never
51
51
  state.get = get as never
52
52
  state.set = set as State<T>['set']
53
+ state.cache = cache
53
54
 
54
55
  return state
55
56
  }
package/src/create.ts CHANGED
@@ -1,40 +1,38 @@
1
1
  import { canUpdate, handleAsyncUpdate } from './utils/common'
2
2
  import { isEqualBase, isFunction, isPromise, isSetValueFunction, isUndefined } from './utils/is'
3
- import type { Cache, DefaultValue, IsEqual, SetStateCb, SetValue, State } from './types'
3
+ import type { DefaultValue, IsEqual, SetStateCb, SetValue, State } from './types'
4
4
  import { createScheduler } from './scheduler'
5
5
  import { subscribeToDevelopmentTools } from './debug/development-tools'
6
6
  import { createState } from './create-state'
7
7
 
8
- export const stateScheduler = createScheduler()
8
+ export const STATE_SCHEDULER = createScheduler()
9
9
 
10
10
  /**
11
11
  * Create state from a default value.
12
12
  */
13
13
  export function create<T>(initialValue: DefaultValue<T>, isEqual: IsEqual<T> = isEqualBase): State<T> {
14
- const cache: Cache<T> = {}
15
-
16
14
  function getValue(): T {
17
15
  try {
18
- if (isUndefined(cache.current)) {
16
+ if (isUndefined(state.cache.current)) {
19
17
  const value = isFunction(initialValue) ? initialValue() : initialValue
20
- const resolvedValue = handleAsyncUpdate(cache, state.emitter.emit, value)
21
- cache.current = resolvedValue
18
+ const resolvedValue = handleAsyncUpdate(state, value)
19
+ state.cache.current = resolvedValue
22
20
 
23
- return cache.current
21
+ return state.cache.current
24
22
  }
25
- return cache.current
23
+ return state.cache.current
26
24
  } catch (error) {
27
- cache.current = error as T
25
+ state.cache.current = error as T
28
26
  }
29
27
 
30
- return cache.current
28
+ return state.cache.current
31
29
  }
32
30
 
33
31
  async function handleAsyncSetValue(previousPromise: Promise<T>, value: SetStateCb<T>) {
34
32
  await previousPromise
35
- const newValue = value(cache.current as Awaited<T>)
36
- const resolvedValue = handleAsyncUpdate(cache, state.emitter.emit, newValue)
37
- cache.current = resolvedValue
33
+ const newValue = value(state.cache.current as Awaited<T>)
34
+ const resolvedValue = handleAsyncUpdate(state, newValue)
35
+ state.cache.current = resolvedValue
38
36
  }
39
37
 
40
38
  function setValue(value: SetValue<T>) {
@@ -45,13 +43,13 @@ export function create<T>(initialValue: DefaultValue<T>, isEqual: IsEqual<T> = i
45
43
  handleAsyncSetValue(previous as Promise<T>, value)
46
44
  return
47
45
  }
48
- if (cache.abortController) {
49
- cache.abortController.abort()
46
+ if (state.cache.abortController) {
47
+ state.cache.abortController.abort()
50
48
  }
51
49
 
52
50
  const newValue = isFunctionValue ? value(previous as Awaited<T>) : value
53
- const resolvedValue = handleAsyncUpdate(cache, state.emitter.emit, newValue)
54
- cache.current = resolvedValue
51
+ const resolvedValue = handleAsyncUpdate(state, newValue)
52
+ state.cache.current = resolvedValue
55
53
  }
56
54
 
57
55
  const state = createState<T>({
@@ -60,18 +58,18 @@ export function create<T>(initialValue: DefaultValue<T>, isEqual: IsEqual<T> = i
60
58
  getValue()
61
59
  clearScheduler()
62
60
  state.emitter.clear()
63
- cache.current = undefined
61
+ state.cache.current = undefined
64
62
  },
65
63
  set(value: SetValue<T>) {
66
- stateScheduler.schedule(state.id, value)
64
+ STATE_SCHEDULER.schedule(state.id, value)
67
65
  },
68
66
  getSnapshot: getValue,
69
67
  })
70
68
 
71
- const clearScheduler = stateScheduler.add(state.id, {
72
- onFinish() {
73
- cache.current = getValue()
74
- if (!canUpdate(cache, isEqual)) {
69
+ const clearScheduler = STATE_SCHEDULER.add(state.id, {
70
+ onScheduleDone() {
71
+ state.cache.current = getValue()
72
+ if (!canUpdate(state.cache, isEqual)) {
75
73
  return
76
74
  }
77
75
  state.emitter.emit()
package/src/scheduler.ts CHANGED
@@ -2,18 +2,26 @@ export const THRESHOLD = 0.2
2
2
  export const THRESHOLD_ITEMS = 10
3
3
  export const RESCHEDULE_COUNT = 0
4
4
 
5
+ type ScheduleId = string | number | symbol
5
6
  interface GlobalSchedulerItem<T> {
6
7
  value: T
7
- id: number
8
+ id: ScheduleId
8
9
  }
9
10
 
10
11
  export interface SchedulerOptions<T> {
11
12
  readonly onResolveItem?: (item: T) => void
12
- readonly onFinish: () => void
13
+ readonly onScheduleDone: () => void | Promise<void>
13
14
  }
14
15
 
16
+ /**
17
+ * A simple scheduler to batch updates and avoid blocking the main thread
18
+ * It uses a combination of time-based and count-based strategies to determine when to flush the queue.
19
+ * - Time-based: If the time taken to process the current batch is less than a threshold (THRESHOLD), it continues processing.
20
+ * - Count-based: If the ScheduleId of items in the batch exceeds a certain limit (THRESHOLD_ITEMS), it defers processing to the next microtask.
21
+ * @returns An object with methods to add listeners and schedule tasks.
22
+ */
15
23
  export function createScheduler() {
16
- const listeners = new Map<number, SchedulerOptions<unknown>>()
24
+ const listeners = new Map<ScheduleId, SchedulerOptions<unknown>>()
17
25
  const batches = new Set<GlobalSchedulerItem<unknown>>()
18
26
 
19
27
  let frame = performance.now()
@@ -44,7 +52,7 @@ export function createScheduler() {
44
52
  return
45
53
  }
46
54
 
47
- const effectedListeners = new Set<number>()
55
+ const effectedListeners = new Set<ScheduleId>()
48
56
  for (const value of batches) {
49
57
  if (listeners.has(value.id)) {
50
58
  effectedListeners.add(value.id)
@@ -62,18 +70,18 @@ export function createScheduler() {
62
70
  }
63
71
 
64
72
  for (const id of effectedListeners) {
65
- listeners.get(id)?.onFinish()
73
+ listeners.get(id)?.onScheduleDone()
66
74
  }
67
75
  }
68
76
 
69
77
  return {
70
- add<T>(id: number, option: SchedulerOptions<T>) {
78
+ add<T>(id: ScheduleId, option: SchedulerOptions<T>) {
71
79
  listeners.set(id, option as SchedulerOptions<unknown>)
72
80
  return () => {
73
81
  listeners.delete(id)
74
82
  }
75
83
  },
76
- schedule<T>(id: number, value: T) {
84
+ schedule<T>(id: ScheduleId, value: T) {
77
85
  batches.add({ value, id })
78
86
  schedule()
79
87
  },
package/src/select.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { stateScheduler } from './create'
1
+ import { STATE_SCHEDULER } from './create'
2
2
  import { createState } from './create-state'
3
3
  import { subscribeToDevelopmentTools } from './debug/development-tools'
4
- import type { Cache, GetState, IsEqual } from './types'
4
+ import type { GetState, IsEqual } from './types'
5
5
  import { AbortError, canUpdate, handleAsyncUpdate } from './utils/common'
6
6
  import { isPromise, isUndefined } from './utils/is'
7
7
 
@@ -21,8 +21,6 @@ export function select<T = unknown, S extends Array<unknown> = []>(
21
21
  selector: (...values: AwaitedArray<S>) => T,
22
22
  isEqual?: IsEqual<T>,
23
23
  ): GetState<T> {
24
- const cache: Cache<T> = {}
25
-
26
24
  function computedValue(): T {
27
25
  let hasPromise = false
28
26
  const values = states.map((state) => {
@@ -50,18 +48,18 @@ export function select<T = unknown, S extends Array<unknown> = []>(
50
48
  return result
51
49
  }
52
50
  function getSnapshot(): T {
53
- if (isUndefined(cache.current)) {
51
+ if (isUndefined(state.cache.current)) {
54
52
  const newValue = computedValue()
55
- cache.current = handleAsyncUpdate(cache, state.emitter.emit, newValue)
53
+ state.cache.current = handleAsyncUpdate(state, newValue)
56
54
  }
57
- return cache.current
55
+ return state.cache.current
58
56
  }
59
57
  function getValue(): T {
60
- if (isUndefined(cache.current)) {
58
+ if (isUndefined(state.cache.current)) {
61
59
  const newValue = computedValue()
62
- cache.current = handleAsyncUpdate(cache, state.emitter.emit, newValue)
60
+ state.cache.current = handleAsyncUpdate(state, newValue)
63
61
  }
64
- const { current } = cache
62
+ const { current } = state.cache
65
63
  if (isPromise(current)) {
66
64
  return new Promise((resolve) => {
67
65
  current.then((value: unknown) => {
@@ -74,13 +72,13 @@ export function select<T = unknown, S extends Array<unknown> = []>(
74
72
  })
75
73
  }) as T
76
74
  }
77
- return cache.current
75
+ return state.cache.current
78
76
  }
79
77
 
80
78
  const cleanups: Array<() => void> = []
81
79
  for (const dependencyState of states) {
82
80
  const clean = dependencyState.emitter.subscribe(() => {
83
- stateScheduler.schedule(state.id, null)
81
+ STATE_SCHEDULER.schedule(state.id, null)
84
82
  })
85
83
  cleanups.push(clean)
86
84
  }
@@ -92,17 +90,17 @@ export function select<T = unknown, S extends Array<unknown> = []>(
92
90
  }
93
91
  clearScheduler()
94
92
  state.emitter.clear()
95
- cache.current = undefined
93
+ state.cache.current = undefined
96
94
  },
97
95
  get: getValue,
98
96
  getSnapshot,
99
97
  })
100
98
 
101
- const clearScheduler = stateScheduler.add(state.id, {
102
- onFinish() {
99
+ const clearScheduler = STATE_SCHEDULER.add(state.id, {
100
+ onScheduleDone() {
103
101
  const newValue = computedValue()
104
- cache.current = handleAsyncUpdate(cache, state.emitter.emit, newValue)
105
- if (!canUpdate(cache, isEqual)) {
102
+ state.cache.current = handleAsyncUpdate(state, newValue)
103
+ if (!canUpdate(state.cache, isEqual)) {
106
104
  return
107
105
  }
108
106
  state.emitter.emit()
@@ -0,0 +1,81 @@
1
+ import { createSqliteState } from '../create-sqlite'
2
+ import { bunMemoryBackend } from '../table/bun-backend'
3
+
4
+ const backend = bunMemoryBackend()
5
+ interface Person {
6
+ id: string
7
+ name: string
8
+ age: number
9
+ }
10
+
11
+ describe('create-sqlite-state', () => {
12
+ it('should batchSet and update multiple documents', async () => {
13
+ const sql = createSqliteState<Person>({ backend, tableName: 'State2', key: 'id' })
14
+ await sql.batchSet([
15
+ { id: '1', name: 'Alice', age: 30 },
16
+ { id: '2', name: 'Bob', age: 25 },
17
+ ])
18
+ const all = []
19
+ for await (const p of sql.search()) all.push(p)
20
+ expect(all).toHaveLength(2)
21
+ // update both
22
+ await sql.batchSet([
23
+ { id: '1', name: 'Alice2', age: 31 },
24
+ { id: '2', name: 'Bob2', age: 26 },
25
+ ])
26
+ const updated = []
27
+ for await (const p of sql.search()) updated.push(p)
28
+ expect(updated).toEqual([
29
+ { id: '1', name: 'Alice2', age: 31 },
30
+ { id: '2', name: 'Bob2', age: 26 },
31
+ ])
32
+ })
33
+
34
+ it('should deleteBy condition', async () => {
35
+ const sql = createSqliteState<Person>({ backend, tableName: 'State3', key: 'id' })
36
+ await sql.batchSet([
37
+ { id: '1', name: 'Alice', age: 30 },
38
+ { id: '2', name: 'Bob', age: 25 },
39
+ { id: '3', name: 'Carol', age: 40 },
40
+ ])
41
+ const deleted = await sql.deleteBy({ age: { gt: 30 } })
42
+ expect(deleted.length).toBe(1)
43
+ const all = []
44
+ for await (const p of sql.search()) all.push(p)
45
+ expect(all.map((p) => p.id)).toEqual(['1', '2'])
46
+ })
47
+
48
+ it('should get by key and with selector', async () => {
49
+ const sql = createSqliteState<Person>({ backend, tableName: 'State4', key: 'id' })
50
+ await sql.set({ id: '1', name: 'Alice', age: 30 })
51
+ const doc = await sql.get('1')
52
+ expect(doc).toEqual({ id: '1', name: 'Alice', age: 30 })
53
+ const name = await sql.get('1', (d) => d.name)
54
+ expect(name).toBe('Alice')
55
+ const missing = await sql.get('999')
56
+ expect(missing).toBeUndefined()
57
+ })
58
+
59
+ it('should count documents with and without where', async () => {
60
+ const sql = createSqliteState<Person>({ backend, tableName: 'State5', key: 'id' })
61
+ await sql.batchSet([
62
+ { id: '1', name: 'Alice', age: 30 },
63
+ { id: '2', name: 'Bob', age: 25 },
64
+ { id: '3', name: 'Carol', age: 40 },
65
+ ])
66
+ expect(await sql.count()).toBe(3)
67
+ expect(await sql.count({ where: { age: { gt: 30 } } })).toBe(1)
68
+ })
69
+
70
+ it('should support search with options', async () => {
71
+ const sql = createSqliteState<Person>({ backend, tableName: 'State6', key: 'id' })
72
+ await sql.batchSet([
73
+ { id: '1', name: 'Alice', age: 30 },
74
+ { id: '2', name: 'Bob', age: 25 },
75
+ { id: '3', name: 'Carol', age: 40 },
76
+ ])
77
+ const results = []
78
+ for await (const p of sql.search({ where: { age: { lt: 35 } } })) results.push(p)
79
+ expect(results.map((p) => p.id)).toEqual(['1', '2'])
80
+ })
81
+ })