@kubun/db 0.5.1 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/db.d.ts +33 -40
- package/lib/db.js +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/migrations/0-init.js +1 -1
- package/lib/migrations/migrations.js +1 -1
- package/lib/types.d.ts +17 -17
- package/package.json +8 -8
- package/lib/migrations/1-add-access-control.d.ts +0 -3
- package/lib/migrations/1-add-access-control.js +0 -1
- package/lib/migrations/2-add-sync.d.ts +0 -3
- package/lib/migrations/2-add-sync.js +0 -1
- package/lib/migrations/3-add-search.d.ts +0 -3
- package/lib/migrations/3-add-search.js +0 -1
package/lib/db.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { EventEmitter } from '@enkaku/event';
|
|
2
2
|
import type { Adapter, AdapterTypes } from '@kubun/db-adapter';
|
|
3
|
-
import {
|
|
3
|
+
import { DocumentID, DocumentModelID } from '@kubun/id';
|
|
4
4
|
import { type Logger } from '@kubun/logger';
|
|
5
5
|
import type { DocumentModel, DocumentModelsRecord, DocumentNode } from '@kubun/protocol';
|
|
6
|
-
import { Kysely, type Migration
|
|
7
|
-
import type { Database, DocumentData,
|
|
6
|
+
import { Kysely, type Migration } from 'kysely';
|
|
7
|
+
import type { CountDocumentsParams, Database, DocumentData, GraphModel, InsertDocumentAttachment, InsertMutationLogEntry, ListDocumentsParams, MutationLogEntry, QueryDocumentsParams, QueryDocumentsResult, SearchConfig, SearchDocumentResult, SearchDocumentsParams } from './types.js';
|
|
8
8
|
export type Migrations = Record<string, Migration>;
|
|
9
9
|
export type DocumentCreatedEvent = {
|
|
10
10
|
type: 'create';
|
|
@@ -31,7 +31,6 @@ export type GraphModelWithRecord = GraphModel & {
|
|
|
31
31
|
export type DocumentParams = {
|
|
32
32
|
id: DocumentID;
|
|
33
33
|
data: DocumentData | null;
|
|
34
|
-
state: Uint8Array | null;
|
|
35
34
|
};
|
|
36
35
|
export type CreateDocumentParams = DocumentParams & {
|
|
37
36
|
owner: string;
|
|
@@ -48,11 +47,22 @@ export type CreateGraphParams = {
|
|
|
48
47
|
search?: SearchConfig;
|
|
49
48
|
};
|
|
50
49
|
export type AddDocumentModelParams = {
|
|
51
|
-
transaction: Transaction<Database>;
|
|
52
50
|
id: string;
|
|
53
51
|
graphModelID: string;
|
|
54
52
|
model: DocumentModel;
|
|
55
53
|
};
|
|
54
|
+
export type WritableDB = {
|
|
55
|
+
readonly events: EventEmitter<DBEvents>;
|
|
56
|
+
getDocument(id: DocumentID): Promise<DocumentNode | null>;
|
|
57
|
+
getDocumentModel(id: DocumentModelID | string): Promise<DocumentModel>;
|
|
58
|
+
createDocument(params: CreateDocumentParams): Promise<DocumentNode>;
|
|
59
|
+
saveDocument(params: SaveDocumentParams): Promise<DocumentNode>;
|
|
60
|
+
insertMutationLogEntry(entry: InsertMutationLogEntry): Promise<void>;
|
|
61
|
+
hasMutationHash(hash: string): Promise<boolean>;
|
|
62
|
+
updateMutationStatus(mutationHash: string, status: string): Promise<void>;
|
|
63
|
+
getFieldHLCs(documentID: string): Promise<Record<string, string> | null>;
|
|
64
|
+
updateFieldHLCs(docID: DocumentID, fieldHLCs: Record<string, string>): Promise<void>;
|
|
65
|
+
};
|
|
56
66
|
export declare class KubunDB<T extends AdapterTypes = AdapterTypes> {
|
|
57
67
|
#private;
|
|
58
68
|
constructor(params: DBParams<T>);
|
|
@@ -60,6 +70,7 @@ export declare class KubunDB<T extends AdapterTypes = AdapterTypes> {
|
|
|
60
70
|
get adapter(): Adapter;
|
|
61
71
|
get events(): EventEmitter<DBEvents>;
|
|
62
72
|
getDB<T extends Database>(): Promise<Kysely<T>>;
|
|
73
|
+
withTransaction<R>(fn: (db: WritableDB) => Promise<R>): Promise<R>;
|
|
63
74
|
getMigrations(): Migrations;
|
|
64
75
|
close(): Promise<void>;
|
|
65
76
|
listGraphs(): Promise<Array<GraphModel>>;
|
|
@@ -67,12 +78,27 @@ export declare class KubunDB<T extends AdapterTypes = AdapterTypes> {
|
|
|
67
78
|
getGraph(id: string): Promise<GraphModelWithRecord | null>;
|
|
68
79
|
getDocumentModel(id: DocumentModelID | string): Promise<DocumentModel>;
|
|
69
80
|
getDocument(id: DocumentID): Promise<DocumentNode | null>;
|
|
70
|
-
getDocumentState(id: string): Promise<Uint8Array | null>;
|
|
71
|
-
getDocumentStates(ids: Array<string>): Promise<Record<string, Uint8Array | null>>;
|
|
72
81
|
listDocuments(params: ListDocumentsParams): Promise<Array<DocumentNode>>;
|
|
82
|
+
countDocuments(params: CountDocumentsParams): Promise<number>;
|
|
73
83
|
queryDocuments(params: QueryDocumentsParams): Promise<QueryDocumentsResult>;
|
|
74
84
|
createDocument(params: CreateDocumentParams): Promise<DocumentNode>;
|
|
75
85
|
saveDocument(params: SaveDocumentParams): Promise<DocumentNode>;
|
|
86
|
+
insertMutationLogEntry(entry: InsertMutationLogEntry): Promise<void>;
|
|
87
|
+
hasMutationHash(hash: string): Promise<boolean>;
|
|
88
|
+
getMutationLogForDocuments(documentIDs: Array<string>): Promise<Array<MutationLogEntry>>;
|
|
89
|
+
getPendingMutations(documentID: string): Promise<Array<MutationLogEntry>>;
|
|
90
|
+
updateMutationStatus(mutationHash: string, status: string): Promise<void>;
|
|
91
|
+
getFieldHLCs(documentID: string): Promise<Record<string, string> | null>;
|
|
92
|
+
updateFieldHLCs(docID: DocumentID, fieldHLCs: Record<string, string>): Promise<void>;
|
|
93
|
+
getDocumentIDsForScope(scopes: Array<{
|
|
94
|
+
modelID: string;
|
|
95
|
+
ownerDID: string;
|
|
96
|
+
}>, excludedDocumentIDs?: Array<string>): Promise<Array<string>>;
|
|
97
|
+
getDocumentMetadataForSync(modelID: string, documentIDs: Array<string>): Promise<Array<{
|
|
98
|
+
id: string;
|
|
99
|
+
model: string;
|
|
100
|
+
owner: string;
|
|
101
|
+
}>>;
|
|
76
102
|
addAttachments(attachments: Array<InsertDocumentAttachment>): Promise<void>;
|
|
77
103
|
getUserModelAccessDefault(ownerDID: string, modelID: string, permissionType: 'read' | 'write'): Promise<{
|
|
78
104
|
level: string;
|
|
@@ -86,41 +112,8 @@ export declare class KubunDB<T extends AdapterTypes = AdapterTypes> {
|
|
|
86
112
|
allowedDIDs: Array<string> | null;
|
|
87
113
|
}): Promise<void>;
|
|
88
114
|
removeUserModelAccessDefaults(ownerDID: string, modelID: string, permissionTypes: Array<string>): Promise<void>;
|
|
89
|
-
storeMutationLog(entry: {
|
|
90
|
-
documentID: string;
|
|
91
|
-
sequenceNumber: string;
|
|
92
|
-
mutationJWT: string;
|
|
93
|
-
authorDID: string;
|
|
94
|
-
}): Promise<void>;
|
|
95
|
-
getMutationLog(documentID: string, fromSequence: number): Promise<Array<DocumentMutationLog>>;
|
|
96
115
|
listDocumentModelIDs(): Promise<Array<string>>;
|
|
97
116
|
queryDocumentsByOwner(modelID: string, ownerDID: string): Promise<Array<DocumentNode>>;
|
|
98
|
-
storeSyncCheckpoint(peerServerID: string, checkpointData: {
|
|
99
|
-
userID: string;
|
|
100
|
-
lastSyncTimestamp: number;
|
|
101
|
-
documentCheckpoints: Record<string, {
|
|
102
|
-
lastKnownHash: string;
|
|
103
|
-
lastSyncedSequence: number;
|
|
104
|
-
}>;
|
|
105
|
-
vectorClock: Record<string, number>;
|
|
106
|
-
}): Promise<boolean>;
|
|
107
|
-
getSyncCheckpoint(peerServerID: string, userID: string): Promise<{
|
|
108
|
-
lastSyncTimestamp: number;
|
|
109
|
-
documentCheckpoints: Record<string, {
|
|
110
|
-
lastKnownHash: string;
|
|
111
|
-
lastSyncedSequence: number;
|
|
112
|
-
}>;
|
|
113
|
-
vectorClock: Record<string, number>;
|
|
114
|
-
} | null>;
|
|
115
|
-
listSyncCheckpoints(peerServerID: string): Promise<Array<{
|
|
116
|
-
userID: string;
|
|
117
|
-
lastSyncTimestamp: number;
|
|
118
|
-
documentCheckpoints: Record<string, {
|
|
119
|
-
lastKnownHash: string;
|
|
120
|
-
lastSyncedSequence: number;
|
|
121
|
-
}>;
|
|
122
|
-
vectorClock: Record<string, number>;
|
|
123
|
-
}>>;
|
|
124
117
|
createSearchIndex(modelID: string, fields: Array<string>): Promise<void>;
|
|
125
118
|
dropSearchIndex(modelID: string): Promise<void>;
|
|
126
119
|
updateSearchEntry(modelID: string, documentID: string, data: Record<string, unknown>, fields: Array<string>): Promise<void>;
|
package/lib/db.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventEmitter as e}from"@enkaku/event";import{DocumentModelID as t}from"@kubun/id";import{getKubunLogger as a}from"@kubun/logger";import{Kysely as i,Migrator as s,ParseJSONResultsPlugin as r,sql as n}from"kysely";import{serializeCursor as d}from"./cursor.js";import{getMigrations as o}from"./migrations/migrations.js";import{applyDocumentFilter as l,applyDocumentOrderBy as c,applyPagination as u}from"./query-builder.js";function m(e){let t={version:e.version,name:e.name,behavior:e.behavior,interfaces:e.interfaces,schema:e.schema,fieldsMeta:e.fields_meta};return"unique"===t.behavior&&(t.uniqueFields=e.unique_fields),t}function h(e,t){return{id:t.id,model:t.model,owner:t.owner,data:t.data,createdAt:e.decodeTimestamp(t.created_at),updatedAt:t.updated_at?e.decodeTimestamp(t.updated_at):null}}function _(e,a){let i=t.fromString(a);return i.isLocal?i.toGlobal(t.fromString(e)).toString():a}export class KubunDB{#e;#t;#a=new e;#i;#s;constructor(e){this.#e=e.adapter,this.#t=new i({dialect:this.#e.dialect,plugins:[new r]}),this.#i=e.logger??a("db"),this.#s=this.#r()}get adapter(){return this.#e}get events(){return this.#a}getDB(){return this.#s.then(()=>this.#t)}async #r(){let e=new s({db:this.#t,provider:{getMigrations:()=>Promise.resolve(this.getMigrations())}}),t=await e.migrateToLatest();if(null!=t.error)throw t.error;this.#i.info("ready")}getMigrations(){return o(this.#e)}async close(){await this.#t.destroy(),this.#i.info("closed")}async listGraphs(){return await this.#s,await this.#t.selectFrom("kubun_graph_models").selectAll().execute()}async createGraph(e){await this.#s;let t=e.id??globalThis.crypto.randomUUID(),a=e.name??t;return await this.#t.transaction().setIsolationLevel("read committed").execute(async i=>{await i.insertInto("kubun_graph_models").values({aliases:JSON.stringify(e.aliases??{}),id:t,name:a,search:e.search?JSON.stringify(e.search):null}).onConflict(e=>e.doNothing()).execute();let s=Object.entries(e.record),r=new Set;for(;r.size<s.length;){let e=s.filter(([e,t])=>!r.has(e)&&t.interfaces.every(t=>r.has(_(e,t))));if(0===e.length)throw Error("Could not create graph: no valid model to add");await Promise.all(e.map(async([e,a])=>{await this.#n({id:e,graphModelID:t,model:a,transaction:i}),r.add(e)}))}}),this.#i.debug("created graph {id}",{id:t}),t}async #n(e){let{id:t,graphModelID:a,model:i,transaction:s}=e,r=this.#e.types;for(let e of(await this.#s,await s.schema.createTable(`k_${t}`).ifNotExists().addColumn("id",r.text,e=>e.notNull().primaryKey()).addColumn("owner",r.text,e=>e.notNull()).addColumn("model",r.text,e=>e.notNull()).addColumn("data",r.json).addColumn("unique",r.binary,e=>e.notNull()).addColumn("created_at",r.timestamp,e=>e.defaultTo(this.#e.functions.now).notNull()).addColumn("updated_at",r.timestamp).execute(),await s.insertInto("kubun_document_models").values({id:t,version:i.version,name:i.name,behavior:i.behavior,unique_fields:"unique"===i.behavior?JSON.stringify(i.uniqueFields):null,interfaces:JSON.stringify(i.interfaces),schema:JSON.stringify(i.schema),fields_meta:JSON.stringify(i.fieldsMeta)}).onConflict(e=>e.doNothing()).execute(),i.interfaces))await s.insertInto("kubun_document_model_interfaces").values({interface_id:_(t,e),implementation_id:t}).onConflict(e=>e.doNothing()).execute();await s.insertInto("kubun_graph_document_models").values({graph_model_id:a,document_model_id:t}).onConflict(e=>e.doNothing()).execute()}async getGraph(e){await this.#s;let t=await this.#t.selectFrom("kubun_graph_models").selectAll().where("id","=",e).executeTakeFirst();if(null==t)return null;let a={};for(let t of(await this.#t.selectFrom("kubun_graph_document_models").innerJoin("kubun_document_models","kubun_graph_document_models.document_model_id","kubun_document_models.id").selectAll("kubun_document_models").where("kubun_graph_document_models.graph_model_id","=",e).execute()))a[t.id]=m(t);return{...t,record:a}}async getDocumentModel(e){return await this.#s,m(await this.#t.selectFrom("kubun_document_models").selectAll().where("id","=",e.toString()).executeTakeFirstOrThrow())}async getDocument(e){await this.#s;let t=await this.#t.selectFrom(`k_${e.model.toString()}`).selectAll().where("id","=",e.toString()).executeTakeFirst();return t?h(this.#e,t):null}async getDocumentState(e){await this.#s;let t=await this.#t.selectFrom("kubun_document_states").selectAll().where("id","=",e).executeTakeFirst();return t?.data??null}async getDocumentStates(e){await this.#s;let t=await this.#t.selectFrom("kubun_document_states").selectAll().where("id","in",e).execute(),a={};for(let e of t)a[e.id]=e.data;return e.reduce((e,t)=>(e[t]=a[t]??null,e),{})}async listDocuments(e){await this.#s;let[t,...a]=e.modelIDs,i=this.#t.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs);for(let t of a)i=i.unionAll(a=>a.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs));return(await i.execute()).map(e=>h(this.#e,e))}async queryDocuments(e){let{filter:t,modelIDs:a,orderBy:i,owner:s,...r}=e,n=null!=e.last;await this.#s;let o=this.#e.coerceFilterValue.bind(this.#e),[m,..._]=a,w=this.#t.selectFrom(`k_${m}`).selectAll();for(let e of(null!=s&&(w=w.where("owner","=",s)),null!=t&&(w=w.where(e=>l(e,t,[],o))),_))w=w.unionAll(a=>{let i=a.selectFrom(`k_${e}`).selectAll();return null!=s&&(i=i.where("owner","=",s)),null!=t&&(i=i.where(e=>l(e,t,[],o))),i});let[p,y]=c(w,i,n),[b,g]=u(p,r,i),f=await b.execute(),k=n?f.slice(0,g).reverse():f.slice(0,g);return{entries:y?k.map(e=>{let t={};for(let a of y){let i=e.data;for(let e of a)null!=i&&(i=i[e]);null!=i&&(t[a.join(".")]=i)}return{cursor:d({id:e.id,values:t}),document:h(this.#e,e)}}):k.map(e=>({cursor:d({id:e.id,ts:+e.created_at}),document:h(this.#e,e)})),hasMore:k.length>g}}async createDocument(e){await this.#s;let t=e.id.toString(),a=e.id.model.toString(),i=await this.#t.transaction().setIsolationLevel("read committed").execute(async i=>{let s=await i.insertInto(`k_${a}`).values({id:t,owner:e.owner,model:a,data:this.#e.encodeJSON(e.data),unique:this.#e.encodeBinary(e.unique)}).returningAll().executeTakeFirst();return await i.insertInto("kubun_document_states").values({id:t,data:e.state?this.#e.encodeBinary(e.state):null}).execute(),s}),s=h(this.#e,i);return this.#a.emit("document:saved",{type:"create",document:s,getCursor:()=>d({id:i.id,ts:+i.created_at})}),this.#i.debug("created document {id} with model {model}",{id:t,model:a}),s}async saveDocument(e){await this.#s;let t=e.id.toString(),a=await this.#t.transaction().setIsolationLevel("read committed").execute(async a=>{let i=await a.updateTable(`k_${e.id.model.toString()}`).set({data:e.data?this.#e.encodeJSON(e.data):null,updated_at:this.#e.encodeTimestamp(new Date)}).where("id","=",t).returningAll().executeTakeFirst();return await a.updateTable("kubun_document_states").set({data:e.state?this.#e.encodeBinary(e.state):null}).where("id","=",t).execute(),i}),i=h(this.#e,a);return this.#a.emit("document:saved",{type:"update",document:i,previous:e.existing,getCursor:()=>d({id:a.id,ts:+a.created_at})}),this.#i.debug("updated document {id}",{id:t}),i}async addAttachments(e){await this.#s,await this.#t.insertInto("kubun_document_attachments").values(e).onConflict(e=>e.doNothing()).execute()}async getUserModelAccessDefault(e,t,a){await this.#s;let i=await this.#t.selectFrom("kubun_user_model_access_defaults").select(["access_level","allowed_dids"]).where("owner_did","=",e).where("model_id","=",t).where("permission_type","=",a).executeTakeFirst();return i?{level:i.access_level,allowedDIDs:i.allowed_dids}:null}async setUserModelAccessDefault(e){await this.#s,await this.#t.insertInto("kubun_user_model_access_defaults").values({owner_did:e.ownerDID,model_id:e.modelID,permission_type:e.permissionType,access_level:e.accessLevel,allowed_dids:e.allowedDIDs?this.#e.encodeJSON(e.allowedDIDs):null}).onConflict(t=>t.columns(["owner_did","model_id","permission_type"]).doUpdateSet({access_level:e.accessLevel,allowed_dids:e.allowedDIDs?this.#e.encodeJSON(e.allowedDIDs):null,updated_at:this.#e.encodeTimestamp(new Date)})).execute()}async removeUserModelAccessDefaults(e,t,a){await this.#s,await this.#t.deleteFrom("kubun_user_model_access_defaults").where("owner_did","=",e).where("model_id","=",t).where("permission_type","in",a).execute()}async storeMutationLog(e){await this.#s;let t=globalThis.crypto.randomUUID();await this.#t.insertInto("kubun_document_mutation_log").values({id:t,document_id:e.documentID,sequence_number:e.sequenceNumber,mutation_jwt:e.mutationJWT,author_did:e.authorDID,timestamp:Date.now()}).execute(),await this.#t.deleteFrom("kubun_document_mutation_log").where("document_id","=",e.documentID).where("id","not in",this.#t.selectFrom("kubun_document_mutation_log").select("id").where("document_id","=",e.documentID).orderBy(n`CAST(sequence_number AS INTEGER)`,"desc").limit(10)).execute()}async getMutationLog(e,t){return await this.#s,await this.#t.selectFrom("kubun_document_mutation_log").selectAll().where("document_id","=",e).where(n`CAST(sequence_number AS INTEGER)`,">=",t).orderBy(n`CAST(sequence_number AS INTEGER)`,"asc").execute()}async listDocumentModelIDs(){return await this.#s,(await this.#t.selectFrom("kubun_document_models").select("id").execute()).map(e=>e.id)}async queryDocumentsByOwner(e,t){return await this.#s,(await this.#t.selectFrom(`k_${e}`).selectAll().where("owner","=",t).execute()).map(e=>h(this.#e,e))}async storeSyncCheckpoint(e,t){await this.#s;let a=`${e}:${t.userID}`,i=JSON.stringify(t.documentCheckpoints),s=JSON.stringify(t.vectorClock);try{return await this.#t.insertInto("kubun_sync_checkpoints").values({id:a,peer_server_id:e,user_id:t.userID,last_sync_timestamp:t.lastSyncTimestamp,document_checkpoints:i,vector_clock:s}).onConflict(e=>e.column("id").doUpdateSet({last_sync_timestamp:t.lastSyncTimestamp,document_checkpoints:i,vector_clock:s})).execute(),!0}catch{return!1}}async getSyncCheckpoint(e,t){await this.#s;let a=`${e}:${t}`,i=await this.#t.selectFrom("kubun_sync_checkpoints").selectAll().where("id","=",a).executeTakeFirst();return i?{lastSyncTimestamp:i.last_sync_timestamp,documentCheckpoints:i.document_checkpoints,vectorClock:i.vector_clock}:null}async listSyncCheckpoints(e){return await this.#s,(await this.#t.selectFrom("kubun_sync_checkpoints").selectAll().where("peer_server_id","=",e).execute()).map(e=>({userID:e.user_id,lastSyncTimestamp:e.last_sync_timestamp,documentCheckpoints:e.document_checkpoints,vectorClock:e.vector_clock}))}async createSearchIndex(e,t){await this.#s,await this.#e.createSearchIndex(this.#t,{modelID:e,fields:t})}async dropSearchIndex(e){await this.#s,await this.#e.dropSearchIndex(this.#t,e)}async updateSearchEntry(e,t,a,i){await this.#s;let s={};for(let e of i){let t=this.#d(a,e);null!=t&&(s[e]=String(t))}await this.#e.updateSearchEntry(this.#t,e,t,s,i)}async removeSearchEntry(e,t){await this.#s,await this.#e.removeSearchEntry(this.#t,e,t)}async searchDocuments(e){await this.#s;let t=[];for(let a of e.modelIDs)for(let i of(await this.#e.searchIndex(this.#t,{query:e.query,modelID:a,limit:e.first??50})))t.push({documentID:i.documentID,modelID:a,rank:i.rank});return(t.sort((e,t)=>Math.abs(t.rank)-Math.abs(e.rank)),e.first)?t.slice(0,e.first):t}#d(e,t){let a=t.split("."),i=e;for(let e of a){if(null==i||"object"!=typeof i)return null;i=i[e]}return i}}
|
|
1
|
+
import{EventEmitter as e}from"@enkaku/event";import{DocumentID as t,DocumentModelID as a}from"@kubun/id";import{getKubunLogger as i}from"@kubun/logger";import{Kysely as r,Migrator as s,ParseJSONResultsPlugin as n}from"kysely";import{serializeCursor as d}from"./cursor.js";import{getMigrations as o}from"./migrations/migrations.js";import{applyDocumentFilter as l,applyDocumentOrderBy as u,applyPagination as c}from"./query-builder.js";function h(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 m(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 w(e,t){let i=a.fromString(t);return i.isLocal?i.toGlobal(a.fromString(e)).toString():t}export class KubunDB{#e;#t;#a;#i;#r;constructor(t){this.#e=t.adapter,this.#t=new r({dialect:this.#e.dialect,plugins:[new n]}),this.#a=new e,this.#i=t.logger??i("db"),this.#r=this.#s()}get adapter(){return this.#e}get events(){return this.#a}getDB(){return this.#r.then(()=>this.#t)}async withTransaction(e){await this.#r;let a=this.#e,i=this.#a,r=[],s=await this.#t.transaction().setIsolationLevel("read committed").execute(async s=>await e({events:i,getDocumentModel:async e=>h(await s.selectFrom("kubun_document_models").selectAll().where("id","=",e.toString()).executeTakeFirstOrThrow()),async getDocument(e){let t=await s.selectFrom(`k_${e.model.toString()}`).selectAll().where("id","=",e.toString()).executeTakeFirst();return t?m(a,t):null},async createDocument(e){let t=e.id.toString(),i=e.id.model.toString(),n=await s.insertInto(`k_${i}`).values({id:t,owner:e.owner,model:i,data:a.encodeJSON(e.data),unique:a.encodeBinary(e.unique)}).returningAll().executeTakeFirst(),o=m(a,n);return r.push({type:"create",document:o,getCursor:()=>d({id:n.id,ts:+n.created_at})}),o},async saveDocument(e){let t=e.id.toString(),i=await s.updateTable(`k_${e.id.model.toString()}`).set({data:e.data?a.encodeJSON(e.data):null,updated_at:a.encodeTimestamp(new Date)}).where("id","=",t).returningAll().executeTakeFirst(),n=m(a,i);return r.push({type:"update",document:n,previous:e.existing,getCursor:()=>d({id:i.id,ts:+i.created_at})}),n},async insertMutationLogEntry(e){await s.insertInto("kubun_mutation_log").values(e).onConflict(e=>e.doNothing()).execute()},hasMutationHash:async e=>null!=await s.selectFrom("kubun_mutation_log").select("mutation_hash").where("mutation_hash","=",e).executeTakeFirst(),async updateMutationStatus(e,t){await s.updateTable("kubun_mutation_log").set({status:t}).where("mutation_hash","=",e).execute()},async getFieldHLCs(e){let a=t.fromString(e).model.toString(),i=await s.selectFrom(`k_${a}`).select("field_hlcs").where("id","=",e).executeTakeFirst();if(i?.field_hlcs==null)return null;let r=i.field_hlcs;return"string"==typeof r?JSON.parse(r):r},async updateFieldHLCs(e,t){let i=e.model.toString();await s.updateTable(`k_${i}`).set({field_hlcs:a.encodeJSON(t)}).where("id","=",e.toString()).execute()}}));for(let e of r)i.emit("document:saved",e);return s}async #s(){let e=new s({db:this.#t,provider:{getMigrations:()=>Promise.resolve(this.getMigrations())}}),t=await e.migrateToLatest();if(null!=t.error)throw t.error;this.#i.info("ready")}getMigrations(){return o(this.#e)}async close(){await this.#r,await this.#t.destroy(),this.#i.info("closed")}async listGraphs(){return await this.#r,await this.#t.selectFrom("kubun_graph_models").selectAll().execute()}async createGraph(e){await this.#r;let t=e.id??globalThis.crypto.randomUUID(),a=e.name??t;return await this.#t.transaction().setIsolationLevel("read committed").execute(async i=>{await i.insertInto("kubun_graph_models").values({aliases:JSON.stringify(e.aliases??{}),id:t,name:a,search:e.search?JSON.stringify(e.search):null}).onConflict(e=>e.doNothing()).execute();let r=Object.entries(e.record),s=new Set;for(;s.size<r.length;){let e=r.filter(([e,t])=>!s.has(e)&&t.interfaces.every(t=>s.has(w(e,t))));if(0===e.length)throw Error("Could not create graph: no valid model to add");await Promise.all(e.map(async([e,a])=>{await this.#n(i,{id:e,graphModelID:t,model:a}),s.add(e)}))}}),this.#i.debug("created graph {id}",{id:t}),t}async #n(e,t){let{id:a,graphModelID:i,model:r}=t,s=this.#e.types;for(let t of(await this.#r,await e.schema.createTable(`k_${a}`).ifNotExists().addColumn("id",s.text,e=>e.notNull().primaryKey()).addColumn("owner",s.text,e=>e.notNull()).addColumn("model",s.text,e=>e.notNull()).addColumn("data",s.json).addColumn("field_hlcs",s.json).addColumn("unique",s.binary,e=>e.notNull()).addColumn("created_at",s.timestamp,e=>e.defaultTo(this.#e.functions.now).notNull()).addColumn("updated_at",s.timestamp).execute(),await e.insertInto("kubun_document_models").values({id:a,version:r.version,name:r.name,behavior:r.behavior,unique_fields:"unique"===r.behavior?JSON.stringify(r.uniqueFields):null,interfaces:JSON.stringify(r.interfaces),schema:JSON.stringify(r.schema),fields_meta:JSON.stringify(r.fieldsMeta)}).onConflict(e=>e.doNothing()).execute(),r.interfaces))await e.insertInto("kubun_document_model_interfaces").values({interface_id:w(a,t),implementation_id:a}).onConflict(e=>e.doNothing()).execute();await e.insertInto("kubun_graph_document_models").values({graph_model_id:i,document_model_id:a}).onConflict(e=>e.doNothing()).execute()}async getGraph(e){await this.#r;let t=await this.#t.selectFrom("kubun_graph_models").selectAll().where("id","=",e).executeTakeFirst();if(null==t)return null;let a={};for(let t of(await this.#t.selectFrom("kubun_graph_document_models").innerJoin("kubun_document_models","kubun_graph_document_models.document_model_id","kubun_document_models.id").selectAll("kubun_document_models").where("kubun_graph_document_models.graph_model_id","=",e).execute()))a[t.id]=h(t);return{...t,record:a}}async getDocumentModel(e){return await this.#r,h(await this.#t.selectFrom("kubun_document_models").selectAll().where("id","=",e.toString()).executeTakeFirstOrThrow())}async getDocument(e){await this.#r;let t=await this.#t.selectFrom(`k_${e.model.toString()}`).selectAll().where("id","=",e.toString()).executeTakeFirst();return t?m(this.#e,t):null}async listDocuments(e){await this.#r;let[t,...a]=e.modelIDs,i=this.#t.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs);for(let t of a)i=i.unionAll(a=>a.selectFrom(`k_${t}`).selectAll().where("id","in",e.docIDs));return(await i.execute()).map(e=>m(this.#e,e))}async countDocuments(e){let{filter:t,modelIDs:a,owner:i}=e;await this.#r;let r=this.#e.coerceFilterValue.bind(this.#e);return(await Promise.all(a.map(async e=>{let a=this.#t.selectFrom(`k_${e}`).select(e=>e.fn.countAll().as("count"));return null!=i&&(a=a.where("owner","=",i)),null!=t&&(a=a.where(e=>l(e,t,[],r))),Number((await a.executeTakeFirstOrThrow()).count)}))).reduce((e,t)=>e+t,0)}async queryDocuments(e){let{filter:t,modelIDs:a,orderBy:i,owner:r,...s}=e,n=null!=e.last;await this.#r;let o=this.#e.coerceFilterValue.bind(this.#e),[h,...w]=a,_=this.#t.selectFrom(`k_${h}`).selectAll();for(let e of(null!=r&&(_=_.where("owner","=",r)),null!=t&&(_=_.where(e=>l(e,t,[],o))),w))_=_.unionAll(a=>{let i=a.selectFrom(`k_${e}`).selectAll();return null!=r&&(i=i.where("owner","=",r)),null!=t&&(i=i.where(e=>l(e,t,[],o))),i});let[p,y]=u(_,i,n),[g,f]=c(p,s,i),b=await g.execute(),k=n?b.slice(0,f).reverse():b.slice(0,f);return{entries:y?k.map(e=>{let t={};for(let a of y){let i=e.data;for(let e of a)null!=i&&(i=i[e]);null!=i&&(t[a.join(".")]=i)}return{cursor:d({id:e.id,values:t}),document:m(this.#e,e)}}):k.map(e=>({cursor:d({id:e.id,ts:+e.created_at}),document:m(this.#e,e)})),hasMore:k.length>f}}async createDocument(e){await this.#r;let t=e.id.toString(),a=e.id.model.toString(),i={id:t,owner:e.owner,model:a,data:this.#e.encodeJSON(e.data),unique:this.#e.encodeBinary(e.unique)},r=await this.#t.transaction().setIsolationLevel("read committed").execute(async e=>await e.insertInto(`k_${a}`).values(i).returningAll().executeTakeFirst()),s=m(this.#e,r);return this.#a.emit("document:saved",{type:"create",document:s,getCursor:()=>d({id:r.id,ts:+r.created_at})}),this.#i.debug("created document {id} with model {model}",{id:t,model:a}),s}async saveDocument(e){await this.#r;let t=e.id.toString(),a={data:e.data?this.#e.encodeJSON(e.data):null,updated_at:this.#e.encodeTimestamp(new Date)},i=await this.#t.transaction().setIsolationLevel("read committed").execute(async i=>await i.updateTable(`k_${e.id.model.toString()}`).set(a).where("id","=",t).returningAll().executeTakeFirst()),r=m(this.#e,i);return this.#a.emit("document:saved",{type:"update",document:r,previous:e.existing,getCursor:()=>d({id:i.id,ts:+i.created_at})}),this.#i.debug("updated document {id}",{id:t}),r}async insertMutationLogEntry(e){await this.#r,await this.#t.insertInto("kubun_mutation_log").values(e).onConflict(e=>e.doNothing()).execute()}async hasMutationHash(e){return await this.#r,null!=await this.#t.selectFrom("kubun_mutation_log").select("mutation_hash").where("mutation_hash","=",e).executeTakeFirst()}async getMutationLogForDocuments(e){return 0===e.length?[]:(await this.#r,await this.#t.selectFrom("kubun_mutation_log").selectAll().where("document_id","in",e).orderBy("hlc","asc").execute())}async getPendingMutations(e){return await this.#r,await this.#t.selectFrom("kubun_mutation_log").selectAll().where("document_id","=",e).where("status","=","pending").orderBy("hlc","asc").execute()}async updateMutationStatus(e,t){await this.#r,await this.#t.updateTable("kubun_mutation_log").set({status:t}).where("mutation_hash","=",e).execute()}async getFieldHLCs(e){await this.#r;let a=t.fromString(e).model.toString(),i=await this.#t.selectFrom(`k_${a}`).select("field_hlcs").where("id","=",e).executeTakeFirst();if(i?.field_hlcs==null)return null;let r=i.field_hlcs;return"string"==typeof r?JSON.parse(r):r}async updateFieldHLCs(e,t){await this.#r;let a=e.model.toString();await this.#t.updateTable(`k_${a}`).set({field_hlcs:this.#e.encodeJSON(t)}).where("id","=",e.toString()).execute()}async getDocumentIDsForScope(e,t=[]){await this.#r;let a=[];for(let t of e)try{let e=await this.#t.selectFrom(`k_${t.modelID}`).select("id").where("owner","=",t.ownerDID).execute();a.push(...e.map(e=>e.id))}catch{}if(t.length>0){let e=new Set(t);return a.filter(t=>!e.has(t))}return a}async getDocumentMetadataForSync(e,t){return 0===t.length?[]:(await this.#r,(await this.#t.selectFrom(`k_${e}`).select(["id","model","owner"]).where("id","in",t).execute()).map(e=>({id:e.id,model:e.model,owner:e.owner})))}async addAttachments(e){await this.#r,await this.#t.insertInto("kubun_document_attachments").values(e).onConflict(e=>e.doNothing()).execute()}async getUserModelAccessDefault(e,t,a){await this.#r;let i=await this.#t.selectFrom("kubun_user_model_access_defaults").select(["access_level","allowed_dids"]).where("owner_did","=",e).where("model_id","=",t).where("permission_type","=",a).executeTakeFirst();return i?{level:i.access_level,allowedDIDs:i.allowed_dids}:null}async setUserModelAccessDefault(e){await this.#r,await this.#t.insertInto("kubun_user_model_access_defaults").values({owner_did:e.ownerDID,model_id:e.modelID,permission_type:e.permissionType,access_level:e.accessLevel,allowed_dids:e.allowedDIDs?this.#e.encodeJSON(e.allowedDIDs):null}).onConflict(t=>t.columns(["owner_did","model_id","permission_type"]).doUpdateSet({access_level:e.accessLevel,allowed_dids:e.allowedDIDs?this.#e.encodeJSON(e.allowedDIDs):null,updated_at:this.#e.encodeTimestamp(new Date)})).execute()}async removeUserModelAccessDefaults(e,t,a){await this.#r,await this.#t.deleteFrom("kubun_user_model_access_defaults").where("owner_did","=",e).where("model_id","=",t).where("permission_type","in",a).execute()}async listDocumentModelIDs(){return await this.#r,(await this.#t.selectFrom("kubun_document_models").select("id").execute()).map(e=>e.id)}async queryDocumentsByOwner(e,t){return await this.#r,(await this.#t.selectFrom(`k_${e}`).selectAll().where("owner","=",t).execute()).map(e=>m(this.#e,e))}async createSearchIndex(e,t){await this.#r,await this.#e.createSearchIndex(this.#t,{modelID:e,fields:t})}async dropSearchIndex(e){await this.#r,await this.#e.dropSearchIndex(this.#t,e)}async updateSearchEntry(e,t,a,i){await this.#r;let r={};for(let e of i){let t=this.#d(a,e);null!=t&&(r[e]=String(t))}await this.#e.updateSearchEntry(this.#t,e,t,r,i)}async removeSearchEntry(e,t){await this.#r,await this.#e.removeSearchEntry(this.#t,e,t)}async searchDocuments(e){await this.#r;let t=[];for(let a of e.modelIDs)for(let i of(await this.#e.searchIndex(this.#t,{query:e.query,modelID:a,limit:e.first??50})))t.push({documentID:i.documentID,modelID:a,rank:i.rank});return(t.sort((e,t)=>Math.abs(t.rank)-Math.abs(e.rank)),e.first)?t.slice(0,e.first):t}#d(e,t){let a=t.split("."),i=e;for(let e of a){if(null==i||"object"!=typeof i)return null;i=i[e]}return i}}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { CreateGraphParams, DBEvents, DBParams, DocumentCreatedEvent, DocumentSavedEvent, GraphModelWithRecord, Migrations, } from './db.js';
|
|
1
|
+
export type { CreateGraphParams, DBEvents, DBParams, DocumentCreatedEvent, DocumentSavedEvent, GraphModelWithRecord, Migrations, WritableDB, } from './db.js';
|
|
2
2
|
export { KubunDB } from './db.js';
|
|
3
3
|
export type * from './types.js';
|
package/lib/migrations/0-init.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export function getMigration(e){let t=e.types;return{up:async function(a){await a.schema.createTable("kubun_document_attachments").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("data",t.binary,e=>e.notNull()).addColumn("created_at",t.timestamp,t=>t.defaultTo(e.functions.now).notNull()).execute(),await a.schema.createTable("kubun_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,t=>t.defaultTo(e.functions.now).notNull()).execute(),await a.schema.createTable("kubun_document_model_interfaces").ifNotExists().addColumn("interface_id",t.text,e=>e.notNull().references("kubun_document_models.id")).addColumn("implementation_id",t.text,e=>e.notNull().references("kubun_document_models.id")).addUniqueConstraint("kubun_document_model_interfaces_pkey",["interface_id","implementation_id"]).execute(),await a.schema.createTable("
|
|
1
|
+
export function getMigration(e){let t=e.types;return{up:async function(a){await a.schema.createTable("kubun_document_attachments").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("data",t.binary,e=>e.notNull()).addColumn("created_at",t.timestamp,t=>t.defaultTo(e.functions.now).notNull()).execute(),await a.schema.createTable("kubun_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,t=>t.defaultTo(e.functions.now).notNull()).execute(),await a.schema.createTable("kubun_document_model_interfaces").ifNotExists().addColumn("interface_id",t.text,e=>e.notNull().references("kubun_document_models.id")).addColumn("implementation_id",t.text,e=>e.notNull().references("kubun_document_models.id")).addUniqueConstraint("kubun_document_model_interfaces_pkey",["interface_id","implementation_id"]).execute(),await a.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("created_at",t.timestamp,t=>t.defaultTo(e.functions.now).notNull()).addColumn("updated_at",t.timestamp).execute(),await a.schema.createTable("kubun_graph_document_models").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_document_models.id")).addUniqueConstraint("kubun_graph_document_models_pkey",["graph_model_id","document_model_id"]).execute(),await a.schema.createTable("kubun_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,t=>t.defaultTo(e.functions.now).notNull()).addColumn("updated_at",t.timestamp).addPrimaryKeyConstraint("kubun_user_model_access_defaults_pkey",["owner_did","model_id","permission_type"]).execute(),await a.schema.createIndex("idx_user_model_access_owner_model").on("kubun_user_model_access_defaults").columns(["owner_did","model_id"]).execute(),await a.schema.createTable("kubun_sync_checkpoints").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("peer_server_id",t.text,e=>e.notNull()).addColumn("user_id",t.text,e=>e.notNull()).addColumn("last_sync_timestamp",t.timestamp,e=>e.notNull()).addColumn("document_checkpoints",t.json,e=>e.notNull()).addColumn("vector_clock",t.json,e=>e.notNull()).execute(),await a.schema.createIndex("idx_sync_checkpoints_peer_user").on("kubun_sync_checkpoints").columns(["peer_server_id","user_id"]).execute(),await a.schema.createTable("kubun_sync_peers").ifNotExists().addColumn("id",t.text,e=>e.notNull().primaryKey()).addColumn("peer_did",t.text,e=>e.notNull().unique()).addColumn("endpoint",t.text,e=>e.notNull()).addColumn("mode",t.text,e=>e.notNull()).addColumn("allowed_users",t.json,e=>e.notNull()).addColumn("priority",t.text,e=>e.notNull().defaultTo("0")).addColumn("trust_level",t.text,e=>e.notNull()).addColumn("config",t.json,e=>e.notNull()).addColumn("created_at",t.timestamp,t=>t.defaultTo(e.functions.now).notNull()).addColumn("updated_at",t.timestamp,t=>t.defaultTo(e.functions.now).notNull()).execute(),await a.schema.createTable("kubun_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 a.schema.createIndex("idx_mutation_log_hlc").on("kubun_mutation_log").column("hlc").execute(),await a.schema.createIndex("idx_mutation_log_document").on("kubun_mutation_log").column("document_id").execute(),await a.schema.createIndex("idx_mutation_log_status").on("kubun_mutation_log").column("status").execute()},down:async function(e){await e.schema.dropTable("kubun_mutation_log").ifExists().execute(),await e.schema.dropTable("kubun_sync_peers").ifExists().execute(),await e.schema.dropTable("kubun_sync_checkpoints").ifExists().execute(),await e.schema.dropTable("kubun_user_model_access_defaults").ifExists().execute(),await e.schema.dropTable("kubun_graph_document_models").ifExists().execute(),await e.schema.dropTable("kubun_graph_models").ifExists().execute(),await e.schema.dropTable("kubun_document_model_interfaces").ifExists().execute(),await e.schema.dropTable("kubun_document_models").ifExists().execute(),await e.schema.dropTable("kubun_document_attachments").ifExists().execute()}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getMigration as i}from"./0-init.js";
|
|
1
|
+
import{getMigration as i}from"./0-init.js";export function getMigrations(t){return{kubunMigration0:i(t)}}
|
package/lib/types.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type DocumentTable<Data extends DocumentData = DocumentData> = {
|
|
|
14
14
|
owner: string;
|
|
15
15
|
model: string;
|
|
16
16
|
data: JSONColumnType<Data> | null;
|
|
17
|
+
field_hlcs: JSONColumnType<Record<string, string>> | null;
|
|
17
18
|
unique: Uint8Array;
|
|
18
19
|
created_at: CreatedAtColumn;
|
|
19
20
|
updated_at: UpdatedAtColumn;
|
|
@@ -49,12 +50,17 @@ export type DocumentModelInterfaceTable = {
|
|
|
49
50
|
};
|
|
50
51
|
export type DocumentModelInterface = Selectable<DocumentModelInterfaceTable>;
|
|
51
52
|
export type InsertDocumentModelInterface = Insertable<DocumentModelInterfaceTable>;
|
|
52
|
-
export type
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
export type MutationLogTable = {
|
|
54
|
+
mutation_hash: string;
|
|
55
|
+
model_id: string;
|
|
56
|
+
document_id: string;
|
|
57
|
+
author_did: string;
|
|
58
|
+
hlc: string;
|
|
59
|
+
mutation_jwt: string;
|
|
60
|
+
status: string;
|
|
55
61
|
};
|
|
56
|
-
export type
|
|
57
|
-
export type
|
|
62
|
+
export type MutationLogEntry = Selectable<MutationLogTable>;
|
|
63
|
+
export type InsertMutationLogEntry = Insertable<MutationLogTable>;
|
|
58
64
|
export type SearchConfig = Record<string, {
|
|
59
65
|
fields?: Array<string>;
|
|
60
66
|
}>;
|
|
@@ -98,16 +104,6 @@ export type UserModelAccessDefaultTable = {
|
|
|
98
104
|
export type UserModelAccessDefault = Selectable<UserModelAccessDefaultTable>;
|
|
99
105
|
export type InsertUserModelAccessDefault = Insertable<UserModelAccessDefaultTable>;
|
|
100
106
|
export type UpdateUserModelAccessDefault = Updateable<UserModelAccessDefaultTable>;
|
|
101
|
-
export type DocumentMutationLogTable = {
|
|
102
|
-
id: string;
|
|
103
|
-
document_id: string;
|
|
104
|
-
sequence_number: string;
|
|
105
|
-
mutation_jwt: string;
|
|
106
|
-
timestamp: CreatedAtColumn;
|
|
107
|
-
author_did: string;
|
|
108
|
-
};
|
|
109
|
-
export type DocumentMutationLog = Selectable<DocumentMutationLogTable>;
|
|
110
|
-
export type InsertDocumentMutationLog = Insertable<DocumentMutationLogTable>;
|
|
111
107
|
export type SyncCheckpointTable = {
|
|
112
108
|
id: string;
|
|
113
109
|
peer_server_id: string;
|
|
@@ -154,11 +150,10 @@ export type Database = {
|
|
|
154
150
|
kubun_document_attachments: DocumentAttachmentTable;
|
|
155
151
|
kubun_document_models: DocumentModelTable;
|
|
156
152
|
kubun_document_model_interfaces: DocumentModelInterfaceTable;
|
|
157
|
-
|
|
153
|
+
kubun_mutation_log: MutationLogTable;
|
|
158
154
|
kubun_graph_document_models: GraphDocumentModelTable;
|
|
159
155
|
kubun_graph_models: GraphModelTable;
|
|
160
156
|
kubun_user_model_access_defaults: UserModelAccessDefaultTable;
|
|
161
|
-
kubun_document_mutation_log: DocumentMutationLogTable;
|
|
162
157
|
kubun_sync_checkpoints: SyncCheckpointTable;
|
|
163
158
|
kubun_sync_peers: SyncPeerTable;
|
|
164
159
|
[key: `k_${string}`]: DocumentTable;
|
|
@@ -177,6 +172,11 @@ export type QueryDocumentsParams = ConnectionArguments & {
|
|
|
177
172
|
orderBy?: DocumentOrderBy;
|
|
178
173
|
owner?: string;
|
|
179
174
|
};
|
|
175
|
+
export type CountDocumentsParams = {
|
|
176
|
+
modelIDs: Array<string>;
|
|
177
|
+
filter?: DocumentFilter;
|
|
178
|
+
owner?: string;
|
|
179
|
+
};
|
|
180
180
|
export type QueryDocumentsResult = {
|
|
181
181
|
entries: Array<CursorDocument>;
|
|
182
182
|
hasMore: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubun/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"license": "see LICENSE.md",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"type": "module",
|
|
@@ -18,15 +18,15 @@
|
|
|
18
18
|
"@enkaku/codec": "^0.13.0",
|
|
19
19
|
"@enkaku/event": "^0.13.0",
|
|
20
20
|
"kysely": "^0.28.11",
|
|
21
|
-
"@kubun/logger": "^0.
|
|
21
|
+
"@kubun/logger": "^0.6.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@
|
|
25
|
-
"@kubun/
|
|
26
|
-
"@kubun/db-adapter": "^0.
|
|
27
|
-
"@kubun/db-
|
|
28
|
-
"@kubun/
|
|
29
|
-
"@kubun/db-
|
|
24
|
+
"@testcontainers/postgresql": "^11.12.0",
|
|
25
|
+
"@kubun/id": "^0.6.0",
|
|
26
|
+
"@kubun/db-adapter": "^0.6.0",
|
|
27
|
+
"@kubun/db-better-sqlite": "^0.6.0",
|
|
28
|
+
"@kubun/protocol": "^0.6.0",
|
|
29
|
+
"@kubun/db-postgres": "^0.6.0"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build:clean": "del lib",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export function getMigration(e){let d=e.types;return{up:async function(t){await t.schema.createTable("kubun_user_model_access_defaults").ifNotExists().addColumn("owner_did",d.text,e=>e.notNull()).addColumn("model_id",d.text,e=>e.notNull()).addColumn("permission_type",d.text,e=>e.notNull()).addColumn("access_level",d.text,e=>e.notNull()).addColumn("allowed_dids",d.json).addColumn("created_at",d.timestamp,d=>d.defaultTo(e.functions.now).notNull()).addColumn("updated_at",d.timestamp).addPrimaryKeyConstraint("kubun_user_model_access_defaults_pkey",["owner_did","model_id","permission_type"]).execute(),await t.schema.createIndex("idx_user_model_access_owner_model").on("kubun_user_model_access_defaults").columns(["owner_did","model_id"]).execute()},down:async function(e){await e.schema.dropIndex("idx_user_model_access_owner_model").execute(),await e.schema.dropTable("kubun_user_model_access_defaults").execute()}}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export function getMigration(t){let e=t.types;return{up:async function(n){await n.schema.createTable("kubun_document_mutation_log").ifNotExists().addColumn("id",e.text,t=>t.notNull().primaryKey()).addColumn("document_id",e.text,t=>t.notNull()).addColumn("sequence_number",e.text,t=>t.notNull()).addColumn("mutation_jwt",e.text,t=>t.notNull()).addColumn("timestamp",e.timestamp,e=>e.defaultTo(t.functions.now).notNull()).addColumn("author_did",e.text,t=>t.notNull()).execute(),await n.schema.createIndex("idx_mutation_log_doc_seq").on("kubun_document_mutation_log").columns(["document_id","sequence_number"]).execute(),await n.schema.createTable("kubun_sync_checkpoints").ifNotExists().addColumn("id",e.text,t=>t.notNull().primaryKey()).addColumn("peer_server_id",e.text,t=>t.notNull()).addColumn("user_id",e.text,t=>t.notNull()).addColumn("last_sync_timestamp",e.timestamp,t=>t.notNull()).addColumn("document_checkpoints",e.json,t=>t.notNull()).addColumn("vector_clock",e.json,t=>t.notNull()).execute(),await n.schema.createIndex("idx_sync_checkpoints_peer_user").on("kubun_sync_checkpoints").columns(["peer_server_id","user_id"]).execute(),await n.schema.createTable("kubun_sync_peers").ifNotExists().addColumn("id",e.text,t=>t.notNull().primaryKey()).addColumn("peer_did",e.text,t=>t.notNull().unique()).addColumn("endpoint",e.text,t=>t.notNull()).addColumn("mode",e.text,t=>t.notNull()).addColumn("allowed_users",e.json,t=>t.notNull()).addColumn("priority",e.text,t=>t.notNull().defaultTo("0")).addColumn("trust_level",e.text,t=>t.notNull()).addColumn("config",e.json,t=>t.notNull()).addColumn("created_at",e.timestamp,e=>e.defaultTo(t.functions.now).notNull()).addColumn("updated_at",e.timestamp,e=>e.defaultTo(t.functions.now).notNull()).execute()},down:async function(t){await t.schema.dropTable("kubun_sync_peers").ifExists().execute(),await t.schema.dropTable("kubun_sync_checkpoints").ifExists().execute(),await t.schema.dropIndex("idx_sync_checkpoints_peer_user").ifExists().execute(),await t.schema.dropIndex("idx_mutation_log_doc_seq").ifExists().execute(),await t.schema.dropTable("kubun_document_mutation_log").ifExists().execute()}}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export function getMigration(e){return{up:async function(a){await a.schema.alterTable("kubun_graph_models").addColumn("search",e.types.json).execute()},down:async function(e){await e.schema.alterTable("kubun_graph_models").dropColumn("search").execute()}}}
|