1
1
import { Injectable } from '@nestjs/common' ;
2
2
import { inArray , node , or , Query , relation } from 'cypher-query-builder' ;
3
- import { RequireAtLeastOne } from 'type-fest' ;
4
- import { EnhancedResource , generateId , ID , ServerException } from '~/common' ;
3
+ import { Except , RequireAtLeastOne } from 'type-fest' ;
4
+ import {
5
+ EnhancedResource ,
6
+ generateId ,
7
+ ID ,
8
+ NotFoundException ,
9
+ ServerException ,
10
+ } from '~/common' ;
5
11
import { CommonRepository } from '~/core' ;
6
12
import { ACTIVE , apoc , merge } from '~/core/database/query' ;
7
13
import { AnyMedia , MediaUserMetadata , resolveMedia } from './media.dto' ;
8
14
9
15
@Injectable ( )
10
16
export class MediaRepository extends CommonRepository {
17
+ async readOne ( input : RequireAtLeastOne < Pick < AnyMedia , 'id' | 'file' > > ) {
18
+ const [ media ] = await this . readMany (
19
+ input . id ? { mediaIds : [ input . id ] } : { fvIds : [ input . file ! ] } ,
20
+ ) ;
21
+ if ( ! media ) {
22
+ throw new NotFoundException ( 'Media not found' ) ;
23
+ }
24
+ return media ;
25
+ }
26
+
11
27
async readMany (
12
28
input : RequireAtLeastOne < Record < 'fvIds' | 'mediaIds' , readonly ID [ ] > > ,
13
29
) {
@@ -31,20 +47,39 @@ export class MediaRepository extends CommonRepository {
31
47
32
48
protected hydrate ( ) {
33
49
return ( query : Query ) =>
34
- query . return < { dto : AnyMedia } > (
35
- merge ( 'node' , {
36
- __typename : 'node.type' ,
37
- file : 'fv.id' ,
38
- dimensions : {
39
- width : 'node.width' ,
40
- height : 'node.height' ,
41
- } ,
42
- } ) . as ( 'dto' ) ,
43
- ) ;
50
+ query
51
+ . subQuery ( 'fv' , ( sub ) =>
52
+ sub
53
+ . comment ( 'Find root file node' )
54
+ . subQuery ( 'fv' , ( sub2 ) =>
55
+ sub2
56
+ . raw ( 'MATCH p=(fv)-[:parent*]->(node:FileNode)' )
57
+ . return ( 'node as root' )
58
+ . orderBy ( 'length(p)' , 'DESC' )
59
+ . raw ( 'LIMIT 1' ) ,
60
+ )
61
+ . comment ( 'Get resource holding root file node' )
62
+ . raw ( 'MATCH (resource:BaseNode)-[rel]->(root)' )
63
+ . raw ( 'WHERE not resource:FileNode' )
64
+ . return ( '[resource, type(rel)] as attachedTo' )
65
+ . raw ( 'LIMIT 1' ) ,
66
+ )
67
+ . return < { dto : AnyMedia } > (
68
+ merge ( 'node' , {
69
+ __typename : 'node.type' ,
70
+ file : 'fv.id' ,
71
+ dimensions : {
72
+ width : 'node.width' ,
73
+ height : 'node.height' ,
74
+ } ,
75
+ attachedTo : 'attachedTo' ,
76
+ } ) . as ( 'dto' ) ,
77
+ ) ;
44
78
}
45
79
46
80
async save (
47
- input : RequireAtLeastOne < Pick < AnyMedia , 'id' | 'file' > > & Partial < AnyMedia > ,
81
+ input : RequireAtLeastOne < Pick < AnyMedia , 'id' | 'file' > > &
82
+ Partial < Except < AnyMedia , 'attachedTo' > > ,
48
83
) {
49
84
const res = input . __typename
50
85
? EnhancedResource . of ( resolveMedia ( input as AnyMedia ) )
@@ -119,10 +154,24 @@ export class MediaRepository extends CommonRepository {
119
154
. apply ( this . hydrate ( ) ) ;
120
155
121
156
const result = await query . first ( ) ;
122
- if ( ! result ) {
123
- throw new ServerException ( 'Failed to save media info' ) ;
157
+ if ( result ) {
158
+ return result . dto ;
159
+ }
160
+ if ( input . file ) {
161
+ const exists = await this . getBaseNode ( input . file , 'FileVersion' ) ;
162
+ if ( ! exists ) {
163
+ throw new NotFoundException (
164
+ 'Media could not be saved to nonexistent file' ,
165
+ ) ;
166
+ }
167
+ }
168
+ if ( input . id ) {
169
+ const exists = await this . getBaseNode ( input . id , 'Media' ) ;
170
+ if ( ! exists ) {
171
+ throw new NotFoundException ( 'Media could not be found' ) ;
172
+ }
124
173
}
125
- return result . dto ;
174
+ throw new ServerException ( 'Failed to save media info' ) ;
126
175
}
127
176
}
128
177
0 commit comments