Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"trailingComma": "all",
"singleQuote": true,
"arrowParens": "avoid"
"arrowParens": "avoid",
"printWidth": 80
}
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo_text.svg" width="320" alt="Nest Logo" /></a>
</p>

<p align="center">
nestjs-storage is manage file Storage wrapping package flydrive
</p>
<p align="center">
<a href="https://www.npmjs.com/org/codebrew"><img src="https://img.shields.io/npm/v/@codebrew/nestjs-storage.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/org/codebrew"><img src="https://img.shields.io/npm/l/@codebrew/nestjs-storage.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/org/codebrew"><img src="https://img.shields.io/npm/dm/@codebrew/nestjs-storage.svg" alt="NPM Downloads" /></a>
</p>

## Installation

```bash
$ npm i --save @codebrew/nestjs-storage @slynova/flydrive

# optional with s3 driver
$ npm i --save @slynova/flydrive-s3

# optional with gcs driver
$ npm i --save @slynova/flydrive-gcs
```

## Example

```typescript
// app.module.ts
import { Module } from '@nestjs/common'
import { StorageModule, DriverType } from '@codebrew/nestjs-storage';

@Module({
imports: [StorageModule.forRoot({
module: AppModule,
imports: [
StorageModule.forRoot({
default: 'local',
disks: {
local: {
driver: DriverType.LOCAL,
config: {
root: process.cwd(),
},
},
},
}),
],
})]
})
export class AppModule {
constructor(private storage: StorageServic) {
this.storage.getDisk().put('test.txt', 'text content');
}
}
```

## Support

nestjs-storage is an MIT-licensed open source project. If this library is helpful, please click star to support it.

## Stay in touch

- Author - [David Kwon](https://github.com/tienne)

## License

nestjs-storage is MIT licensed.
2 changes: 2 additions & 0 deletions lib/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './Storage-module-options';
export * from './storage-module-async-options';
export * from './storage-options-factory';
13 changes: 13 additions & 0 deletions lib/interfaces/storage-module-async-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ModuleMetadata, Type } from '@nestjs/common';
import { StorageModuleOptions } from './storage-module-options';
import { StorageOptionsFactory } from './storage-options-factory';

export interface StorageModuleAsyncOptions
extends Pick<ModuleMetadata, 'imports'> {
name?: string;
useFactory?: (
...args: any[]
) => Promise<StorageModuleOptions> | StorageModuleOptions;
useClass?: Type<StorageOptionsFactory>;
inject?: any[];
}
27 changes: 24 additions & 3 deletions lib/interfaces/storage-module-options.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
import { StorageManagerConfig } from '@slynova/flydrive';
import { DiskConfigType, DriverType } from '../types';
import {
DiskConfigType,
DiskGCSConfigType,
DiskLocalConfigType,
DiskS3ConfigType,
DriverType,
DiskType,
} from '../types';

export interface StorageModuleOptions extends StorageManagerConfig {
isGlobal?: boolean;
default: string;
disks: Record<string, StorageDiskConfig>;
disks: Record<string, DiskType>;
}

export interface StorageDiskConfig {
driver: DriverType | string;
config: DiskConfigType;
}

export interface AwsS3StorageDisk extends StorageDiskConfig {
driver: DriverType.S3 | 's3';
config: DiskS3ConfigType;
}

export interface LocalStorageDisk extends StorageDiskConfig {
driver: DriverType.LOCAL | 'local';
config: DiskLocalConfigType;
}

export interface GoogleGcsStorageDisk extends StorageDiskConfig {
driver: DriverType.GCS | 'gcs';
config: DiskGCSConfigType;
}
5 changes: 5 additions & 0 deletions lib/interfaces/storage-options-factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { StorageModuleOptions } from './storage-module-options';

export interface StorageOptionsFactory {
createStorageOptions(): Promise<StorageModuleOptions> | StorageModuleOptions;
}
84 changes: 84 additions & 0 deletions lib/storage-core.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import {
DynamicModule,
Global,
Inject,
Module,
Provider,
Type,
} from '@nestjs/common';
import { StorageService } from './storage.service';

import { STORAGE_MODULE_OPTIONS } from './storage.constants';
import { StorageModuleOptions, StorageOptionsFactory } from './interfaces';
import { ModuleRef } from '@nestjs/core';
import { StorageModuleAsyncOptions } from './interfaces/storage-module-async-options';
@Global()
@Module({})
export class StorageCoreModule {
constructor(
@Inject(STORAGE_MODULE_OPTIONS)
private readonly options: StorageModuleOptions,
private readonly moduleRef: ModuleRef,
) {}

static forRoot(options: StorageModuleOptions): DynamicModule {
const storageModuleOptions: Provider = {
provide: STORAGE_MODULE_OPTIONS,
useValue: options,
};

return {
module: StorageCoreModule,
providers: [storageModuleOptions, StorageService],
exports: [StorageService],
};
}

static forRootAsync(options: StorageModuleAsyncOptions): DynamicModule {
const asyncProviders = this.createAsyncProviders(options);

return {
module: StorageCoreModule,
imports: options.imports,
providers: [...asyncProviders, StorageService],
exports: [StorageService],
};
}

private static createAsyncProviders(
options: StorageModuleAsyncOptions,
): Provider[] {
if (options.useFactory) {
return [this.createAsyncOptionsProvider(options)];
}
const useClass = options.useClass as Type<StorageOptionsFactory>;
return [
this.createAsyncOptionsProvider(options),
{
provide: useClass,
useClass,
},
];
}

private static createAsyncOptionsProvider(
options: StorageModuleAsyncOptions,
): Provider {
if (options.useFactory) {
return {
provide: STORAGE_MODULE_OPTIONS,
useFactory: options.useFactory,
inject: options.inject || [],
};
}

const inject = [options.useClass as Type<StorageOptionsFactory>];

return {
provide: STORAGE_MODULE_OPTIONS,
useFactory: async (optionsFactory: StorageOptionsFactory) =>
optionsFactory.createStorageOptions(),
inject,
};
}
}
1 change: 1 addition & 0 deletions lib/storage.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
* Injection tokens
*/
export const STORAGE_TOKEN = 'STORAGE_TOKEN';
export const STORAGE_MODULE_OPTIONS = 'STORAGE_MODULE_OPTIONS';
27 changes: 12 additions & 15 deletions lib/storage.module.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
import { DynamicModule, FactoryProvider, Module } from '@nestjs/common';
import { StorageService } from './storage.service';
import { DynamicModule, Module } from '@nestjs/common';

