mirror of
https://github.com/docmost/docmost
synced 2025-03-28 21:13:28 +00:00
Setup TypeORM
This commit is contained in:
parent
11018ea976
commit
cebad0e0a5
36
.gitignore
vendored
Normal file
36
.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
.env
|
||||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Tests
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
3
server/.gitignore
vendored
3
server/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.env
|
||||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
@ -32,4 +33,4 @@ lerna-debug.log*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/extensions.json
|
||||
|
@ -45,6 +45,30 @@ $ npm run start:dev
|
||||
$ npm run start:prod
|
||||
```
|
||||
|
||||
|
||||
## Migrations
|
||||
|
||||
```bash
|
||||
# This creates a new empty migration file named 'init'
|
||||
$ npm run migration:create --name=init
|
||||
|
||||
# Generates 'init' migration file from existing entities to update the database schema
|
||||
$ npm run migration:generate --name=init
|
||||
|
||||
# Runs all pending migrations to update the database schema
|
||||
$ npm run migration:run
|
||||
|
||||
# Reverts the last executed migration
|
||||
$ npm run migration:revert
|
||||
|
||||
# Reverts all migrations
|
||||
$ npm run migration:revert
|
||||
|
||||
# Shows the list of executed and pending migrations
|
||||
$ npm run migration:show
|
||||
|
||||
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
|
677
server/package-lock.json
generated
677
server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -17,16 +17,30 @@
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"typeorm": "typeorm-ts-node-commonjs -d ./src/database/typeorm.config.ts",
|
||||
"migration:generate": "npm run typeorm migration:generate ./src/database/migrations/$npm_config_name",
|
||||
"migration:create": "typeorm-ts-node-commonjs migration:create ./src/database/migrations/$npm_config_name",
|
||||
"migration:run": "npm run typeorm migration:run",
|
||||
"migration:revert": "npm run typeorm migration:revert",
|
||||
"migration:revert:all": "while npm run migration:revert; do :; done",
|
||||
"migration:show": "npm run typeorm migration:show"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^3.0.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/mapped-types": "^2.0.2",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/platform-fastify": "^10.1.3",
|
||||
"@nestjs/typeorm": "^10.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"fastify": "^4.21.0",
|
||||
"pg": "^8.11.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1"
|
||||
"rxjs": "^7.8.1",
|
||||
"typeorm": "^0.3.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
|
@ -1,22 +0,0 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
describe('AppController', () => {
|
||||
let appController: AppController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const app: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
}).compile();
|
||||
|
||||
appController = app.get<AppController>(AppController);
|
||||
});
|
||||
|
||||
describe('root', () => {
|
||||
it('should return "Hello World!"', () => {
|
||||
expect(appController.getHello()).toBe('Hello World!');
|
||||
});
|
||||
});
|
||||
});
|
@ -1,9 +1,22 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { CoreModule } from './core/core.module';
|
||||
import { EnvironmentModule } from './environment/environment.module';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AppDataSource } from './database/typeorm.config';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
imports: [
|
||||
CoreModule,
|
||||
EnvironmentModule,
|
||||
TypeOrmModule.forRoot({
|
||||
...AppDataSource.options,
|
||||
entities: ['dist/src/**/*.entity.ts'],
|
||||
migrations: ['dist/src/**/migrations/*.{ts,js}'],
|
||||
autoLoadEntities: true,
|
||||
}),
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
})
|
||||
|
7
server/src/core/core.module.ts
Normal file
7
server/src/core/core.module.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UserModule } from './user/user.module';
|
||||
|
||||
@Module({
|
||||
imports: [UserModule],
|
||||
})
|
||||
export class CoreModule {}
|
1
server/src/core/user/dto/create-user.dto.ts
Normal file
1
server/src/core/user/dto/create-user.dto.ts
Normal file
@ -0,0 +1 @@
|
||||
export class CreateUserDto {}
|
4
server/src/core/user/dto/update-user.dto.ts
Normal file
4
server/src/core/user/dto/update-user.dto.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateUserDto } from './create-user.dto';
|
||||
|
||||
export class UpdateUserDto extends PartialType(CreateUserDto) {}
|
49
server/src/core/user/entities/user.entity.ts
Normal file
49
server/src/core/user/entities/user.entity.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity('users')
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column({ unique: true })
|
||||
email: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
emailVerifiedAt: Date;
|
||||
|
||||
@Column()
|
||||
password: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
avatar_url: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
locale: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
timezone: string;
|
||||
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
settings: any;
|
||||
|
||||
@Column({ nullable: true })
|
||||
lastLoginAt: Date;
|
||||
|
||||
@Column({ nullable: true })
|
||||
lastLoginIp: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
4
server/src/core/user/repositories/user.repository.ts
Normal file
4
server/src/core/user/repositories/user.repository.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { Repository } from 'typeorm';
|
||||
import { User } from '../entities/user.entity';
|
||||
|
||||
export class UserRepository extends Repository<User> {}
|
20
server/src/core/user/user.controller.spec.ts
Normal file
20
server/src/core/user/user.controller.spec.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UserController } from './user.controller';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
describe('UserController', () => {
|
||||
let controller: UserController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [UserController],
|
||||
providers: [UserService],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<UserController>(UserController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
37
server/src/core/user/user.controller.ts
Normal file
37
server/src/core/user/user.controller.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
} from '@nestjs/common';
|
||||
import { UserService } from './user.service';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
import { UpdateUserDto } from './dto/update-user.dto';
|
||||
|
||||
@Controller('user')
|
||||
export class UserController {
|
||||
constructor(private readonly userService: UserService) {}
|
||||
|
||||
@Post()
|
||||
create(@Body() createUserDto: CreateUserDto) {
|
||||
return this.userService.create(createUserDto);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.userService.findOne(+id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
|
||||
return this.userService.update(+id, updateUserDto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string) {
|
||||
return this.userService.remove(+id);
|
||||
}
|
||||
}
|
12
server/src/core/user/user.module.ts
Normal file
12
server/src/core/user/user.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UserService } from './user.service';
|
||||
import { UserController } from './user.controller';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { User } from './entities/user.entity';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([User])],
|
||||
controllers: [UserController],
|
||||
providers: [UserService],
|
||||
})
|
||||
export class UserModule {}
|
18
server/src/core/user/user.service.spec.ts
Normal file
18
server/src/core/user/user.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
describe('UserService', () => {
|
||||
let service: UserService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [UserService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<UserService>(UserService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
30
server/src/core/user/user.service.ts
Normal file
30
server/src/core/user/user.service.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
import { UpdateUserDto } from './dto/update-user.dto';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { User } from './entities/user.entity';
|
||||
import { UserRepository } from './repositories/user.repository';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
constructor(@InjectRepository(User) private userRepository: UserRepository) {}
|
||||
create(createUserDto: CreateUserDto) {
|
||||
return 'This action adds a new user';
|
||||
}
|
||||
|
||||
findAll() {
|
||||
return `This action returns all user`;
|
||||
}
|
||||
|
||||
findOne(id: number) {
|
||||
return `This action returns a #${id} user`;
|
||||
}
|
||||
|
||||
update(id: number, updateUserDto: UpdateUserDto) {
|
||||
return `This action updates a #${id} user`;
|
||||
}
|
||||
|
||||
remove(id: number) {
|
||||
return `This action removes a #${id} user`;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class CreateUserTable1691158956520 implements MigrationInterface {
|
||||
name = 'CreateUserTable1691158956520';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "users" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying NOT NULL, "email" character varying NOT NULL, "emailVerifiedAt" TIMESTAMP, "password" character varying NOT NULL, "avatar_url" character varying, "locale" character varying, "timezone" character varying, "settings" jsonb, "lastLoginAt" TIMESTAMP, "lastLoginIp" character varying, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_97672ac88f789774dd47f7c8be3" UNIQUE ("email"), CONSTRAINT "PK_a3ffb1c0c8416b9fc6f907b7433" PRIMARY KEY ("id"))`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP TABLE "users"`);
|
||||
}
|
||||
}
|
14
server/src/database/typeorm.config.ts
Normal file
14
server/src/database/typeorm.config.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { DataSource } from 'typeorm';
|
||||
import * as dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
export const AppDataSource = new DataSource({
|
||||
type: 'postgres',
|
||||
url:
|
||||
process.env.DATABASE_URL ||
|
||||
'postgresql://postgres:password@localhost:5432/dc?schema=public',
|
||||
entities: ['src/**/*.entity.ts'],
|
||||
migrations: ['src/**/migrations/*.{ts,js}'],
|
||||
subscribers: [],
|
||||
synchronize: process.env.NODE_ENV === 'development',
|
||||
logging: process.env.NODE_ENV === 'development',
|
||||
});
|
18
server/src/environment/environment.module.ts
Normal file
18
server/src/environment/environment.module.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { EnvironmentService } from './environment.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { validate } from './environment.validation';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
expandVariables: true,
|
||||
validate,
|
||||
}),
|
||||
],
|
||||
providers: [EnvironmentService],
|
||||
exports: [EnvironmentService],
|
||||
})
|
||||
export class EnvironmentModule {}
|
18
server/src/environment/environment.service.spec.ts
Normal file
18
server/src/environment/environment.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { EnvironmentService } from './environment.service';
|
||||
|
||||
describe('EnvironmentService', () => {
|
||||
let service: EnvironmentService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [EnvironmentService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<EnvironmentService>(EnvironmentService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
26
server/src/environment/environment.service.ts
Normal file
26
server/src/environment/environment.service.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
@Injectable()
|
||||
export class EnvironmentService {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
getEnv(): string {
|
||||
return this.configService.get<string>('NODE_ENV');
|
||||
}
|
||||
|
||||
getPort(): string {
|
||||
return this.configService.get<string>('PORT');
|
||||
}
|
||||
getDatabaseURL(): string {
|
||||
return this.configService.get<string>('DATABASE_URL');
|
||||
}
|
||||
|
||||
getJwtSecret(): string {
|
||||
return this.configService.get<string>('JWT_SECRET_KEY');
|
||||
}
|
||||
|
||||
getJwtTokenExpiresIn(): string {
|
||||
return this.configService.get<string>('JWT_TOKEN_EXPIRES_IN');
|
||||
}
|
||||
}
|
20
server/src/environment/environment.validation.ts
Normal file
20
server/src/environment/environment.validation.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { IsString, IsUrl, validateSync } from 'class-validator';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
|
||||
export class EnvironmentVariables {
|
||||
@IsString()
|
||||
NODE_ENV: string;
|
||||
|
||||
@IsUrl({ protocols: ['postgres', 'postgresql'], require_tld: false })
|
||||
DATABASE_URL: string;
|
||||
}
|
||||
|
||||
export function validate(config: Record<string, any>) {
|
||||
const validatedConfig = plainToClass(EnvironmentVariables, config);
|
||||
|
||||
const errors = validateSync(validatedConfig);
|
||||
if (errors.length > 0) {
|
||||
throw new Error(errors.toString());
|
||||
}
|
||||
return validatedConfig;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user