Skip to content

Commit

Permalink
Merge e0ec5b8 into 644acfd
Browse files Browse the repository at this point in the history
  • Loading branch information
rychkog committed Jul 5, 2020
2 parents 644acfd + e0ec5b8 commit a6fc744
Show file tree
Hide file tree
Showing 97 changed files with 5,232 additions and 21 deletions.
1 change: 1 addition & 0 deletions .npmrc
@@ -0,0 +1 @@
scripts-prepend-node-path=true
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -91,6 +91,7 @@ We believe that everyone who's working with NestJs and building some RESTful ser
- [**@nestjsx/crud**](https://www.npmjs.com/package/@nestjsx/crud) - core package which provides `@Crud()` decorator for endpoints generation, global configuration, validation, helper decorators ([docs](https://github.com/nestjsx/crud/wiki/Controllers#description))
- [**@nestjsx/crud-request**](https://www.npmjs.com/package/@nestjsx/crud-request) - request builder/parser package which provides `RequestQueryBuilder` class for a frontend usage and `RequestQueryParser` that is being used internally for handling and validating query/path params on a backend side ([docs](https://github.com/nestjsx/crud/wiki/Requests#frontend-usage))
- [**@nestjsx/crud-typeorm**](https://www.npmjs.com/package/@nestjsx/crud-typeorm) - TypeORM package which provides base `TypeOrmCrudService` with methods for CRUD database operations ([docs](https://github.com/nestjsx/crud/wiki/ServiceTypeorm))
- [**@nestjsx/crud-objection**](https://www.npmjs.com/package/@nestjsx/crud-objection) - Objection.js package which provides base `ObjectionCrudService` with methods for CRUD database operations ([docs](https://github.com/nestjsx/crud/wiki/ServiceObjection))

## Documentation

Expand Down
18 changes: 18 additions & 0 deletions integration/crud-objection/app.module.ts
@@ -0,0 +1,18 @@
import { Module } from '@nestjs/common';
import { CompaniesModule } from './companies/companies.module';
import { ProjectsModule } from './projects/projects.module';
import { UsersModule } from './users/users.module';
import { DatabaseModule } from './database.module';
import { APP_GUARD } from '@nestjs/core';
import { AuthGuard } from './auth.guard';

@Module({
imports: [DatabaseModule, CompaniesModule, ProjectsModule, UsersModule],
providers: [
{
provide: APP_GUARD,
useClass: AuthGuard,
},
],
})
export class AppModule {}
16 changes: 16 additions & 0 deletions integration/crud-objection/auth.guard.ts
@@ -0,0 +1,16 @@
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';

import { UsersService } from './users';
import { USER_REQUEST_KEY } from './constants';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private usersService: UsersService) {}

async canActivate(ctx: ExecutionContext): Promise<boolean> {
const req = ctx.switchToHttp().getRequest();
req[USER_REQUEST_KEY] = await this.usersService.modelClass.query().findById(1);

return true;
}
}
16 changes: 16 additions & 0 deletions integration/crud-objection/base.model.ts
@@ -0,0 +1,16 @@
import { Model } from 'objection';

export class BaseModel extends Model {
readonly id: number;

createdAt: Date;
updatedAt: Date;

$beforeUpdate() {
this.updatedAt = new Date();
}

$beforeInsert() {
this.createdAt = new Date();
}
}
48 changes: 48 additions & 0 deletions integration/crud-objection/companies/companies.controller.ts
@@ -0,0 +1,48 @@
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Crud } from '@nestjsx/crud';

import { Company } from './company.model';
import { CompaniesService } from './companies.service';
import { serialize } from './responses';

@Crud({
model: {
type: Company,
},
serialize,
routes: {
deleteOneBase: {
returnDeleted: false,
},
},
query: {
alwaysPaginate: false,
allow: ['name'],
join: {
users: {
alias: 'companyUsers',
exclude: ['email'],
eager: true,
},
'users.projects': {
eager: true,
alias: 'usersProjects',
allow: ['name'],
},
'users.projects.company': {
eager: true,
alias: 'usersProjectsCompany',
},
projects: {
eager: true,
select: false,
},
},
},
})
@ApiTags('companies')
@Controller('companies')
export class CompaniesController {
constructor(public service: CompaniesService) {}
}
10 changes: 10 additions & 0 deletions integration/crud-objection/companies/companies.module.ts
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { CompaniesService } from './companies.service';
import { CompaniesController } from './companies.controller';

@Module({
providers: [CompaniesService],
exports: [CompaniesService],
controllers: [CompaniesController],
})
export class CompaniesModule {}
12 changes: 12 additions & 0 deletions integration/crud-objection/companies/companies.service.ts
@@ -0,0 +1,12 @@
import { Inject, Injectable } from '@nestjs/common';

import { Company } from './company.model';
import { ModelClass } from 'objection';
import { ObjectionCrudService } from '@nestjsx/crud-objection';

@Injectable()
export class CompaniesService extends ObjectionCrudService<Company> {
constructor(@Inject('Company') modelClass: ModelClass<Company>) {
super(modelClass);
}
}
58 changes: 58 additions & 0 deletions integration/crud-objection/companies/company.model.ts
@@ -0,0 +1,58 @@
import * as path from 'path';
import { IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
import { CrudValidationGroups } from '@nestjsx/crud';

import { User } from '../users/user.model';
import { Project } from '../projects/project.model';
import { BaseModel } from '../base.model';
import { Model } from 'objection';
import { Type } from 'class-transformer';

const { CREATE, UPDATE } = CrudValidationGroups;

export class Company extends BaseModel {
static tableName = 'companies';

@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString({ always: true })
@MaxLength(100, { always: true })
name: string;

@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString({ groups: [CREATE, UPDATE] })
@MaxLength(100, { groups: [CREATE, UPDATE] })
domain: string;

@IsOptional({ always: true })
@IsString({ always: true })
description: string;

/**
* Relations
*/

@Type((t) => User)
users?: User[];
projects?: Project[];

static relationMappings = {
users: {
relation: Model.HasManyRelation,
modelClass: path.resolve(__dirname, '../users/user.model'),
join: {
from: 'companies.id',
to: 'users.companyId',
},
},
projects: {
relation: Model.HasManyRelation,
modelClass: path.resolve(__dirname, '../projects/project.model'),
join: {
from: 'companies.id',
to: 'projects.companyId',
},
},
};
}
2 changes: 2 additions & 0 deletions integration/crud-objection/companies/index.ts
@@ -0,0 +1,2 @@
export * from './company.model';
export * from './companies.service';
@@ -0,0 +1,19 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, MaxLength } from 'class-validator';

export class CreateCompanyDto {
@ApiProperty({ type: 'string' })
@IsString()
@MaxLength(100)
name: string;

@ApiProperty({ type: 'string' })
@IsString()
@MaxLength(100)
domain: string;

@ApiProperty({ type: 'string' })
@IsString()
@MaxLength(100)
description: string;
}
5 changes: 5 additions & 0 deletions integration/crud-objection/companies/requests/index.ts
@@ -0,0 +1,5 @@
import { CreateCompanyDto } from './create-company.dto';

export const dto = {
create: CreateCompanyDto,
};
@@ -0,0 +1,22 @@
import { ApiProperty } from '@nestjs/swagger';
import { Exclude } from 'class-transformer';

export class GetCompanyResponseDto {
@ApiProperty({ type: 'number' })
id: string;

@ApiProperty({ type: 'string' })
name: string;

@ApiProperty({ type: 'string' })
domain: string;

@ApiProperty({ type: 'string' })
description: string;

@Exclude()
createdAt: any;

@Exclude()
updatedAt: any;
}
6 changes: 6 additions & 0 deletions integration/crud-objection/companies/responses/index.ts
@@ -0,0 +1,6 @@
import { SerializeOptions } from '@nestjsx/crud';
import { GetCompanyResponseDto } from './get-company-response.dto';

export const serialize: SerializeOptions = {
get: GetCompanyResponseDto,
};
1 change: 1 addition & 0 deletions integration/crud-objection/constants.ts
@@ -0,0 +1 @@
export const USER_REQUEST_KEY = 'user';
55 changes: 55 additions & 0 deletions integration/crud-objection/database.module.ts
@@ -0,0 +1,55 @@
import { Global, Module } from '@nestjs/common';
import * as Knex from 'knex';
import { knexSnakeCaseMappers, Model } from 'objection';
import { UserProfile } from './users-profiles';
import { Project, UserProject } from './projects';
import { Company } from './companies';
import { User } from './users';
import { KNEX_CONNECTION } from './injection-tokens';
import { Device } from './devices';
import { License, UserLicense } from './users-licenses';
import { Note } from './notes';

const models = [
User,
Company,
Project,
UserProfile,
UserProject,
Device,
License,
UserLicense,
Note,
];

const modelProviders = models.map((model) => {
return {
provide: model.name,
useValue: model,
};
});

const providers = [
...modelProviders,
{
provide: KNEX_CONNECTION,
useFactory: async () => {
const knex = Knex({
client: 'pg',
connection: 'postgres://root:root@127.0.0.1:5455/nestjsx_crud_objection',
debug: process.env.KNEX_DEBUG === 'true',
...knexSnakeCaseMappers(),
});

Model.knex(knex);
return knex;
},
},
];

@Global()
@Module({
providers: [...providers],
exports: [...providers],
})
export class DatabaseModule {}
18 changes: 18 additions & 0 deletions integration/crud-objection/devices/device.model.ts
@@ -0,0 +1,18 @@
import { IsOptional, IsString, IsUUID } from 'class-validator';
import { Model } from 'objection';

export class Device extends Model {
static readonly tableName = 'devices';

static get idColumn() {
return ['deviceKey'];
}

@IsOptional({ always: true })
@IsUUID('4', { always: true })
deviceKey: string;

@IsOptional({ always: true })
@IsString({ always: true })
description?: string;
}
29 changes: 29 additions & 0 deletions integration/crud-objection/devices/devices.controller.ts
@@ -0,0 +1,29 @@
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Crud } from '@nestjsx/crud';

