@kubun/db 0.5.0 → 0.5.1

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/lib/db.js CHANGED
@@ -1 +1 @@
1
- import{EventEmitter as e}from"@enkaku/event";import{DocumentModelID as t}from"@kubun/id";import{getKubunLogger as a}from"@kubun/logger";import{Kysely as i,Migrator as s,ParseJSONResultsPlugin as r,sql as n}from"kysely";import{serializeCursor as d}from"./cursor.js";import{getMigrations as o}from"./migrations/migrations.js";import{applyDocumentFilter as l,applyDocumentOrderBy as c,applyPagination as u}from"./query-builder.js";function m(e){let t={version:e.version,name:e.name,behavior:e.behavior,interfaces:e.interfaces,schema:e.schema,fieldsMeta:e.fields_meta};return"unique"===t.behavior&&(t.uniqueFields=e.unique_fields),t}function h(e,t){return{id:t.id,model:t.model,owner:t.owner,data:t.data,createdAt:e.decodeTimestamp(t.created_at),updatedAt:t.updated_at?e.decodeTimestamp(t.updated_at):null}}function _(e,a){let i=t.fromString(a);return i.isLocal?i.toGlobal(t.fromString(e)).toString():a}export class KubunDB{#e;#t;#a=new e;#i;#s;constructor(e){this.#e=e.adapter,this.#t=new i({dialect:this.#e.dialect,plugins:[new r]}),this.#i=e.logger??a("db"),this.#s=this.#r()}get adapter(){return this.#e}get events(){return this.#a}getDB(){return this.#s.then(()=>this.#t)}async #r(){let e=new s({db:this.#t,provider:{getMigrations:()=>Promise.resolve(this.getMigrations())}}),t=await e.migrateToLatest();if(null!=t.error)throw t.error;this.#i.info("ready")}getMigrations(){return o(this.#e)}async close(){await this.#t.destroy(),this.#i.info("closed")}async listGraphs(){return await this.#s,await this.#t.selectFrom("kubun_graph_models").selectAll().execute()}async createGraph(e){await this.#s;let t=e.id??globalThis.crypto.randomUUID(),a=e.name??t;return await this.#t.transaction().setIsolationLevel("read committed").execute(async i=>{await i.insertInto("kubun_graph_models").values({aliases:JSON.stringify(e.aliases??{}),id:t,name:a,search:e.search?JSON.stringify(e.search):null}).onConflict(e=>e.doNothing()).execute();let s=Object.entries(e.record),r=new Set;for(;r.size<s.length;){let e=s.filter(([e,t])=>!r.has(e)&&t.interfaces.every(t=>r.has(_(e,t))));if(0===e.length)throw Error("Could not create graph: no valid model to add");await Promise.all(e.map(async([e,a])=>{await this.#n({id:e,graphModelID:t,model:a,transaction:i}),r.add(e)}))}}),this.#i.debug("created graph {id}",{id:t}),t}async #n(e){let{id:t,graphModelID:a,model:i,transaction:s}=e,r=this.#e.types;for(let e of(await this.#s,await s.schema.createTable(`k_${t}`).ifNotExists().addColumn("id",r.text,e=>e.notNull().primaryKey()).addColumn("owner",r.text,e=>e.notNull()).addColumn("model",r.text,e=>e.notNull()).addColumn("data",r.json).addColumn("unique",r.binary,e=>e.notNull()).addColumn("created_at",r.timestamp,e=>e.defaultTo(this.#e.functions.now).notNull()).addColumn("updated_at",r.timestamp).execute(),await s.insertInto("kubun_document_models").values({id:t,version:i.version,name:i.name,behavior:i.behavior,unique_fields:"unique"===i.behavior?JSON.stringify(i.uniqueFields):null,interfaces:JSON.stringify(i.interfaces),schema:JSON.stringify(i.schema),fields_meta:JSON.stringify(i.fieldsMeta)}).onConflict(e=>e.doNothing()).execute(),i.interfaces))await s.insertInto("kubun_document_model_interfaces").values({interface_id:_(t,e),implementation_id:t}).onConflict(e=>e.doNothing()).execute();await s.insertInto("kubun_graph_document_models").values({graph_model_id:a,document_model_id:t}).onConflict(e=>e.doNothing()).execute()}async getGraph(e){await this.#s;let t=await this.#t.selectFrom("kubun_graph_models").selectAll().where("id","=",e).executeTakeFirst();if(null==t)return null;let a={};for(let t of(await this.#t.selectFrom("kubun_graph_document_models").innerJoin("kubun_document_models","kubun_graph_document_models.document_model_id","kubun_document_models.id").selectAll("kubun_document_models").where("kubun_graph_document_models.graph_model_id","=",e).execute()))a[t.id]=m(t);return{...t,record:a}}async getDocumentModel(e){return await this.#s,m(await this.#t.selectFrom("kubun_document_models").selectAll().where("id","=",e.toString()).executeTakeFirstOrThrow())}async getDocument(e){await this.#s;let t=await this.#t.selectFrom(`k_${e.model.toString()}`).selectAll().where("id","=",e.toString()).executeTakeFirst();return t?h(this.#e,t):null}async getDocumentState(e){await this.#s;let t=await this.#t.selectFrom("kubun_document_states").selectAll().where("id","=",e).executeTakeFirst();return t?.data??null}async getDocumentStates(e){await this.#s;let t=await this.#t.selectFrom("kubun_document_states").selectAll().where("id","in",e).execute(),a={};for(let e of t)a[e.id]=e.data;return e.reduce((e,t)=>(e[t]=a[t]??null,e),{})}async listDocuments(e){await this.#s;let[t,...a]=e.modelIDs,i=this.#t.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs);for(let t of a)i=i.unionAll(a=>a.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs));return(await i.execute()).map(e=>h(this.#e,e))}async queryDocuments(e){let{filter:t,modelIDs:a,orderBy:i,owner:s,...r}=e,n=null!=e.last;await this.#s;let[o,...m]=a,_=this.#t.selectFrom(`k_${o}`).selectAll();for(let e of(null!=s&&(_=_.where("owner","=",s)),null!=t&&(_=_.where(e=>l(e,t))),m))_=_.unionAll(a=>{let i=a.selectFrom(`k_${e}`).selectAll();return null!=s&&(i=i.where("owner","=",s)),null!=t&&(i=i.where(e=>l(e,t))),i});let[w,p]=c(_,i,n),[y,b]=u(w,r,i),g=await y.execute(),f=n?g.slice(0,b).reverse():g.slice(0,b);return{entries:p?f.map(e=>{let t={};for(let a of p){let i=e.data;for(let e of a)null!=i&&(i=i[e]);null!=i&&(t[a.join(".")]=i)}return{cursor:d({id:e.id,values:t}),document:h(this.#e,e)}}):f.map(e=>({cursor:d({id:e.id,ts:+e.created_at}),document:h(this.#e,e)})),hasMore:f.length>b}}async createDocument(e){await this.#s;let t=e.id.toString(),a=e.id.model.toString(),i=await this.#t.transaction().setIsolationLevel("read committed").execute(async i=>{let s=await i.insertInto(`k_${a}`).values({id:t,owner:e.owner,model:a,data:this.#e.encodeJSON(e.data),unique:this.#e.encodeBinary(e.unique)}).returningAll().executeTakeFirst();return await i.insertInto("kubun_document_states").values({id:t,data:e.state?this.#e.encodeBinary(e.state):null}).execute(),s}),s=h(this.#e,i);return this.#a.emit("document:saved",{type:"create",document:s,getCursor:()=>d({id:i.id,ts:+i.created_at})}),this.#i.debug("created document {id} with model {model}",{id:t,model:a}),s}async saveDocument(e){await this.#s;let t=e.id.toString(),a=await this.#t.transaction().setIsolationLevel("read committed").execute(async a=>{let i=await a.updateTable(`k_${e.id.model.toString()}`).set({data:e.data?this.#e.encodeJSON(e.data):null,updated_at:this.#e.encodeTimestamp(new Date)}).where("id","=",t).returningAll().executeTakeFirst();return await a.updateTable("kubun_document_states").set({data:e.state?this.#e.encodeBinary(e.state):null}).where("id","=",t).execute(),i}),i=h(this.#e,a);return this.#a.emit("document:saved",{type:"update",document:i,previous:e.existing,getCursor:()=>d({id:a.id,ts:+a.created_at})}),this.#i.debug("updated document {id}",{id:t}),i}async addAttachments(e){await this.#s,await this.#t.insertInto("kubun_document_attachments").values(e).onConflict(e=>e.doNothing()).execute()}async getUserModelAccessDefault(e,t,a){await this.#s;let i=await this.#t.selectFrom("kubun_user_model_access_defaults").select(["access_level","allowed_dids"]).where("owner_did","=",e).where("model_id","=",t).where("permission_type","=",a).executeTakeFirst();return i?{level:i.access_level,allowedDIDs:i.allowed_dids}:null}async setUserModelAccessDefault(e){await this.#s,await this.#t.insertInto("kubun_user_model_access_defaults").values({owner_did:e.ownerDID,model_id:e.modelID,permission_type:e.permissionType,access_level:e.accessLevel,allowed_dids:e.allowedDIDs?this.#e.encodeJSON(e.allowedDIDs):null}).onConflict(t=>t.columns(["owner_did","model_id","permission_type"]).doUpdateSet({access_level:e.accessLevel,allowed_dids:e.allowedDIDs?this.#e.encodeJSON(e.allowedDIDs):null,updated_at:this.#e.encodeTimestamp(new Date)})).execute()}async removeUserModelAccessDefaults(e,t,a){await this.#s,await this.#t.deleteFrom("kubun_user_model_access_defaults").where("owner_did","=",e).where("model_id","=",t).where("permission_type","in",a).execute()}async storeMutationLog(e){await this.#s;let t=globalThis.crypto.randomUUID();await this.#t.insertInto("kubun_document_mutation_log").values({id:t,document_id:e.documentID,sequence_number:e.sequenceNumber,mutation_jwt:e.mutationJWT,author_did:e.authorDID,timestamp:Date.now()}).execute(),await this.#t.deleteFrom("kubun_document_mutation_log").where("document_id","=",e.documentID).where("id","not in",this.#t.selectFrom("kubun_document_mutation_log").select("id").where("document_id","=",e.documentID).orderBy(n`CAST(sequence_number AS INTEGER)`,"desc").limit(10)).execute()}async getMutationLog(e,t){return await this.#s,await this.#t.selectFrom("kubun_document_mutation_log").selectAll().where("document_id","=",e).where(n`CAST(sequence_number AS INTEGER)`,">=",t).orderBy(n`CAST(sequence_number AS INTEGER)`,"asc").execute()}async listDocumentModelIDs(){return await this.#s,(await this.#t.selectFrom("kubun_document_models").select("id").execute()).map(e=>e.id)}async queryDocumentsByOwner(e,t){return await this.#s,(await this.#t.selectFrom(`k_${e}`).selectAll().where("owner","=",t).execute()).map(e=>h(this.#e,e))}async storeSyncCheckpoint(e,t){await this.#s;let a=`${e}:${t.userID}`,i=JSON.stringify(t.documentCheckpoints),s=JSON.stringify(t.vectorClock);try{return await this.#t.insertInto("kubun_sync_checkpoints").values({id:a,peer_server_id:e,user_id:t.userID,last_sync_timestamp:t.lastSyncTimestamp,document_checkpoints:i,vector_clock:s}).onConflict(e=>e.column("id").doUpdateSet({last_sync_timestamp:t.lastSyncTimestamp,document_checkpoints:i,vector_clock:s})).execute(),!0}catch{return!1}}async getSyncCheckpoint(e,t){await this.#s;let a=`${e}:${t}`,i=await this.#t.selectFrom("kubun_sync_checkpoints").selectAll().where("id","=",a).executeTakeFirst();return i?{lastSyncTimestamp:i.last_sync_timestamp,documentCheckpoints:i.document_checkpoints,vectorClock:i.vector_clock}:null}async listSyncCheckpoints(e){return await this.#s,(await this.#t.selectFrom("kubun_sync_checkpoints").selectAll().where("peer_server_id","=",e).execute()).map(e=>({userID:e.user_id,lastSyncTimestamp:e.last_sync_timestamp,documentCheckpoints:e.document_checkpoints,vectorClock:e.vector_clock}))}async createSearchIndex(e,t){await this.#s,await this.#e.createSearchIndex(this.#t,{modelID:e,fields:t})}async dropSearchIndex(e){await this.#s,await this.#e.dropSearchIndex(this.#t,e)}async updateSearchEntry(e,t,a,i){await this.#s;let s={};for(let e of i){let t=this.#d(a,e);null!=t&&(s[e]=String(t))}await this.#e.updateSearchEntry(this.#t,e,t,s,i)}async removeSearchEntry(e,t){await this.#s,await this.#e.removeSearchEntry(this.#t,e,t)}async searchDocuments(e){await this.#s;let t=[];for(let a of e.modelIDs)for(let i of(await this.#e.searchIndex(this.#t,{query:e.query,modelID:a,limit:e.first??50})))t.push({documentID:i.documentID,modelID:a,rank:i.rank});return(t.sort((e,t)=>Math.abs(t.rank)-Math.abs(e.rank)),e.first)?t.slice(0,e.first):t}#d(e,t){let a=t.split("."),i=e;for(let e of a){if(null==i||"object"!=typeof i)return null;i=i[e]}return i}}
1
+ import{EventEmitter as e}from"@enkaku/event";import{DocumentModelID as t}from"@kubun/id";import{getKubunLogger as a}from"@kubun/logger";import{Kysely as i,Migrator as s,ParseJSONResultsPlugin as r,sql as n}from"kysely";import{serializeCursor as d}from"./cursor.js";import{getMigrations as o}from"./migrations/migrations.js";import{applyDocumentFilter as l,applyDocumentOrderBy as c,applyPagination as u}from"./query-builder.js";function m(e){let t={version:e.version,name:e.name,behavior:e.behavior,interfaces:e.interfaces,schema:e.schema,fieldsMeta:e.fields_meta};return"unique"===t.behavior&&(t.uniqueFields=e.unique_fields),t}function h(e,t){return{id:t.id,model:t.model,owner:t.owner,data:t.data,createdAt:e.decodeTimestamp(t.created_at),updatedAt:t.updated_at?e.decodeTimestamp(t.updated_at):null}}function _(e,a){let i=t.fromString(a);return i.isLocal?i.toGlobal(t.fromString(e)).toString():a}export class KubunDB{#e;#t;#a=new e;#i;#s;constructor(e){this.#e=e.adapter,this.#t=new i({dialect:this.#e.dialect,plugins:[new r]}),this.#i=e.logger??a("db"),this.#s=this.#r()}get adapter(){return this.#e}get events(){return this.#a}getDB(){return this.#s.then(()=>this.#t)}async #r(){let e=new s({db:this.#t,provider:{getMigrations:()=>Promise.resolve(this.getMigrations())}}),t=await e.migrateToLatest();if(null!=t.error)throw t.error;this.#i.info("ready")}getMigrations(){return o(this.#e)}async close(){await this.#t.destroy(),this.#i.info("closed")}async listGraphs(){return await this.#s,await this.#t.selectFrom("kubun_graph_models").selectAll().execute()}async createGraph(e){await this.#s;let t=e.id??globalThis.crypto.randomUUID(),a=e.name??t;return await this.#t.transaction().setIsolationLevel("read committed").execute(async i=>{await i.insertInto("kubun_graph_models").values({aliases:JSON.stringify(e.aliases??{}),id:t,name:a,search:e.search?JSON.stringify(e.search):null}).onConflict(e=>e.doNothing()).execute();let s=Object.entries(e.record),r=new Set;for(;r.size<s.length;){let e=s.filter(([e,t])=>!r.has(e)&&t.interfaces.every(t=>r.has(_(e,t))));if(0===e.length)throw Error("Could not create graph: no valid model to add");await Promise.all(e.map(async([e,a])=>{await this.#n({id:e,graphModelID:t,model:a,transaction:i}),r.add(e)}))}}),this.#i.debug("created graph {id}",{id:t}),t}async #n(e){let{id:t,graphModelID:a,model:i,transaction:s}=e,r=this.#e.types;for(let e of(await this.#s,await s.schema.createTable(`k_${t}`).ifNotExists().addColumn("id",r.text,e=>e.notNull().primaryKey()).addColumn("owner",r.text,e=>e.notNull()).addColumn("model",r.text,e=>e.notNull()).addColumn("data",r.json).addColumn("unique",r.binary,e=>e.notNull()).addColumn("created_at",r.timestamp,e=>e.defaultTo(this.#e.functions.now).notNull()).addColumn("updated_at",r.timestamp).execute(),await s.insertInto("kubun_document_models").values({id:t,version:i.version,name:i.name,behavior:i.behavior,unique_fields:"unique"===i.behavior?JSON.stringify(i.uniqueFields):null,interfaces:JSON.stringify(i.interfaces),schema:JSON.stringify(i.schema),fields_meta:JSON.stringify(i.fieldsMeta)}).onConflict(e=>e.doNothing()).execute(),i.interfaces))await s.insertInto("kubun_document_model_interfaces").values({interface_id:_(t,e),implementation_id:t}).onConflict(e=>e.doNothing()).execute();await s.insertInto("kubun_graph_document_models").values({graph_model_id:a,document_model_id:t}).onConflict(e=>e.doNothing()).execute()}async getGraph(e){await this.#s;let t=await this.#t.selectFrom("kubun_graph_models").selectAll().where("id","=",e).executeTakeFirst();if(null==t)return null;let a={};for(let t of(await this.#t.selectFrom("kubun_graph_document_models").innerJoin("kubun_document_models","kubun_graph_document_models.document_model_id","kubun_document_models.id").selectAll("kubun_document_models").where("kubun_graph_document_models.graph_model_id","=",e).execute()))a[t.id]=m(t);return{...t,record:a}}async getDocumentModel(e){return await this.#s,m(await this.#t.selectFrom("kubun_document_models").selectAll().where("id","=",e.toString()).executeTakeFirstOrThrow())}async getDocument(e){await this.#s;let t=await this.#t.selectFrom(`k_${e.model.toString()}`).selectAll().where("id","=",e.toString()).executeTakeFirst();return t?h(this.#e,t):null}async getDocumentState(e){await this.#s;let t=await this.#t.selectFrom("kubun_document_states").selectAll().where("id","=",e).executeTakeFirst();return t?.data??null}async getDocumentStates(e){await this.#s;let t=await this.#t.selectFrom("kubun_document_states").selectAll().where("id","in",e).execute(),a={};for(let e of t)a[e.id]=e.data;return e.reduce((e,t)=>(e[t]=a[t]??null,e),{})}async listDocuments(e){await this.#s;let[t,...a]=e.modelIDs,i=this.#t.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs);for(let t of a)i=i.unionAll(a=>a.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs));return(await i.execute()).map(e=>h(this.#e,e))}async queryDocuments(e){let{filter:t,modelIDs:a,orderBy:i,owner:s,...r}=e,n=null!=e.last;await this.#s;let o=this.#e.coerceFilterValue.bind(this.#e),[m,..._]=a,w=this.#t.selectFrom(`k_${m}`).selectAll();for(let e of(null!=s&&(w=w.where("owner","=",s)),null!=t&&(w=w.where(e=>l(e,t,[],o))),_))w=w.unionAll(a=>{let i=a.selectFrom(`k_${e}`).selectAll();return null!=s&&(i=i.where("owner","=",s)),null!=t&&(i=i.where(e=>l(e,t,[],o))),i});let[p,y]=c(w,i,n),[b,g]=u(p,r,i),f=await b.execute(),k=n?f.slice(0,g).reverse():f.slice(0,g);return{entries:y?k.map(e=>{let t={};for(let a of y){let i=e.data;for(let e of a)null!=i&&(i=i[e]);null!=i&&(t[a.join(".")]=i)}return{cursor:d({id:e.id,values:t}),document:h(this.#e,e)}}):k.map(e=>({cursor:d({id:e.id,ts:+e.created_at}),document:h(this.#e,e)})),hasMore:k.length>g}}async createDocument(e){await this.#s;let t=e.id.toString(),a=e.id.model.toString(),i=await this.#t.transaction().setIsolationLevel("read committed").execute(async i=>{let s=await i.insertInto(`k_${a}`).values({id:t,owner:e.owner,model:a,data:this.#e.encodeJSON(e.data),unique:this.#e.encodeBinary(e.unique)}).returningAll().executeTakeFirst();return await i.insertInto("kubun_document_states").values({id:t,data:e.state?this.#e.encodeBinary(e.state):null}).execute(),s}),s=h(this.#e,i);return this.#a.emit("document:saved",{type:"create",document:s,getCursor:()=>d({id:i.id,ts:+i.created_at})}),this.#i.debug("created document {id} with model {model}",{id:t,model:a}),s}async saveDocument(e){await this.#s;let t=e.id.toString(),a=await this.#t.transaction().setIsolationLevel("read committed").execute(async a=>{let i=await a.updateTable(`k_${e.id.model.toString()}`).set({data:e.data?this.#e.encodeJSON(e.data):null,updated_at:this.#e.encodeTimestamp(new Date)}).where("id","=",t).returningAll().executeTakeFirst();return await a.updateTable("kubun_document_states").set({data:e.state?this.#e.encodeBinary(e.state):null}).where("id","=",t).execute(),i}),i=h(this.#e,a);return this.#a.emit("document:saved",{type:"update",document:i,previous:e.existing,getCursor:()=>d({id:a.id,ts:+a.created_at})}),this.#i.debug("updated document {id}",{id:t}),i}async addAttachments(e){await this.#s,await this.#t.insertInto("kubun_document_attachments").values(e).onConflict(e=>e.doNothing()).execute()}async getUserModelAccessDefault(e,t,a){await this.#s;let i=await this.#t.selectFrom("kubun_user_model_access_defaults").select(["access_level","allowed_dids"]).where("owner_did","=",e).where("model_id","=",t).where("permission_type","=",a).executeTakeFirst();return i?{level:i.access_level,allowedDIDs:i.allowed_dids}:null}async setUserModelAccessDefault(e){await this.#s,await this.#t.insertInto("kubun_user_model_access_defaults").values({owner_did:e.ownerDID,model_id:e.modelID,permission_type:e.permissionType,access_level:e.accessLevel,allowed_dids:e.allowedDIDs?this.#e.encodeJSON(e.allowedDIDs):null}).onConflict(t=>t.columns(["owner_did","model_id","permission_type"]).doUpdateSet({access_level:e.accessLevel,allowed_dids:e.allowedDIDs?this.#e.encodeJSON(e.allowedDIDs):null,updated_at:this.#e.encodeTimestamp(new Date)})).execute()}async removeUserModelAccessDefaults(e,t,a){await this.#s,await this.#t.deleteFrom("kubun_user_model_access_defaults").where("owner_did","=",e).where("model_id","=",t).where("permission_type","in",a).execute()}async storeMutationLog(e){await this.#s;let t=globalThis.crypto.randomUUID();await this.#t.insertInto("kubun_document_mutation_log").values({id:t,document_id:e.documentID,sequence_number:e.sequenceNumber,mutation_jwt:e.mutationJWT,author_did:e.authorDID,timestamp:Date.now()}).execute(),await this.#t.deleteFrom("kubun_document_mutation_log").where("document_id","=",e.documentID).where("id","not in",this.#t.selectFrom("kubun_document_mutation_log").select("id").where("document_id","=",e.documentID).orderBy(n`CAST(sequence_number AS INTEGER)`,"desc").limit(10)).execute()}async getMutationLog(e,t){return await this.#s,await this.#t.selectFrom("kubun_document_mutation_log").selectAll().where("document_id","=",e).where(n`CAST(sequence_number AS INTEGER)`,">=",t).orderBy(n`CAST(sequence_number AS INTEGER)`,"asc").execute()}async listDocumentModelIDs(){return await this.#s,(await this.#t.selectFrom("kubun_document_models").select("id").execute()).map(e=>e.id)}async queryDocumentsByOwner(e,t){return await this.#s,(await this.#t.selectFrom(`k_${e}`).selectAll().where("owner","=",t).execute()).map(e=>h(this.#e,e))}async storeSyncCheckpoint(e,t){await this.#s;let a=`${e}:${t.userID}`,i=JSON.stringify(t.documentCheckpoints),s=JSON.stringify(t.vectorClock);try{return await this.#t.insertInto("kubun_sync_checkpoints").values({id:a,peer_server_id:e,user_id:t.userID,last_sync_timestamp:t.lastSyncTimestamp,document_checkpoints:i,vector_clock:s}).onConflict(e=>e.column("id").doUpdateSet({last_sync_timestamp:t.lastSyncTimestamp,document_checkpoints:i,vector_clock:s})).execute(),!0}catch{return!1}}async getSyncCheckpoint(e,t){await this.#s;let a=`${e}:${t}`,i=await this.#t.selectFrom("kubun_sync_checkpoints").selectAll().where("id","=",a).executeTakeFirst();return i?{lastSyncTimestamp:i.last_sync_timestamp,documentCheckpoints:i.document_checkpoints,vectorClock:i.vector_clock}:null}async listSyncCheckpoints(e){return await this.#s,(await this.#t.selectFrom("kubun_sync_checkpoints").selectAll().where("peer_server_id","=",e).execute()).map(e=>({userID:e.user_id,lastSyncTimestamp:e.last_sync_timestamp,documentCheckpoints:e.document_checkpoints,vectorClock:e.vector_clock}))}async createSearchIndex(e,t){await this.#s,await this.#e.createSearchIndex(this.#t,{modelID:e,fields:t})}async dropSearchIndex(e){await this.#s,await this.#e.dropSearchIndex(this.#t,e)}async updateSearchEntry(e,t,a,i){await this.#s;let s={};for(let e of i){let t=this.#d(a,e);null!=t&&(s[e]=String(t))}await this.#e.updateSearchEntry(this.#t,e,t,s,i)}async removeSearchEntry(e,t){await this.#s,await this.#e.removeSearchEntry(this.#t,e,t)}async searchDocuments(e){await this.#s;let t=[];for(let a of e.modelIDs)for(let i of(await this.#e.searchIndex(this.#t,{query:e.query,modelID:a,limit:e.first??50})))t.push({documentID:i.documentID,modelID:a,rank:i.rank});return(t.sort((e,t)=>Math.abs(t.rank)-Math.abs(e.rank)),e.first)?t.slice(0,e.first):t}#d(e,t){let a=t.split("."),i=e;for(let e of a){if(null==i||"object"!=typeof i)return null;i=i[e]}return i}}
@@ -1,11 +1,12 @@
1
1
  import type { AnyValueFilter, DocumentFilter, DocumentOrderBy } from '@kubun/protocol';
2
2
  import type { ExpressionBuilder, ExpressionWrapper, SelectQueryBuilder } from 'kysely';
3
3
  import type { ConnectionArguments, Database, Document } from './types.js';
4
+ export type CoerceFilterValue = (value: unknown) => unknown;
4
5
  type DocumentExpressionBuilder = ExpressionBuilder<Database, 'k_document'>;
5
6
  type DocumentExpressionWrapper = ExpressionWrapper<Database, 'k_document', any>;
6
7
  export type DocumentQueryBuilder = SelectQueryBuilder<Database, 'k_document', Document>;
7
8
  export declare function applyPagination(query: DocumentQueryBuilder, args: ConnectionArguments, orderBy?: DocumentOrderBy): [DocumentQueryBuilder, number];
8
- export declare function applyDocumentFilter(eb: DocumentExpressionBuilder, filter: DocumentFilter, path?: Array<string>): DocumentExpressionWrapper;
9
- export declare function applyValueFilter(eb: DocumentExpressionBuilder, keys: Array<string>, filter: AnyValueFilter): DocumentExpressionWrapper;
9
+ export declare function applyDocumentFilter(eb: DocumentExpressionBuilder, filter: DocumentFilter, path?: Array<string>, coerce?: CoerceFilterValue): DocumentExpressionWrapper;
10
+ export declare function applyValueFilter(eb: DocumentExpressionBuilder, keys: Array<string>, filter: AnyValueFilter, coerce?: CoerceFilterValue): DocumentExpressionWrapper;
10
11
  export declare function applyDocumentOrderBy(queryBuilder: DocumentQueryBuilder, orderBy?: DocumentOrderBy, isReverse?: boolean): [DocumentQueryBuilder, Array<Array<string>> | null];
11
12
  export {};
@@ -1 +1 @@
1
- import{parseCursor as e}from"./cursor.js";function t(e=50){return Math.min(e,100)}function r(e,t){let r=e.ref("data","->>");for(let e of t)r=r.key(e);return r}function n(e){let t=[],r=e;do{let[e,n]=Object.entries(r)[0];if(t.push(e),"string"==typeof n)return{keys:t,direction:n};r=n}while(null!=r)throw Error("Could not extract field entry")}function l(e,t=!1){return t?"asc"===e?"desc":"asc":e}export function applyPagination(l,a,o=[]){let{first:i,last:u,before:c,after:d}=a;if(null!=i){let a=t(i);return[function(t,l,a,o){let i=t;if(null!=a){let{id:t,ts:l,values:u}=e(a);null!=l?i=i.where(e=>e.or([e("created_at",">",l),e("created_at","=",l).and("id",">",t)])):null!=u&&(i=i.where(e=>{let l=[];for(let a of o){let o=n(a),i=u[o.keys.join(".")];if(null==i)continue;let c=r(e,o.keys);l.push(e.or([e(c,"asc"===o.direction?">":"<",i),e(c,"=",i).and("id",">",t)]))}return e.and(l)}))}return i.orderBy("created_at","asc").limit(l)}(l,a+1,d,o),a]}if(null!=u){let a=t(u);return[function(t,l,a,o){let i=t;if(null!=a){let{id:t,ts:l,values:u}=e(a);null!=l?i=i.where(e=>e.or([e("created_at","<",l),e("created_at","=",l).and("id","<",t)])):null!=u&&(i=i.where(e=>{let l=[];for(let a of o){let o=n(a),i=u[o.keys.join(".")];if(null==i)continue;let c=r(e,o.keys);l.push(e.or([e(c,"asc"===o.direction?"<":">",i),e(c,"=",i).and("id",">",t)]))}return e.and(l)}))}return i.orderBy("created_at","desc").limit(l)}(l,a+1,c,o),a]}let s=t();return[l.orderBy("created_at","asc").limit(s+1),s]}export function applyDocumentFilter(e,t,r=[]){let n=Object.entries(t);if(1!==n.length)throw Error("Invalid document filter");let[l,a]=n[0];switch(l){case"where":var o,i,u;let c;return o=e,i=a,u=r,c=Object.entries(i).map(([e,t])=>applyValueFilter(o,[...u,e],t)),o.and(c);case"and":return e.and(a.map(t=>applyDocumentFilter(e,t,r)));case"or":return e.or(a.map(t=>applyDocumentFilter(e,t,r)));case"not":return e.not(applyDocumentFilter(e,a,r));default:throw Error(`Invalid document filter type: ${l}`)}}export function applyValueFilter(e,t,n){let l=Object.entries(n);if(1!==l.length)throw Error("Invalid value filter");let a=r(e,t),[o,i]=l[0];switch(o){case"isNull":return e(a,!0===i?"is":"is not",null);case"equalTo":return e(a,"=",i);case"notEqualTo":return e(a,"!=",i);case"in":return e(a,"in",i);case"notIn":return e(a,"not in",i);case"lessThan":return e(a,"<",i);case"lessThanOrEqualTo":return e(a,"<=",i);case"greaterThan":return e(a,">",i);case"greaterThanOrEqualTo":return e(a,">=",i);default:throw Error(`Invalid value filter type: ${o}`)}}export function applyDocumentOrderBy(e,t=[],n=!1){if(0===t.length)return[e.orderBy("created_at",l("asc",n)),null];let o=e,i=[];for(let e of t){let[t,u]=function e(t,n,o,i=[]){let u=Object.entries(n);if(1!==u.length)throw Error("Invalid order by field");let[c,d]=u[0],s=[...i,c],f=a[c];return null!=f?[t.orderBy(f,l(d,o)),s]:"string"==typeof d?[t.orderBy(e=>r(e,s),l(d,o)),s]:e(t,d,o,s)}(o,e,n);o=t,i.push(u)}return[o,i]}let a={_createdAt:"created_at",_owner:"owner"};
1
+ import{parseCursor as e}from"./cursor.js";function t(e=50){return Math.min(e,100)}function r(e,t){let r=e.ref("data","->>");for(let e of t)r=r.key(e);return r}function n(e){let t=[],r=e;do{let[e,n]=Object.entries(r)[0];if(t.push(e),"string"==typeof n)return{keys:t,direction:n};r=n}while(null!=r)throw Error("Could not extract field entry")}function l(e,t=!1){return t?"asc"===e?"desc":"asc":e}export function applyPagination(l,a,o=[]){let{first:i,last:u,before:c,after:d}=a;if(null!=i){let a=t(i);return[function(t,l,a,o){let i=t;if(null!=a){let{id:t,ts:l,values:u}=e(a);null!=l?i=i.where(e=>e.or([e("created_at",">",l),e("created_at","=",l).and("id",">",t)])):null!=u&&(i=i.where(e=>{let l=[];for(let a of o){let o=n(a),i=u[o.keys.join(".")];if(null==i)continue;let c=r(e,o.keys);l.push(e.or([e(c,"asc"===o.direction?">":"<",i),e(c,"=",i).and("id",">",t)]))}return e.and(l)}))}return i.orderBy("created_at","asc").limit(l)}(l,a+1,d,o),a]}if(null!=u){let a=t(u);return[function(t,l,a,o){let i=t;if(null!=a){let{id:t,ts:l,values:u}=e(a);null!=l?i=i.where(e=>e.or([e("created_at","<",l),e("created_at","=",l).and("id","<",t)])):null!=u&&(i=i.where(e=>{let l=[];for(let a of o){let o=n(a),i=u[o.keys.join(".")];if(null==i)continue;let c=r(e,o.keys);l.push(e.or([e(c,"asc"===o.direction?"<":">",i),e(c,"=",i).and("id",">",t)]))}return e.and(l)}))}return i.orderBy("created_at","desc").limit(l)}(l,a+1,c,o),a]}let s=t();return[l.orderBy("created_at","asc").limit(s+1),s]}export function applyDocumentFilter(e,t,r=[],n){let l=Object.entries(t);if(1!==l.length)throw Error("Invalid document filter");let[a,o]=l[0];switch(a){case"where":var i,u,c,d;let s;return i=e,u=o,c=r,d=n,s=Object.entries(u).map(([e,t])=>applyValueFilter(i,[...c,e],t,d)),i.and(s);case"and":return e.and(o.map(t=>applyDocumentFilter(e,t,r,n)));case"or":return e.or(o.map(t=>applyDocumentFilter(e,t,r,n)));case"not":return e.not(applyDocumentFilter(e,o,r,n));default:throw Error(`Invalid document filter type: ${a}`)}}export function applyValueFilter(e,t,n,l){let a=Object.entries(n);if(1!==a.length)throw Error("Invalid value filter");let o=r(e,t),[i,u]=a[0],c=l??(e=>e);switch(i){case"isNull":return e(o,!0===u?"is":"is not",null);case"equalTo":return e(o,"=",c(u));case"notEqualTo":return e(o,"!=",c(u));case"in":return e(o,"in",u.map(c));case"notIn":return e(o,"not in",u.map(c));case"lessThan":return e(o,"<",c(u));case"lessThanOrEqualTo":return e(o,"<=",c(u));case"greaterThan":return e(o,">",c(u));case"greaterThanOrEqualTo":return e(o,">=",c(u));default:throw Error(`Invalid value filter type: ${i}`)}}export function applyDocumentOrderBy(e,t=[],n=!1){if(0===t.length)return[e.orderBy("created_at",l("asc",n)),null];let o=e,i=[];for(let e of t){let[t,u]=function e(t,n,o,i=[]){let u=Object.entries(n);if(1!==u.length)throw Error("Invalid order by field");let[c,d]=u[0],s=[...i,c],f=a[c];return null!=f?[t.orderBy(f,l(d,o)),s]:"string"==typeof d?[t.orderBy(e=>r(e,s),l(d,o)),s]:e(t,d,o,s)}(o,e,n);o=t,i.push(u)}return[o,i]}let a={_createdAt:"created_at",_owner:"owner"};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubun/db",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "license": "see LICENSE.md",
5
5
  "keywords": [],
6
6
  "type": "module",
@@ -22,11 +22,11 @@
22
22
  },
23
23
  "devDependencies": {
24
24
  "@databases/pg-test": "^3.1.2",
25
+ "@kubun/protocol": "^0.5.3",
26
+ "@kubun/db-adapter": "^0.5.1",
27
+ "@kubun/db-postgres": "^0.5.0",
25
28
  "@kubun/id": "^0.5.0",
26
- "@kubun/protocol": "^0.5.0",
27
- "@kubun/db-adapter": "^0.5.0",
28
- "@kubun/db-sqlite": "^0.5.0",
29
- "@kubun/db-postgres": "^0.5.0"
29
+ "@kubun/db-sqlite": "^0.5.0"
30
30
  },
31
31
  "scripts": {
32
32
  "build:clean": "del lib",