document-drive 1.0.0-alpha.60 → 1.0.0-alpha.61
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/package.json +1 -1
- package/src/storage/prisma.ts +105 -28
package/package.json
CHANGED
package/src/storage/prisma.ts
CHANGED
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
DocumentDriveState
|
|
7
7
|
} from 'document-model-libs/document-drive';
|
|
8
8
|
import type {
|
|
9
|
+
Action,
|
|
10
|
+
AttachmentInput,
|
|
11
|
+
DocumentOperations,
|
|
12
|
+
FileRegistry,
|
|
9
13
|
BaseAction,
|
|
10
14
|
Document,
|
|
11
15
|
DocumentHeader,
|
|
@@ -32,7 +36,9 @@ type Transaction =
|
|
|
32
36
|
| ExtendedPrismaClient;
|
|
33
37
|
|
|
34
38
|
function storageToOperation(
|
|
35
|
-
op: Prisma.$OperationPayload['scalars']
|
|
39
|
+
op: Prisma.$OperationPayload['scalars'] & {
|
|
40
|
+
attachments?: AttachmentInput[];
|
|
41
|
+
}
|
|
36
42
|
): Operation {
|
|
37
43
|
const operation: Operation = {
|
|
38
44
|
skip: op.skip,
|
|
@@ -42,9 +48,10 @@ function storageToOperation(
|
|
|
42
48
|
input: JSON.parse(op.input),
|
|
43
49
|
type: op.type,
|
|
44
50
|
scope: op.scope as OperationScope,
|
|
45
|
-
resultingState: op.resultingState
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
resultingState: op.resultingState
|
|
52
|
+
? op.resultingState.toString()
|
|
53
|
+
: undefined,
|
|
54
|
+
attachments: op.attachments
|
|
48
55
|
};
|
|
49
56
|
if (op.context) {
|
|
50
57
|
operation.context = op.context as Prisma.JsonObject;
|
|
@@ -176,9 +183,8 @@ export class PrismaStorage implements IDriveStorage {
|
|
|
176
183
|
branch: 'main',
|
|
177
184
|
skip: op.skip,
|
|
178
185
|
context: op.context,
|
|
179
|
-
opId: op.id,
|
|
180
186
|
resultingState: op.resultingState
|
|
181
|
-
? JSON.stringify(op.resultingState)
|
|
187
|
+
? Buffer.from(JSON.stringify(op.resultingState))
|
|
182
188
|
: undefined
|
|
183
189
|
}))
|
|
184
190
|
});
|
|
@@ -193,6 +199,31 @@ export class PrismaStorage implements IDriveStorage {
|
|
|
193
199
|
revision: JSON.stringify(header.revision)
|
|
194
200
|
}
|
|
195
201
|
});
|
|
202
|
+
|
|
203
|
+
await Promise.all(
|
|
204
|
+
operations
|
|
205
|
+
.filter(o => o.attachments?.length)
|
|
206
|
+
.map(op => {
|
|
207
|
+
return tx.operation.update({
|
|
208
|
+
where: {
|
|
209
|
+
unique_operation: {
|
|
210
|
+
driveId: drive,
|
|
211
|
+
documentId: id,
|
|
212
|
+
index: op.index,
|
|
213
|
+
scope: op.scope,
|
|
214
|
+
branch: 'main'
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
data: {
|
|
218
|
+
attachments: {
|
|
219
|
+
createMany: {
|
|
220
|
+
data: op.attachments ?? []
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
})
|
|
226
|
+
);
|
|
196
227
|
} catch (e) {
|
|
197
228
|
// P2002: Unique constraint failed
|
|
198
229
|
// Operation with existing index
|
|
@@ -219,6 +250,7 @@ export class PrismaStorage implements IDriveStorage {
|
|
|
219
250
|
);
|
|
220
251
|
|
|
221
252
|
if (!existingOperation || !conflictOp) {
|
|
253
|
+
console.error(e);
|
|
222
254
|
throw e;
|
|
223
255
|
} else {
|
|
224
256
|
throw new ConflictOperationError(
|
|
@@ -316,22 +348,13 @@ export class PrismaStorage implements IDriveStorage {
|
|
|
316
348
|
}
|
|
317
349
|
|
|
318
350
|
async getDocument(driveId: string, id: string, tx?: Transaction) {
|
|
319
|
-
const
|
|
351
|
+
const prisma = tx ?? this.db;
|
|
352
|
+
const result = await prisma.document.findUnique({
|
|
320
353
|
where: {
|
|
321
354
|
id_driveId: {
|
|
322
355
|
driveId,
|
|
323
356
|
id
|
|
324
357
|
}
|
|
325
|
-
},
|
|
326
|
-
include: {
|
|
327
|
-
operations: {
|
|
328
|
-
orderBy: {
|
|
329
|
-
index: 'asc'
|
|
330
|
-
},
|
|
331
|
-
include: {
|
|
332
|
-
attachments: true
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
358
|
}
|
|
336
359
|
});
|
|
337
360
|
|
|
@@ -339,6 +362,69 @@ export class PrismaStorage implements IDriveStorage {
|
|
|
339
362
|
throw new Error(`Document with id ${id} not found`);
|
|
340
363
|
}
|
|
341
364
|
|
|
365
|
+
// retrieves operations with resulting state
|
|
366
|
+
// for the last operation of each scope
|
|
367
|
+
const operations = await prisma.$queryRaw<
|
|
368
|
+
Prisma.$OperationPayload['scalars'][]
|
|
369
|
+
>`
|
|
370
|
+
WITH ranked_operations AS (
|
|
371
|
+
SELECT
|
|
372
|
+
*,
|
|
373
|
+
ROW_NUMBER() OVER (PARTITION BY scope ORDER BY index DESC) AS rn
|
|
374
|
+
FROM "Operation"
|
|
375
|
+
)
|
|
376
|
+
SELECT
|
|
377
|
+
"id",
|
|
378
|
+
"opId",
|
|
379
|
+
"scope",
|
|
380
|
+
"branch",
|
|
381
|
+
"index",
|
|
382
|
+
"skip",
|
|
383
|
+
"hash",
|
|
384
|
+
"timestamp",
|
|
385
|
+
"input",
|
|
386
|
+
"type",
|
|
387
|
+
"context",
|
|
388
|
+
CASE
|
|
389
|
+
WHEN rn = 1 THEN "resultingState"
|
|
390
|
+
ELSE NULL
|
|
391
|
+
END AS "resultingState"
|
|
392
|
+
FROM ranked_operations
|
|
393
|
+
ORDER BY scope, index;
|
|
394
|
+
`;
|
|
395
|
+
|
|
396
|
+
const operationIds = operations.map(o => o.id);
|
|
397
|
+
const attachments = await prisma.attachment.findMany({
|
|
398
|
+
where: {
|
|
399
|
+
operationId: {
|
|
400
|
+
in: operationIds
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
const fileRegistry: FileRegistry = {};
|
|
406
|
+
const operationsByScope = operations.reduce<DocumentOperations<Action>>(
|
|
407
|
+
(acc, operation) => {
|
|
408
|
+
const scope = operation.scope as OperationScope;
|
|
409
|
+
if (!acc[scope]) {
|
|
410
|
+
acc[scope] = [];
|
|
411
|
+
}
|
|
412
|
+
const result = storageToOperation(operation);
|
|
413
|
+
result.attachments = attachments.filter(
|
|
414
|
+
a => a.operationId === operation.id
|
|
415
|
+
);
|
|
416
|
+
result.attachments.forEach(({ hash, ...file }) => {
|
|
417
|
+
fileRegistry[hash] = file;
|
|
418
|
+
});
|
|
419
|
+
acc[scope].push(result);
|
|
420
|
+
return acc;
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
global: [],
|
|
424
|
+
local: []
|
|
425
|
+
}
|
|
426
|
+
);
|
|
427
|
+
|
|
342
428
|
const dbDoc = result;
|
|
343
429
|
const doc: Document = {
|
|
344
430
|
created: dbDoc.created.toISOString(),
|
|
@@ -350,17 +436,8 @@ export class PrismaStorage implements IDriveStorage {
|
|
|
350
436
|
>,
|
|
351
437
|
state: undefined,
|
|
352
438
|
lastModified: new Date(dbDoc.lastModified).toISOString(),
|
|
353
|
-
operations:
|
|
354
|
-
|
|
355
|
-
.filter(op => op.scope === 'global' && !op.clipboard)
|
|
356
|
-
.map(storageToOperation),
|
|
357
|
-
local: dbDoc.operations
|
|
358
|
-
.filter(op => op.scope === 'local' && !op.clipboard)
|
|
359
|
-
.map(storageToOperation)
|
|
360
|
-
},
|
|
361
|
-
clipboard: dbDoc.operations
|
|
362
|
-
.filter(op => op.clipboard)
|
|
363
|
-
.map(storageToOperation),
|
|
439
|
+
operations: operationsByScope,
|
|
440
|
+
clipboard: [],
|
|
364
441
|
revision: JSON.parse(dbDoc.revision) as Record<
|
|
365
442
|
OperationScope,
|
|
366
443
|
number
|