@kubun/store-graph 0.9.0 → 0.10.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/api.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { Adapter } from '@kubun/db-adapter';
2
2
  import { DocumentID, DocumentModelID } from '@kubun/id';
3
- import type { DocumentModel, DocumentNode } from '@kubun/protocol';
3
+ import type { AggregateDocumentsParams, AggregateValues, DocumentModel, DocumentNode, GroupedAggregateDocumentsParams, GroupedAggregateValue } from '@kubun/protocol';
4
4
  import type { Kysely } from 'kysely';
5
- import type { AccessLevel, Catalog, ClusterDefinitionRow, ClusterModel, CountDocumentsParams, CreateDocumentParams, CreateGraphParams, GraphModel, GraphModelWithRecord, GraphTables, InsertCatalog, InsertClusterModel, InsertDocumentAttachment, InsertMutationLogEntry, ListDocumentsParams, MutationLogEntry, QueryDocumentsParams, QueryDocumentsResult, SaveDocumentParams, SearchDocumentResult, SearchDocumentsParams } from './tables.js';
5
+ import type { AccessLevel, Catalog, ClusterDefinitionRow, ClusterModel, CreateDocumentParams, CreateGraphParams, GraphModel, GraphModelWithRecord, GraphTables, InsertCatalog, InsertClusterModel, InsertDocumentAttachment, InsertMutationLogEntry, ListDocumentsParams, MutationLogEntry, QueryDocumentsParams, QueryDocumentsResult, SaveDocumentParams, SearchDocumentResult, SearchDocumentsParams } from './tables.js';
6
6
  /**
7
7
  * Persisted access rule shape as stored in `user_model_access_defaults`.
8
8
  */
