mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
feature(@nestjs) dynamic modules, global scope, bugfixes, improvements
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,6 +1,16 @@
|
||||
## 4.5.0@soon
|
||||
- **common**: bugfix #286
|
||||
- **core**: dynamic modules feature
|
||||
- **core**: global scope feature
|
||||
- **core**: `ExternalContextCreator` & `ModulesContainer`
|
||||
- **core**: merge `NestApplicationContext` with `NestApplication`
|
||||
- **core**: `NotFoundException` is thrown when route is not available #298
|
||||
- **core**: add `set()` wrapper around native express methods
|
||||
- **core**: bugfix #281
|
||||
- **websockets**: bugfix #271
|
||||
- **microservices**: log RPC exceptions #303
|
||||
- **microservices**: merge `NestApplicationContext` with `NestMicroservice`
|
||||
- **microservices**: handle ECONNREFUSED #288
|
||||
|
||||
## 4.4.1
|
||||
- **common**: `ValidationPipe` improvement
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import * as express from 'express';
|
||||
import * as bodyParser from 'body-parser';
|
||||
import * as request from 'supertest';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { CatsModule } from '../../src/modules/cats/cats.module';
|
||||
import { CatsService } from '../../src/modules/cats/cats.service';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
|
||||
describe('Cats', () => {
|
||||
const server = express();
|
||||
server.use(bodyParser.json());
|
||||
let server;
|
||||
let app: INestApplication;
|
||||
|
||||
const catsService = { findAll: () => ['test'] };
|
||||
|
||||
@@ -15,10 +15,12 @@ describe('Cats', () => {
|
||||
const module = await Test.createTestingModule({
|
||||
modules: [CatsModule],
|
||||
})
|
||||
.overrideComponent(CatsService).useValue(catsService)
|
||||
.overrideComponent(CatsService)
|
||||
.useValue(catsService)
|
||||
.compile();
|
||||
|
||||
const app = module.createNestApplication(server);
|
||||
server = express();
|
||||
app = module.createNestApplication(server);
|
||||
await app.init();
|
||||
});
|
||||
|
||||
@@ -30,4 +32,8 @@ describe('Cats', () => {
|
||||
data: catsService.findAll(),
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
10
examples/05-sql-typeorm/ormconfig.json
Normal file
10
examples/05-sql-typeorm/ormconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"type": "mysql",
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"username": "root",
|
||||
"password": "root",
|
||||
"database": "test",
|
||||
"entities": ["src/**/**.entity{.ts,.js}"],
|
||||
"autoSchemaSync": true
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
"@nestjs/core": "^4.3.0",
|
||||
"@nestjs/microservices": "^4.3.0",
|
||||
"@nestjs/testing": "^4.3.0",
|
||||
"@nestjs/typeorm": "^1.0.0",
|
||||
"@nestjs/websockets": "^4.3.0",
|
||||
"mysql": "^2.14.1",
|
||||
"redis": "^2.7.1",
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { PhotoModule } from './photo/photo.module';
|
||||
import { Photo } from './photo/photo.entity';
|
||||
|
||||
@Module({
|
||||
modules: [PhotoModule],
|
||||
modules: [
|
||||
TypeOrmModule.forRoot([Photo]),
|
||||
PhotoModule,
|
||||
],
|
||||
})
|
||||
export class ApplicationModule {}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { databaseProviders } from './database.providers';
|
||||
|
||||
@Module({
|
||||
components: [...databaseProviders],
|
||||
exports: [...databaseProviders],
|
||||
})
|
||||
export class DatabaseModule {}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { createConnection } from 'typeorm';
|
||||
|
||||
export const databaseProviders = [
|
||||
{
|
||||
provide: 'DbConnectionToken',
|
||||
useFactory: async () => await createConnection({
|
||||
type: 'mysql',
|
||||
host: 'localhost',
|
||||
port: 3306,
|
||||
username: 'root',
|
||||
password: 'root',
|
||||
database: 'test',
|
||||
entities: [
|
||||
__dirname + '/../**/**.entity{.ts,.js}',
|
||||
],
|
||||
autoSchemaSync: true,
|
||||
}),
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { PhotoService } from './photo.service';
|
||||
import { Photo } from './photo.entity';
|
||||
|
||||
@Controller('photo')
|
||||
export class PhotoController {
|
||||
constructor(private readonly photoService: PhotoService) {}
|
||||
|
||||
@Get()
|
||||
findAll(): Promise<Photo[]> {
|
||||
return this.photoService.findAll();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DatabaseModule } from '../database/database.module';
|
||||
import { photoProviders } from './photo.providers';
|
||||
import { PhotoService } from './photo.service';
|
||||
import { PhotoController } from './photo.controller';
|
||||
|
||||
@Module({
|
||||
modules: [DatabaseModule],
|
||||
components: [
|
||||
...photoProviders,
|
||||
PhotoService,
|
||||
],
|
||||
components: [PhotoService],
|
||||
controllers: [PhotoController],
|
||||
})
|
||||
export class PhotoModule {}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Connection, Repository } from 'typeorm';
|
||||
import { Photo } from './photo.entity';
|
||||
|
||||
export const photoProviders = [
|
||||
{
|
||||
provide: 'PhotoRepositoryToken',
|
||||
useFactory: (connection: Connection) => connection.getRepository(Photo),
|
||||
inject: ['DbConnectionToken'],
|
||||
},
|
||||
];
|
||||
@@ -1,11 +1,15 @@
|
||||
import { Component, Inject } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { Photo } from './photo.entity';
|
||||
|
||||
@Component()
|
||||
export class PhotoService {
|
||||
constructor(
|
||||
@Inject('PhotoRepositoryToken') private readonly photoRepository: Repository<Photo>) {}
|
||||
@InjectRepository(Photo)
|
||||
private readonly photoRepository: Repository<Photo>,
|
||||
) {}
|
||||
|
||||
async findAll(): Promise<Photo[]> {
|
||||
return await this.photoRepository.find();
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"ban-types": false,
|
||||
"indent": false,
|
||||
"ordered-imports": [
|
||||
false
|
||||
],
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
"redis": "^2.7.1",
|
||||
"reflect-metadata": "^0.1.10",
|
||||
"rxjs": "^5.4.3",
|
||||
"sequelize": "^4.12.0",
|
||||
"sequelize-typescript": "^0.5.0",
|
||||
"typescript": "^2.4.2"
|
||||
"sequelize": "^4.28.0",
|
||||
"sequelize-typescript": "^0.6.1",
|
||||
"typescript": "^2.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^7.0.41",
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Cat } from './cat.entity';
|
||||
@Component()
|
||||
export class CatsService {
|
||||
constructor(
|
||||
@Inject('CatsRepository') private readonly catsRepository: typeof Model) {}
|
||||
@Inject('CatsRepository') private readonly catsRepository: typeof Cat) {}
|
||||
|
||||
async create(createCatDto: CreateCatDto): Promise<Cat> {
|
||||
const cat = new Cat();
|
||||
|
||||
21
examples/12-graphql-apollo/.gitignore
vendored
Normal file
21
examples/12-graphql-apollo/.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDE
|
||||
/.idea
|
||||
/.awcache
|
||||
/.vscode
|
||||
|
||||
# misc
|
||||
npm-debug.log
|
||||
|
||||
# example
|
||||
/quick-start
|
||||
|
||||
# tests
|
||||
/test
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# dist
|
||||
/dist
|
||||
@@ -1,5 +1,5 @@
|
||||
require('ts-node/register');
|
||||
require('./example/server');
|
||||
require('./src/server');
|
||||
|
||||
|
||||
|
||||
26
examples/12-graphql-apollo/package.json
Normal file
26
examples/12-graphql-apollo/package.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "nest-typescript-starter",
|
||||
"version": "1.0.0",
|
||||
"description": "Nest TypeScript starter repository",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"prestart:prod": "tsc",
|
||||
"start:prod": "node dist/server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^4.3.0",
|
||||
"@nestjs/core": "^4.3.0",
|
||||
"@nestjs/graphql": "^1.0.0",
|
||||
"apollo-server-express": "^1.2.0",
|
||||
"graphql": "^0.11.7",
|
||||
"graphql-tools": "^2.11.0",
|
||||
"reflect-metadata": "^0.1.10",
|
||||
"rxjs": "^5.4.3",
|
||||
"typescript": "^2.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^7.0.41",
|
||||
"ts-node": "^3.3.0"
|
||||
}
|
||||
}
|
||||
63
examples/12-graphql-apollo/src/modules/app.module.ts
Normal file
63
examples/12-graphql-apollo/src/modules/app.module.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
Module,
|
||||
MiddlewaresConsumer,
|
||||
NestModule,
|
||||
RequestMethod,
|
||||
} from '@nestjs/common';
|
||||
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
|
||||
import {
|
||||
makeExecutableSchema,
|
||||
addMockFunctionsToSchema,
|
||||
mergeSchemas,
|
||||
} from 'graphql-tools';
|
||||
import { GraphQLModule, GraphQLFactory } from '@nestjs/graphql';
|
||||
|
||||
import { CatsModule } from './cats/cats.module';
|
||||
|
||||
@Module({
|
||||
modules: [CatsModule, GraphQLModule],
|
||||
})
|
||||
export class ApplicationModule {
|
||||
constructor(private readonly graphQLFactory: GraphQLFactory) {}
|
||||
|
||||
configure(consumer: MiddlewaresConsumer) {
|
||||
const schema = this.createSchema();
|
||||
consumer
|
||||
.apply(graphiqlExpress({ endpointURL: '/graphql' }))
|
||||
.forRoutes({ path: '/graphiql', method: RequestMethod.GET })
|
||||
.apply(graphqlExpress(req => ({ schema, rootValue: req })))
|
||||
.forRoutes({ path: '/graphql', method: RequestMethod.ALL });
|
||||
}
|
||||
|
||||
createSchema() {
|
||||
const typeDefs = this.graphQLFactory.mergeTypesByPaths('./**/*.graphql');
|
||||
const schema = this.graphQLFactory.createSchema({ typeDefs });
|
||||
|
||||
const delegates = this.graphQLFactory.createDelegates();
|
||||
const { humanSchema, linkTypeDefs } = this.createDelegatedSchema();
|
||||
return mergeSchemas({
|
||||
schemas: [schema, humanSchema, linkTypeDefs],
|
||||
resolvers: delegates,
|
||||
});
|
||||
}
|
||||
|
||||
createDelegatedSchema() {
|
||||
const linkTypeDefs = `
|
||||
extend type Cat {
|
||||
human: Human
|
||||
}
|
||||
`;
|
||||
const humanSchema = makeExecutableSchema({
|
||||
typeDefs: `
|
||||
type Human {
|
||||
id: ID!
|
||||
}
|
||||
type Query {
|
||||
humanById(id: ID!): Human
|
||||
}
|
||||
`,
|
||||
});
|
||||
addMockFunctionsToSchema({ schema: humanSchema });
|
||||
return { humanSchema, linkTypeDefs };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { CanActivate, Guard, ExecutionContext } from '@nestjs/common';
|
||||
|
||||
@Guard()
|
||||
export class CatsGuard implements CanActivate {
|
||||
canActivate(request: any, context: ExecutionContext): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { CatsService } from './cats.service';
|
||||
import { CatsResolvers } from './cats.resolvers';
|
||||
|
||||
@Module({
|
||||
components: [CatsService, CatsResolvers],
|
||||
})
|
||||
export class CatsModule {}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Component, UseGuards } from '@nestjs/common';
|
||||
import {
|
||||
Query,
|
||||
Mutation,
|
||||
Resolver,
|
||||
DelegateProperty,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import { Cat } from './interfaces/cat.interface';
|
||||
import { CatsService } from './cats.service';
|
||||
import { CatsGuard } from './cats.guard';
|
||||
import { MergeInfo } from 'graphql-tools/dist/Interfaces';
|
||||
|
||||
@Resolver('Cat')
|
||||
export class CatsResolvers {
|
||||
constructor(private readonly catsService: CatsService) {}
|
||||
|
||||
@Query()
|
||||
@UseGuards(CatsGuard)
|
||||
async getCats() {
|
||||
return await this.catsService.findAll();
|
||||
}
|
||||
|
||||
@Query('cat')
|
||||
async findOneById(id: number) {
|
||||
return await this.catsService.findOneById(id);
|
||||
}
|
||||
|
||||
@Mutation('createCat')
|
||||
async create(cat: Cat) {
|
||||
await this.catsService.create(cat);
|
||||
}
|
||||
|
||||
@DelegateProperty('human')
|
||||
findHumansById(cat: Cat) {
|
||||
return (mergeInfo: MergeInfo) => ({
|
||||
fragment: `fragment CatFragment on Cat { humanId }`,
|
||||
resolve(parent, args, context, info) {
|
||||
const humanId = parent.id;
|
||||
return mergeInfo.delegate(
|
||||
'query',
|
||||
'humanById',
|
||||
{
|
||||
id: humanId,
|
||||
},
|
||||
context,
|
||||
info,
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
21
examples/12-graphql-apollo/src/modules/cats/cats.service.ts
Normal file
21
examples/12-graphql-apollo/src/modules/cats/cats.service.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Component } from '@nestjs/common';
|
||||
import { Cat } from './interfaces/cat.interface';
|
||||
|
||||
@Component()
|
||||
export class CatsService {
|
||||
private readonly cats: Cat[] = [
|
||||
{ id: 1, name: 'Cat', age: 5 },
|
||||
];
|
||||
|
||||
create(cat: Cat) {
|
||||
this.cats.push(cat);
|
||||
}
|
||||
|
||||
findAll(): Cat[] {
|
||||
return this.cats;
|
||||
}
|
||||
|
||||
findOneById(id: number): Cat {
|
||||
return this.cats.find((cat) => cat.id === id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
type Query {
|
||||
getCats: [Cat]
|
||||
cat(id: ID!): Cat
|
||||
catByHumanId(id: ID!): Cat
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createCat(name: String): Cat
|
||||
}
|
||||
|
||||
type Cat {
|
||||
id: Int
|
||||
name: String
|
||||
age: Int
|
||||
humanId: Int
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface Cat {
|
||||
readonly id: number;
|
||||
readonly name: string;
|
||||
readonly age: number;
|
||||
}
|
||||
8
examples/12-graphql-apollo/src/server.ts
Normal file
8
examples/12-graphql-apollo/src/server.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { ApplicationModule } from './modules/app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(ApplicationModule);
|
||||
await app.listen(3000);
|
||||
}
|
||||
bootstrap();
|
||||
22
examples/12-graphql-apollo/tsconfig.json
Normal file
22
examples/12-graphql-apollo/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
54
examples/12-graphql-apollo/tslint.json
Normal file
54
examples/12-graphql-apollo/tslint.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"defaultSeverity": "error",
|
||||
"extends": [
|
||||
"tslint:recommended"
|
||||
],
|
||||
"jsRules": {
|
||||
"no-unused-expression": true
|
||||
},
|
||||
"rules": {
|
||||
"eofline": false,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"indent": false,
|
||||
"ordered-imports": [
|
||||
false
|
||||
],
|
||||
"max-line-length": [
|
||||
150
|
||||
],
|
||||
"member-ordering": [
|
||||
false
|
||||
],
|
||||
"curly": false,
|
||||
"interface-name": [
|
||||
false
|
||||
],
|
||||
"array-type": [
|
||||
false
|
||||
],
|
||||
"member-access": [
|
||||
false
|
||||
],
|
||||
"no-empty-interface": false,
|
||||
"no-empty": false,
|
||||
"arrow-parens": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"no-unused-expression": false,
|
||||
"max-classes-per-file": [
|
||||
false
|
||||
],
|
||||
"variable-name": [
|
||||
false
|
||||
],
|
||||
"one-line": [
|
||||
false
|
||||
],
|
||||
"one-variable-per-declaration": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"rulesDirectory": []
|
||||
}
|
||||
21
examples/13-mongo-typeorm/.gitignore
vendored
Normal file
21
examples/13-mongo-typeorm/.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDE
|
||||
/.idea
|
||||
/.awcache
|
||||
/.vscode
|
||||
|
||||
# misc
|
||||
npm-debug.log
|
||||
|
||||
# example
|
||||
/quick-start
|
||||
|
||||
# tests
|
||||
/test
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# dist
|
||||
/dist
|
||||
14
examples/13-mongo-typeorm/index.js
Normal file
14
examples/13-mongo-typeorm/index.js
Normal file
@@ -0,0 +1,14 @@
|
||||
require('ts-node/register');
|
||||
require('./src/server');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
7
examples/13-mongo-typeorm/ormconfig.json
Normal file
7
examples/13-mongo-typeorm/ormconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"type": "mongodb",
|
||||
"host": "localhost",
|
||||
"database": "nest",
|
||||
"entities": ["src/**/**.entity{.ts,.js}"],
|
||||
"synchronize": true
|
||||
}
|
||||
25
examples/13-mongo-typeorm/package.json
Normal file
25
examples/13-mongo-typeorm/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "nest-typescript-starter",
|
||||
"version": "1.0.0",
|
||||
"description": "Nest TypeScript starter repository",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"prestart:prod": "tsc",
|
||||
"start:prod": "node dist/server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^4.3.0",
|
||||
"@nestjs/core": "^4.3.0",
|
||||
"@nestjs/typeorm": "^1.0.0",
|
||||
"mongodb": "^2.2.31",
|
||||
"reflect-metadata": "^0.1.10",
|
||||
"rxjs": "^5.4.3",
|
||||
"typeorm": "0.1.0-alpha.40",
|
||||
"typescript": "^2.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^7.0.41",
|
||||
"ts-node": "^3.3.0"
|
||||
}
|
||||
}
|
||||
13
examples/13-mongo-typeorm/src/modules/app.module.ts
Normal file
13
examples/13-mongo-typeorm/src/modules/app.module.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { PhotoModule } from './photo/photo.module';
|
||||
import { Photo } from './photo/photo.entity';
|
||||
|
||||
@Module({
|
||||
modules: [
|
||||
TypeOrmModule.forRoot([Photo]),
|
||||
PhotoModule,
|
||||
],
|
||||
})
|
||||
export class ApplicationModule {}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { PhotoService } from './photo.service';
|
||||
import { Photo } from './photo.entity';
|
||||
|
||||
@Controller('photo')
|
||||
export class PhotoController {
|
||||
constructor(private readonly photoService: PhotoService) {}
|
||||
|
||||
@Get()
|
||||
findAll(): Promise<Photo[]> {
|
||||
return this.photoService.findAll();
|
||||
}
|
||||
}
|
||||
19
examples/13-mongo-typeorm/src/modules/photo/photo.entity.ts
Normal file
19
examples/13-mongo-typeorm/src/modules/photo/photo.entity.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Entity, Column, PrimaryGeneratedColumn, ObjectIdColumn, ObjectID } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class Photo {
|
||||
@ObjectIdColumn()
|
||||
id: ObjectID;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
description: string;
|
||||
|
||||
@Column()
|
||||
filename: string;
|
||||
|
||||
@Column()
|
||||
isPublished: boolean;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { PhotoService } from './photo.service';
|
||||
import { PhotoController } from './photo.controller';
|
||||
|
||||
@Module({
|
||||
components: [PhotoService],
|
||||
controllers: [PhotoController],
|
||||
})
|
||||
export class PhotoModule {}
|
||||
17
examples/13-mongo-typeorm/src/modules/photo/photo.service.ts
Normal file
17
examples/13-mongo-typeorm/src/modules/photo/photo.service.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Component, Inject } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { Photo } from './photo.entity';
|
||||
|
||||
@Component()
|
||||
export class PhotoService {
|
||||
constructor(
|
||||
@InjectRepository(Photo)
|
||||
private readonly photoRepository: Repository<Photo>,
|
||||
) {}
|
||||
|
||||
async findAll(): Promise<Photo[]> {
|
||||
return await this.photoRepository.find();
|
||||
}
|
||||
}
|
||||
8
examples/13-mongo-typeorm/src/server.ts
Normal file
8
examples/13-mongo-typeorm/src/server.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { ApplicationModule } from './modules/app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(ApplicationModule);
|
||||
await app.listen(3001);
|
||||
}
|
||||
bootstrap();
|
||||
22
examples/13-mongo-typeorm/tsconfig.json
Normal file
22
examples/13-mongo-typeorm/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
55
examples/13-mongo-typeorm/tslint.json
Normal file
55
examples/13-mongo-typeorm/tslint.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"defaultSeverity": "error",
|
||||
"extends": [
|
||||
"tslint:recommended"
|
||||
],
|
||||
"jsRules": {
|
||||
"no-unused-expression": true
|
||||
},
|
||||
"rules": {
|
||||
"eofline": false,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"ban-types": false,
|
||||
"indent": false,
|
||||
"ordered-imports": [
|
||||
false
|
||||
],
|
||||
"max-line-length": [
|
||||
150
|
||||
],
|
||||
"member-ordering": [
|
||||
false
|
||||
],
|
||||
"curly": false,
|
||||
"interface-name": [
|
||||
false
|
||||
],
|
||||
"array-type": [
|
||||
false
|
||||
],
|
||||
"member-access": [
|
||||
false
|
||||
],
|
||||
"no-empty-interface": false,
|
||||
"no-empty": false,
|
||||
"arrow-parens": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"no-unused-expression": false,
|
||||
"max-classes-per-file": [
|
||||
false
|
||||
],
|
||||
"variable-name": [
|
||||
false
|
||||
],
|
||||
"one-line": [
|
||||
false
|
||||
],
|
||||
"one-variable-per-declaration": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"rulesDirectory": []
|
||||
}
|
||||
21
examples/14-mongoose-module/.gitignore
vendored
Normal file
21
examples/14-mongoose-module/.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDE
|
||||
/.idea
|
||||
/.awcache
|
||||
/.vscode
|
||||
|
||||
# misc
|
||||
npm-debug.log
|
||||
|
||||
# example
|
||||
/quick-start
|
||||
|
||||
# tests
|
||||
/test
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# dist
|
||||
/dist
|
||||
14
examples/14-mongoose-module/index.js
Normal file
14
examples/14-mongoose-module/index.js
Normal file
@@ -0,0 +1,14 @@
|
||||
require('ts-node/register');
|
||||
require('./src/server');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
examples/14-mongoose-module/package.json
Normal file
25
examples/14-mongoose-module/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "nest-typescript-starter",
|
||||
"version": "1.0.0",
|
||||
"description": "Nest TypeScript starter repository",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"prestart:prod": "tsc",
|
||||
"start:prod": "node dist/server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^4.3.0",
|
||||
"@nestjs/core": "^4.3.0",
|
||||
"@nestjs/mongoose": "^1.0.1",
|
||||
"mongoose": "^4.11.13",
|
||||
"reflect-metadata": "^0.1.10",
|
||||
"rxjs": "^5.4.3",
|
||||
"typescript": "^2.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mongoose": "^4.7.23",
|
||||
"@types/node": "^7.0.41",
|
||||
"ts-node": "^3.3.0"
|
||||
}
|
||||
}
|
||||
15
examples/14-mongoose-module/src/modules/app.module.ts
Normal file
15
examples/14-mongoose-module/src/modules/app.module.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
|
||||
import { CatsModule } from './cats/cats.module';
|
||||
import { CatSchema } from './cats/schemas/cat.schema';
|
||||
|
||||
@Module({
|
||||
modules: [
|
||||
MongooseModule.forRoot('mongodb://localhost/nest', [
|
||||
{ name: 'Cat', schema: CatSchema },
|
||||
]),
|
||||
CatsModule,
|
||||
],
|
||||
})
|
||||
export class ApplicationModule {}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
|
||||
import { CreateCatDto } from './dto/create-cat.dto';
|
||||
import { CatsService } from './cats.service';
|
||||
import { Cat } from './interfaces/cat.interface';
|
||||
|
||||
@Controller('cats')
|
||||
export class CatsController {
|
||||
constructor(private readonly catsService: CatsService) {}
|
||||
|
||||
@Post()
|
||||
async create(@Body() createCatDto: CreateCatDto) {
|
||||
this.catsService.create(createCatDto);
|
||||
}
|
||||
|
||||
@Get()
|
||||
async findAll(): Promise<Cat[]> {
|
||||
return this.catsService.findAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { CatsController } from './cats.controller';
|
||||
import { CatsService } from './cats.service';
|
||||
|
||||
@Module({
|
||||
controllers: [CatsController],
|
||||
components: [CatsService],
|
||||
})
|
||||
export class CatsModule {}
|
||||
21
examples/14-mongoose-module/src/modules/cats/cats.service.ts
Normal file
21
examples/14-mongoose-module/src/modules/cats/cats.service.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Model } from 'mongoose';
|
||||
import { Component, Inject } from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
|
||||
import { Cat } from './interfaces/cat.interface';
|
||||
import { CreateCatDto } from './dto/create-cat.dto';
|
||||
import { CatSchema } from './schemas/cat.schema';
|
||||
|
||||
@Component()
|
||||
export class CatsService {
|
||||
constructor(@InjectModel(CatSchema) private readonly catModel: Model<Cat>) {}
|
||||
|
||||
async create(createCatDto: CreateCatDto): Promise<Cat> {
|
||||
const createdCat = new this.catModel(createCatDto);
|
||||
return await createdCat.save();
|
||||
}
|
||||
|
||||
async findAll(): Promise<Cat[]> {
|
||||
return await this.catModel.find().exec();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export class CreateCatDto {
|
||||
readonly name: string;
|
||||
readonly age: number;
|
||||
readonly breed: string;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Document } from 'mongoose';
|
||||
|
||||
export interface Cat extends Document {
|
||||
readonly name: string;
|
||||
readonly age: number;
|
||||
readonly breed: string;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import * as mongoose from 'mongoose';
|
||||
|
||||
export const CatSchema = new mongoose.Schema({
|
||||
name: String,
|
||||
age: Number,
|
||||
breed: String,
|
||||
});
|
||||
8
examples/14-mongoose-module/src/server.ts
Normal file
8
examples/14-mongoose-module/src/server.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { ApplicationModule } from './modules/app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(ApplicationModule);
|
||||
await app.listen(3001);
|
||||
}
|
||||
bootstrap();
|
||||
22
examples/14-mongoose-module/tsconfig.json
Normal file
22
examples/14-mongoose-module/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
54
examples/14-mongoose-module/tslint.json
Normal file
54
examples/14-mongoose-module/tslint.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"defaultSeverity": "error",
|
||||
"extends": [
|
||||
"tslint:recommended"
|
||||
],
|
||||
"jsRules": {
|
||||
"no-unused-expression": true
|
||||
},
|
||||
"rules": {
|
||||
"eofline": false,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"ban-types": false,
|
||||
"ordered-imports": [
|
||||
false
|
||||
],
|
||||
"max-line-length": [
|
||||
150
|
||||
],
|
||||
"member-ordering": [
|
||||
false
|
||||
],
|
||||
"curly": false,
|
||||
"interface-name": [
|
||||
false
|
||||
],
|
||||
"array-type": [
|
||||
false
|
||||
],
|
||||
"member-access": [
|
||||
false
|
||||
],
|
||||
"no-empty-interface": false,
|
||||
"no-empty": false,
|
||||
"arrow-parens": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"no-unused-expression": false,
|
||||
"max-classes-per-file": [
|
||||
false
|
||||
],
|
||||
"variable-name": [
|
||||
false
|
||||
],
|
||||
"one-line": [
|
||||
false
|
||||
],
|
||||
"one-variable-per-declaration": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"rulesDirectory": []
|
||||
}
|
||||
@@ -57,5 +57,7 @@ gulp.task('move', function() {
|
||||
gulp.dest('examples/09-babel-example/node_modules/@nestjs')
|
||||
).pipe(
|
||||
gulp.dest('examples/11-swagger/node_modules/@nestjs')
|
||||
).pipe(
|
||||
gulp.dest('examples/12-graphql-apollo/node_modules/@nestjs')
|
||||
);
|
||||
});
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
"description": "Modern, fast, powerful node.js web framework",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"start:live": "nodemon -e ts --watch src index.js",
|
||||
"test": "nyc --require ts-node/register mocha src/**/*.spec.ts --reporter spec",
|
||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
||||
"build": "gulp build && gulp move",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export class HttpException {
|
||||
private readonly message: string | object;
|
||||
|
||||
/**
|
||||
* The base Nest Application exception, which is handled by the default Exceptions Handler.
|
||||
* If you throw an exception from your HTTP route handlers, Nest will map them to the appropriate HTTP response and send to the client.
|
||||
@@ -16,7 +18,9 @@ export class HttpException {
|
||||
constructor(
|
||||
private readonly response: string | object,
|
||||
private readonly status: number,
|
||||
) {}
|
||||
) {
|
||||
this.message = response;
|
||||
}
|
||||
|
||||
public getResponse(): string | object {
|
||||
return this.response;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { MicroserviceConfiguration } from '@nestjs/microservices';
|
||||
import { INestMicroservice, ExceptionFilter, PipeTransform } from './index';
|
||||
import { WebSocketAdapter } from './web-socket-adapter.interface';
|
||||
import { CanActivate } from './can-activate.interface';
|
||||
import { NestInterceptor } from './nest-interceptor.interface';
|
||||
import { INestApplicationContext } from './nest-application-context.interface';
|
||||
|
||||
export interface INestApplication {
|
||||
export interface INestApplication extends INestApplicationContext {
|
||||
/**
|
||||
* Initializes application. It is not necessary to call this method directly.
|
||||
*
|
||||
@@ -20,6 +20,14 @@ export interface INestApplication {
|
||||
*/
|
||||
use(...args): void;
|
||||
|
||||
/**
|
||||
* The wrapper function around native `express.set()` method.
|
||||
* Example `app.set('trust proxy', 'loopback')`
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
set(...args): void;
|
||||
|
||||
/**
|
||||
* Starts the application.
|
||||
*
|
||||
@@ -63,7 +71,7 @@ export interface INestApplication {
|
||||
* @param {MicroserviceConfiguration} config Microservice configuration objet
|
||||
* @returns INestMicroservice
|
||||
*/
|
||||
connectMicroservice(config: MicroserviceConfiguration): INestMicroservice;
|
||||
connectMicroservice(config): INestMicroservice;
|
||||
|
||||
/**
|
||||
* Returns array of the connected microservices to the NestApplication.
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import { MessageMappingProperties } from '@nestjs/websockets/gateway-metadata-explorer';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
export interface WebSocketAdapter {
|
||||
create(port: number);
|
||||
createWithNamespace?(port: number, namespace: string);
|
||||
createWithNamespace?(port: number, namespace: string, server?);
|
||||
bindClientConnect(server, callback: (...args) => void);
|
||||
bindClientDisconnect?(client, callback: (...args) => void);
|
||||
bindMessageHandlers(client, handler: MessageMappingProperties[], process: (data) => Observable<any>);
|
||||
bindMessageHandlers(
|
||||
client,
|
||||
handler: {
|
||||
message: string;
|
||||
callback: (...args) => Observable<any> | Promise<any> | void;
|
||||
}[],
|
||||
process: (data) => Observable<any>,
|
||||
);
|
||||
bindMiddleware?(server, middleware: (socket, next) => void);
|
||||
}
|
||||
76
src/core/helpers/external-context-creator.ts
Normal file
76
src/core/helpers/external-context-creator.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import 'reflect-metadata';
|
||||
import { GuardsContextCreator } from './../guards/guards-context-creator';
|
||||
import { GuardsConsumer } from './../guards/guards-consumer';
|
||||
import { InterceptorsContextCreator } from './../interceptors/interceptors-context-creator';
|
||||
import { InterceptorsConsumer } from './../interceptors/interceptors-consumer';
|
||||
import { Controller } from '@nestjs/common/interfaces';
|
||||
import { FORBIDDEN_MESSAGE } from '../guards/constants';
|
||||
import { HttpStatus, HttpException } from '@nestjs/common';
|
||||
import { Module } from './../injector/module';
|
||||
import { ModulesContainer } from './../injector/modules-container';
|
||||
|
||||
export class ExternalContextCreator {
|
||||
constructor(
|
||||
private readonly guardsContextCreator: GuardsContextCreator,
|
||||
private readonly guardsConsumer: GuardsConsumer,
|
||||
private readonly interceptorsContextCreator: InterceptorsContextCreator,
|
||||
private readonly interceptorsConsumer: InterceptorsConsumer,
|
||||
private readonly modulesContainer: ModulesContainer,
|
||||
) {}
|
||||
|
||||
public create(
|
||||
instance: Controller,
|
||||
callback: (...args) => any,
|
||||
methodName: string,
|
||||
) {
|
||||
const module = this.findContextModuleName(instance.constructor);
|
||||
const guards = this.guardsContextCreator.create(instance, callback, module);
|
||||
const interceptors = this.interceptorsContextCreator.create(
|
||||
instance,
|
||||
callback,
|
||||
module,
|
||||
);
|
||||
return async (...args) => {
|
||||
const [req] = args;
|
||||
const canActivate = await this.guardsConsumer.tryActivate(
|
||||
guards,
|
||||
req,
|
||||
instance,
|
||||
callback,
|
||||
);
|
||||
if (!canActivate) {
|
||||
throw new HttpException(FORBIDDEN_MESSAGE, HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
const handler = () => callback.apply(instance, args);
|
||||
return await this.interceptorsConsumer.intercept(
|
||||
interceptors,
|
||||
req,
|
||||
instance,
|
||||
callback,
|
||||
handler,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public findContextModuleName(constructor: Function): string {
|
||||
const className = constructor.name;
|
||||
if (!className) {
|
||||
return '';
|
||||
}
|
||||
for (const [key, module] of [...this.modulesContainer.entries()]) {
|
||||
if (this.findComponentByClassName(module, className)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public findComponentByClassName(module: Module, className: string): boolean {
|
||||
const { components } = module;
|
||||
const hasComponent = [...components.keys()].find(
|
||||
component => component === className,
|
||||
);
|
||||
return !!hasComponent;
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,11 @@ import { UnknownModuleException } from '../errors/exceptions/unknown-module.exce
|
||||
import { ModuleTokenFactory } from './module-token-factory';
|
||||
import { InvalidModuleException } from './../errors/exceptions/invalid-module.exception';
|
||||
import { DynamicModule } from '@nestjs/common';
|
||||
import { ModulesContainer } from './modules-container';
|
||||
|
||||
export class NestContainer {
|
||||
private readonly globalModules = new Set<Module>();
|
||||
private readonly modules = new Map<string, Module>();
|
||||
private readonly modules = new ModulesContainer();
|
||||
private readonly dynamicModulesMetadata = new Map<string, Partial<DynamicModule>>();
|
||||
private readonly moduleTokenFactory = new ModuleTokenFactory();
|
||||
|
||||
@@ -26,7 +27,7 @@ export class NestContainer {
|
||||
if (this.modules.has(token)) {
|
||||
return;
|
||||
}
|
||||
const module = new Module(type, scope);
|
||||
const module = new Module(type, scope, this);
|
||||
this.modules.set(token, module);
|
||||
|
||||
this.addDynamicMetadata(token, dynamicMetadata);
|
||||
@@ -62,7 +63,7 @@ export class NestContainer {
|
||||
this.globalModules.add(module);
|
||||
}
|
||||
|
||||
public getModules(): Map<string, Module> {
|
||||
public getModules(): ModulesContainer {
|
||||
return this.modules;
|
||||
}
|
||||
|
||||
|
||||
1
src/core/injector/index.ts
Normal file
1
src/core/injector/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './modules-container';
|
||||
@@ -1,4 +1,4 @@
|
||||
import { InstanceWrapper } from './container';
|
||||
import { InstanceWrapper, NestContainer } from './container';
|
||||
import { Injectable, Controller, NestModule } from '@nestjs/common/interfaces';
|
||||
import { UnknownExportException } from '../errors/exceptions/unknown-export.exception';
|
||||
import { NestModuleMetatype } from '@nestjs/common/interfaces/modules/module-metatype.interface';
|
||||
@@ -7,6 +7,12 @@ import { ModuleRef } from './module-ref';
|
||||
import { isFunction, isNil, isUndefined } from '@nestjs/common/utils/shared.utils';
|
||||
import { RuntimeException } from '../errors/exceptions/runtime.exception';
|
||||
import { Reflector } from '../services/reflector.service';
|
||||
import { ExternalContextCreator } from './../helpers/external-context-creator';
|
||||
import { GuardsContextCreator } from './../guards/guards-context-creator';
|
||||
import { InterceptorsContextCreator } from './../interceptors/interceptors-context-creator';
|
||||
import { InterceptorsConsumer } from './../interceptors/interceptors-consumer';
|
||||
import { GuardsConsumer } from './../guards/guards-consumer';
|
||||
import { ModulesContainer } from './modules-container';
|
||||
|
||||
export interface CustomComponent {
|
||||
provide: any;
|
||||
@@ -27,9 +33,10 @@ export class Module {
|
||||
|
||||
constructor(
|
||||
private _metatype: NestModuleMetatype,
|
||||
private _scope: NestModuleMetatype[]) {
|
||||
|
||||
this.addCoreInjectables();
|
||||
private _scope: NestModuleMetatype[],
|
||||
container: NestContainer,
|
||||
) {
|
||||
this.addCoreInjectables(container);
|
||||
}
|
||||
|
||||
get scope(): NestModuleMetatype[] {
|
||||
@@ -68,10 +75,12 @@ export class Module {
|
||||
return this._metatype;
|
||||
}
|
||||
|
||||
public addCoreInjectables() {
|
||||
public addCoreInjectables(container: NestContainer) {
|
||||
this.addModuleRef();
|
||||
this.addModuleAsComponent();
|
||||
this.addReflector();
|
||||
this.addExternalContextCreator(container);
|
||||
this.addModulesContainer(container);
|
||||
}
|
||||
|
||||
public addModuleRef() {
|
||||
@@ -102,6 +111,30 @@ export class Module {
|
||||
});
|
||||
}
|
||||
|
||||
public addExternalContextCreator(container: NestContainer) {
|
||||
this._components.set(ExternalContextCreator.name, {
|
||||
name: ExternalContextCreator.name,
|
||||
metatype: ExternalContextCreator,
|
||||
isResolved: true,
|
||||
instance: new ExternalContextCreator(
|
||||
new GuardsContextCreator(container),
|
||||
new GuardsConsumer(),
|
||||
new InterceptorsContextCreator(container),
|
||||
new InterceptorsConsumer(),
|
||||
container.getModules(),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
public addModulesContainer(container: NestContainer) {
|
||||
this._components.set(ModulesContainer.name, {
|
||||
name: ModulesContainer.name,
|
||||
metatype: ModulesContainer,
|
||||
isResolved: true,
|
||||
instance: container.getModules(),
|
||||
});
|
||||
}
|
||||
|
||||
public addInjectable(injectable: Metatype<Injectable>) {
|
||||
if (this.isCustomProvider(injectable)) {
|
||||
return this.addCustomProvider(injectable, this._injectables);
|
||||
|
||||
3
src/core/injector/modules-container.ts
Normal file
3
src/core/injector/modules-container.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { Module } from './module';
|
||||
|
||||
export class ModulesContainer extends Map<string, Module> {}
|
||||
@@ -12,7 +12,8 @@ export class NestApplicationContext implements INestApplicationContext {
|
||||
constructor(
|
||||
protected readonly container: NestContainer,
|
||||
private readonly scope: NestModuleMetatype[],
|
||||
private readonly contextModule) {}
|
||||
protected contextModule,
|
||||
) {}
|
||||
|
||||
public select<T>(module: Metatype<T>): INestApplicationContext {
|
||||
const modules = this.container.getModules();
|
||||
|
||||
@@ -24,13 +24,14 @@ import { Resolver } from './router/interfaces/resolver.interface';
|
||||
import { RoutesResolver } from './router/routes-resolver';
|
||||
import { MicroservicesPackageNotFoundException } from './errors/exceptions/microservices-package-not-found.exception';
|
||||
import { MiddlewaresContainer } from './middlewares/container';
|
||||
import { NestApplicationContext } from './nest-application-context';
|
||||
|
||||
const { SocketModule } = optional('@nestjs/websockets/socket-module') || {} as any;
|
||||
const { MicroservicesModule } = optional('@nestjs/microservices/microservices-module') || {} as any;
|
||||
const { NestMicroservice } = optional('@nestjs/microservices/nest-microservice') || {} as any;
|
||||
const { IoAdapter } = optional('@nestjs/websockets/adapters/io-adapter') || {} as any;
|
||||
|
||||
export class NestApplication implements INestApplication {
|
||||
export class NestApplication extends NestApplicationContext implements INestApplication {
|
||||
private readonly logger = new Logger(NestApplication.name, true);
|
||||
private readonly middlewaresModule = new MiddlewaresModule();
|
||||
private readonly middlewaresContainer = new MiddlewaresContainer();
|
||||
@@ -47,11 +48,11 @@ export class NestApplication implements INestApplication {
|
||||
private readonly microservices = [];
|
||||
private isInitialized = false;
|
||||
|
||||
constructor(
|
||||
private readonly container: NestContainer,
|
||||
private readonly express,
|
||||
) {
|
||||
this.setupParserMiddlewares();
|
||||
constructor(container: NestContainer, private readonly express) {
|
||||
super(container, [], null);
|
||||
|
||||
const modules = this.container.getModules().values();
|
||||
this.contextModule = modules.next().value;
|
||||
this.httpServer = http.createServer(express);
|
||||
|
||||
const ioAdapter = IoAdapter ? new IoAdapter(this.httpServer) : null;
|
||||
@@ -61,11 +62,6 @@ export class NestApplication implements INestApplication {
|
||||
);
|
||||
}
|
||||
|
||||
public setupParserMiddlewares() {
|
||||
this.express.use(bodyParser.json());
|
||||
this.express.use(bodyParser.urlencoded({ extended: true }));
|
||||
}
|
||||
|
||||
public async setupModules() {
|
||||
this.socketModule && this.socketModule.setup(this.container, this.config);
|
||||
|
||||
@@ -81,6 +77,8 @@ export class NestApplication implements INestApplication {
|
||||
}
|
||||
|
||||
public async init() {
|
||||
this.setupParserMiddlewares();
|
||||
|
||||
await this.setupModules();
|
||||
await this.setupRouter();
|
||||
|
||||
@@ -89,6 +87,22 @@ export class NestApplication implements INestApplication {
|
||||
this.isInitialized = true;
|
||||
}
|
||||
|
||||
public setupParserMiddlewares() {
|
||||
const parserMiddlewares = {
|
||||
jsonParser: bodyParser.json(),
|
||||
urlencodedParser: bodyParser.urlencoded({ extended: true }),
|
||||
};
|
||||
Object.keys(parserMiddlewares)
|
||||
.filter((parser) => !this.isMiddlewareApplied(this.express, parser))
|
||||
.forEach((parserKey) => this.express.use(parserMiddlewares[parserKey]));
|
||||
}
|
||||
|
||||
public isMiddlewareApplied(app, name: string): boolean {
|
||||
return !!app._router && !!app._router.stack.filter(
|
||||
(layer) => layer && layer.handle && layer.handle.name === name,
|
||||
).length;
|
||||
}
|
||||
|
||||
public async setupRouter() {
|
||||
const router = ExpressAdapter.createRouter();
|
||||
await this.setupMiddlewares(router);
|
||||
@@ -128,6 +142,10 @@ export class NestApplication implements INestApplication {
|
||||
this.express.use(...args);
|
||||
}
|
||||
|
||||
public set(...args) {
|
||||
this.express.set(...args);
|
||||
}
|
||||
|
||||
public async listen(port: number, callback?: () => void);
|
||||
public async listen(port: number, hostname: string, callback?: () => void);
|
||||
public async listen(port: number, ...args) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { RequestMethod, HttpStatus } from '@nestjs/common';
|
||||
import { isNil, isObject } from '@nestjs/common/utils/shared.utils';
|
||||
import { isNil, isObject, isFunction } from '@nestjs/common/utils/shared.utils';
|
||||
import 'rxjs/add/operator/toPromise';
|
||||
|
||||
export class RouterResponseController {
|
||||
@@ -18,7 +17,7 @@ export class RouterResponseController {
|
||||
if (resultOrDeffered instanceof Promise) {
|
||||
return await resultOrDeffered;
|
||||
}
|
||||
else if (resultOrDeffered instanceof Observable) {
|
||||
else if (resultOrDeffered && isFunction(resultOrDeffered.subscribe)) {
|
||||
return await resultOrDeffered.toPromise();
|
||||
}
|
||||
return resultOrDeffered;
|
||||
|
||||
@@ -10,6 +10,7 @@ import { MetadataScanner } from '../metadata-scanner';
|
||||
import { RouterExplorer } from './interfaces/explorer.inteface';
|
||||
import { ExpressRouterExplorer } from './router-explorer';
|
||||
import { ApplicationConfig } from './../application-config';
|
||||
import { NotFoundException } from '@nestjs/common';
|
||||
|
||||
export class RoutesResolver implements Resolver {
|
||||
private readonly logger = new Logger(RoutesResolver.name, true);
|
||||
@@ -32,6 +33,9 @@ export class RoutesResolver implements Resolver {
|
||||
public resolve(express: Application) {
|
||||
const modules = this.container.getModules();
|
||||
modules.forEach(({ routes }, moduleName) => this.setupRouters(routes, moduleName, express));
|
||||
|
||||
this.setupNotFoundHandler(express);
|
||||
this.setupExceptionHandler(express);
|
||||
}
|
||||
|
||||
public setupRouters(
|
||||
@@ -48,7 +52,15 @@ export class RoutesResolver implements Resolver {
|
||||
const router = this.routerBuilder.explore(instance, metatype, moduleName);
|
||||
express.use(path, router);
|
||||
});
|
||||
this.setupExceptionHandler(express);
|
||||
}
|
||||
|
||||
public setupNotFoundHandler(express: Application) {
|
||||
const callback = (req, res) => {
|
||||
throw new NotFoundException(`Cannot ${req.method} ${req.url}`);
|
||||
};
|
||||
const exceptionHandler = this.routerExceptionsFilter.create({}, callback as any);
|
||||
const proxy = this.routerProxy.createProxy(callback, exceptionHandler);
|
||||
express.use(proxy);
|
||||
}
|
||||
|
||||
public setupExceptionHandler(express: Application) {
|
||||
|
||||
135
src/core/test/helpers/external-context-creator.spec.ts
Normal file
135
src/core/test/helpers/external-context-creator.spec.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { GuardsConsumer } from '../../guards/guards-consumer';
|
||||
import { GuardsContextCreator } from '../../guards/guards-context-creator';
|
||||
import { ModulesContainer } from '../../injector/modules-container';
|
||||
import { NestContainer } from '../../injector/container';
|
||||
import { InterceptorsContextCreator } from '../../interceptors/interceptors-context-creator';
|
||||
import { InterceptorsConsumer } from '../../interceptors/interceptors-consumer';
|
||||
import { ExternalContextCreator } from '../../helpers/external-context-creator';
|
||||
|
||||
describe('ExternalContextCreator', () => {
|
||||
let contextCreator: ExternalContextCreator;
|
||||
let callback;
|
||||
let applySpy: sinon.SinonSpy;
|
||||
let bindSpy: sinon.SinonSpy;
|
||||
let guardsConsumer: GuardsConsumer;
|
||||
|
||||
beforeEach(() => {
|
||||
callback = {
|
||||
bind: () => ({}),
|
||||
apply: () => ({}),
|
||||
};
|
||||
bindSpy = sinon.spy(callback, 'bind');
|
||||
applySpy = sinon.spy(callback, 'apply');
|
||||
|
||||
guardsConsumer = new GuardsConsumer();
|
||||
contextCreator = new ExternalContextCreator(
|
||||
new GuardsContextCreator(new NestContainer()),
|
||||
guardsConsumer,
|
||||
new InterceptorsContextCreator(new NestContainer()),
|
||||
new InterceptorsConsumer(),
|
||||
new ModulesContainer(),
|
||||
);
|
||||
});
|
||||
describe('create', () => {
|
||||
it('should call "findContextModuleName" with expected argument', done => {
|
||||
const findContextModuleNameSpy = sinon.spy(
|
||||
contextCreator,
|
||||
'findContextModuleName',
|
||||
);
|
||||
contextCreator.create({ foo: 'bar' }, callback as any, '');
|
||||
expect(findContextModuleNameSpy.called).to.be.true;
|
||||
done();
|
||||
});
|
||||
describe('returns proxy function', () => {
|
||||
let proxyContext;
|
||||
let instance;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = { foo: 'bar' };
|
||||
proxyContext = contextCreator.create(instance, callback as any, '');
|
||||
});
|
||||
it('should be a function', () => {
|
||||
expect(proxyContext).to.be.a('function');
|
||||
});
|
||||
describe('when proxy function called', () => {
|
||||
describe('when can not activate', () => {
|
||||
it('should throw exception when "tryActivate" returns false', () => {
|
||||
sinon.stub(guardsConsumer, 'tryActivate', () => false);
|
||||
expect(proxyContext(1, 2, 3)).to.eventually.throw();
|
||||
});
|
||||
});
|
||||
describe('when can activate', () => {
|
||||
it('should apply context and args', async () => {
|
||||
const args = [1, 2, 3];
|
||||
sinon.stub(guardsConsumer, 'tryActivate', () => true);
|
||||
|
||||
await proxyContext(...args);
|
||||
expect(applySpy.calledWith(instance, args)).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('findContextModuleName', () => {
|
||||
describe('when constructor name is undefined', () => {
|
||||
it('should return empty string', () => {
|
||||
expect(contextCreator.findContextModuleName({} as any)).to.be.eql('');
|
||||
});
|
||||
});
|
||||
describe('when component exists', () => {
|
||||
it('should return module key', () => {
|
||||
const modules = new Map();
|
||||
const componentKey = 'test';
|
||||
const moduleKey = 'key';
|
||||
|
||||
modules.set(moduleKey, {});
|
||||
(contextCreator as any).modulesContainer = modules;
|
||||
sinon.stub(contextCreator, 'findComponentByClassName', () => true);
|
||||
|
||||
expect(
|
||||
contextCreator.findContextModuleName({ name: componentKey } as any),
|
||||
).to.be.eql(moduleKey);
|
||||
});
|
||||
});
|
||||
describe('when component does not exists', () => {
|
||||
it('should return empty string', () => {
|
||||
sinon.stub(contextCreator, 'findComponentByClassName', () => false);
|
||||
expect(contextCreator.findContextModuleName({} as any)).to.be.eql('');
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('findComponentByClassName', () => {
|
||||
describe('when component exists', () => {
|
||||
it('should return true', () => {
|
||||
const components = new Map();
|
||||
const key = 'test';
|
||||
components.set(key, key);
|
||||
|
||||
expect(
|
||||
contextCreator.findComponentByClassName(
|
||||
{
|
||||
components,
|
||||
} as any,
|
||||
key,
|
||||
),
|
||||
).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('when component does not exists', () => {
|
||||
it('should return false', () => {
|
||||
const components = new Map();
|
||||
const key = 'test';
|
||||
expect(
|
||||
contextCreator.findComponentByClassName(
|
||||
{
|
||||
components,
|
||||
} as any,
|
||||
key,
|
||||
),
|
||||
).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { InstanceWrapper } from '../../injector/container';
|
||||
import { InstanceWrapper, NestContainer } from '../../injector/container';
|
||||
import { Injector } from '../../injector/injector';
|
||||
import { Component } from '../../../common/decorators/core/component.decorator';
|
||||
import { RuntimeException } from '../../errors/exceptions/runtime.exception';
|
||||
@@ -8,7 +8,7 @@ import { Module } from '../../injector/module';
|
||||
import { UnknownDependenciesException } from '../../errors/exceptions/unknown-dependencies.exception';
|
||||
import * as chai from 'chai';
|
||||
import * as chaiAsPromised from 'chai-as-promised';
|
||||
import { UndefinedDependencyException } from "../../errors/exceptions/undefined-dependency.exception";
|
||||
import { UndefinedDependencyException } from '../../errors/exceptions/undefined-dependency.exception';
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
describe('Injector', () => {
|
||||
@@ -37,7 +37,7 @@ describe('Injector', () => {
|
||||
let mainTest, depOne, depTwo;
|
||||
|
||||
beforeEach(() => {
|
||||
moduleDeps = new Module(DependencyTwo as any, []);
|
||||
moduleDeps = new Module(DependencyTwo as any, [], new NestContainer());
|
||||
mainTest = {
|
||||
name: 'MainTest',
|
||||
metatype: MainTest,
|
||||
@@ -117,7 +117,7 @@ describe('Injector', () => {
|
||||
let test;
|
||||
|
||||
beforeEach(() => {
|
||||
moduleDeps = new Module(Test as any, []);
|
||||
moduleDeps = new Module(Test as any, [], new NestContainer());
|
||||
test = {
|
||||
name: 'Test',
|
||||
metatype: Test,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { UnknownExportException } from '../../errors/exceptions/unknown-export.e
|
||||
import { Module } from '../../injector/module';
|
||||
import { Component } from '../../../common/decorators/core/component.decorator';
|
||||
import { RuntimeException } from '../../errors/exceptions/runtime.exception';
|
||||
import { NestContainer } from '../../injector/container';
|
||||
|
||||
describe('Module', () => {
|
||||
let module: Module;
|
||||
@@ -13,7 +14,7 @@ describe('Module', () => {
|
||||
@Component() class TestComponent {}
|
||||
|
||||
beforeEach(() => {
|
||||
module = new Module(TestModule as any, []);
|
||||
module = new Module(TestModule as any, [], new NestContainer());
|
||||
});
|
||||
|
||||
it('should add route', () => {
|
||||
|
||||
@@ -63,7 +63,7 @@ describe('RoutesResolver', () => {
|
||||
modules.set('TestModule2', { routes });
|
||||
|
||||
const spy = sinon.stub(routesResolver, 'setupRouters').callsFake(() => undefined);
|
||||
routesResolver.resolve({} as any);
|
||||
routesResolver.resolve({ use: sinon.spy() } as any);
|
||||
expect(spy.calledTwice).to.be.true;
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ export class ClientRedis extends ClientProxy {
|
||||
|
||||
protected sendSingleMessage(msg, callback: (...args) => any) {
|
||||
if (!this.pub || !this.sub) {
|
||||
this.init();
|
||||
this.init(callback);
|
||||
}
|
||||
const pattern = JSON.stringify(msg.pattern);
|
||||
const responseCallback = (channel, message) => {
|
||||
@@ -56,19 +56,24 @@ export class ClientRedis extends ClientProxy {
|
||||
this.sub && this.sub.quit();
|
||||
}
|
||||
|
||||
public init() {
|
||||
public init(callback: (...args) => any) {
|
||||
this.pub = this.createClient();
|
||||
this.sub = this.createClient();
|
||||
|
||||
this.handleErrors(this.pub);
|
||||
this.handleErrors(this.sub);
|
||||
this.handleErrors(this.pub, callback);
|
||||
this.handleErrors(this.sub, callback);
|
||||
}
|
||||
|
||||
public createClient(): redis.RedisClient {
|
||||
return redis.createClient({ url: this.url });
|
||||
}
|
||||
|
||||
public handleErrors(stream) {
|
||||
stream.on(ERROR_EVENT, (err) => this.logger.error(err));
|
||||
public handleErrors(stream, callback: (...args) => any) {
|
||||
stream.on(ERROR_EVENT, (err) => {
|
||||
if (err.code === 'ECONNREFUSED') {
|
||||
callback(err, null);
|
||||
}
|
||||
this.logger.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -24,12 +24,13 @@ export class ClientTCP extends ClientProxy {
|
||||
this.host = host || DEFAULT_HOST;
|
||||
}
|
||||
|
||||
public init(): Promise<{}> {
|
||||
public init(callback: (...args) => any): Promise<{}> {
|
||||
this.socket = this.createSocket();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.bindEvents(this.socket, callback);
|
||||
this.socket.on(CONNECT_EVENT, () => {
|
||||
this.isConnected = true;
|
||||
this.bindEvents(this.socket);
|
||||
resolve(this.socket);
|
||||
});
|
||||
this.socket.connect(this.port, this.host);
|
||||
@@ -45,7 +46,7 @@ export class ClientTCP extends ClientProxy {
|
||||
sendMessage(this.socket);
|
||||
return Promise.resolve();
|
||||
}
|
||||
const socket = await this.init();
|
||||
const socket = await this.init(callback);
|
||||
sendMessage(socket);
|
||||
}
|
||||
|
||||
@@ -64,15 +65,18 @@ export class ClientTCP extends ClientProxy {
|
||||
}
|
||||
|
||||
public close() {
|
||||
if (this.socket) {
|
||||
this.socket.end();
|
||||
this.socket && this.socket.end();
|
||||
this.isConnected = false;
|
||||
this.socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
public bindEvents(socket) {
|
||||
socket.on(ERROR_EVENT, (err) => this.logger.error(err));
|
||||
public bindEvents(socket, callback: (...args) => any) {
|
||||
socket.on(ERROR_EVENT, (err) => {
|
||||
if (err.code === 'ECONNREFUSED') {
|
||||
callback(err, null);
|
||||
}
|
||||
this.logger.error(err);
|
||||
});
|
||||
socket.on(CLOSE_EVENT, () => {
|
||||
this.isConnected = false;
|
||||
this.socket = null;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { RpcExceptionFilterMetadata } from '@nestjs/common/interfaces/exceptions
|
||||
import 'rxjs/add/observable/throw';
|
||||
|
||||
export class RpcExceptionsHandler {
|
||||
private static readonly logger = new Logger(RpcExceptionsHandler.name);
|
||||
private filters: RpcExceptionFilterMetadata[] = [];
|
||||
|
||||
public handle(exception: Error | RpcException | any): Observable<any> {
|
||||
@@ -18,10 +19,18 @@ export class RpcExceptionsHandler {
|
||||
const status = 'error';
|
||||
if (!(exception instanceof RpcException)) {
|
||||
const message = messages.UNKNOWN_EXCEPTION_MESSAGE;
|
||||
|
||||
const isError = isObject(exception) && (exception as Error).message;
|
||||
const loggerArgs = isError
|
||||
? [(exception as Error).message, (exception as Error).stack]
|
||||
: [exception];
|
||||
const logger = RpcExceptionsHandler.logger;
|
||||
logger.error.apply(logger, loggerArgs);
|
||||
|
||||
return Observable.throw({ status, message });
|
||||
}
|
||||
const res = exception.getError();
|
||||
const message = isObject(res) ? res : ({ status, message: res });
|
||||
const message = isObject(res) ? res : { status, message: res };
|
||||
return Observable.throw(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ describe('ClientRedis', () => {
|
||||
beforeEach(() => {
|
||||
createClientSpy = sinon.spy(client, 'createClient');
|
||||
handleErrorsSpy = sinon.spy(client, 'handleErrors');
|
||||
client.init();
|
||||
client.init(sinon.spy());
|
||||
});
|
||||
afterEach(() => {
|
||||
createClientSpy.restore();
|
||||
|
||||
@@ -16,7 +16,7 @@ export class IoAdapter implements WebSocketAdapter {
|
||||
return this.createIOServer(port);
|
||||
}
|
||||
|
||||
public createWithNamespace(port: number, namespace: string) {
|
||||
public createWithNamespace(port: number, namespace: string, server?) {
|
||||
return this.createIOServer(port).of(namespace);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,17 @@ export class SocketsContainer {
|
||||
return this.observableServers;
|
||||
}
|
||||
|
||||
public getServer(namespace: string, port: number): ObservableSocketServer {
|
||||
return this.observableServers.get(`${namespace}:${port}`);
|
||||
public getServerByPort(port: number): ObservableSocketServer {
|
||||
return this.observableServers.get(`${port}`);
|
||||
}
|
||||
|
||||
public addServer(namespace: string, port: number, server: ObservableSocketServer) {
|
||||
this.observableServers.set(`${namespace}:${port}`, server);
|
||||
this.observableServers.set(
|
||||
namespace
|
||||
? `${namespace}:${port}`
|
||||
: `${port}`,
|
||||
server,
|
||||
);
|
||||
}
|
||||
|
||||
public clear() {
|
||||
|
||||
@@ -10,24 +10,36 @@ export class SocketServerProvider {
|
||||
private readonly applicationConfig: ApplicationConfig) {}
|
||||
|
||||
public scanForSocketServer(namespace: string, port: number): ObservableSocketServer {
|
||||
const observableServer = this.socketsContainer.getServer(namespace, port);
|
||||
return observableServer ? observableServer : this.createSocketServer(namespace, port);
|
||||
const observableServer = this.socketsContainer.getServerByPort(port);
|
||||
return observableServer
|
||||
? this.createWithNamespace(namespace, port, observableServer)
|
||||
: this.createSocketServer(namespace, port);
|
||||
}
|
||||
|
||||
private createSocketServer(namespace: string, port: number) {
|
||||
const server = this.getServerOfNamespace(namespace, port);
|
||||
private createSocketServer(namespace: string, port: number): ObservableSocketServer {
|
||||
const adapter = this.applicationConfig.getIoAdapter();
|
||||
const server = adapter.create(port);
|
||||
const observableSocket = ObservableSocket.create(server);
|
||||
|
||||
this.socketsContainer.addServer(namespace, port, observableSocket);
|
||||
return observableSocket;
|
||||
this.socketsContainer.addServer(null, port, observableSocket);
|
||||
return this.createWithNamespace(namespace, port, observableSocket);
|
||||
}
|
||||
|
||||
private getServerOfNamespace(namespace: string, port: number) {
|
||||
private createWithNamespace(namespace: string, port: number, observableSocket: ObservableSocketServer): ObservableSocketServer {
|
||||
const adapter = this.applicationConfig.getIoAdapter();
|
||||
if (namespace && adapter.createWithNamespace) {
|
||||
return adapter.createWithNamespace(port, this.validateNamespace(namespace));
|
||||
if (!namespace || !adapter.createWithNamespace) {
|
||||
return observableSocket;
|
||||
}
|
||||
return adapter.create(port);
|
||||
const namespaceServer = this.getServerOfNamespace(namespace, port, observableSocket.server);
|
||||
const observableNamespaceSocket = ObservableSocket.create(namespaceServer);
|
||||
this.socketsContainer.addServer(namespace, port, observableNamespaceSocket);
|
||||
|
||||
return observableNamespaceSocket;
|
||||
}
|
||||
|
||||
private getServerOfNamespace(namespace: string, port: number, server) {
|
||||
const adapter = this.applicationConfig.getIoAdapter();
|
||||
return adapter.createWithNamespace(port, this.validateNamespace(namespace), server);
|
||||
}
|
||||
|
||||
private validateNamespace(namespace: string): string {
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('SocketsContainer', () => {
|
||||
});
|
||||
describe('getSocketServer', () => {
|
||||
it(`should call "observableServers" get method with expected arguments`, () => {
|
||||
instance.getServer(namespace, port);
|
||||
instance.getServerByPort(port);
|
||||
expect(getSpy.calledWith({ namespace, port }));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,15 +28,15 @@ describe('SocketServerProvider', () => {
|
||||
});
|
||||
it(`should returns stored server`, () => {
|
||||
const server = { test: 'test' };
|
||||
mockContainer.expects('getServer').returns(server);
|
||||
mockContainer.expects('getServerByPort').returns(server);
|
||||
|
||||
const result = instance.scanForSocketServer(namespace, port);
|
||||
const result = instance.scanForSocketServer(null, port);
|
||||
|
||||
expect(createSocketServerSpy.called).to.be.false;
|
||||
expect(result).to.eq(server);
|
||||
});
|
||||
it(`should call "createSocketServer" when server is not stored already`, () => {
|
||||
mockContainer.expects('getServer').returns(null);
|
||||
mockContainer.expects('getServerByPort').returns(null);
|
||||
|
||||
instance.scanForSocketServer(namespace, port);
|
||||
expect(createSocketServerSpy.called).to.be.true;
|
||||
|
||||
Reference in New Issue
Block a user