import { STORAGE_TOKEN } from './storage.constants';
import { StorageModuleOptions } from './interfaces';
import { StorageCoreModule } from './storage-core.module';
import { StorageModuleAsyncOptions } from './interfaces/storage-module-async-options';

@Module({
providers: [StorageService],
exports: [StorageService],
})
@Module({})
export class StorageModule {
static forRoot(options: StorageModuleOptions): DynamicModule {
return {
module: StorageModule,
global: options.isGlobal,
providers: [
{
provide: STORAGE_TOKEN,
useValue: options,
},
],
exports: [StorageService],
imports: [StorageCoreModule.forRoot(options)],
};
}

static forRootAsync(options: StorageModuleAsyncOptions): DynamicModule {
return {
module: StorageModule,
imports: [StorageCoreModule.forRootAsync(options)],
};
}
}
6 changes: 4 additions & 2 deletions lib/storage.service.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Inject, Injectable } from '@nestjs/common';
import { Storage, StorageManager } from '@slynova/flydrive';

import { STORAGE_TOKEN } from './storage.constants';
import { STORAGE_MODULE_OPTIONS } from './storage.constants';
import { StorageModuleOptions } from './interfaces';

@Injectable()
export class StorageService {
private storageManager: StorageManager;

constructor(@Inject(STORAGE_TOKEN) private options: StorageModuleOptions) {
constructor(
@Inject(STORAGE_MODULE_OPTIONS) private options: StorageModuleOptions,
) {
this.storageManager = new StorageManager(options);
}

Expand Down
12 changes: 12 additions & 0 deletions lib/types/disk.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {
AwsS3StorageDisk,
GoogleGcsStorageDisk,
LocalStorageDisk,
StorageDiskConfig,
} from '../interfaces';

export type DiskType =
| AwsS3StorageDisk
| LocalStorageDisk
| GoogleGcsStorageDisk
| StorageDiskConfig;
1 change: 1 addition & 0 deletions lib/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './driver.type';
export * from './disk-config.type';
export * from './disk.type';
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@
"prerelease": "npm run build",
"release": "release-it"
},
"dependencies": {
"@slynova/flydrive": "^1.0.2"
},
"dependencies": {},
"devDependencies": {
"@commitlint/cli": "^9.1.1",
"@commitlint/config-angular": "^9.1.1",
"@nestjs/common": "^7.3.2",
"@nestjs/core": "^7.3.2",
"@nestjs/platform-express": "^7.3.2",
"@nestjs/testing": "^7.3.2",
"@slynova/flydrive": "^1.0.2",
"@slynova/flydrive-gcs": "^1.0.2",
"@slynova/flydrive-s3": "^1.0.2",
"@types/jest": "^26.0.5",
Expand Down
37 changes: 37 additions & 0 deletions tests/e2e/local-driver-async.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { AsyncFactoryModule } from '../src/async-factory.module';
import { StorageService } from '../../lib';

describe('async local driver module', () => {
let app: INestApplication, storageService: StorageService;

const fileName = 'local_async_test.txt',
fileContent = 'hi async module local storage test';

beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
imports: [AsyncFactoryModule],
}).compile();

app = moduleRef.createNestApplication();
await app.init();
});

it(`should load configuration with "async module local driver"`, async () => {
storageService = app.get<StorageService>(StorageService);
});

it(`async module put text`, async () => {
await storageService.getDisk().put(`tests/data/${fileName}`, fileContent);
});

it(`async module get text file`, async () => {
const res = await storageService.getDisk().get(`tests/data/${fileName}`);
expect(res.raw).toEqual(fileContent);
});

afterEach(async () => {
await app.close();
});
});
4 changes: 0 additions & 4 deletions tests/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { DynamicModule, Module } from '@nestjs/common';

import { DriverType, StorageModule } from '../../lib';
import { StorageService } from '../../lib/storage.service';

@Module({})
export class AppModule {
constructor(private readonly storageService: StorageService) {}

static withLocalStorage(): DynamicModule {
return {
module: AppModule,
Expand Down
21 changes: 21 additions & 0 deletions tests/src/async-factory.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Module } from '@nestjs/common';
import { DriverType, StorageModule } from '../../lib';

@Module({
imports: [
StorageModule.forRootAsync({
useFactory: () => ({
default: 'local',
disks: {
local: {
driver: DriverType.LOCAL,
config: {
root: process.cwd(),
},
},
},
}),
}),
],
})
export class AsyncFactoryModule {}