import { DevicesService } from './devices.service';
import { serialize } from './response';
import { Device } from './device.model';

@Crud({
model: { type: Device },
serialize,
params: {
deviceKey: {
field: 'deviceKey',
type: 'uuid',
primary: true,
},
},
routes: {
deleteOneBase: {
returnDeleted: true,
},
},
})
@ApiTags('devices')
@Controller('/devices')
export class DevicesController {
constructor(public service: DevicesService) {}
}
11 changes: 11 additions & 0 deletions integration/crud-objection/devices/devices.module.ts
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';

import { DevicesService } from './devices.service';
import { DevicesController } from './devices.controller';

@Module({
providers: [DevicesService],
exports: [DevicesService],
controllers: [DevicesController],
})
export class DevicesModule {}
12 changes: 12 additions & 0 deletions integration/crud-objection/devices/devices.service.ts
@@ -0,0 +1,12 @@
import { Inject, Injectable } from '@nestjs/common';

import { Device } from './device.model';
import { ObjectionCrudService } from '@nestjsx/crud-objection';
import { ModelClass } from 'objection';

@Injectable()
export class DevicesService extends ObjectionCrudService<Device> {
constructor(@Inject('Device') modelClass: ModelClass<Device>) {
super(modelClass);
}
}
2 changes: 2 additions & 0 deletions integration/crud-objection/devices/index.ts
@@ -0,0 +1,2 @@
export * from './device.model';
export * from './devices.service';
@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { Exclude } from 'class-transformer';

export class DeleteDeviceResponseDto {
@ApiProperty({ type: 'string' })
deviceKey: string;

@Exclude()
description?: string;
}

0 comments on commit a6fc744

Please sign in to comment.