@kubun/store-graph 0.10.1 → 0.10.2
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/api.d.ts +8 -0
- package/lib/api.js +1 -1
- package/package.json +5 -5
package/lib/api.d.ts
CHANGED
|
@@ -36,6 +36,14 @@ export type GraphStoreAPI = {
|
|
|
36
36
|
updateMutationStatus(mutationHash: string, status: string): Promise<void>;
|
|
37
37
|
getMutationLogForDocuments(documentIDs: Array<string>): Promise<Array<MutationLogEntry>>;
|
|
38
38
|
getPendingMutations(documentID: string): Promise<Array<MutationLogEntry>>;
|
|
39
|
+
/**
|
|
40
|
+
* Return the lexicographically greatest `hlc` across the entire mutation log,
|
|
41
|
+
* or null when the log is empty. With the fixed-width counter pad, the string
|
|
42
|
+
* MAX equals the true HLC maximum — usable as a monotonic clock floor on
|
|
43
|
+
* restart so a fresh local write out-orders the node's own prior writes even
|
|
44
|
+
* after the wall clock stepped backward.
|
|
45
|
+
*/
|
|
46
|
+
getMaxMutationHLC(): Promise<string | null>;
|
|
39
47
|
getFieldHLCs(documentID: string): Promise<Record<string, string> | null>;
|
|
40
48
|
updateFieldHLCs(docID: DocumentID, fieldHLCs: Record<string, string>): Promise<void>;
|
|
41
49
|
listGraphs(): Promise<Array<GraphModel>>;
|
package/lib/api.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DocumentID as e,DocumentModelID as t}from"@kubun/id";import{serializeCursor as l}from"./cursor.js";function n(e,t){if(!(e instanceof Error))return!1;let l=e.message;return l.includes("no such table")&&l.includes(t)||l.includes("does not exist")&&l.includes(t)}import{aggregateFieldName as r,applyAggregateSelections as a,applyDocumentFilter as o,applyDocumentOrderBy as u,applyGroupBySelections as s,applyPagination as i,groupKeyAlias as c}from"./query-builder.js";function d(e){if(null==e)return null;let t="number"==typeof e?e:Number(e);return Number.isNaN(t)?null:t}function m(){return{count:0,sums:new Map,fieldCounts:new Map,mins:new Map,maxes:new Map}}function _(e,t,l){e.count+=Number(l.count??0);let n=new Set,a=new Set;for(let o of t){let t=r(o.keys);switch(o.op){case"sum":case"average":if(!n.has(t)){n.add(t);let r=d(l[`sum_${t}`]);null!=r&&e.sums.set(t,(e.sums.get(t)??0)+r)}if("average"===o.op&&!a.has(t)){a.add(t);let n=d(l[`count_${t}`]);null!=n&&e.fieldCounts.set(t,(e.fieldCounts.get(t)??0)+n)}break;case"min":{let n=o.numeric?d(l[`min_${t}`]):l[`min_${t}`]??null;null!=n&&(!e.mins.has(t)||function(e,t,l){if(l){let l=d(e),n=d(t);return null!=l&&(null==n||l<n)}return e<t}(n,e.mins.get(t),o.numeric))&&e.mins.set(t,n);break}case"max":{let n=o.numeric?d(l[`max_${t}`]):l[`max_${t}`]??null;null!=n&&(!e.maxes.has(t)||function(e,t,l){if(l){let l=d(e),n=d(t);return null!=l&&(null==n||l>n)}return e>t}(n,e.maxes.get(t),o.numeric))&&e.maxes.set(t,n)}}}}function h(e,t,l){let n={};for(let a of(e&&(n.count=l.count),t)){let e=r(a.keys);switch(a.op){case"sum":n.sum??={},n.sum[e]=l.sums.get(e)??null;break;case"average":{n.average??={};let t=l.sums.get(e),r=l.fieldCounts.get(e)??0;n.average[e]=null==t||0===r?null:t/r;break}case"min":n.min??={},n.min[e]=l.mins.get(e)??null;break;case"max":n.max??={},n.max[e]=l.maxes.get(e)??null}}return n}function w(e,t){return null==e?null:e<t?-1:+(e>t)}function f(e,t){if(null!=t.isNull&&t.isNull!==(null==e)||null!=t.equalTo&&e!==t.equalTo||null!=t.notEqualTo&&e===t.notEqualTo||null!=t.in&&!t.in.includes(e)||t.notIn?.includes(e))return!1;if(null!=t.greaterThan){let l=w(e,t.greaterThan);if(null==l||l<=0)return!1}if(null!=t.greaterThanOrEqualTo){let l=w(e,t.greaterThanOrEqualTo);if(null==l||l<0)return!1}if(null!=t.lessThan){let l=w(e,t.lessThan);if(null==l||l>=0)return!1}if(null!=t.lessThanOrEqualTo){let l=w(e,t.lessThanOrEqualTo);if(null==l||l>0)return!1}return!0}function g(e,t){let l=e;for(let e of t){if(null==l||"object"!=typeof l)return null;l=l[e]}return l??null}function p(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 y(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 k(e,l){let n=t.fromString(l);return n.isLocal?n.toGlobal(t.fromString(e)).toString():l}async function x(e,t,l){let{id:n,graphModelID:r,model:a}=l,o=t.types;for(let l of(await e.schema.createTable(`k_${n}`).ifNotExists().addColumn("id",o.text,e=>e.notNull().primaryKey()).addColumn("owner",o.text,e=>e.notNull()).addColumn("model",o.text,e=>e.notNull()).addColumn("data",o.json).addColumn("field_hlcs",o.json).addColumn("unique",o.binary,e=>e.notNull()).addColumn("created_at",o.timestamp,e=>e.defaultTo(t.functions.now).notNull()).addColumn("updated_at",o.timestamp).execute(),await e.insertInto("kubun_graph_document_models").values({id:n,version:a.version,name:a.name,behavior:a.behavior,unique_fields:"unique"===a.behavior?t.encodeJSON(a.uniqueFields):null,interfaces:t.encodeJSON(a.interfaces),schema:t.encodeJSON(a.schema),fields_meta:t.encodeJSON(a.fieldsMeta)}).onConflict(e=>e.doNothing()).execute(),a.interfaces))await e.insertInto("kubun_graph_document_model_interfaces").values({interface_id:k(n,l),implementation_id:n}).onConflict(e=>e.doNothing()).execute();await e.insertInto("kubun_graph_document_model_links").values({graph_model_id:r,document_model_id:n}).onConflict(e=>e.doNothing()).execute()}export function createGraphStore(t,w){let b=w.coerceFilterValue.bind(w);async function S(e,t){if(null==t)return{effectiveModelIDs:e,effectiveOwners:void 0};let{models:l,owners:n}=await v.resolveCatalogScope(t),r=e;if(null!=l){let e=new Set(l);r=r.filter(t=>e.has(t))}return{effectiveModelIDs:r,effectiveOwners:n}}let v={async getDocument(l){let n=e.from(l),r=await t.selectFrom(`k_${n.model.toString()}`).selectAll().where("id","=",n.toString()).executeTakeFirst();return r?y(w,r):null},getDocumentModel:async e=>p(await t.selectFrom("kubun_graph_document_models").selectAll().where("id","=",e.toString()).executeTakeFirstOrThrow()),getModelInterfaces:async e=>(await t.selectFrom("kubun_graph_document_model_interfaces").select("interface_id").where("implementation_id","=",e).execute()).map(e=>e.interface_id),async createDocument(e){let l=e.id.toString(),n=e.id.model.toString(),r=await t.insertInto(`k_${n}`).values({id:l,owner:e.owner,model:n,data:w.encodeJSON(e.data),unique:w.encodeBinary(e.unique)}).returningAll().executeTakeFirstOrThrow(()=>Error(`createDocument failed to return row for ${l}`));return y(w,r)},async saveDocument(e){let l=e.id.toString(),n=await t.updateTable(`k_${e.id.model.toString()}`).set({data:e.data?w.encodeJSON(e.data):null,updated_at:w.encodeTimestamp(new Date)}).where("id","=",l).returningAll().executeTakeFirstOrThrow(()=>Error(`saveDocument: document not found for id=${l}`));return y(w,n)},async queryDocuments(e){let{catalogID:n,filter:r,modelIDs:a,orderBy:s,owner:c,...d}=e,m=null!=e.last,{effectiveModelIDs:_,effectiveOwners:h}=await S(a,n);if(0===_.length)return{entries:[],hasMore:!1};let[f,...g]=_,p=t.selectFrom(`k_${f}`).selectAll().where("data","is not",null);for(let e of(null!=c&&(p=p.where("owner","=",c)),null!=h&&(p=p.where("owner","in",h)),null!=r&&(p=p.where(e=>o(e,r,[],b))),g))p=p.unionAll(t=>{let l=t.selectFrom(`k_${e}`).selectAll().where("data","is not",null);return null!=c&&(l=l.where("owner","=",c)),null!=h&&(l=l.where("owner","in",h)),null!=r&&(l=l.where(e=>o(e,r,[],b))),l});let[k,x]=u(p,s,m),[v,F]=i(k,d,s),D=await v.execute(),C=m?D.slice(0,F).reverse():D.slice(0,F);return{entries:x?C.map(e=>{let t={};for(let l of x){let n=e.data;for(let e of l)null!=n&&(n=n[e]);null!=n&&(t[l.join(".")]=n)}return{cursor:l({id:e.id,values:t}),document:y(w,e)}}):C.map(e=>({cursor:l({id:e.id,ts:+e.created_at}),document:y(w,e)})),hasMore:D.length>F}},async aggregateDocuments(e){let{aggregates:l,catalogID:u,count:s,filter:i,modelIDs:c,owner:d,readAccess:f}=e,g=function(e,t){let l={};for(let n of(e&&(l.count=0),t)){let e=r(n.keys);switch(n.op){case"sum":l.sum??={},l.sum[e]=null;break;case"average":l.average??={},l.average[e]=null;break;case"min":l.min??={},l.min[e]=null;break;case"max":l.max??={},l.max[e]=null}}return l}(s,l);if(!s&&0===l.length)return g;let{effectiveModelIDs:p,effectiveOwners:y}=await S(c,u);if(0===p.length)return g;let k=await Promise.all(p.map(async e=>{let r=t.selectFrom(`k_${e}`).select(e=>{let t=a(e,l,w);return s&&t.push(e.fn.countAll().as("count")),t});r=r.where("data","is not",null),null!=d&&(r=r.where("owner","=",d)),null!=y&&(r=r.where("owner","in",y)),null!=i&&(r=r.where(e=>o(e,i,[],b))),null!=f&&(r=r.where(w.readAccessPredicate(f,e)));try{return await r.executeTakeFirst()}catch(t){if(n(t,`k_${e}`))return;throw t}})),x=m(),v=!1;for(let e of k)null!=e&&(v=!0,_(x,l,e));return v?h(s,l,x):g},async groupedAggregateDocuments(e){let{aggregates:l,catalogID:u,count:i,filter:p,groupBy:y,having:k,limit:x,modelIDs:v,orderBy:F,owner:D,readAccess:C}=e,{effectiveModelIDs:T,effectiveOwners:N}=await S(v,u);if(0===T.length)return[];let I=await Promise.all(T.map(async e=>{let r=t.selectFrom(`k_${e}`).select(e=>{let{selections:t}=s(e,y),n=[...t,...a(e,l,w)];return i&&n.push(e.fn.countAll().as("count")),n});r=(r=r.groupBy(e=>s(e,y).expressions)).where("data","is not",null),null!=D&&(r=r.where("owner","=",D)),null!=N&&(r=r.where("owner","in",N)),null!=p&&(r=r.where(e=>o(e,p,[],b))),null!=C&&(r=r.where(w.readAccessPredicate(C,e)));try{return await r.execute()}catch(t){if(n(t,`k_${e}`))return[];throw t}})),A=new Map;for(let e of I)for(let t of e){let e={};for(let l of y){let n=t[c(l.keys)];e[r(l.keys)]=n??null}let n=JSON.stringify(y.map(t=>e[r(t.keys)])),a=A.get(n);null==a&&(a={keys:e,acc:m()},A.set(n,a)),_(a.acc,l,t)}let O=Array.from(A.values()).map(e=>({keys:e.keys,...h(i,l,e.acc)})),M=null==k?O:O.filter(e=>(function(e,t){if(null!=t.count&&!f(e.count??null,t.count))return!1;for(let l of["sum","average","min","max"]){let n=t[l];if(null==n)continue;let r=e[l];for(let[e,t]of Object.entries(n))if(!f(r?.[e]??null,t))return!1}return!0})(e,k)),$=null!=F&&F.length>0?[...M].sort((e,t)=>(function(e,t,l){for(let n of l){let l=function(e,t,l){let n,r=g(e,l.path),a=g(t,l.path),o=l.numeric?d(r):r,u=l.numeric?d(a):a,s=null==o,i=null==u;return s&&i?0:s?1:i?-1:(n=o<u?-1:+(o>u),"desc"===l.direction?-n:n)}(e,t,n);if(0!==l)return l}return 0})(e,t,F)):M;return null!=x?$.slice(0,Math.max(0,x)):$},async listDocuments(e){let[l,...n]=e.modelIDs,r=t.selectFrom(`k_${l}`).selectAll().where("id","in",e.docIDs).where("data","is not",null);for(let t of n)r=r.unionAll(l=>l.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs).where("data","is not",null));return(await r.execute()).map(e=>y(w,e))},listDocumentModelIDs:async()=>(await t.selectFrom("kubun_graph_document_models").select("id").execute()).map(e=>e.id),async getDistinctOwnersForModel(e){try{return(await t.selectFrom(`k_${e}`).select("owner").distinct().execute()).map(e=>e.owner)}catch(t){if(n(t,`k_${e}`))return[];throw t}},queryDocumentsByOwner:async(e,l)=>(await t.selectFrom(`k_${e}`).selectAll().where("owner","=",l).execute()).map(e=>y(w,e)),async insertMutationLogEntry(e){await t.insertInto("kubun_graph_mutation_log").values(e).onConflict(e=>e.doNothing()).execute()},hasMutationHash:async e=>null!=await t.selectFrom("kubun_graph_mutation_log").select("mutation_hash").where("mutation_hash","=",e).executeTakeFirst(),async updateMutationStatus(e,l){await t.updateTable("kubun_graph_mutation_log").set({status:l}).where("mutation_hash","=",e).execute()},getMutationLogForDocuments:async e=>0===e.length?[]:await t.selectFrom("kubun_graph_mutation_log").selectAll().where("document_id","in",e).orderBy("hlc","asc").execute(),getPendingMutations:async e=>await t.selectFrom("kubun_graph_mutation_log").selectAll().where("document_id","=",e).where("status","=","pending").orderBy("hlc","asc").execute(),async getFieldHLCs(l){let n=e.fromString(l).model.toString(),r=await t.selectFrom(`k_${n}`).select("field_hlcs").where("id","=",l).executeTakeFirst();if(r?.field_hlcs==null)return null;let a=r.field_hlcs;return"string"==typeof a?JSON.parse(a):a},async updateFieldHLCs(e,l){let n=e.model.toString();await t.updateTable(`k_${n}`).set({field_hlcs:w.encodeJSON(l)}).where("id","=",e.toString()).execute()},listGraphs:async()=>await t.selectFrom("kubun_graph_models").selectAll().execute(),async createGraph(e){let l=e.id,n=e.name??l;return await t.transaction().setIsolationLevel("read committed").execute(async t=>{await t.insertInto("kubun_graph_models").values({aliases:w.encodeJSON(e.aliases??{}),extension_sdl:e.extensionSDL??null,id:l,name:n,plugin_config:e.pluginConfig?w.encodeJSON(e.pluginConfig):null,search:e.search?w.encodeJSON(e.search):null}).onConflict(e=>e.doNothing()).execute();let r=Object.entries(e.record),a=new Set;for(;a.size<r.length;){let e=r.filter(([e,t])=>!a.has(e)&&t.interfaces.every(t=>a.has(k(e,t))));if(0===e.length)throw Error("Could not create graph: no valid model to add");await Promise.all(e.map(async([e,n])=>{await x(t,w,{id:e,graphModelID:l,model:n}),a.add(e)}))}}),l},async getGraph(e){let l=await t.selectFrom("kubun_graph_models").selectAll().where("id","=",e).executeTakeFirst();if(null==l)return null;let n={};for(let l of(await t.selectFrom("kubun_graph_document_model_links").innerJoin("kubun_graph_document_models","kubun_graph_document_model_links.document_model_id","kubun_graph_document_models.id").selectAll("kubun_graph_document_models").where("kubun_graph_document_model_links.graph_model_id","=",e).execute()))n[l.id]=p(l);return{...l,record:n}},async getClusterForModel(e){let l=await t.selectFrom("kubun_graph_cluster_models").select("cluster_id").where("model_id","=",e).executeTakeFirst();return l?.cluster_id},getClusterModels:async e=>await t.selectFrom("kubun_graph_cluster_models").selectAll().where("cluster_id","=",e).orderBy("cluster_index").execute(),async saveCluster(e,l){await t.insertInto("kubun_graph_clusters").values({id:e,definition:w.encodeJSON(l)}).onConflict(e=>e.column("id").doUpdateSet(e=>({definition:e.ref("excluded.definition")}))).execute()},getCluster:async e=>await t.selectFrom("kubun_graph_clusters").selectAll().where("id","=",e).executeTakeFirst(),async getClusters(e){if(0===e.length)return{};let l=await t.selectFrom("kubun_graph_clusters").selectAll().where("id","in",e).execute(),n={};for(let e of l)n[e.id]=e.definition;return n},async addAttachments(e){await t.insertInto("kubun_graph_document_attachments").values(e).onConflict(e=>e.doNothing()).execute()},async createSearchIndex(e,l){await w.createSearchIndex(t,{modelID:e,fields:l})},async dropSearchIndex(e){await w.dropSearchIndex(t,e)},async updateSearchEntry(e,l,n,r){let a={};for(let e of r){let t=function(e,t){let l=t.split("."),n=e;for(let e of l){if(null==n||"object"!=typeof n)return null;n=n[e]}return n}(n,e);null!=t&&(a[e]=String(t))}await w.updateSearchEntry(t,e,l,a,r)},async removeSearchEntry(e,l){await w.removeSearchEntry(t,e,l)},async searchDocuments(e){let l=[];for(let n of e.modelIDs)for(let r of(await w.searchIndex(t,{query:e.query,modelID:n,limit:e.first??50})))l.push({documentID:r.documentID,modelID:n,rank:r.rank});return(l.sort((e,t)=>Math.abs(t.rank)-Math.abs(e.rank)),e.first)?l.slice(0,e.first):l},async createCatalog(e){await t.insertInto("kubun_graph_catalogs").values({id:e.id,owner_did:e.owner_did,name:e.name,description:e.description,filter_criteria:w.encodeJSON(e.filter_criteria),hlc:e.hlc}).execute()},getCatalog:async e=>await t.selectFrom("kubun_graph_catalogs").selectAll().where("id","=",e).executeTakeFirst(),async getCatalogs(e){let l=new Map;if(0===e.length)return l;for(let n of(await t.selectFrom("kubun_graph_catalogs").selectAll().where("id","in",e).execute()))l.set(n.id,n);return l},async updateCatalog(e,l){let n={};null!=l.name&&(n.name=l.name),null!=l.description&&(n.description=l.description),null!=l.filter_criteria&&(n.filter_criteria=w.encodeJSON(l.filter_criteria)),null!=l.hlc&&(n.hlc=l.hlc),n.updated_at=w.encodeTimestamp(new Date),await t.updateTable("kubun_graph_catalogs").set(n).where("id","=",e).execute()},async deleteCatalog(e){await t.deleteFrom("kubun_graph_catalogs").where("id","=",e).execute()},listCatalogs:async e=>await t.selectFrom("kubun_graph_catalogs").selectAll().where("owner_did","=",e).execute(),async resolveCatalogScope(e){let t,l=await v.getCatalog(e);if(null==l)return{models:void 0,owners:void 0};let n=l.filter_criteria,r=null!=n.models&&n.models.length>0?n.models:void 0;return null!=n.owners&&n.owners.length>0&&(t=[...n.owners]),{models:r,owners:t}},async registerClusterModels(e,l){0!==l.length&&await t.insertInto("kubun_graph_cluster_models").values(l).onConflict(e=>e.column("model_id").doUpdateSet(e=>({cluster_id:e.ref("excluded.cluster_id"),cluster_index:e.ref("excluded.cluster_index")}))).execute()},async getUserModelAccessDefault(e,l,n){let r=await t.selectFrom("kubun_graph_user_model_access_defaults").select(["access_level","allowed_dids","allowed_circles","allowed_groups"]).where("owner_did","=",e).where("model_id","=",l).where("permission_type","=",n).executeTakeFirst();return r?{level:r.access_level,allowedDIDs:r.allowed_dids,allowedCircles:r.allowed_circles,allowedGroups:r.allowed_groups}:null},async setUserModelAccessDefault(e){await t.insertInto("kubun_graph_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?w.encodeJSON(e.allowedDIDs):null,allowed_circles:e.allowedCircles?w.encodeJSON(e.allowedCircles):null,allowed_groups:e.allowedGroups?w.encodeJSON(e.allowedGroups):null}).onConflict(t=>t.columns(["owner_did","model_id","permission_type"]).doUpdateSet({access_level:e.accessLevel,allowed_dids:e.allowedDIDs?w.encodeJSON(e.allowedDIDs):null,allowed_circles:e.allowedCircles?w.encodeJSON(e.allowedCircles):null,allowed_groups:e.allowedGroups?w.encodeJSON(e.allowedGroups):null,updated_at:w.encodeTimestamp(new Date)})).execute()},async removeUserModelAccessDefaults(e,l,n){await t.deleteFrom("kubun_graph_user_model_access_defaults").where("owner_did","=",e).where("model_id","=",l).where("permission_type","in",n).execute()},async getDocumentIDsForScope(e,l=[]){let r=[];for(let l of e)try{let e=await t.selectFrom(`k_${l.modelID}`).select("id").where("owner","=",l.ownerDID).execute();r.push(...e.map(e=>e.id))}catch(e){if(!n(e,`k_${l.modelID}`))throw e}if(l.length>0){let e=new Set(l);return r.filter(t=>!e.has(t))}return r},getDocumentMetadataForSync:async(e,l)=>0===l.length?[]:(await t.selectFrom(`k_${e}`).select(["id","model","owner"]).where("id","in",l).execute()).map(e=>({id:e.id,model:e.model,owner:e.owner}))};return v}
|
|
1
|
+
import{DocumentID as e,DocumentModelID as t}from"@kubun/id";import{serializeCursor as l}from"./cursor.js";function n(e,t){if(!(e instanceof Error))return!1;let l=e.message;return l.includes("no such table")&&l.includes(t)||l.includes("does not exist")&&l.includes(t)}import{aggregateFieldName as r,applyAggregateSelections as a,applyDocumentFilter as o,applyDocumentOrderBy as u,applyGroupBySelections as s,applyPagination as i,groupKeyAlias as c}from"./query-builder.js";function d(e){if(null==e)return null;let t="number"==typeof e?e:Number(e);return Number.isNaN(t)?null:t}function m(){return{count:0,sums:new Map,fieldCounts:new Map,mins:new Map,maxes:new Map}}function _(e,t,l){e.count+=Number(l.count??0);let n=new Set,a=new Set;for(let o of t){let t=r(o.keys);switch(o.op){case"sum":case"average":if(!n.has(t)){n.add(t);let r=d(l[`sum_${t}`]);null!=r&&e.sums.set(t,(e.sums.get(t)??0)+r)}if("average"===o.op&&!a.has(t)){a.add(t);let n=d(l[`count_${t}`]);null!=n&&e.fieldCounts.set(t,(e.fieldCounts.get(t)??0)+n)}break;case"min":{let n=o.numeric?d(l[`min_${t}`]):l[`min_${t}`]??null;null!=n&&(!e.mins.has(t)||function(e,t,l){if(l){let l=d(e),n=d(t);return null!=l&&(null==n||l<n)}return e<t}(n,e.mins.get(t),o.numeric))&&e.mins.set(t,n);break}case"max":{let n=o.numeric?d(l[`max_${t}`]):l[`max_${t}`]??null;null!=n&&(!e.maxes.has(t)||function(e,t,l){if(l){let l=d(e),n=d(t);return null!=l&&(null==n||l>n)}return e>t}(n,e.maxes.get(t),o.numeric))&&e.maxes.set(t,n)}}}}function h(e,t,l){let n={};for(let a of(e&&(n.count=l.count),t)){let e=r(a.keys);switch(a.op){case"sum":n.sum??={},n.sum[e]=l.sums.get(e)??null;break;case"average":{n.average??={};let t=l.sums.get(e),r=l.fieldCounts.get(e)??0;n.average[e]=null==t||0===r?null:t/r;break}case"min":n.min??={},n.min[e]=l.mins.get(e)??null;break;case"max":n.max??={},n.max[e]=l.maxes.get(e)??null}}return n}function f(e,t){return null==e?null:e<t?-1:+(e>t)}function w(e,t){if(null!=t.isNull&&t.isNull!==(null==e)||null!=t.equalTo&&e!==t.equalTo||null!=t.notEqualTo&&e===t.notEqualTo||null!=t.in&&!t.in.includes(e)||t.notIn?.includes(e))return!1;if(null!=t.greaterThan){let l=f(e,t.greaterThan);if(null==l||l<=0)return!1}if(null!=t.greaterThanOrEqualTo){let l=f(e,t.greaterThanOrEqualTo);if(null==l||l<0)return!1}if(null!=t.lessThan){let l=f(e,t.lessThan);if(null==l||l>=0)return!1}if(null!=t.lessThanOrEqualTo){let l=f(e,t.lessThanOrEqualTo);if(null==l||l>0)return!1}return!0}function g(e,t){let l=e;for(let e of t){if(null==l||"object"!=typeof l)return null;l=l[e]}return l??null}function p(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 y(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 k(e,l){let n=t.fromString(l);return n.isLocal?n.toGlobal(t.fromString(e)).toString():l}async function x(e,t,l){let{id:n,graphModelID:r,model:a}=l,o=t.types;for(let l of(await e.schema.createTable(`k_${n}`).ifNotExists().addColumn("id",o.text,e=>e.notNull().primaryKey()).addColumn("owner",o.text,e=>e.notNull()).addColumn("model",o.text,e=>e.notNull()).addColumn("data",o.json).addColumn("field_hlcs",o.json).addColumn("unique",o.binary,e=>e.notNull()).addColumn("created_at",o.timestamp,e=>e.defaultTo(t.functions.now).notNull()).addColumn("updated_at",o.timestamp).execute(),await e.insertInto("kubun_graph_document_models").values({id:n,version:a.version,name:a.name,behavior:a.behavior,unique_fields:"unique"===a.behavior?t.encodeJSON(a.uniqueFields):null,interfaces:t.encodeJSON(a.interfaces),schema:t.encodeJSON(a.schema),fields_meta:t.encodeJSON(a.fieldsMeta)}).onConflict(e=>e.doNothing()).execute(),a.interfaces))await e.insertInto("kubun_graph_document_model_interfaces").values({interface_id:k(n,l),implementation_id:n}).onConflict(e=>e.doNothing()).execute();await e.insertInto("kubun_graph_document_model_links").values({graph_model_id:r,document_model_id:n}).onConflict(e=>e.doNothing()).execute()}export function createGraphStore(t,f){let b=f.coerceFilterValue.bind(f);async function S(e,t){if(null==t)return{effectiveModelIDs:e,effectiveOwners:void 0};let{models:l,owners:n}=await v.resolveCatalogScope(t),r=e;if(null!=l){let e=new Set(l);r=r.filter(t=>e.has(t))}return{effectiveModelIDs:r,effectiveOwners:n}}let v={async getDocument(l){let n=e.from(l),r=await t.selectFrom(`k_${n.model.toString()}`).selectAll().where("id","=",n.toString()).executeTakeFirst();return r?y(f,r):null},getDocumentModel:async e=>p(await t.selectFrom("kubun_graph_document_models").selectAll().where("id","=",e.toString()).executeTakeFirstOrThrow()),getModelInterfaces:async e=>(await t.selectFrom("kubun_graph_document_model_interfaces").select("interface_id").where("implementation_id","=",e).execute()).map(e=>e.interface_id),async createDocument(e){let l=e.id.toString(),n=e.id.model.toString(),r=await t.insertInto(`k_${n}`).values({id:l,owner:e.owner,model:n,data:f.encodeJSON(e.data),unique:f.encodeBinary(e.unique)}).returningAll().executeTakeFirstOrThrow(()=>Error(`createDocument failed to return row for ${l}`));return y(f,r)},async saveDocument(e){let l=e.id.toString(),n=await t.updateTable(`k_${e.id.model.toString()}`).set({data:e.data?f.encodeJSON(e.data):null,updated_at:f.encodeTimestamp(new Date)}).where("id","=",l).returningAll().executeTakeFirstOrThrow(()=>Error(`saveDocument: document not found for id=${l}`));return y(f,n)},async queryDocuments(e){let{catalogID:n,filter:r,modelIDs:a,orderBy:s,owner:c,...d}=e,m=null!=e.last,{effectiveModelIDs:_,effectiveOwners:h}=await S(a,n);if(0===_.length)return{entries:[],hasMore:!1};let[w,...g]=_,p=t.selectFrom(`k_${w}`).selectAll().where("data","is not",null);for(let e of(null!=c&&(p=p.where("owner","=",c)),null!=h&&(p=p.where("owner","in",h)),null!=r&&(p=p.where(e=>o(e,r,[],b))),g))p=p.unionAll(t=>{let l=t.selectFrom(`k_${e}`).selectAll().where("data","is not",null);return null!=c&&(l=l.where("owner","=",c)),null!=h&&(l=l.where("owner","in",h)),null!=r&&(l=l.where(e=>o(e,r,[],b))),l});let[k,x]=u(p,s,m),[v,F]=i(k,d,s),D=await v.execute(),C=m?D.slice(0,F).reverse():D.slice(0,F);return{entries:x?C.map(e=>{let t={};for(let l of x){let n=e.data;for(let e of l)null!=n&&(n=n[e]);null!=n&&(t[l.join(".")]=n)}return{cursor:l({id:e.id,values:t}),document:y(f,e)}}):C.map(e=>({cursor:l({id:e.id,ts:+e.created_at}),document:y(f,e)})),hasMore:D.length>F}},async aggregateDocuments(e){let{aggregates:l,catalogID:u,count:s,filter:i,modelIDs:c,owner:d,readAccess:w}=e,g=function(e,t){let l={};for(let n of(e&&(l.count=0),t)){let e=r(n.keys);switch(n.op){case"sum":l.sum??={},l.sum[e]=null;break;case"average":l.average??={},l.average[e]=null;break;case"min":l.min??={},l.min[e]=null;break;case"max":l.max??={},l.max[e]=null}}return l}(s,l);if(!s&&0===l.length)return g;let{effectiveModelIDs:p,effectiveOwners:y}=await S(c,u);if(0===p.length)return g;let k=await Promise.all(p.map(async e=>{let r=t.selectFrom(`k_${e}`).select(e=>{let t=a(e,l,f);return s&&t.push(e.fn.countAll().as("count")),t});r=r.where("data","is not",null),null!=d&&(r=r.where("owner","=",d)),null!=y&&(r=r.where("owner","in",y)),null!=i&&(r=r.where(e=>o(e,i,[],b))),null!=w&&(r=r.where(f.readAccessPredicate(w,e)));try{return await r.executeTakeFirst()}catch(t){if(n(t,`k_${e}`))return;throw t}})),x=m(),v=!1;for(let e of k)null!=e&&(v=!0,_(x,l,e));return v?h(s,l,x):g},async groupedAggregateDocuments(e){let{aggregates:l,catalogID:u,count:i,filter:p,groupBy:y,having:k,limit:x,modelIDs:v,orderBy:F,owner:D,readAccess:C}=e,{effectiveModelIDs:T,effectiveOwners:N}=await S(v,u);if(0===T.length)return[];let I=await Promise.all(T.map(async e=>{let r=t.selectFrom(`k_${e}`).select(e=>{let{selections:t}=s(e,y),n=[...t,...a(e,l,f)];return i&&n.push(e.fn.countAll().as("count")),n});r=(r=r.groupBy(e=>s(e,y).expressions)).where("data","is not",null),null!=D&&(r=r.where("owner","=",D)),null!=N&&(r=r.where("owner","in",N)),null!=p&&(r=r.where(e=>o(e,p,[],b))),null!=C&&(r=r.where(f.readAccessPredicate(C,e)));try{return await r.execute()}catch(t){if(n(t,`k_${e}`))return[];throw t}})),A=new Map;for(let e of I)for(let t of e){let e={};for(let l of y){let n=t[c(l.keys)];e[r(l.keys)]=n??null}let n=JSON.stringify(y.map(t=>e[r(t.keys)])),a=A.get(n);null==a&&(a={keys:e,acc:m()},A.set(n,a)),_(a.acc,l,t)}let O=Array.from(A.values()).map(e=>({keys:e.keys,...h(i,l,e.acc)})),M=null==k?O:O.filter(e=>(function(e,t){if(null!=t.count&&!w(e.count??null,t.count))return!1;for(let l of["sum","average","min","max"]){let n=t[l];if(null==n)continue;let r=e[l];for(let[e,t]of Object.entries(n))if(!w(r?.[e]??null,t))return!1}return!0})(e,k)),$=null!=F&&F.length>0?[...M].sort((e,t)=>(function(e,t,l){for(let n of l){let l=function(e,t,l){let n,r=g(e,l.path),a=g(t,l.path),o=l.numeric?d(r):r,u=l.numeric?d(a):a,s=null==o,i=null==u;return s&&i?0:s?1:i?-1:(n=o<u?-1:+(o>u),"desc"===l.direction?-n:n)}(e,t,n);if(0!==l)return l}return 0})(e,t,F)):M;return null!=x?$.slice(0,Math.max(0,x)):$},async listDocuments(e){let[l,...n]=e.modelIDs,r=t.selectFrom(`k_${l}`).selectAll().where("id","in",e.docIDs).where("data","is not",null);for(let t of n)r=r.unionAll(l=>l.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs).where("data","is not",null));return(await r.execute()).map(e=>y(f,e))},listDocumentModelIDs:async()=>(await t.selectFrom("kubun_graph_document_models").select("id").execute()).map(e=>e.id),async getDistinctOwnersForModel(e){try{return(await t.selectFrom(`k_${e}`).select("owner").distinct().execute()).map(e=>e.owner)}catch(t){if(n(t,`k_${e}`))return[];throw t}},queryDocumentsByOwner:async(e,l)=>(await t.selectFrom(`k_${e}`).selectAll().where("owner","=",l).execute()).map(e=>y(f,e)),async insertMutationLogEntry(e){await t.insertInto("kubun_graph_mutation_log").values(e).onConflict(e=>e.doNothing()).execute()},hasMutationHash:async e=>null!=await t.selectFrom("kubun_graph_mutation_log").select("mutation_hash").where("mutation_hash","=",e).executeTakeFirst(),async updateMutationStatus(e,l){await t.updateTable("kubun_graph_mutation_log").set({status:l}).where("mutation_hash","=",e).execute()},getMutationLogForDocuments:async e=>0===e.length?[]:await t.selectFrom("kubun_graph_mutation_log").selectAll().where("document_id","in",e).orderBy("hlc","asc").execute(),async getMaxMutationHLC(){let e=await t.selectFrom("kubun_graph_mutation_log").select(e=>e.fn.max("hlc").as("max_hlc")).executeTakeFirst();return e?.max_hlc??null},getPendingMutations:async e=>await t.selectFrom("kubun_graph_mutation_log").selectAll().where("document_id","=",e).where("status","=","pending").orderBy("hlc","asc").execute(),async getFieldHLCs(l){let n=e.fromString(l).model.toString(),r=await t.selectFrom(`k_${n}`).select("field_hlcs").where("id","=",l).executeTakeFirst();if(r?.field_hlcs==null)return null;let a=r.field_hlcs;return"string"==typeof a?JSON.parse(a):a},async updateFieldHLCs(e,l){let n=e.model.toString();await t.updateTable(`k_${n}`).set({field_hlcs:f.encodeJSON(l)}).where("id","=",e.toString()).execute()},listGraphs:async()=>await t.selectFrom("kubun_graph_models").selectAll().execute(),async createGraph(e){let l=e.id,n=e.name??l;return await t.transaction().setIsolationLevel("read committed").execute(async t=>{let r=e.pluginConfig?f.encodeJSON(e.pluginConfig):null;await t.insertInto("kubun_graph_models").values({aliases:f.encodeJSON(e.aliases??{}),extension_sdl:e.extensionSDL??null,id:l,name:n,plugin_config:r,search:e.search?f.encodeJSON(e.search):null}).onConflict(t=>null!=e.pluginConfig?t.column("id").doUpdateSet({extension_sdl:e.extensionSDL??null,plugin_config:r}):t.doNothing()).execute();let a=Object.entries(e.record),o=new Set;for(;o.size<a.length;){let e=a.filter(([e,t])=>!o.has(e)&&t.interfaces.every(t=>o.has(k(e,t))));if(0===e.length)throw Error("Could not create graph: no valid model to add");await Promise.all(e.map(async([e,n])=>{await x(t,f,{id:e,graphModelID:l,model:n}),o.add(e)}))}}),l},async getGraph(e){let l=await t.selectFrom("kubun_graph_models").selectAll().where("id","=",e).executeTakeFirst();if(null==l)return null;let n={};for(let l of(await t.selectFrom("kubun_graph_document_model_links").innerJoin("kubun_graph_document_models","kubun_graph_document_model_links.document_model_id","kubun_graph_document_models.id").selectAll("kubun_graph_document_models").where("kubun_graph_document_model_links.graph_model_id","=",e).execute()))n[l.id]=p(l);return{...l,record:n}},async getClusterForModel(e){let l=await t.selectFrom("kubun_graph_cluster_models").select("cluster_id").where("model_id","=",e).executeTakeFirst();return l?.cluster_id},getClusterModels:async e=>await t.selectFrom("kubun_graph_cluster_models").selectAll().where("cluster_id","=",e).orderBy("cluster_index").execute(),async saveCluster(e,l){await t.insertInto("kubun_graph_clusters").values({id:e,definition:f.encodeJSON(l)}).onConflict(e=>e.column("id").doUpdateSet(e=>({definition:e.ref("excluded.definition")}))).execute()},getCluster:async e=>await t.selectFrom("kubun_graph_clusters").selectAll().where("id","=",e).executeTakeFirst(),async getClusters(e){if(0===e.length)return{};let l=await t.selectFrom("kubun_graph_clusters").selectAll().where("id","in",e).execute(),n={};for(let e of l)n[e.id]=e.definition;return n},async addAttachments(e){await t.insertInto("kubun_graph_document_attachments").values(e).onConflict(e=>e.doNothing()).execute()},async createSearchIndex(e,l){await f.createSearchIndex(t,{modelID:e,fields:l})},async dropSearchIndex(e){await f.dropSearchIndex(t,e)},async updateSearchEntry(e,l,n,r){let a={};for(let e of r){let t=function(e,t){let l=t.split("."),n=e;for(let e of l){if(null==n||"object"!=typeof n)return null;n=n[e]}return n}(n,e);null!=t&&(a[e]=String(t))}await f.updateSearchEntry(t,e,l,a,r)},async removeSearchEntry(e,l){await f.removeSearchEntry(t,e,l)},async searchDocuments(e){let l=[];for(let n of e.modelIDs)for(let r of(await f.searchIndex(t,{query:e.query,modelID:n,limit:e.first??50})))l.push({documentID:r.documentID,modelID:n,rank:r.rank});return(l.sort((e,t)=>Math.abs(t.rank)-Math.abs(e.rank)),e.first)?l.slice(0,e.first):l},async createCatalog(e){await t.insertInto("kubun_graph_catalogs").values({id:e.id,owner_did:e.owner_did,name:e.name,description:e.description,filter_criteria:f.encodeJSON(e.filter_criteria),hlc:e.hlc}).execute()},getCatalog:async e=>await t.selectFrom("kubun_graph_catalogs").selectAll().where("id","=",e).executeTakeFirst(),async getCatalogs(e){let l=new Map;if(0===e.length)return l;for(let n of(await t.selectFrom("kubun_graph_catalogs").selectAll().where("id","in",e).execute()))l.set(n.id,n);return l},async updateCatalog(e,l){let n={};null!=l.name&&(n.name=l.name),null!=l.description&&(n.description=l.description),null!=l.filter_criteria&&(n.filter_criteria=f.encodeJSON(l.filter_criteria)),null!=l.hlc&&(n.hlc=l.hlc),n.updated_at=f.encodeTimestamp(new Date),await t.updateTable("kubun_graph_catalogs").set(n).where("id","=",e).execute()},async deleteCatalog(e){await t.deleteFrom("kubun_graph_catalogs").where("id","=",e).execute()},listCatalogs:async e=>await t.selectFrom("kubun_graph_catalogs").selectAll().where("owner_did","=",e).execute(),async resolveCatalogScope(e){let t,l=await v.getCatalog(e);if(null==l)return{models:void 0,owners:void 0};let n=l.filter_criteria,r=null!=n.models&&n.models.length>0?n.models:void 0;return null!=n.owners&&n.owners.length>0&&(t=[...n.owners]),{models:r,owners:t}},async registerClusterModels(e,l){0!==l.length&&await t.insertInto("kubun_graph_cluster_models").values(l).onConflict(e=>e.column("model_id").doUpdateSet(e=>({cluster_id:e.ref("excluded.cluster_id"),cluster_index:e.ref("excluded.cluster_index")}))).execute()},async getUserModelAccessDefault(e,l,n){let r=await t.selectFrom("kubun_graph_user_model_access_defaults").select(["access_level","allowed_dids","allowed_circles","allowed_groups"]).where("owner_did","=",e).where("model_id","=",l).where("permission_type","=",n).executeTakeFirst();return r?{level:r.access_level,allowedDIDs:r.allowed_dids,allowedCircles:r.allowed_circles,allowedGroups:r.allowed_groups}:null},async setUserModelAccessDefault(e){await t.insertInto("kubun_graph_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?f.encodeJSON(e.allowedDIDs):null,allowed_circles:e.allowedCircles?f.encodeJSON(e.allowedCircles):null,allowed_groups:e.allowedGroups?f.encodeJSON(e.allowedGroups):null}).onConflict(t=>t.columns(["owner_did","model_id","permission_type"]).doUpdateSet({access_level:e.accessLevel,allowed_dids:e.allowedDIDs?f.encodeJSON(e.allowedDIDs):null,allowed_circles:e.allowedCircles?f.encodeJSON(e.allowedCircles):null,allowed_groups:e.allowedGroups?f.encodeJSON(e.allowedGroups):null,updated_at:f.encodeTimestamp(new Date)})).execute()},async removeUserModelAccessDefaults(e,l,n){await t.deleteFrom("kubun_graph_user_model_access_defaults").where("owner_did","=",e).where("model_id","=",l).where("permission_type","in",n).execute()},async getDocumentIDsForScope(e,l=[]){let r=[];for(let l of e)try{let e=await t.selectFrom(`k_${l.modelID}`).select("id").where("owner","=",l.ownerDID).execute();r.push(...e.map(e=>e.id))}catch(e){if(!n(e,`k_${l.modelID}`))throw e}if(l.length>0){let e=new Set(l);return r.filter(t=>!e.has(t))}return r},getDocumentMetadataForSync:async(e,l)=>0===l.length?[]:(await t.selectFrom(`k_${e}`).select(["id","model","owner"]).where("id","in",l).execute()).map(e=>({id:e.id,model:e.model,owner:e.owner}))};return v}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubun/store-graph",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"license": "see LICENSE.md",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"type": "module",
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@enkaku/codec": "^0.16.0",
|
|
19
19
|
"kysely": "^0.29.2",
|
|
20
|
-
"@kubun/db-adapter": "^0.10.0",
|
|
21
|
-
"@kubun/id": "^0.10.0",
|
|
22
20
|
"@kubun/db": "^0.10.0",
|
|
21
|
+
"@kubun/id": "^0.10.0",
|
|
22
|
+
"@kubun/db-adapter": "^0.10.0",
|
|
23
23
|
"@kubun/protocol": "^0.10.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@testcontainers/postgresql": "^12.0.1",
|
|
27
|
-
"@kubun/db-
|
|
28
|
-
"@kubun/db-
|
|
27
|
+
"@kubun/db-better-sqlite": "^0.10.0",
|
|
28
|
+
"@kubun/db-postgres": "^0.10.0"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"build:clean": "del lib",
|