Skip to content

Commit 91ebba0

Browse files
committed
Unify media saving queries
I was mistakenly creating multiple media nodes with each migration attempt. This fixes that by merging, so a media node is only created when needed. I could've done other ways too, but this seems better as now it's idempotent.
1 parent 37f6cc5 commit 91ebba0

File tree

2 files changed

+32
-45
lines changed

2 files changed

+32
-45
lines changed

src/components/file/media/media.repository.ts

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
import { Injectable } from '@nestjs/common';
22
import { inArray, node, or, Query, relation } from 'cypher-query-builder';
3-
import { Except, RequireAtLeastOne } from 'type-fest';
4-
import { ID, ServerException } from '~/common';
3+
import { RequireAtLeastOne } from 'type-fest';
4+
import { EnhancedResource, generateId, ID, ServerException } from '~/common';
55
import { CommonRepository } from '~/core';
6-
import {
7-
ACTIVE,
8-
apoc,
9-
createNode,
10-
createRelationships,
11-
merge,
12-
variable,
13-
} from '~/core/database/query';
14-
import { AnyMedia, Media, MediaUserMetadata, resolveMedia } from './media.dto';
6+
import { ACTIVE, apoc, merge } from '~/core/database/query';
7+
import { AnyMedia, MediaUserMetadata, resolveMedia } from './media.dto';
158

169
@Injectable()
1710
export class MediaRepository extends CommonRepository {
@@ -50,19 +43,33 @@ export class MediaRepository extends CommonRepository {
5043
);
5144
}
5245

53-
async create(input: Except<AnyMedia, 'id'>) {
46+
async save(
47+
input: RequireAtLeastOne<Pick<AnyMedia, 'id' | 'file'>> & Partial<AnyMedia>,
48+
) {
49+
const res = input.__typename
50+
? EnhancedResource.of(resolveMedia(input as AnyMedia))
51+
: undefined;
5452
const query = this.db
5553
.query()
56-
.matchNode('fv', 'FileVersion', { id: input.file })
57-
.apply(
58-
await createNode(resolveMedia(input), {
59-
baseNodeProps: toDbShape(input),
60-
}),
61-
)
62-
.apply(
63-
createRelationships(Media, 'in', {
64-
media: variable('fv'),
65-
}),
54+
.merge([
55+
node('fv', 'FileVersion', input.file ? { id: input.file } : {}),
56+
relation('out', '', 'media'),
57+
node('node', 'Media', input.id ? { id: input.id } : {}),
58+
])
59+
.onCreate.set({
60+
values: { 'node.id': await generateId() },
61+
variables: { 'node.createdAt': 'datetime()' },
62+
})
63+
.setValues({ node: toDbShape(input) }, true)
64+
.with('node, fv')
65+
// Update the labels if typename is given, and maybe changed.
66+
.apply((q) =>
67+
res
68+
? q.raw(
69+
'CALL apoc.create.setLabels(node, $newLabels) yield node as labelsAdded',
70+
{ newLabels: res.dbLabels },
71+
)
72+
: q,
6673
)
6774
// Grab the previous media node or null
6875
.subQuery('fv', (sub) =>
@@ -81,7 +88,7 @@ export class MediaRepository extends CommonRepository {
8188
])
8289
.return('prevMedia')
8390
.orderBy('fvs.createdAt', 'DESC')
84-
.limit(1),
91+
.raw('LIMIT 1'),
8592
)
8693
// Use previous user metadata as defaults for new media
8794
.with('node, fv, prevMedia')
@@ -100,26 +107,6 @@ export class MediaRepository extends CommonRepository {
100107
)
101108
.apply(this.hydrate());
102109

103-
const result = await query.first();
104-
if (!result) {
105-
throw new ServerException('Failed to create media info');
106-
}
107-
return result.dto;
108-
}
109-
110-
async update(
111-
input: RequireAtLeastOne<Pick<AnyMedia, 'id' | 'file'>> & Partial<AnyMedia>,
112-
) {
113-
const query = this.db
114-
.query()
115-
.match([
116-
node('fv', 'FileVersion', input.file ? { id: input.file } : {}),
117-
relation('out', '', 'media'),
118-
node('node', 'Media', input.id ? { id: input.id } : {}),
119-
])
120-
.setValues({ node: toDbShape(input) }, true)
121-
.apply(this.hydrate());
122-
123110
const result = await query.first();
124111
if (!result) {
125112
throw new ServerException('Failed to save media info');

src/components/file/media/media.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export class MediaService {
1818
if (!media) {
1919
return null;
2020
}
21-
return await this.repo.create({
21+
return await this.repo.save({
2222
file: file.id as IdOf<FileVersion>,
2323
mimeType: file.mimeType,
2424
...media,
@@ -30,7 +30,7 @@ export class MediaService {
3030
input: RequireAtLeastOne<Pick<AnyMedia, 'id' | 'file'>> & MediaUserMetadata,
3131
) {
3232
try {
33-
return await this.repo.update(input);
33+
return await this.repo.save(input);
3434
} catch (e) {
3535
if (e instanceof ServerException) {
3636
const exists = await this.repo.getBaseNode(

0 commit comments

Comments
 (0)