tinybase
Version:
A reactive data store and sync engine.
2 lines (1 loc) • 8.56 kB
JavaScript
const a=a=>typeof a,t="tinybase",e=",",n=a(""),s=Promise,i=a=>null==a,r=(a,t,e)=>i(a)?e?.():t(a),o=t=>a(t)==n,c=a=>Array.isArray(a),E=(a,t,e)=>a.slice(t,e),l=a=>a.length,w=async a=>s.all(a),y=a=>{throw Error(a)},u=(a,t)=>a.forEach(t),d=(a,t="")=>a.join(t),T=(a,t)=>a.map(t),R=a=>0==l(a),A=(a,t)=>a.filter(t),N=(a,...t)=>a.push(...t),g=a=>a.shift(),p=(a,t)=>a?.has(t)??!1,C=a=>i(a)||0==(a=>a?.size??0)(a),O=a=>[...a?.values()??[]],L=(a,t)=>a?.forEach(t),v=(a,t)=>a?.delete(t),$=Object,S=a=>$.getPrototypeOf(a),I=$.entries,m=$.keys,_=$.freeze,h=(a=[])=>$.fromEntries(a),f=(...a)=>$.assign({},...a),b=(a,t)=>(delete a[t],a),D=(a,t)=>T(I(a),(([a,e])=>t(e,a))),P=(a,t)=>h(D(a,((a,e)=>[e,t(a,e)]))),U=a=>$.values(a),F=a=>l(m(a)),M=a=>(a=>!i(a)&&r(S(a),(a=>a==$.prototype||i(S(a))),(()=>!0)))(a)&&0==F(a),G=JSON.stringify,B=JSON.parse,j="_",x="_id",X="SELECT",Y="WHERE",q="TABLE",H="ALTER "+q,W="DELETE FROM",k=X+"*FROM",z=a=>`"${a.replace(/"/g,'""')}"`,J=(a,t=[1])=>d(T(a,(()=>"$"+t[0]++)),e),K=a=>new Map(a),V=(a,t)=>a?.get(t),Q=(a,t)=>T([...a?.entries()??[]],(([a,e])=>t(e,a))),Z=(a,t,e)=>i(e)?(v(a,t),a):a?.set(t,e),aa=(a,t,e,n)=>(p(a,t)?n?.(V(a,t)):Z(a,t,e()),V(a,t)),ta=(a,t,e,n,s=0)=>r((e?aa:V)(a,t[s],s>l(t)-2?e:K),(i=>{if(s>l(t)-2)return n?.(i)&&Z(a,t[s]),i;const r=ta(i,t,e,n,s+1);return C(i)&&Z(a,t[s]),r})),ea=a=>new Set(c(a)||i(a)?a:[a]),na=(a,t)=>a?.add(t),sa="ColumnName",ia="store",ra="json",oa=ia+"TableName",ca=ia+"Id"+sa,Ea=ia+sa,la="autoLoadIntervalSeconds",wa="rowId"+sa,ya="tableId",ua="tableName",da="deleteEmptyColumns",Ta="deleteEmptyTable",Ra={mode:ra,[la]:1},Aa={load:0,save:0,[ua]:t+"_values"},Na=(a,t,e,n,s)=>{const r=K();return P(a,((a,c)=>{const l=E(U(f(t,o(a)?{[e]:a}:a)),0,F(t));i(l[0])||n(c,l[0])||(s(c,l[0]),Z(r,c,l))})),r},ga=/^\d+$/,pa=K(),Ca=K(),Oa=(a,t,e,n,s,o,E,w={},d=0,T=[])=>{let R,A,p,O=0,$=0,S=0;aa(pa,T,(()=>0)),aa(Ca,T,(()=>[]));const I=K(),[m,h,f,b,D]=((a=1,t,e)=>1!=a&&t.isMergeable()?[1,t.getMergeableContent,()=>t.getTransactionMergeableChanges(!e),([[a],[t]])=>!M(a)||!M(t),t.setDefaultContent]:2!=a?[0,t.getContent,t.getTransactionChanges,([a,t])=>!M(a)||!M(t),t.setContent]:y("Store type not supported by this Persister"))(E,a,d),[P,U,F]=(()=>{let a;const[t,e]=(()=>{const a=[];let t=0;return[e=>(e?g(a):null)??""+t++,t=>{ga.test(t)&&l(a)<1e3&&N(a,t)}]})(),n=K();return[(e,s,i,r=[],o=()=>[])=>{a??=H;const c=t(1);return Z(n,c,[e,s,i,r,o]),na(ta(s,i??[""],ea),c),c},(t,e,...s)=>u(((a,t=[""])=>{const e=[],n=(a,s)=>s==l(t)?N(e,a):null===t[s]?L(a,(a=>n(a,s+1))):u([t[s],null],(t=>n(V(a,t),s+1)));return n(a,0),e})(t,e),(t=>L(t,(t=>V(n,t)[0](a,...e??[],...s))))),a=>r(V(n,a),(([,t,s])=>(ta(t,s??[""],void 0,(t=>(v(t,a),C(t)?1:0))),Z(n,a),e(a),s))),t=>r(V(n,t),(([t,,e=[],n,s])=>{const r=(...o)=>{const c=l(o);c==l(e)?t(a,...o,...s(o)):i(e[c])?u(n[c]?.(...o)??[],(a=>r(...o,a))):r(...o,e[c])};r()}))]})(),G=a=>{a!=O&&(O=a,U(I,void 0,O))},B=t=>{(m&&c(t?.[0])?1===t?.[2]?a.applyMergeableChanges:a.setMergeableContent:1===t?.[2]?a.applyChanges:a.setContent)(t)},j=async a=>(2!=O&&(G(1),$++,await q((async()=>{try{const e=await t();c(e)?B(e):a?D(a):y("Content is not an array: "+e)}catch(t){o?.(t),a&&D(a)}G(0)}))),H),x=()=>(A&&(s(A),A=void 0),H),X=async a=>(1!=O&&(G(2),S++,await q((async()=>{try{await e(h,a)}catch(a){o?.(a)}G(0)}))),H),Y=()=>(p&&(a.delListener(p),p=void 0),H),q=async(...a)=>(N(V(Ca,T),...a),await(async()=>{if(!V(pa,T)){for(Z(pa,T,1);!i(R=g(V(Ca,T)));)try{await R()}catch(a){o?.(a)}Z(pa,T,0)}})(),H),H={load:j,startAutoLoad:async a=>{x(),await j(a);try{A=await n((async(a,t)=>{t||a?2!=O&&(G(1),$++,B(t??a),G(0)):await j()}))}catch(a){o?.(a)}return H},stopAutoLoad:x,isAutoLoading:()=>!i(A),save:X,startAutoSave:async()=>(Y(),await X(),p=a.addDidFinishTransactionListener((()=>{const a=f();b(a)&&X(a)})),H),stopAutoSave:Y,isAutoSaving:()=>!i(p),getStatus:()=>O,addStatusListener:a=>P(a,I),delListener:t=>(F(t),a),schedule:q,getStore:()=>a,destroy:()=>(V(Ca,T).splice(0,void 0),x().stopAutoSave()),getStats:()=>({loads:$,saves:S}),...w};return _(H)},La=(a,t,n,s,r,o=va,c,E)=>{const l=K();return[async()=>{l.clear(),T(await n(a,t),(({tn:a,cn:t})=>na(aa(l,a,ea),t)))},async(t,e)=>((a,t)=>p(V(l,a),t))(t,e)?h(A(T(await a(k+z(t)),(a=>[a[e],E?P(b(a,e),E):b(a,e)])),(([a,t])=>!i(a)&&!M(t)))):{},async(t,n,s,E,y,u=!1)=>{const g=ea();P(s??{},(a=>T(m(a??{}),(a=>na(g,a)))));const C=O(g);if(!u&&y&&R(C)&&p(l,t))return await a("DROP "+q+z(t)),void Z(l,t);const L=V(l,t),$=ea(O(L));if(R(C)||(p(l,t)?await w(T([n,...C],(async(e,s)=>{v($,e)||(await a(H+z(t)+"ADD"+z(e)+r),0==s&&await a("CREATE UNIQUE INDEX pk ON "+z(t)+`(${z(n)})`),na(L,e))}))):(await a("CREATE "+q+z(t)+`(${z(n)}${r} PRIMARY KEY${d(T(C,(a=>e+z(a)+r)))});`),Z(l,t,ea([n,...C])))),await w([...!u&&E?T(O($),(async e=>{e!=n&&(await a(H+z(t)+"DROP"+z(e)),v(L,e))})):[]]),u)i(s)?await a(W+z(t)+Y+" true"):await w(D(s,(async(e,s)=>{i(e)?await a(W+z(t)+Y+z(n)+"=$1",[s]):R(C)||await o(a,t,n,m(e),{[s]:c?T(U(e),c):U(e)},L)})));else if(R(C))p(l,t)&&await a(W+z(t)+Y+" true");else{const e=A(O(V(l,t)),(a=>a!=n)),i={},r=[];P(s??{},((a,t)=>{i[t]=T(e,(t=>c?c(a?.[t]):a?.[t])),N(r,t)})),await o(a,t,n,e,i),await a(W+z(t)+Y+z(n)+`NOT IN(${J(r)})`,r)}},async t=>{let e;await a("BEGIN");try{e=await t()}catch(a){s?.(a)}return await a("END"),e}]},va=async(a,t,n,s,i)=>{const r=[1];await a("INSERT INTO"+z(t)+"("+((...a)=>d(T(a,z),e))(n,...s)+")VALUES"+d(D(i,(a=>"($"+r[0]+++","+J(a,r)+")")),e)+"ON CONFLICT("+z(n)+")DO UPDATE SET"+d(T(s,(a=>z(a)+"=excluded."+z(a))),e),D(i,((a,t)=>[t,...T(a,(a=>a??null))])).flat())},$a=(a,t,e,n,s,i,r,[o,c,E],l,w,y,u,d,T)=>{const[R,A,N,g]=La(t,l,w,s,d,T),p=Oa(a,(async()=>await g((async()=>{return await R(),a=(await A(o,c))[j]?.[E]??"null",B(a,((a,t)=>""===t?void 0:t));var a}))),(async a=>await g((async()=>{var t;await R(),await N(o,c,{[j]:{[E]:(t=a()??null,G(t,((a,t)=>void 0===t?"":t)))}},!0,!0)}))),e,n,s,r,{[u]:()=>y,destroy:()=>(p.stopAutoLoad().stopAutoSave(),i(),p)},0,y);return p},Sa=(a,t,e,n,s,r,o,[c,E,[l,y,u]],d,T,R,N,g,p,C,O)=>{const[L,v,$,S]=La(t,d,T,s,g,p,C,O),I=async(a,t)=>await w(Q(E,(async([e,n,s,i],r)=>{t&&!(r in a)||await $(e,n,a[r],s,i,t)}))),m=async(a,t)=>y?await $(u,x,{[j]:a},!0,!0,t):null,_=Oa(a,(async()=>await S((async()=>{await L();const a=await(async()=>h(A(await w(Q(c,(async([a,t],e)=>[a,await v(e,t)]))),(a=>!M(a[1])))))(),t=await(async()=>l?(await v(u,x))[j]:{})();return M(a)&&i(t)?void 0:[a,t]}))),(async(a,t)=>await S((async()=>{if(await L(),i(t)){const[t,e]=a();await I(t),await m(e)}else await I(t[0],!0),await m(t[1],!0)}))),e,n,s,o,{[N]:()=>R,destroy:()=>(_.stopAutoLoad().stopAutoSave(),r(),_)},0,R);return _},Ia=t,ma=/^([cd]:)(.+)/,_a=t+"_data",ha=t+"_table",fa=async(a,e,n,s,i)=>{const c=await(e.reserve?.());return((a,e,n,s,i,c,l,y,u,d,R="getDb")=>{const A=((a,t)=>t?async(e,n)=>(t(e,n),await a(e,n)):a)(n,c),[N,,g,C]=(a=>{const e=(a=>f(Ra,o(a)?{[oa]:a}:a??{}))(a),n=e[la];if(e.mode==ra){const a=e[oa]??t;return[1,n,[a,e[ca]??x,e[Ea]??ia],ea(a)]}const{tables:{load:s={},save:i={}}={},values:r={}}=e,c=E(U(f(Aa,r)),0,F(Aa)),l=c[2],w=ea(l),y=ea(l);return[0,n,[Na(s,{[ya]:null,[wa]:x},ya,(a=>p(y,a)),(a=>na(w,a))),Na(i,{[ua]:null,[wa]:x,[da]:0,[Ta]:0},ua,((a,t)=>p(y,t)),((a,t)=>na(w,t))),c],w]})(e),L=async a=>{await A(`CREATE OR REPLACE TRIGGER ${z(_a+"_"+a)} AFTER INSERT OR UPDATE OR DELETE ON ${z(a)} EXECUTE FUNCTION ${_a}()`)};return(N?$a:Sa)(a,A,(async a=>{await A(`CREATE OR REPLACE FUNCTION ${ha}()RETURNS event_trigger AS $t2$ DECLARE row record; BEGIN FOR row IN SELECT object_identity FROM pg_event_trigger_ddl_commands()WHERE command_tag='CREATE TABLE' LOOP PERFORM pg_notify('${Ia}','c:'||SPLIT_PART(row.object_identity,'.',2));END LOOP;END;$t2$ LANGUAGE plpgsql;`);try{await A(`CREATE EVENT TRIGGER ${ha} ON ddl_command_end WHEN TAG IN('CREATE TABLE')EXECUTE FUNCTION ${ha}();`)}catch{}return await A(`CREATE OR REPLACE FUNCTION ${_a}()RETURNS trigger AS $t1$ BEGIN PERFORM pg_notify('${Ia}','d:'||TG_TABLE_NAME);RETURN NULL;END;$t1$ LANGUAGE plpgsql;`),await w(T(O(C),(async a=>{await A(`CREATE TABLE IF NOT EXISTS ${z(a)}("_id"text PRIMARY KEY)`),await L(a)}))),await s(Ia,(async t=>{return await r((e=t,n=ma,e?.match(n)),(async([,t,e])=>{p(C,e)&&("c:"==t&&await L(e),a())}));var e,n}))}),i,l,y,u,g,O(C),(async(a,t)=>await a(`${X} table_name tn,column_name cn FROM information_schema.columns ${Y} table_schema='public'AND table_name IN(${J(t)})`,t)),d,R,"text",void 0,(a=>G(a)),(a=>B(a)))})(a,n,c?.unsafe,(async(a,t)=>e.listen(a,t)),(async a=>{try{await a.unlisten()}catch(a){i?.(a)}}),s,i,(()=>c?.release?.()),3,e,"getSql")};export{fa as createPostgresPersister};