Skip to content

Commit e6c8826

Browse files
committed
Merge branch 'develop'
2 parents 1d198b3 + 4a89fd6 commit e6c8826

File tree

3 files changed

+45
-47
lines changed

3 files changed

+45
-47
lines changed

src/components/file/media/detect-existing-media.migration.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { FileVersion } from '../dto';
66
import { FileRepository } from '../file.repository';
77
import { MediaService } from './media.service';
88

9-
@Migration('2023-09-01T18:00:00')
9+
@Migration('2023-09-05T19:00:00')
1010
export class DetectExistingMediaMigration extends BaseMigration {
1111
constructor(
1212
private readonly mediaService: MediaService,
@@ -16,8 +16,9 @@ export class DetectExistingMediaMigration extends BaseMigration {
1616
}
1717

1818
async up() {
19+
await this.dropAllDuplicatedMedia();
20+
1921
const detect = async (f: FileVersion) => {
20-
this.logger.info('Detecting', f);
2122
try {
2223
const result = await this.mediaService.detectAndSave(f);
2324
this.logger.info('Detected and saved media', {
@@ -80,4 +81,14 @@ export class DetectExistingMediaMigration extends BaseMigration {
8081
// eslint-disable-next-line no-constant-condition
8182
} while (true);
8283
}
84+
85+
private async dropAllDuplicatedMedia() {
86+
await this.db.query().raw`
87+
match (fv:FileVersion)-->(media:Media)
88+
with fv, collect(media) as medias
89+
where size(medias) > 1
90+
unwind medias as media
91+
detach delete media
92+
`.executeAndLogStats();
93+
}
8394
}

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)