Skip to content

Commit 4d13ee8

Browse files
feature(common) add MulterModule
1 parent 6b0ae06 commit 4d13ee8

12 files changed

Lines changed: 185 additions & 47 deletions

packages/common/interceptors/file-fields.interceptor.ts renamed to packages/common/files/file-fields.interceptor.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,36 @@
11
import * as multer from 'multer';
22
import { Observable } from 'rxjs';
3+
import { Inject, Optional } from '../decorators';
34
import { mixin } from '../decorators/core/component.decorator';
45
import { ExecutionContext } from '../interfaces';
5-
import { MulterField, MulterOptions } from '../interfaces/external/multer-options.interface';
6+
import {
7+
MulterField,
8+
MulterOptions,
9+
} from '../interfaces/external/multer-options.interface';
610
import { NestInterceptor } from './../interfaces/features/nest-interceptor.interface';
11+
import { MULTER_MODULE_OPTIONS } from './files.constants';
12+
import { MulterModuleOptions } from './interfaces';
713
import { transformException } from './multer/multer.utils';
814

15+
type MulterInstance = any;
16+
917
export function FileFieldsInterceptor(
1018
uploadFields: MulterField[],
11-
options?: MulterOptions,
19+
localOptions?: MulterOptions,
1220
) {
13-
const Interceptor = mixin(class implements NestInterceptor {
14-
readonly upload = multer(options);
21+
class MixinInterceptor implements NestInterceptor {
22+
readonly upload: MulterInstance;
23+
24+
constructor(
25+
@Optional()
26+
@Inject(MULTER_MODULE_OPTIONS)
27+
options: MulterModuleOptions = {},
28+
) {
29+
this.upload = multer({
30+
...options,
31+
...localOptions,
32+
});
33+
}
1534

1635
async intercept(
1736
context: ExecutionContext,
@@ -34,6 +53,7 @@ export function FileFieldsInterceptor(
3453
);
3554
return call$;
3655
}
37-
});
56+
}
57+
const Interceptor = mixin(MixinInterceptor);
3858
return Interceptor;
3959
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import * as multer from 'multer';
2+
import { Observable } from 'rxjs';
3+
import { Inject, Optional } from '../decorators';
4+
import { mixin } from '../decorators/core/component.decorator';
5+
import { ExecutionContext } from '../interfaces';
6+
import { MulterOptions } from '../interfaces/external/multer-options.interface';
7+
import { NestInterceptor } from './../interfaces/features/nest-interceptor.interface';
8+
import { MULTER_MODULE_OPTIONS } from './files.constants';
9+
import { MulterModuleOptions } from './interfaces';
10+
import { transformException } from './multer/multer.utils';
11+
12+
type MulterInstance = any;
13+
14+
export function FileInterceptor(
15+
fieldName: string,
16+
localOptions?: MulterOptions,
17+
) {
18+
class MixinInterceptor implements NestInterceptor {
19+
readonly upload: MulterInstance;
20+
21+
constructor(
22+
@Optional()
23+
@Inject(MULTER_MODULE_OPTIONS)
24+
options: MulterModuleOptions = {},
25+
) {
26+
this.upload = multer({
27+
...options,
28+
...localOptions,
29+
});
30+
}
31+
32+
async intercept(
33+
context: ExecutionContext,
34+
call$: Observable<any>,
35+
): Promise<Observable<any>> {
36+
const ctx = context.switchToHttp();
37+
38+
await new Promise((resolve, reject) =>
39+
this.upload.single(fieldName)(
40+
ctx.getRequest(),
41+
ctx.getResponse(),
42+
err => {
43+
if (err) {
44+
const error = transformException(err);
45+
return reject(error);
46+
}
47+
resolve();
48+
},
49+
),
50+
);
51+
return call$;
52+
}
53+
}
54+
const Interceptor = mixin(MixinInterceptor);
55+
return Interceptor;
56+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const MULTER_MODULE_OPTIONS = 'MULTER_MODULE_OPTIONS';

packages/common/interceptors/files.interceptor.ts renamed to packages/common/files/files.interceptor.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
11
import * as multer from 'multer';
22
import { Observable } from 'rxjs';
3+
import { Inject, Optional } from '../decorators';
34
import { mixin } from '../decorators/core/component.decorator';
45
import { ExecutionContext } from '../interfaces';
56
import { MulterOptions } from '../interfaces/external/multer-options.interface';
67
import { NestInterceptor } from './../interfaces/features/nest-interceptor.interface';
8+
import { MULTER_MODULE_OPTIONS } from './files.constants';
9+
import { MulterModuleOptions } from './interfaces';
710
import { transformException } from './multer/multer.utils';
811

12+
type MulterInstance = any;
13+
914
export function FilesInterceptor(
1015
fieldName: string,
1116
maxCount?: number,
12-
options?: MulterOptions,
17+
localOptions?: MulterOptions,
1318
) {
14-
const Interceptor = mixin(class implements NestInterceptor {
15-
readonly upload = multer(options);
19+
class MixinInterceptor implements NestInterceptor {
20+
readonly upload: MulterInstance;
21+
22+
constructor(
23+
@Optional()
24+
@Inject(MULTER_MODULE_OPTIONS)
25+
options: MulterModuleOptions = {},
26+
) {
27+
this.upload = multer({
28+
...options,
29+
...localOptions,
30+
});
31+
}
1632

1733
async intercept(
1834
context: ExecutionContext,
@@ -35,6 +51,7 @@ export function FilesInterceptor(
3551
);
3652
return call$;
3753
}
38-
});
54+
}
55+
const Interceptor = mixin(MixinInterceptor);
3956
return Interceptor;
4057
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export * from './file-fields.interceptor';
22
export * from './file.interceptor';
33
export * from './files.interceptor';
4+
export * from './interfaces';
5+
export * from './multer.module';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ModuleMetadata, Type } from '@nestjs/common/interfaces';
2+
import { MulterOptions } from './../../interfaces/external/multer-options.interface';
3+
4+
export interface MulterModuleOptions extends MulterOptions {}
5+
6+
export interface MulterOptionsFactory {
7+
createMulterOptions(): Promise<MulterModuleOptions> | MulterModuleOptions;
8+
}
9+
10+
export interface MulterModuleAsyncOptions
11+
extends Pick<ModuleMetadata, 'imports'> {
12+
useExisting?: Type<MulterOptionsFactory>;
13+
useClass?: Type<MulterOptionsFactory>;
14+
useFactory?: (
15+
...args: any[],
16+
) => Promise<MulterModuleOptions> | MulterModuleOptions;
17+
inject?: any[];
18+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './files-upload-module.interface';
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { DynamicModule, Module, Provider } from '@nestjs/common';
2+
import { MULTER_MODULE_OPTIONS } from './files.constants';
3+
import {
4+
MulterModuleAsyncOptions,
5+
MulterModuleOptions,
6+
MulterOptionsFactory,
7+
} from './interfaces/files-upload-module.interface';
8+
9+
@Module({})
10+
export class MulterModule {
11+
static register(options: MulterModuleOptions): DynamicModule {
12+
return {
13+
module: MulterModule,
14+
providers: [{ provide: MULTER_MODULE_OPTIONS, useValue: options }],
15+
exports: [MULTER_MODULE_OPTIONS],
16+
};
17+
}
18+
19+
static registerAsync(options: MulterModuleAsyncOptions): DynamicModule {
20+
return {
21+
module: MulterModule,
22+
imports: options.imports,
23+
providers: this.createAsyncProviders(options),
24+
exports: [MULTER_MODULE_OPTIONS],
25+
};
26+
}
27+
28+
private static createAsyncProviders(
29+
options: MulterModuleAsyncOptions,
30+
): Provider[] {
31+
if (options.useExisting || options.useFactory) {
32+
return [this.createAsyncOptionsProvider(options)];
33+
}
34+
return [
35+
this.createAsyncOptionsProvider(options),
36+
{
37+
provide: options.useClass,
38+
useClass: options.useClass,
39+
},
40+
];
41+
}
42+
43+
private static createAsyncOptionsProvider(
44+
options: MulterModuleAsyncOptions,
45+
): Provider {
46+
if (options.useFactory) {
47+
return {
48+
provide: MULTER_MODULE_OPTIONS,
49+
useFactory: options.useFactory,
50+
inject: options.inject || [],
51+
};
52+
}
53+
return {
54+
provide: MULTER_MODULE_OPTIONS,
55+
useFactory: async (optionsFactory: MulterOptionsFactory) =>
56+
await optionsFactory.createMulterOptions(),
57+
inject: [options.useExisting || options.useClass],
58+
};
59+
}
60+
}
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)