@kubun/store-graph 0.8.1 → 0.10.0
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 +33 -9
- package/lib/api.js +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/migrations.d.ts +1 -1
- package/lib/migrations.js +1 -1
- package/lib/query-builder.d.ts +13 -2
- package/lib/query-builder.js +1 -1
- package/lib/tables.d.ts +9 -9
- package/package.json +10 -10
package/lib/api.d.ts
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
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 { Catalog, ClusterDefinitionRow, ClusterModel,
|
|
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
|
+
/**
|
|
7
|
+
* Persisted access rule shape as stored in `user_model_access_defaults`.
|
|
8
|
+
*/
|
|
9
|
+
export type StoredAccessRule = {
|
|
10
|
+
level: AccessLevel;
|
|
11
|
+
allowedDIDs: Array<string> | null;
|
|
12
|
+
allowedCircles: Array<string> | null;
|
|
13
|
+
allowedGroups: Array<string> | null;
|
|
14
|
+
};
|
|
6
15
|
export type GraphStoreAPI = {
|
|
7
|
-
getDocument(id: DocumentID): Promise<DocumentNode | null>;
|
|
16
|
+
getDocument(id: DocumentID | string): Promise<DocumentNode | null>;
|
|
8
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>>;
|
|
9
25
|
createDocument(params: CreateDocumentParams): Promise<DocumentNode>;
|
|
10
26
|
saveDocument(params: SaveDocumentParams): Promise<DocumentNode>;
|
|
11
27
|
queryDocuments(params: QueryDocumentsParams): Promise<QueryDocumentsResult>;
|
|
12
|
-
|
|
28
|
+
aggregateDocuments(params: AggregateDocumentsParams): Promise<AggregateValues>;
|
|
29
|
+
groupedAggregateDocuments(params: GroupedAggregateDocumentsParams): Promise<Array<GroupedAggregateValue>>;
|
|
13
30
|
listDocuments(params: ListDocumentsParams): Promise<Array<DocumentNode>>;
|
|
14
31
|
listDocumentModelIDs(): Promise<Array<string>>;
|
|
15
32
|
getDistinctOwnersForModel(modelID: string): Promise<Array<string>>;
|
|
@@ -37,6 +54,14 @@ export type GraphStoreAPI = {
|
|
|
37
54
|
searchDocuments(params: SearchDocumentsParams): Promise<Array<SearchDocumentResult>>;
|
|
38
55
|
createCatalog(catalog: InsertCatalog): Promise<void>;
|
|
39
56
|
getCatalog(id: string): Promise<Catalog | undefined>;
|
|
57
|
+
/**
|
|
58
|
+
* Batch fetch catalogs by ID. Returns a Map keyed by ID; missing IDs are
|
|
59
|
+
* absent from the map. Single SQL query with `WHERE id IN (...)`. Empty
|
|
60
|
+
* input short-circuits with an empty Map (no SQL).
|
|
61
|
+
*
|
|
62
|
+
* Caller is responsible for deduplicating IDs (e.g. via `Array.from(new Set(...))`).
|
|
63
|
+
*/
|
|
64
|
+
getCatalogs(ids: Array<string>): Promise<Map<string, Catalog>>;
|
|
40
65
|
updateCatalog(id: string, update: Partial<Pick<InsertCatalog, 'name' | 'description' | 'filter_criteria' | 'hlc'>>): Promise<void>;
|
|
41
66
|
deleteCatalog(id: string): Promise<void>;
|
|
42
67
|
listCatalogs(ownerDID: string): Promise<Array<Catalog>>;
|
|
@@ -45,16 +70,15 @@ export type GraphStoreAPI = {
|
|
|
45
70
|
owners: Array<string> | undefined;
|
|
46
71
|
}>;
|
|
47
72
|
registerClusterModels(clusterID: string, entries: Array<InsertClusterModel>): Promise<void>;
|
|
48
|
-
getUserModelAccessDefault(ownerDID: string, modelID: string, permissionType: 'read' | 'write'): Promise<
|
|
49
|
-
level: string;
|
|
50
|
-
allowedDIDs: Array<string> | null;
|
|
51
|
-
} | null>;
|
|
73
|
+
getUserModelAccessDefault(ownerDID: string, modelID: string, permissionType: 'read' | 'write'): Promise<StoredAccessRule | null>;
|
|
52
74
|
setUserModelAccessDefault(params: {
|
|
53
75
|
ownerDID: string;
|
|
54
76
|
modelID: string;
|
|
55
77
|
permissionType: 'read' | 'write';
|
|
56
|
-
accessLevel:
|
|
78
|
+
accessLevel: AccessLevel;
|
|
57
79
|
allowedDIDs: Array<string> | null;
|
|
80
|
+
allowedCircles: Array<string> | null;
|
|
81
|
+
allowedGroups: Array<string> | null;
|
|
58
82
|
}): Promise<void>;
|
|
59
83
|
removeUserModelAccessDefaults(ownerDID: string, modelID: string, permissionTypes: Array<string>): Promise<void>;
|
|
60
84
|
getDocumentIDsForScope(scopes: Array<{
|
package/lib/api.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DocumentID as e,DocumentModelID as t}from"@kubun/id";import{serializeCursor as n}from"./cursor.js";function l(e,t){if(!(e instanceof Error))return!1;let n=e.message;return n.includes("no such table")&&n.includes(t)||n.includes("does not exist")&&n.includes(t)}import{applyDocumentFilter as a,applyDocumentOrderBy as r,applyPagination as o}from"./query-builder.js";function i(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 s(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 u(e,n){let l=t.fromString(n);return l.isLocal?l.toGlobal(t.fromString(e)).toString():n}async function c(e,t,n){let{id:l,graphModelID:a,model:r}=n,o=t.types;for(let n of(await e.schema.createTable(`k_${l}`).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:l,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:u(l,n),implementation_id:l}).onConflict(e=>e.doNothing()).execute();await e.insertInto("kubun_graph_document_model_links").values({graph_model_id:a,document_model_id:l}).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:n,owners:l}=await h.resolveCatalogScope(t),a=e;if(null!=n){let e=new Set(n);a=a.filter(t=>e.has(t))}return{effectiveModelIDs:a,effectiveOwners:l}}let h={async getDocument(e){let n=await t.selectFrom(`k_${e.model.toString()}`).selectAll().where("id","=",e.toString()).executeTakeFirst();return n?s(d,n):null},getDocumentModel:async e=>i(await t.selectFrom("kubun_graph_document_models").selectAll().where("id","=",e.toString()).executeTakeFirstOrThrow()),async createDocument(e){let n=e.id.toString(),l=e.id.model.toString(),a=await t.insertInto(`k_${l}`).values({id:n,owner:e.owner,model:l,data:d.encodeJSON(e.data),unique:d.encodeBinary(e.unique)}).returningAll().executeTakeFirstOrThrow(()=>Error(`createDocument failed to return row for ${n}`));return s(d,a)},async saveDocument(e){let n=e.id.toString(),l=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","=",n).returningAll().executeTakeFirstOrThrow(()=>Error(`saveDocument: document not found for id=${n}`));return s(d,l)},async queryDocuments(e){let{catalogID:l,filter:i,modelIDs:u,orderBy:c,owner:h,...w}=e,f=null!=e.last,{effectiveModelIDs:g,effectiveOwners:p}=await _(u,l);if(0===g.length)return{entries:[],hasMore:!1};let[y,...k]=g,x=t.selectFrom(`k_${y}`).selectAll();for(let e of(null!=h&&(x=x.where("owner","=",h)),null!=p&&(x=x.where("owner","in",p)),null!=i&&(x=x.where(e=>a(e,i,[],m))),k))x=x.unionAll(t=>{let n=t.selectFrom(`k_${e}`).selectAll();return null!=h&&(n=n.where("owner","=",h)),null!=p&&(n=n.where("owner","in",p)),null!=i&&(n=n.where(e=>a(e,i,[],m))),n});let[b,S]=r(x,c,f),[F,D]=o(b,w,c),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 n of S){let l=e.data;for(let e of n)null!=l&&(l=l[e]);null!=l&&(t[n.join(".")]=l)}return{cursor:n({id:e.id,values:t}),document:s(d,e)}}):C.map(e=>({cursor:n({id:e.id,ts:+e.created_at}),document:s(d,e)})),hasMore:v.length>D}},async countDocuments(e){let{catalogID:n,filter:l,modelIDs:r,owner:o}=e,{effectiveModelIDs:i,effectiveOwners:s}=await _(r,n);return 0===i.length?0:(await Promise.all(i.map(async e=>{let n=t.selectFrom(`k_${e}`).select(e=>e.fn.countAll().as("count"));return null!=o&&(n=n.where("owner","=",o)),null!=s&&(n=n.where("owner","in",s)),null!=l&&(n=n.where(e=>a(e,l,[],m))),Number((await n.executeTakeFirstOrThrow()).count)}))).reduce((e,t)=>e+t,0)},async listDocuments(e){let[n,...l]=e.modelIDs,a=t.selectFrom(`k_${n}`).selectAll().where("id","in",e.docIDs);for(let t of l)a=a.unionAll(n=>n.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs));return(await a.execute()).map(e=>s(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(l(t,`k_${e}`))return[];throw t}},queryDocumentsByOwner:async(e,n)=>(await t.selectFrom(`k_${e}`).selectAll().where("owner","=",n).execute()).map(e=>s(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,n){await t.updateTable("kubun_graph_mutation_log").set({status:n}).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(n){let l=e.fromString(n).model.toString(),a=await t.selectFrom(`k_${l}`).select("field_hlcs").where("id","=",n).executeTakeFirst();if(a?.field_hlcs==null)return null;let r=a.field_hlcs;return"string"==typeof r?JSON.parse(r):r},async updateFieldHLCs(e,n){let l=e.model.toString();await t.updateTable(`k_${l}`).set({field_hlcs:d.encodeJSON(n)}).where("id","=",e.toString()).execute()},listGraphs:async()=>await t.selectFrom("kubun_graph_models").selectAll().execute(),async createGraph(e){let n=e.id,l=e.name??n;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:n,name:l,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(u(e,t))));if(0===e.length)throw Error("Could not create graph: no valid model to add");await Promise.all(e.map(async([e,l])=>{await c(t,d,{id:e,graphModelID:n,model:l}),r.add(e)}))}}),n},async getGraph(e){let n=await t.selectFrom("kubun_graph_models").selectAll().where("id","=",e).executeTakeFirst();if(null==n)return null;let l={};for(let n 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()))l[n.id]=i(n);return{...n,record:l}},async getClusterForModel(e){let n=await t.selectFrom("kubun_graph_cluster_models").select("cluster_id").where("model_id","=",e).executeTakeFirst();return n?.cluster_id},getClusterModels:async e=>await t.selectFrom("kubun_graph_cluster_models").selectAll().where("cluster_id","=",e).orderBy("cluster_index").execute(),async saveCluster(e,n){await t.insertInto("kubun_graph_clusters").values({id:e,definition:d.encodeJSON(n)}).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 n=await t.selectFrom("kubun_graph_clusters").selectAll().where("id","in",e).execute(),l={};for(let e of n)l[e.id]=e.definition;return l},async addAttachments(e){await t.insertInto("kubun_graph_document_attachments").values(e).onConflict(e=>e.doNothing()).execute()},async createSearchIndex(e,n){await d.createSearchIndex(t,{modelID:e,fields:n})},async dropSearchIndex(e){await d.dropSearchIndex(t,e)},async updateSearchEntry(e,n,l,a){let r={};for(let e of a){let t=function(e,t){let n=t.split("."),l=e;for(let e of n){if(null==l||"object"!=typeof l)return null;l=l[e]}return l}(l,e);null!=t&&(r[e]=String(t))}await d.updateSearchEntry(t,e,n,r,a)},async removeSearchEntry(e,n){await d.removeSearchEntry(t,e,n)},async searchDocuments(e){let n=[];for(let l of e.modelIDs)for(let a of(await d.searchIndex(t,{query:e.query,modelID:l,limit:e.first??50})))n.push({documentID:a.documentID,modelID:l,rank:a.rank});return(n.sort((e,t)=>Math.abs(t.rank)-Math.abs(e.rank)),e.first)?n.slice(0,e.first):n},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 updateCatalog(e,n){let l={};null!=n.name&&(l.name=n.name),null!=n.description&&(l.description=n.description),null!=n.filter_criteria&&(l.filter_criteria=d.encodeJSON(n.filter_criteria)),null!=n.hlc&&(l.hlc=n.hlc),l.updated_at=d.encodeTimestamp(new Date),await t.updateTable("kubun_graph_catalogs").set(l).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,n=await h.getCatalog(e);if(null==n)return{models:void 0,owners:void 0};let l=n.filter_criteria,a=null!=l.models&&l.models.length>0?l.models:void 0;return null!=l.owners&&l.owners.length>0&&(t=[...l.owners]),{models:a,owners:t}},async registerClusterModels(e,n){0!==n.length&&await t.insertInto("kubun_graph_cluster_models").values(n).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,n,l){let a=await t.selectFrom("kubun_graph_user_model_access_defaults").select(["access_level","allowed_dids"]).where("owner_did","=",e).where("model_id","=",n).where("permission_type","=",l).executeTakeFirst();return a?{level:a.access_level,allowedDIDs:a.allowed_dids}: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}).onConflict(t=>t.columns(["owner_did","model_id","permission_type"]).doUpdateSet({access_level:e.accessLevel,allowed_dids:e.allowedDIDs?d.encodeJSON(e.allowedDIDs):null,updated_at:d.encodeTimestamp(new Date)})).execute()},async removeUserModelAccessDefaults(e,n,l){await t.deleteFrom("kubun_graph_user_model_access_defaults").where("owner_did","=",e).where("model_id","=",n).where("permission_type","in",l).execute()},async getDocumentIDsForScope(e,n=[]){let a=[];for(let n of e)try{let e=await t.selectFrom(`k_${n.modelID}`).select("id").where("owner","=",n.ownerDID).execute();a.push(...e.map(e=>e.id))}catch(e){if(!l(e,`k_${n.modelID}`))throw e}if(n.length>0){let e=new Set(n);return a.filter(t=>!e.has(t))}return a},getDocumentMetadataForSync:async(e,n)=>0===n.length?[]:(await t.selectFrom(`k_${e}`).select(["id","model","owner"]).where("id","in",n).execute()).map(e=>({id:e.id,model:e.model,owner:e.owner}))};return h}
|
|
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 f(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 h(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=h(e,t.greaterThan);if(null==l||l<=0)return!1}if(null!=t.greaterThanOrEqualTo){let l=h(e,t.greaterThanOrEqualTo);if(null==l||l<0)return!1}if(null!=t.lessThan){let l=h(e,t.lessThan);if(null==l||l>=0)return!1}if(null!=t.lessThanOrEqualTo){let l=h(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,h){let b=h.coerceFilterValue.bind(h);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(h,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:h.encodeJSON(e.data),unique:h.encodeBinary(e.unique)}).returningAll().executeTakeFirstOrThrow(()=>Error(`createDocument failed to return row for ${l}`));return y(h,r)},async saveDocument(e){let l=e.id.toString(),n=await t.updateTable(`k_${e.id.model.toString()}`).set({data:e.data?h.encodeJSON(e.data):null,updated_at:h.encodeTimestamp(new Date)}).where("id","=",l).returningAll().executeTakeFirstOrThrow(()=>Error(`saveDocument: document not found for id=${l}`));return y(h,n)},async queryDocuments(e){let{catalogID:n,filter:r,modelIDs:a,orderBy:s,owner:c,...d}=e,m=null!=e.last,{effectiveModelIDs:_,effectiveOwners:f}=await S(a,n);if(0===_.length)return{entries:[],hasMore:!1};let[w,...g]=_,p=t.selectFrom(`k_${w}`).selectAll();for(let e of(null!=c&&(p=p.where("owner","=",c)),null!=f&&(p=p.where("owner","in",f)),null!=r&&(p=p.where(e=>o(e,r,[],b))),g))p=p.unionAll(t=>{let l=t.selectFrom(`k_${e}`).selectAll();return null!=c&&(l=l.where("owner","=",c)),null!=f&&(l=l.where("owner","in",f)),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(h,e)}}):C.map(e=>({cursor:l({id:e.id,ts:+e.created_at}),document:y(h,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,h);return s&&t.push(e.fn.countAll().as("count")),t});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(h.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?f(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,h)];return i&&n.push(e.fn.countAll().as("count")),n});r=r.groupBy(e=>s(e,y).expressions),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(h.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,...f(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);for(let t of n)r=r.unionAll(l=>l.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs));return(await r.execute()).map(e=>y(h,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(h,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:h.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:h.encodeJSON(e.aliases??{}),extension_sdl:e.extensionSDL??null,id:l,name:n,plugin_config:e.pluginConfig?h.encodeJSON(e.pluginConfig):null,search:e.search?h.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,h,{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:h.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 h.createSearchIndex(t,{modelID:e,fields:l})},async dropSearchIndex(e){await h.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 h.updateSearchEntry(t,e,l,a,r)},async removeSearchEntry(e,l){await h.removeSearchEntry(t,e,l)},async searchDocuments(e){let l=[];for(let n of e.modelIDs)for(let r of(await h.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:h.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=h.encodeJSON(l.filter_criteria)),null!=l.hlc&&(n.hlc=l.hlc),n.updated_at=h.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?h.encodeJSON(e.allowedDIDs):null,allowed_circles:e.allowedCircles?h.encodeJSON(e.allowedCircles):null,allowed_groups:e.allowedGroups?h.encodeJSON(e.allowedGroups):null}).onConflict(t=>t.columns(["owner_did","model_id","permission_type"]).doUpdateSet({access_level:e.accessLevel,allowed_dids:e.allowedDIDs?h.encodeJSON(e.allowedDIDs):null,allowed_circles:e.allowedCircles?h.encodeJSON(e.allowedCircles):null,allowed_groups:e.allowedGroups?h.encodeJSON(e.allowedGroups):null,updated_at:h.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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { StoreProvider } from '@kubun/db';
|
|
2
2
|
import type { GraphStoreAPI } from './api.js';
|
|
3
|
-
export type { GraphStoreAPI } from './api.js';
|
|
3
|
+
export type { GraphStoreAPI, StoredAccessRule } from './api.js';
|
|
4
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 { AccessPermissions, AddDocumentModelParams, Catalog, ClusterDefinitionRow, ClusterModel, ConnectionArguments,
|
|
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';
|
package/lib/migrations.d.ts
CHANGED
package/lib/migrations.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export function getGraphMigrations(e){let t=e.types,a=e.functions.now;return{"0-init":{async up(e){await e.schema.createTable("kubun_graph_document_attachments").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("data",t.binary,e=>e.notNull()).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).execute(),await e.schema.createTable("kubun_graph_document_models").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("version",t.text,e=>e.notNull()).addColumn("name",t.text,e=>e.notNull()).addColumn("behavior",t.text,e=>e.notNull()).addColumn("unique_fields",t.json).addColumn("interfaces",t.json,e=>e.notNull()).addColumn("schema",t.json,e=>e.notNull()).addColumn("fields_meta",t.json,e=>e.notNull()).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).execute(),await e.schema.createTable("kubun_graph_document_model_interfaces").ifNotExists().addColumn("interface_id",t.text,e=>e.notNull().references("kubun_graph_document_models.id")).addColumn("implementation_id",t.text,e=>e.notNull().references("kubun_graph_document_models.id")).addUniqueConstraint("kubun_graph_document_model_interfaces_pkey",["interface_id","implementation_id"]).execute(),await e.schema.createTable("kubun_graph_models").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("name",t.text,e=>e.notNull()).addColumn("aliases",t.json,e=>e.defaultTo("{}").notNull()).addColumn("search",t.json).addColumn("extension_sdl",t.text).addColumn("plugin_config",t.json).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).addColumn("updated_at",t.timestamp).execute(),await e.schema.createTable("kubun_graph_document_model_links").ifNotExists().addColumn("graph_model_id",t.text,e=>e.notNull().references("kubun_graph_models.id")).addColumn("document_model_id",t.text,e=>e.notNull().references("kubun_graph_document_models.id")).addUniqueConstraint("kubun_graph_document_model_links_pkey",["graph_model_id","document_model_id"]).execute(),await e.schema.createTable("kubun_graph_user_model_access_defaults").ifNotExists().addColumn("owner_did",t.text,e=>e.notNull()).addColumn("model_id",t.text,e=>e.notNull()).addColumn("permission_type",t.text,e=>e.notNull()).addColumn("access_level",t.text,e=>e.notNull()).addColumn("allowed_dids",t.json).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).addColumn("updated_at",t.timestamp).addPrimaryKeyConstraint("kubun_graph_user_model_access_defaults_pkey",["owner_did","model_id","permission_type"]).execute(),await e.schema.createIndex("idx_graph_user_model_access_owner_model").on("kubun_graph_user_model_access_defaults").columns(["owner_did","model_id"]).execute(),await e.schema.createTable("kubun_graph_mutation_log").ifNotExists().addColumn("mutation_hash",t.text,e=>e.primaryKey()).addColumn("model_id",t.text,e=>e.notNull()).addColumn("document_id",t.text,e=>e.notNull()).addColumn("author_did",t.text,e=>e.notNull()).addColumn("hlc",t.text,e=>e.notNull()).addColumn("mutation_jwt",t.text,e=>e.notNull()).addColumn("status",t.text,e=>e.notNull().defaultTo("applied")).execute(),await e.schema.createIndex("idx_graph_mutation_log_hlc").on("kubun_graph_mutation_log").column("hlc").execute(),await e.schema.createIndex("idx_graph_mutation_log_document").on("kubun_graph_mutation_log").column("document_id").execute(),await e.schema.createIndex("idx_graph_mutation_log_status").on("kubun_graph_mutation_log").column("status").execute(),await e.schema.createTable("kubun_graph_cluster_models").ifNotExists().addColumn("model_id",t.text,e=>e.notNull().primaryKey()).addColumn("cluster_id",t.text,e=>e.notNull()).addColumn("cluster_index","integer",e=>e.notNull()).execute(),await e.schema.createIndex("idx_graph_cluster_models_cluster").on("kubun_graph_cluster_models").column("cluster_id").execute(),await e.schema.createTable("kubun_graph_clusters").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("definition",t.json,e=>e.notNull()).execute(),await e.schema.createTable("kubun_graph_catalogs").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("owner_did",t.text,e=>e.notNull()).addColumn("name",t.text,e=>e.notNull()).addColumn("description",t.text,e=>e.notNull().defaultTo("")).addColumn("filter_criteria",t.json,e=>e.notNull()).addColumn("hlc",t.text,e=>e.notNull()).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).addColumn("updated_at",t.timestamp).execute(),await e.schema.createIndex("idx_graph_catalogs_owner").ifNotExists().on("kubun_graph_catalogs").column("owner_did").execute()},async down(e){await e.schema.dropTable("kubun_graph_catalogs").ifExists().execute(),await e.schema.dropTable("kubun_graph_clusters").ifExists().execute(),await e.schema.dropTable("kubun_graph_cluster_models").ifExists().execute(),await e.schema.dropTable("kubun_graph_mutation_log").ifExists().execute(),await e.schema.dropTable("kubun_graph_user_model_access_defaults").ifExists().execute(),await e.schema.dropTable("kubun_graph_document_model_links").ifExists().execute(),await e.schema.dropTable("kubun_graph_models").ifExists().execute(),await e.schema.dropTable("kubun_graph_document_model_interfaces").ifExists().execute(),await e.schema.dropTable("kubun_graph_document_models").ifExists().execute(),await e.schema.dropTable("kubun_graph_document_attachments").ifExists().execute()}}}}
|
|
1
|
+
export function getGraphMigrations(e){let t=e.types,a=e.functions.now;return{"0-init":{async up(e){await e.schema.createTable("kubun_graph_document_attachments").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("data",t.binary,e=>e.notNull()).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).execute(),await e.schema.createTable("kubun_graph_document_models").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("version",t.text,e=>e.notNull()).addColumn("name",t.text,e=>e.notNull()).addColumn("behavior",t.text,e=>e.notNull()).addColumn("unique_fields",t.json).addColumn("interfaces",t.json,e=>e.notNull()).addColumn("schema",t.json,e=>e.notNull()).addColumn("fields_meta",t.json,e=>e.notNull()).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).execute(),await e.schema.createTable("kubun_graph_document_model_interfaces").ifNotExists().addColumn("interface_id",t.text,e=>e.notNull().references("kubun_graph_document_models.id")).addColumn("implementation_id",t.text,e=>e.notNull().references("kubun_graph_document_models.id")).addUniqueConstraint("kubun_graph_document_model_interfaces_pkey",["interface_id","implementation_id"]).execute(),await e.schema.createTable("kubun_graph_models").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("name",t.text,e=>e.notNull()).addColumn("aliases",t.json,e=>e.defaultTo("{}").notNull()).addColumn("search",t.json).addColumn("extension_sdl",t.text).addColumn("plugin_config",t.json).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).addColumn("updated_at",t.timestamp).execute(),await e.schema.createTable("kubun_graph_document_model_links").ifNotExists().addColumn("graph_model_id",t.text,e=>e.notNull().references("kubun_graph_models.id")).addColumn("document_model_id",t.text,e=>e.notNull().references("kubun_graph_document_models.id")).addUniqueConstraint("kubun_graph_document_model_links_pkey",["graph_model_id","document_model_id"]).execute(),await e.schema.createTable("kubun_graph_user_model_access_defaults").ifNotExists().addColumn("owner_did",t.text,e=>e.notNull()).addColumn("model_id",t.text,e=>e.notNull()).addColumn("permission_type",t.text,e=>e.notNull()).addColumn("access_level",t.text,e=>e.notNull()).addColumn("allowed_dids",t.json).addColumn("allowed_circles",t.json).addColumn("allowed_groups",t.json).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).addColumn("updated_at",t.timestamp).addPrimaryKeyConstraint("kubun_graph_user_model_access_defaults_pkey",["owner_did","model_id","permission_type"]).execute(),await e.schema.createIndex("idx_graph_user_model_access_owner_model").on("kubun_graph_user_model_access_defaults").columns(["owner_did","model_id"]).execute(),await e.schema.createTable("kubun_graph_mutation_log").ifNotExists().addColumn("mutation_hash",t.text,e=>e.primaryKey()).addColumn("model_id",t.text,e=>e.notNull()).addColumn("document_id",t.text,e=>e.notNull()).addColumn("author_did",t.text,e=>e.notNull()).addColumn("hlc",t.text,e=>e.notNull()).addColumn("mutation_jwt",t.text,e=>e.notNull()).addColumn("status",t.text,e=>e.notNull().defaultTo("applied")).execute(),await e.schema.createIndex("idx_graph_mutation_log_hlc").on("kubun_graph_mutation_log").column("hlc").execute(),await e.schema.createIndex("idx_graph_mutation_log_document").on("kubun_graph_mutation_log").column("document_id").execute(),await e.schema.createIndex("idx_graph_mutation_log_status").on("kubun_graph_mutation_log").column("status").execute(),await e.schema.createTable("kubun_graph_cluster_models").ifNotExists().addColumn("model_id",t.text,e=>e.notNull().primaryKey()).addColumn("cluster_id",t.text,e=>e.notNull()).addColumn("cluster_index","integer",e=>e.notNull()).execute(),await e.schema.createIndex("idx_graph_cluster_models_cluster").on("kubun_graph_cluster_models").column("cluster_id").execute(),await e.schema.createTable("kubun_graph_clusters").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("definition",t.json,e=>e.notNull()).execute(),await e.schema.createTable("kubun_graph_catalogs").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("owner_did",t.text,e=>e.notNull()).addColumn("name",t.text,e=>e.notNull()).addColumn("description",t.text,e=>e.notNull().defaultTo("")).addColumn("filter_criteria",t.json,e=>e.notNull()).addColumn("hlc",t.text,e=>e.notNull()).addColumn("created_at",t.timestamp,e=>e.defaultTo(a).notNull()).addColumn("updated_at",t.timestamp).execute(),await e.schema.createIndex("idx_graph_catalogs_owner").ifNotExists().on("kubun_graph_catalogs").column("owner_did").execute()},async down(e){await e.schema.dropTable("kubun_graph_catalogs").ifExists().execute(),await e.schema.dropTable("kubun_graph_clusters").ifExists().execute(),await e.schema.dropTable("kubun_graph_cluster_models").ifExists().execute(),await e.schema.dropTable("kubun_graph_mutation_log").ifExists().execute(),await e.schema.dropTable("kubun_graph_user_model_access_defaults").ifExists().execute(),await e.schema.dropTable("kubun_graph_document_model_links").ifExists().execute(),await e.schema.dropTable("kubun_graph_models").ifExists().execute(),await e.schema.dropTable("kubun_graph_document_model_interfaces").ifExists().execute(),await e.schema.dropTable("kubun_graph_document_models").ifExists().execute(),await e.schema.dropTable("kubun_graph_document_attachments").ifExists().execute()}}}}
|
package/lib/query-builder.d.ts
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
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;
|
package/lib/query-builder.js
CHANGED
|
@@ -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
|
|
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
|
@@ -96,6 +96,8 @@ export type UserModelAccessDefaultTable = {
|
|
|
96
96
|
permission_type: string;
|
|
97
97
|
access_level: string;
|
|
98
98
|
allowed_dids: JSONValueColumn<Array<string>> | null;
|
|
99
|
+
allowed_circles: JSONValueColumn<Array<string>> | null;
|
|
100
|
+
allowed_groups: JSONValueColumn<Array<string>> | null;
|
|
99
101
|
created_at: CreatedAtColumn;
|
|
100
102
|
updated_at: UpdatedAtColumn;
|
|
101
103
|
};
|
|
@@ -173,12 +175,6 @@ export type QueryDocumentsParams = ConnectionArguments & {
|
|
|
173
175
|
owner?: string;
|
|
174
176
|
catalogID?: string;
|
|
175
177
|
};
|
|
176
|
-
export type CountDocumentsParams = {
|
|
177
|
-
modelIDs: Array<string>;
|
|
178
|
-
filter?: DocumentFilter;
|
|
179
|
-
owner?: string;
|
|
180
|
-
catalogID?: string;
|
|
181
|
-
};
|
|
182
178
|
export type CursorDocument = {
|
|
183
179
|
cursor: string;
|
|
184
180
|
document: DocumentNode;
|
|
@@ -206,14 +202,18 @@ export type SearchDocumentResult = {
|
|
|
206
202
|
modelID: string;
|
|
207
203
|
rank: number;
|
|
208
204
|
};
|
|
205
|
+
/**
|
|
206
|
+
* Access level token used in `AccessRule`, persisted access defaults, and
|
|
207
|
+
* document access overrides.
|
|
208
|
+
*/
|
|
209
|
+
export type { AccessLevel, ViewerReadAccess } from '@kubun/protocol';
|
|
209
210
|
export type AccessPermissions = {
|
|
210
211
|
read?: {
|
|
211
|
-
level: 'only_owner' | 'anyone' | '
|
|
212
|
+
level: 'only_owner' | 'anyone' | 'restricted';
|
|
212
213
|
allowedDIDs?: Array<string>;
|
|
213
214
|
};
|
|
214
215
|
write?: {
|
|
215
|
-
level: 'only_owner' | '
|
|
216
|
+
level: 'only_owner' | 'restricted';
|
|
216
217
|
allowedDIDs?: Array<string>;
|
|
217
218
|
};
|
|
218
219
|
};
|
|
219
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubun/store-graph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
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.
|
|
19
|
-
"kysely": "^0.
|
|
20
|
-
"@kubun/db": "^0.
|
|
21
|
-
"@kubun/db-adapter": "^0.
|
|
22
|
-
"@kubun/
|
|
23
|
-
"@kubun/
|
|
18
|
+
"@enkaku/codec": "^0.16.0",
|
|
19
|
+
"kysely": "^0.29.2",
|
|
20
|
+
"@kubun/db": "^0.10.0",
|
|
21
|
+
"@kubun/db-adapter": "^0.10.0",
|
|
22
|
+
"@kubun/id": "^0.10.0",
|
|
23
|
+
"@kubun/protocol": "^0.10.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@testcontainers/postgresql": "^
|
|
27
|
-
"@kubun/db-better-sqlite": "^0.
|
|
28
|
-
"@kubun/db-postgres": "^0.
|
|
26
|
+
"@testcontainers/postgresql": "^12.0.1",
|
|
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",
|