@@ -15,10 +15,18 @@ export type StoredAccessRule = {
15
15
  export type GraphStoreAPI = {
16
16
  getDocument(id: DocumentID | string): Promise<DocumentNode | null>;
17
17
  getDocumentModel(id: DocumentModelID | string): Promise<DocumentModel>;
18
+ /**
19
+ * Return the interface model IDs declared by `modelID` from the
20
+ * `kubun_graph_document_model_interfaces` join table. Empty array when the
21
+ * model declares no interfaces or is unknown. Result order matches insertion
22
+ * order from `addDocumentModel` (stable for a given graph creation).
23
+ */
24
+ getModelInterfaces(modelID: string): Promise<Array<string>>;
18
25
  createDocument(params: CreateDocumentParams): Promise<DocumentNode>;
19
26
  saveDocument(params: SaveDocumentParams): Promise<DocumentNode>;
20
27
  queryDocuments(params: QueryDocumentsParams): Promise<QueryDocumentsResult>;
21
- countDocuments(params: CountDocumentsParams): Promise<number>;
28
+ aggregateDocuments(params: AggregateDocumentsParams): Promise<AggregateValues>;
29
+ groupedAggregateDocuments(params: GroupedAggregateDocumentsParams): Promise<Array<GroupedAggregateValue>>;
22
30
  listDocuments(params: ListDocumentsParams): Promise<Array<DocumentNode>>;
23
31
  listDocumentModelIDs(): Promise<Array<string>>;
24
32
  getDistinctOwnersForModel(modelID: string): Promise<Array<string>>;
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{applyDocumentFilter as a,applyDocumentOrderBy as r,applyPagination as o}from"./query-builder.js";function s(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 i(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 c(e,l){let n=t.fromString(l);return n.isLocal?n.toGlobal(t.fromString(e)).toString():l}async function u(e,t,l){let{id:n,graphModelID:a,model:r}=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:r.version,name:r.name,behavior:r.behavior,unique_fields:"unique"===r.behavior?t.encodeJSON(r.uniqueFields):null,interfaces:t.encodeJSON(r.interfaces),schema:t.encodeJSON(r.schema),fields_meta:t.encodeJSON(r.fieldsMeta)}).onConflict(e=>e.doNothing()).execute(),r.interfaces))await e.insertInto("kubun_graph_document_model_interfaces").values({interface_id:c(n,l),implementation_id:n}).onConflict(e=>e.doNothing()).execute();await e.insertInto("kubun_graph_document_model_links").values({graph_model_id:a,document_model_id:n}).onConflict(e=>e.doNothing()).execute()}export function createGraphStore(t,d){let m=d.coerceFilterValue.bind(d);async function _(e,t){if(null==t)return{effectiveModelIDs:e,effectiveOwners:void 0};let{models:l,owners:n}=await w.resolveCatalogScope(t),a=e;if(null!=l){let e=new Set(l);a=a.filter(t=>e.has(t))}return{effectiveModelIDs:a,effectiveOwners:n}}let w={async getDocument(l){let n=e.from(l),a=await t.selectFrom(`k_${n.model.toString()}`).selectAll().where("id","=",n.toString()).executeTakeFirst();return a?i(d,a):null},getDocumentModel:async e=>s(await t.selectFrom("kubun_graph_document_models").selectAll().where("id","=",e.toString()).executeTakeFirstOrThrow()),async createDocument(e){let l=e.id.toString(),n=e.id.model.toString(),a=await t.insertInto(`k_${n}`).values({id:l,owner:e.owner,model:n,data:d.encodeJSON(e.data),unique:d.encodeBinary(e.unique)}).returningAll().executeTakeFirstOrThrow(()=>Error(`createDocument failed to return row for ${l}`));return i(d,a)},async saveDocument(e){let l=e.id.toString(),n=await t.updateTable(`k_${e.id.model.toString()}`).set({data:e.data?d.encodeJSON(e.data):null,updated_at:d.encodeTimestamp(new Date)}).where("id","=",l).returningAll().executeTakeFirstOrThrow(()=>Error(`saveDocument: document not found for id=${l}`));return i(d,n)},async queryDocuments(e){let{catalogID:n,filter:s,modelIDs:c,orderBy:u,owner:w,...h}=e,f=null!=e.last,{effectiveModelIDs:g,effectiveOwners:p}=await _(c,n);if(0===g.length)return{entries:[],hasMore:!1};let[y,...k]=g,x=t.selectFrom(`k_${y}`).selectAll();for(let e of(null!=w&&(x=x.where("owner","=",w)),null!=p&&(x=x.where("owner","in",p)),null!=s&&(x=x.where(e=>a(e,s,[],m))),k))x=x.unionAll(t=>{let l=t.selectFrom(`k_${e}`).selectAll();return null!=w&&(l=l.where("owner","=",w)),null!=p&&(l=l.where("owner","in",p)),null!=s&&(l=l.where(e=>a(e,s,[],m))),l});let[b,S]=r(x,u,f),[F,D]=o(b,h,u),v=await F.execute(),C=f?v.slice(0,D).reverse():v.slice(0,D);return{entries:S?C.map(e=>{let t={};for(let l of S){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:i(d,e)}}):C.map(e=>({cursor:l({id:e.id,ts:+e.created_at}),document:i(d,e)})),hasMore:v.length>D}},async countDocuments(e){let{catalogID:l,filter:n,modelIDs:r,owner:o}=e,{effectiveModelIDs:s,effectiveOwners:i}=await _(r,l);return 0===s.length?0:(await Promise.all(s.map(async e=>{let l=t.selectFrom(`k_${e}`).select(e=>e.fn.countAll().as("count"));return null!=o&&(l=l.where("owner","=",o)),null!=i&&(l=l.where("owner","in",i)),null!=n&&(l=l.where(e=>a(e,n,[],m))),Number((await l.executeTakeFirstOrThrow()).count)}))).reduce((e,t)=>e+t,0)},async listDocuments(e){let[l,...n]=e.modelIDs,a=t.selectFrom(`k_${l}`).selectAll().where("id","in",e.docIDs);for(let t of n)a=a.unionAll(l=>l.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs));return(await a.execute()).map(e=>i(d,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=>i(d,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(),a=await t.selectFrom(`k_${n}`).select("field_hlcs").where("id","=",l).executeTakeFirst();if(a?.field_hlcs==null)return null;let r=a.field_hlcs;return"string"==typeof r?JSON.parse(r):r},async updateFieldHLCs(e,l){let n=e.model.toString();await t.updateTable(`k_${n}`).set({field_hlcs:d.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:d.encodeJSON(e.aliases??{}),extension_sdl:e.extensionSDL??null,id:l,name:n,plugin_config:e.pluginConfig?d.encodeJSON(e.pluginConfig):null,search:e.search?d.encodeJSON(e.search):null}).onConflict(e=>e.doNothing()).execute();let a=Object.entries(e.record),r=new Set;for(;r.size<a.length;){let e=a.filter(([e,t])=>!r.has(e)&&t.interfaces.every(t=>r.has(c(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 u(t,d,{id:e,graphModelID:l,model:n}),r.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]=s(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:d.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 d.createSearchIndex(t,{modelID:e,fields:l})},async dropSearchIndex(e){await d.dropSearchIndex(t,e)},async updateSearchEntry(e,l,n,a){let r={};for(let e of a){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&&(r[e]=String(t))}await d.updateSearchEntry(t,e,l,r,a)},async removeSearchEntry(e,l){await d.removeSearchEntry(t,e,l)},async searchDocuments(e){let l=[];for(let n of e.modelIDs)for(let a of(await d.searchIndex(t,{query:e.query,modelID:n,limit:e.first??50})))l.push({documentID:a.documentID,modelID:n,rank:a.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:d.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=d.encodeJSON(l.filter_criteria)),null!=l.hlc&&(n.hlc=l.hlc),n.updated_at=d.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 w.getCatalog(e);if(null==l)return{models:void 0,owners:void 0};let n=l.filter_criteria,a=null!=n.models&&n.models.length>0?n.models:void 0;return null!=n.owners&&n.owners.length>0&&(t=[...n.owners]),{models:a,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 a=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 a?{level:a.access_level,allowedDIDs:a.allowed_dids,allowedCircles:a.allowed_circles,allowedGroups:a.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?d.encodeJSON(e.allowedDIDs):null,allowed_circles:e.allowedCircles?d.encodeJSON(e.allowedCircles):null,allowed_groups:e.allowedGroups?d.encodeJSON(e.allowedGroups):null}).onConflict(t=>t.columns(["owner_did","model_id","permission_type"]).doUpdateSet({access_level:e.accessLevel,allowed_dids:e.allowedDIDs?d.encodeJSON(e.allowedDIDs):null,allowed_circles:e.allowedCircles?d.encodeJSON(e.allowedCircles):null,allowed_groups:e.allowedGroups?d.encodeJSON(e.allowedGroups):null,updated_at:d.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 a=[];for(let l of e)try{let e=await t.selectFrom(`k_${l.modelID}`).select("id").where("owner","=",l.ownerDID).execute();a.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 a.filter(t=>!e.has(t))}return a},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 w}
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}
package/lib/index.d.ts CHANGED
@@ -5,4 +5,4 @@ export { createGraphStore } from './api.js';
5
5
  export { graphStoreDefinition } from './definition.js';
6
6
  export declare const GRAPH_STORE: "graph";
7
7
  export declare function getGraphStore(provider: StoreProvider): Promise<GraphStoreAPI>;
8
- export type { AccessLevel, AccessPermissions, AddDocumentModelParams, Catalog, ClusterDefinitionRow, ClusterModel, ConnectionArguments, CountDocumentsParams, CreateDocumentParams, CreateGraphParams, CursorDocument, Document, DocumentAttachment, DocumentData, DocumentModelRow, DocumentParams, GraphModel, GraphModelWithRecord, GraphTables, InsertCatalog, InsertClusterModel, InsertDocument, InsertDocumentAttachment, InsertDocumentModel, InsertDocumentModelInterface, InsertMutationLogEntry, ListDocumentsParams, MutationLogEntry, PaginatedResult, PaginationParams, QueryDocumentsParams, QueryDocumentsResult, SaveDocumentParams, SearchConfig, SearchDocumentResult, SearchDocumentsParams, UpdateDocument, UpdateDocumentModel, } from './tables.js';
8
+ export type { AccessLevel, AccessPermissions, AddDocumentModelParams, Catalog, ClusterDefinitionRow, ClusterModel, ConnectionArguments, CreateDocumentParams, CreateGraphParams, CursorDocument, Document, DocumentAttachment, DocumentData, DocumentModelRow, DocumentParams, GraphModel, GraphModelWithRecord, GraphTables, InsertCatalog, InsertClusterModel, InsertDocument, InsertDocumentAttachment, InsertDocumentModel, InsertDocumentModelInterface, InsertMutationLogEntry, ListDocumentsParams, MutationLogEntry, PaginatedResult, PaginationParams, QueryDocumentsParams, QueryDocumentsResult, SaveDocumentParams, SearchConfig, SearchDocumentResult, SearchDocumentsParams, UpdateDocument, UpdateDocumentModel, ViewerReadAccess, } from './tables.js';
@@ -1,3 +1,3 @@
1
1
  import type { MigrationContext } from '@kubun/db';
2
- import type { Migration } from 'kysely';
2
+ import type { Migration } from 'kysely/migration';
3
3
  export declare function getGraphMigrations(ctx: MigrationContext): Record<string, Migration>;
@@ -1,10 +1,21 @@
1
- import type { AnyValueFilter, DocumentFilter, DocumentOrderBy } from '@kubun/protocol';
2
- import type { ExpressionBuilder, ExpressionWrapper, SelectQueryBuilder } from 'kysely';
1
+ import type { Adapter } from '@kubun/db-adapter';
2
+ import type { AggregateSpec, AnyValueFilter, DocumentFilter, DocumentOrderBy } from '@kubun/protocol';
3
+ import type { AliasedExpression, ExpressionBuilder, ExpressionWrapper, SelectQueryBuilder } from 'kysely';
3
4
  import type { ConnectionArguments, Document, GraphTables } from './tables.js';
4
5
  export type CoerceFilterValue = (value: unknown) => unknown;
5
6
  type DocumentExpressionBuilder = ExpressionBuilder<GraphTables, 'k_document'>;
6
7
  type DocumentExpressionWrapper = ExpressionWrapper<GraphTables, 'k_document', any>;
7
8
  export type DocumentQueryBuilder = SelectQueryBuilder<GraphTables, 'k_document', Document>;
9
+ export declare function aggregateFieldName(keys: Array<string>): string;
10
+ export type AggregateSelection = AliasedExpression<unknown, string>;
11
+ export declare function applyAggregateSelections(eb: DocumentExpressionBuilder, specs: Array<AggregateSpec>, adapter: Adapter): Array<AggregateSelection>;
12
+ export declare function groupKeyAlias(keys: Array<string>): string;
13
+ export declare function applyGroupBySelections(eb: DocumentExpressionBuilder, groupBy: Array<{
14
+ keys: Array<string>;
15
+ }>): {
16
+ selections: Array<AggregateSelection>;
17
+ expressions: Array<DocumentExpressionWrapper>;
18
+ };
8
19
  export declare function applyPagination(query: DocumentQueryBuilder, args: ConnectionArguments, orderBy?: DocumentOrderBy): [DocumentQueryBuilder, number];
9
20
  export declare function applyDocumentFilter(eb: DocumentExpressionBuilder, filter: DocumentFilter, path?: Array<string>, coerce?: CoerceFilterValue): DocumentExpressionWrapper;
10
21
  export declare function applyValueFilter(eb: DocumentExpressionBuilder, keys: Array<string>, filter: AnyValueFilter, coerce?: CoerceFilterValue): DocumentExpressionWrapper;
@@ -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=[],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"};
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}export function aggregateFieldName(e){return e.join(".")}export function applyAggregateSelections(e,t,n){let a=[];for(let l of t){let t=aggregateFieldName(l.keys),o=r(e,l.keys),u=l.numeric?n.numericCast(o):o;switch(l.op){case"sum":a.push(e.fn.sum(u).as(`sum_${t}`));break;case"average":a.push(e.fn.sum(u).as(`sum_${t}`)),a.push(e.fn.count(u).as(`count_${t}`));break;case"min":a.push(e.fn.min(u).as(`min_${t}`));break;case"max":a.push(e.fn.max(u).as(`max_${t}`));break;default:throw Error(`Invalid aggregate op: ${l.op}`)}}return a}export function groupKeyAlias(e){return`key_${e.join(".")}`}export function applyGroupBySelections(e,t){let n=[],a=[];for(let l of t){let t=r(e,l.keys);n.push(t.as(groupKeyAlias(l.keys))),a.push(t)}return{selections:n,expressions:a}}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 a(e,t=!1){return t?"asc"===e?"desc":"asc":e}export function applyPagination(a,l,o=[]){let{first:u,last:i,before:s,after:c}=l;if(null!=u){let l=t(u);return[function(t,a,l,o){let u=t;if(null!=l){let{id:t,ts:a,values:i}=e(l);null!=a?u=u.where(e=>e.or([e("created_at",">",a),e("created_at","=",a).and("id",">",t)])):null!=i&&(u=u.where(e=>{let a=[];for(let l of o){let o=n(l),u=i[o.keys.join(".")];if(null==u)continue;let s=r(e,o.keys);a.push(e.or([e(s,"asc"===o.direction?">":"<",u),e(s,"=",u).and("id",">",t)]))}return e.and(a)}))}return u.orderBy("created_at","asc").limit(a)}(a,l+1,c,o),l]}if(null!=i){let l=t(i);return[function(t,a,l,o){let u=t;if(null!=l){let{id:t,ts:a,values:i}=e(l);null!=a?u=u.where(e=>e.or([e("created_at","<",a),e("created_at","=",a).and("id","<",t)])):null!=i&&(u=u.where(e=>{let a=[];for(let l of o){let o=n(l),u=i[o.keys.join(".")];if(null==u)continue;let s=r(e,o.keys);a.push(e.or([e(s,"asc"===o.direction?"<":">",u),e(s,"=",u).and("id",">",t)]))}return e.and(a)}))}return u.orderBy("created_at","desc").limit(a)}(a,l+1,s,o),l]}let f=t();return[a.orderBy("created_at","asc").limit(f+1),f]}export function applyDocumentFilter(e,t,r=[],n){let a=Object.entries(t);if(1!==a.length)throw Error("Invalid document filter");let[l,o]=a[0];switch(l){case"where":var u,i,s,c;let f;return u=e,i=o,s=r,c=n,f=Object.entries(i).map(([e,t])=>applyValueFilter(u,[...s,e],t,c)),u.and(f);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: ${l}`)}}export function applyValueFilter(e,t,n,a){let l=Object.entries(n);if(1!==l.length)throw Error("Invalid value filter");let o=r(e,t),[u,i]=l[0],s=a??(e=>e);switch(u){case"isNull":return e(o,!0===i?"is":"is not",null);case"equalTo":return e(o,"=",s(i));case"notEqualTo":return e(o,"!=",s(i));case"in":return e(o,"in",i.map(s));case"notIn":return e(o,"not in",i.map(s));case"lessThan":return e(o,"<",s(i));case"lessThanOrEqualTo":return e(o,"<=",s(i));case"greaterThan":return e(o,">",s(i));case"greaterThanOrEqualTo":return e(o,">=",s(i));default:throw Error(`Invalid value filter type: ${u}`)}}export function applyDocumentOrderBy(e,t=[],n=!1){if(0===t.length)return[e.orderBy("created_at",a("asc",n)),null];let o=e,u=[];for(let e of t){let[t,i]=function e(t,n,o,u=[]){let i=Object.entries(n);if(1!==i.length)throw Error("Invalid order by field");let[s,c]=i[0],f=[...u,s],p=l[s];return null!=p?[t.orderBy(p,a(c,o)),f]:"string"==typeof c?[t.orderBy(e=>r(e,f),a(c,o)),f]:e(t,c,o,f)}(o,e,n);o=t,u.push(i)}return[o,u]}let l={_createdAt:"created_at",_owner:"owner"};
package/lib/tables.d.ts CHANGED
@@ -175,12 +175,6 @@ export type QueryDocumentsParams = ConnectionArguments & {
175
175
  owner?: string;
176
176
  catalogID?: string;
177
177
  };
178
- export type CountDocumentsParams = {
179
- modelIDs: Array<string>;
180
- filter?: DocumentFilter;
181
- owner?: string;
182
- catalogID?: string;
183
- };
184
178
  export type CursorDocument = {
185
179
  cursor: string;
186
180
  document: DocumentNode;
@@ -212,7 +206,7 @@ export type SearchDocumentResult = {
212
206
  * Access level token used in `AccessRule`, persisted access defaults, and
213
207
  * document access overrides.
214
208
  */
215
- export type AccessLevel = 'only_owner' | 'anyone' | 'restricted';
209
+ export type { AccessLevel, ViewerReadAccess } from '@kubun/protocol';
216
210
  export type AccessPermissions = {
217
211
  read?: {
218
212
  level: 'only_owner' | 'anyone' | 'restricted';
@@ -223,4 +217,3 @@ export type AccessPermissions = {
223
217
  allowedDIDs?: Array<string>;
224
218
  };
225
219
  };
226
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubun/store-graph",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "license": "see LICENSE.md",
5
5
  "keywords": [],
6
6
  "type": "module",
@@ -15,17 +15,17 @@
15
15
  ],
16
16
  "sideEffects": false,
17
17
  "dependencies": {
18
- "@enkaku/codec": "^0.15.0",
19
- "kysely": "^0.28.17",
20
- "@kubun/db": "^0.9.0",
21
- "@kubun/db-adapter": "^0.9.0",
22
- "@kubun/id": "^0.9.0",
23
- "@kubun/protocol": "^0.9.0"
18
+ "@enkaku/codec": "^0.16.0",
19
+ "kysely": "^0.29.2",
20
+ "@kubun/db-adapter": "^0.10.0",
21
+ "@kubun/id": "^0.10.0",
22
+ "@kubun/db": "^0.10.0",
23
+ "@kubun/protocol": "^0.10.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@testcontainers/postgresql": "^11.14.0",
27
- "@kubun/db-postgres": "^0.9.0",
28
- "@kubun/db-better-sqlite": "^0.9.0"
26
+ "@testcontainers/postgresql": "^12.0.1",
27
+ "@kubun/db-postgres": "^0.10.0",
28
+ "@kubun/db-better-sqlite": "^0.10.0"
29
29
  },
30
30
  "scripts": {
31
31
  "build:clean": "del lib",