document-drive 1.28.2 → 1.28.4

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.
@@ -3,58 +3,59 @@ import { mergeOperations } from "#utils/misc";
3
3
  export class MemoryStorage {
4
4
  documents;
5
5
  drives;
6
+ driveManifests;
6
7
  slugToDriveId = {};
7
8
  constructor() {
8
9
  this.documents = {};
9
10
  this.drives = {};
11
+ this.driveManifests = {};
10
12
  }
11
- exists(id) {
12
- for (const drive of Object.values(this.documents)) {
13
- if (drive[id]) {
14
- return Promise.resolve(true);
15
- }
16
- }
17
- return Promise.resolve(false);
13
+ ////////////////////////////////
14
+ // IDocumentStorage
15
+ ////////////////////////////////
16
+ exists(documentId) {
17
+ return Promise.resolve(!!this.documents[documentId]);
18
+ }
19
+ create(documentId, document) {
20
+ this.documents[documentId] = document;
21
+ return Promise.resolve();
18
22
  }
23
+ ////////////////////////////////
24
+ // IDriveStorage
25
+ ////////////////////////////////
19
26
  checkDocumentExists(drive, id) {
20
27
  return this.exists(id);
21
28
  }
22
- async getDocuments(drive) {
23
- return Object.keys(this.documents[drive] ?? {});
29
+ getDocuments(drive) {
30
+ const manifest = this.getDriveManifest(drive);
31
+ return Promise.resolve([...manifest.documentIds]);
24
32
  }
25
33
  async getDocument(driveId, id) {
26
- const drive = this.documents[driveId];
27
- if (!drive) {
28
- throw new DriveNotFoundError(driveId);
29
- }
30
- const document = drive[id];
34
+ const document = this.documents[id];
31
35
  if (!document) {
32
36
  throw new Error(`Document with id ${id} not found`);
33
37
  }
34
38
  return document;
35
39
  }
36
40
  async saveDocument(drive, id, document) {
37
- this.documents[drive] = this.documents[drive] ?? {};
38
- this.documents[drive][id] = document;
41
+ this.documents[id] = document;
42
+ // Update the drive manifest
43
+ const manifest = this.getDriveManifest(drive);
44
+ manifest.documentIds.add(id);
45
+ this.updateDriveManifest(drive, manifest);
39
46
  }
40
47
  async clearStorage() {
41
48
  this.documents = {};
42
49
  this.drives = {};
50
+ this.driveManifests = {};
51
+ this.slugToDriveId = {};
43
52
  }
44
53
  async createDocument(drive, id, document) {
45
- this.documents[drive] = this.documents[drive] ?? {};
46
- const { operations, initialState, name, revision, documentType, created, lastModified, clipboard, state, } = document;
47
- this.documents[drive][id] = {
48
- operations,
49
- initialState,
50
- name,
51
- revision,
52
- documentType,
53
- created,
54
- lastModified,
55
- clipboard,
56
- state,
57
- };
54
+ await this.create(id, document);
55
+ // Update the drive manifest
56
+ const manifest = this.getDriveManifest(drive);
57
+ manifest.documentIds.add(id);
58
+ this.updateDriveManifest(drive, manifest);
58
59
  }
59
60
  async addDocumentOperations(drive, id, operations, header) {
60
61
  const document = await this.getDocument(drive, id);
@@ -62,17 +63,23 @@ export class MemoryStorage {
62
63
  throw new Error(`Document with id ${id} not found`);
63
64
  }
64
65
  const mergedOperations = mergeOperations(document.operations, operations);
65
- this.documents[drive][id] = {
66
+ this.documents[id] = {
66
67
  ...document,
67
68
  ...header,
68
69
  operations: mergedOperations,
69
70
  };
70
71
  }
71
72
  async deleteDocument(drive, id) {
72
- if (!this.documents[drive]) {
73
- throw new DriveNotFoundError(drive);
73
+ // delete the document from all drive manifests
74
+ const drives = await this.getDrives();
75
+ for (const driveId of drives) {
76
+ const manifest = this.getDriveManifest(driveId);
77
+ if (manifest.documentIds.has(id)) {
78
+ manifest.documentIds.delete(id);
79
+ this.updateDriveManifest(driveId, manifest);
80
+ }
74
81
  }
75
- delete this.documents[drive][id];
82
+ delete this.documents[id];
76
83
  }
77
84
  async getDrives() {
78
85
  return Object.keys(this.drives);
@@ -93,7 +100,8 @@ export class MemoryStorage {
93
100
  }
94
101
  async createDrive(id, drive) {
95
102
  this.drives[id] = drive;
96
- this.documents[id] = {};
103
+ // Initialize an empty manifest for the new drive
104
+ this.updateDriveManifest(id, { documentIds: new Set() });
97
105
  const { slug } = drive.initialState.state.global;
98
106
  if (slug) {
99
107
  this.slugToDriveId[slug] = id;
@@ -109,8 +117,31 @@ export class MemoryStorage {
109
117
  };
110
118
  }
111
119
  async deleteDrive(id) {
112
- delete this.documents[id];
120
+ // Get all documents in this drive
121
+ const manifest = this.getDriveManifest(id);
122
+ // delete each document that belongs only to this drive
123
+ const drives = await this.getDrives();
124
+ await Promise.all([...manifest.documentIds].map((docId) => {
125
+ for (const driveId of drives) {
126
+ if (driveId === id) {
127
+ continue;
128
+ }
129
+ const manifest = this.getDriveManifest(driveId);
130
+ if (manifest.documentIds.has(docId)) {
131
+ return;
132
+ }
133
+ }
134
+ delete this.documents[docId];
135
+ }));
136
+ // Delete the drive manifest and the drive itself
137
+ delete this.driveManifests[id];
113
138
  delete this.drives[id];
139
+ // Clean up slug mapping if needed
140
+ for (const [slug, driveId] of Object.entries(this.slugToDriveId)) {
141
+ if (driveId === id) {
142
+ delete this.slugToDriveId[slug];
143
+ }
144
+ }
114
145
  }
115
146
  async getSynchronizationUnitsRevision(units) {
116
147
  const results = await Promise.allSettled(units.map(async (unit) => {
@@ -144,4 +175,16 @@ export class MemoryStorage {
144
175
  return acc;
145
176
  }, []);
146
177
  }
178
+ ////////////////////////////////
179
+ // Private
180
+ ////////////////////////////////
181
+ getDriveManifest(driveId) {
182
+ if (!this.driveManifests[driveId]) {
183
+ this.driveManifests[driveId] = { documentIds: new Set() };
184
+ }
185
+ return this.driveManifests[driveId];
186
+ }
187
+ updateDriveManifest(driveId, manifest) {
188
+ this.driveManifests[driveId] = manifest;
189
+ }
147
190
  }
@@ -3,7 +3,7 @@ import type { BaseStateFromDocument, DocumentHeader, Operation, OperationFromDoc
3
3
  import { type IBackOffOptions } from "exponential-backoff";
4
4
  import { type DocumentDriveAction, type DocumentDriveDocument } from "../../drive-document-model/gen/types.js";
5
5
  import { type SynchronizationUnitQuery } from "../../server/types.js";
6
- import { type IDriveStorage, type IStorageDelegate } from "../types.js";
6
+ import type { IDocumentStorage, IDriveStorage, IStorageDelegate } from "../types.js";
7
7
  export * from "./factory.js";
8
8
  type Transaction = Omit<PrismaClient<Prisma.PrismaClientOptions, never>, "$connect" | "$disconnect" | "$on" | "$transaction" | "$use" | "$extends"> | ExtendedPrismaClient;
9
9
  export type PrismaStorageOptions = {
@@ -25,10 +25,12 @@ declare function getRetryTransactionsClient<T extends PrismaClient>(prisma: T, b
25
25
  };
26
26
  }, {}>;
27
27
  type ExtendedPrismaClient = ReturnType<typeof getRetryTransactionsClient<PrismaClient>>;
28
- export declare class PrismaStorage implements IDriveStorage {
28
+ export declare class PrismaStorage implements IDriveStorage, IDocumentStorage {
29
29
  private db;
30
30
  private delegate;
31
31
  constructor(db: PrismaClient, options?: PrismaStorageOptions);
32
+ exists(documentId: string): Promise<boolean>;
33
+ create(documentId: string, document: PHDocument): Promise<void>;
32
34
  setStorageDelegate(delegate: IStorageDelegate): void;
33
35
  createDrive(id: string, drive: DocumentDriveDocument): Promise<void>;
34
36
  addDriveOperations(id: string, operations: Operation<DocumentDriveAction>[], header: DocumentHeader): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/storage/prisma/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/storage/prisma/index.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
2
2
  import { backOff } from "exponential-backoff";
3
- import { ConflictOperationError, DriveNotFoundError, } from "../../server/error.js";
3
+ import { ConflictOperationError } from "../../server/error.js";
4
4
  import { logger } from "../../utils/logger.js";
5
5
  export * from "./factory.js";
6
6
  function storageToOperation(op) {
@@ -54,22 +54,88 @@ export class PrismaStorage {
54
54
  jitter: backOffOptions?.jitter ?? "full",
55
55
  });
56
56
  }
57
+ ////////////////////////////////
58
+ // IDocumentStorage
59
+ ////////////////////////////////
60
+ async exists(documentId) {
61
+ const count = await this.db.document.count({
62
+ where: {
63
+ id: documentId,
64
+ },
65
+ });
66
+ return count > 0;
67
+ }
68
+ async create(documentId, document) {
69
+ await this.db.document.upsert({
70
+ where: {
71
+ id: documentId,
72
+ },
73
+ update: {},
74
+ create: {
75
+ name: document.name,
76
+ documentType: document.documentType,
77
+ isDrive: false,
78
+ initialState: JSON.stringify(document.initialState),
79
+ lastModified: document.lastModified,
80
+ revision: JSON.stringify(document.revision),
81
+ meta: document.meta ? JSON.stringify(document.meta) : undefined,
82
+ id: documentId,
83
+ },
84
+ });
85
+ }
86
+ ////////////////////////////////
87
+ // IDriveStorage
88
+ ////////////////////////////////
57
89
  setStorageDelegate(delegate) {
58
90
  this.delegate = delegate;
59
91
  }
60
92
  async createDrive(id, drive) {
61
- // drive for all drive documents
62
- await this.createDocument("drives", id, drive);
93
+ const doc = {
94
+ name: drive.name,
95
+ documentType: drive.documentType,
96
+ isDrive: true,
97
+ initialState: JSON.stringify(drive.initialState),
98
+ lastModified: drive.lastModified,
99
+ revision: JSON.stringify(drive.revision),
100
+ meta: drive.meta ? JSON.stringify(drive.meta) : undefined,
101
+ id,
102
+ };
103
+ await this.db.document.upsert({
104
+ where: {
105
+ id,
106
+ },
107
+ update: doc,
108
+ create: doc,
109
+ });
110
+ // backwards compatibility -- if the drive has a slug, check if it already exists
111
+ if (drive.initialState.state.global.slug) {
112
+ const existingDrive = await this.db.drive.findFirst({
113
+ where: {
114
+ slug: drive.initialState.state.global.slug,
115
+ },
116
+ });
117
+ if (existingDrive) {
118
+ await this.db.drive.update({
119
+ where: { id: existingDrive.id },
120
+ data: {
121
+ id,
122
+ slug: drive.initialState.state.global.slug,
123
+ },
124
+ });
125
+ return;
126
+ }
127
+ }
63
128
  await this.db.drive.upsert({
64
129
  where: {
65
- slug: drive.initialState.state.global.slug ?? id,
130
+ id,
66
131
  },
67
132
  create: {
68
- id: id,
133
+ id,
69
134
  slug: drive.initialState.state.global.slug ?? id,
70
135
  },
71
136
  update: {
72
137
  id,
138
+ slug: drive.initialState.state.global.slug ?? id,
73
139
  },
74
140
  });
75
141
  }
@@ -80,24 +146,15 @@ export class PrismaStorage {
80
146
  return this.addDocumentOperationsWithTransaction("drives", drive, (document) => callback(document));
81
147
  }
82
148
  async createDocument(drive, id, document) {
83
- await this.db.document.upsert({
149
+ await this.create(id, document);
150
+ // create the many-to-many relation
151
+ await this.db.document.update({
84
152
  where: {
85
- id_driveId: {
86
- id,
87
- driveId: drive,
88
- },
89
- },
90
- update: {},
91
- create: {
92
- name: document.name,
93
- documentType: document.documentType,
94
- driveId: drive,
95
- initialState: JSON.stringify(document.initialState),
96
- lastModified: document.lastModified,
97
- revision: JSON.stringify(document.revision),
98
- meta: document.meta ? JSON.stringify(document.meta) : undefined,
99
153
  id,
100
154
  },
155
+ data: {
156
+ driveDocuments: { create: { driveId: drive } },
157
+ },
101
158
  });
102
159
  }
103
160
  async _addDocumentOperations(tx, drive, id, operations, header) {
@@ -124,7 +181,6 @@ export class PrismaStorage {
124
181
  await tx.document.updateMany({
125
182
  where: {
126
183
  id,
127
- driveId: drive,
128
184
  },
129
185
  data: {
130
186
  lastModified: header.lastModified,
@@ -210,10 +266,9 @@ export class PrismaStorage {
210
266
  id: true,
211
267
  },
212
268
  where: {
213
- AND: {
214
- driveId: drive,
215
- NOT: {
216
- id: "drives",
269
+ driveDocuments: {
270
+ some: {
271
+ driveId: drive,
217
272
  },
218
273
  },
219
274
  },
@@ -224,21 +279,31 @@ export class PrismaStorage {
224
279
  const count = await this.db.document.count({
225
280
  where: {
226
281
  id: id,
227
- driveId: driveId,
282
+ driveDocuments: {
283
+ some: {
284
+ driveId: driveId,
285
+ },
286
+ },
228
287
  },
229
288
  });
230
289
  return count > 0;
231
290
  }
232
291
  async getDocument(driveId, id, tx) {
233
292
  const prisma = tx ?? this.db;
234
- const result = await prisma.document.findUnique({
293
+ const query = {
235
294
  where: {
236
- id_driveId: {
295
+ id,
296
+ },
297
+ };
298
+ if (driveId !== "drives") {
299
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
300
+ query.where.driveDocuments = {
301
+ some: {
237
302
  driveId,
238
- id,
239
303
  },
240
- },
241
- });
304
+ };
305
+ }
306
+ const result = await prisma.document.findUnique(query);
242
307
  if (result === null) {
243
308
  throw new Error(`Document with id ${id} not found`);
244
309
  }
@@ -327,10 +392,25 @@ export class PrismaStorage {
327
392
  }
328
393
  async deleteDocument(drive, id) {
329
394
  try {
395
+ // delete out of drives
396
+ await this.db.drive.deleteMany({
397
+ where: {
398
+ driveDocuments: {
399
+ none: {
400
+ documentId: id,
401
+ },
402
+ },
403
+ },
404
+ });
405
+ // delete document
330
406
  await this.db.document.deleteMany({
331
407
  where: {
332
- driveId: drive,
333
- id: id,
408
+ driveDocuments: {
409
+ some: {
410
+ driveId: drive,
411
+ },
412
+ },
413
+ id,
334
414
  },
335
415
  });
336
416
  }
@@ -345,17 +425,15 @@ export class PrismaStorage {
345
425
  }
346
426
  }
347
427
  async getDrives() {
348
- return this.getDocuments("drives");
428
+ const drives = await this.db.drive.findMany({
429
+ select: {
430
+ id: true,
431
+ },
432
+ });
433
+ return drives.map((d) => d.id);
349
434
  }
350
435
  async getDrive(id) {
351
- try {
352
- const doc = await this.getDocument("drives", id);
353
- return doc;
354
- }
355
- catch (e) {
356
- logger.error(e);
357
- throw new DriveNotFoundError(id);
358
- }
436
+ return this.getDocument("drives", id);
359
437
  }
360
438
  async getDriveBySlug(slug) {
361
439
  const driveEntity = await this.db.drive.findFirst({
@@ -369,18 +447,26 @@ export class PrismaStorage {
369
447
  return this.getDrive(driveEntity.id);
370
448
  }
371
449
  async deleteDrive(id) {
372
- // delete drive and associated slug
373
- await this.db.drive.deleteMany({
450
+ // delete drive
451
+ await this.db.drive.delete({
374
452
  where: {
375
453
  id,
376
454
  },
377
455
  });
378
- // delete drive document and its operations
379
- await this.deleteDocument("drives", id);
380
- // deletes all documents of the drive
456
+ // delete drive document (will cascade)
457
+ await this.db.document.delete({
458
+ where: {
459
+ id,
460
+ },
461
+ });
462
+ // deletes all documents that only belong to this drive
381
463
  await this.db.document.deleteMany({
382
464
  where: {
383
- driveId: id,
465
+ driveDocuments: {
466
+ none: {
467
+ driveId: id,
468
+ },
469
+ },
384
470
  },
385
471
  });
386
472
  }
@@ -1,33 +1,2 @@
1
- import { type DocumentDriveAction, type DocumentDriveDocument } from "#drive-document-model/gen/types";
2
- import { type SynchronizationUnitQuery } from "#server/types";
3
- import { type AttachmentInput, type DocumentHeader, type Operation, type PHDocument } from "document-model";
4
- import { type Options, Sequelize } from "sequelize";
5
- import { type IDocumentStorage, type IDriveStorage } from "./types.js";
6
- export declare class SequelizeStorage implements IDriveStorage, IDocumentStorage {
7
- private db;
8
- constructor(options: Options);
9
- syncModels(): Promise<Sequelize>;
10
- createDrive(id: string, drive: DocumentDriveDocument): Promise<void>;
11
- addDriveOperations(id: string, operations: Operation<DocumentDriveAction>[], header: DocumentHeader): Promise<void>;
12
- createDocument(drive: string, id: string, document: PHDocument): Promise<void>;
13
- addDocumentOperations(drive: string, id: string, operations: Operation[], header: DocumentHeader): Promise<void>;
14
- _addDocumentOperationAttachments(driveId: string, documentId: string, operation: Operation, attachments: AttachmentInput[]): Promise<import("sequelize").Model<any, any>[]>;
15
- getDocuments(drive: string): Promise<string[]>;
16
- exists(id: string): Promise<boolean>;
17
- checkDocumentExists(drive: string, id: string): Promise<boolean>;
18
- getDocument<TDocument extends PHDocument>(driveId: string, id: string): Promise<TDocument>;
19
- deleteDocument(drive: string, id: string): Promise<void>;
20
- getDrives(): Promise<string[]>;
21
- getDrive(id: string): Promise<DocumentDriveDocument>;
22
- getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;
23
- deleteDrive(id: string): Promise<void>;
24
- getSynchronizationUnitsRevision(units: SynchronizationUnitQuery[]): Promise<{
25
- driveId: string;
26
- documentId: string;
27
- scope: string;
28
- branch: string;
29
- lastUpdated: string;
30
- revision: number;
31
- }[]>;
32
- }
1
+ export {};
33
2
  //# sourceMappingURL=sequelize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sequelize.d.ts","sourceRoot":"","sources":["../../../src/storage/sequelize.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAG3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,cAAc,EAEnB,KAAK,SAAS,EAEd,KAAK,UAAU,EAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAa,KAAK,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvE,qBAAa,gBAAiB,YAAW,aAAa,EAAE,gBAAgB;IACtE,OAAO,CAAC,EAAE,CAAY;gBAEV,OAAO,EAAE,OAAO;IAIrB,UAAU;IAuGX,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpE,kBAAkB,CACtB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,CAAC,mBAAmB,CAAC,EAAE,EAC5C,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAGV,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,UAAU,GACnB,OAAO,CAAC,IAAI,CAAC;IAiBV,qBAAqB,CACzB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAyEV,gCAAgC,CACpC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,eAAe,EAAE;IAuB1B,YAAY,CAAC,KAAK,EAAE,MAAM;IAoB1B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAcpC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIhE,WAAW,CAAC,SAAS,SAAS,UAAU,EAC5C,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,SAAS,CAAC;IA6Ef,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAcxC,SAAS;IAIT,QAAQ,CAAC,EAAE,EAAE,MAAM;IAKnB,cAAc,CAAC,IAAI,EAAE,MAAM;IAoB3B,WAAW,CAAC,EAAE,EAAE,MAAM;IAwBtB,+BAA+B,CACnC,KAAK,EAAE,wBAAwB,EAAE,GAChC,OAAO,CACR;QACE,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,EAAE,CACJ;CA2CF"}
1
+ {"version":3,"file":"sequelize.d.ts","sourceRoot":"","sources":["../../../src/storage/sequelize.ts"],"names":[],"mappings":""}