init db with migration, create users table
This commit is contained in:
@@ -17,16 +17,19 @@
|
||||
"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",
|
||||
"migrate:latest": "ts-node src/migrate.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@my-monorepo/common": "workspace:*",
|
||||
"@nestjs/common": "^11.0.1",
|
||||
"@nestjs/core": "^11.0.1",
|
||||
"@nestjs/platform-express": "^11.0.1",
|
||||
"kysely": "^0.28.3",
|
||||
"pg": "^8.16.3",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"zod": "^3.22.3"
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
@@ -39,6 +42,7 @@
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.10.7",
|
||||
"@types/pg": "^8.15.4",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
|
||||
@@ -5,7 +5,7 @@ import { AppService } from './app.service';
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get()
|
||||
@Get('hello')
|
||||
getHello(): string {
|
||||
return this.appService.getHello();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { HelloController } from './hello/hello.controller';
|
||||
import { AuthController } from './controllers/auth/auth.controller';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [AppController, HelloController],
|
||||
controllers: [AppController, AuthController],
|
||||
providers: [AppService],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { HelloController } from './hello.controller';
|
||||
import { AuthController } from './auth.controller';
|
||||
|
||||
describe('HelloController', () => {
|
||||
let controller: HelloController;
|
||||
describe('AuthController', () => {
|
||||
let controller: AuthController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [HelloController],
|
||||
controllers: [AuthController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<HelloController>(HelloController);
|
||||
controller = module.get<AuthController>(AuthController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
12
apps/backend/src/controllers/auth/auth.controller.ts
Normal file
12
apps/backend/src/controllers/auth/auth.controller.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { AuthApiService } from '@my-monorepo/common';
|
||||
import { Controller, Post } from '@nestjs/common';
|
||||
|
||||
@Controller(AuthApiService.baseUrl)
|
||||
export class AuthController implements AuthApiService {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
@Post(AuthApiService.postCredentials)
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
async postCredentials() {
|
||||
return 'hello';
|
||||
}
|
||||
}
|
||||
22
apps/backend/src/database/kysely-config.ts
Normal file
22
apps/backend/src/database/kysely-config.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Pool } from 'pg';
|
||||
import { Kysely, PostgresDialect } from 'kysely';
|
||||
|
||||
const dialect = new PostgresDialect({
|
||||
// TODO : temporary data, make to .env
|
||||
pool: new Pool({
|
||||
database: 'cowsi',
|
||||
host: 'localhost',
|
||||
user: 'postgres',
|
||||
password: 'postgres',
|
||||
port: 5432,
|
||||
max: 10,
|
||||
}),
|
||||
});
|
||||
|
||||
// Database interface is passed to Kysely's constructor, and from now on, Kysely
|
||||
// knows your database structure.
|
||||
// Dialect is passed to Kysely's constructor, and from now on, Kysely knows how
|
||||
// to communicate with your database.
|
||||
export const db = new Kysely<any>({
|
||||
dialect,
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller()
|
||||
export class HelloController {}
|
||||
56
apps/backend/src/migrate.ts
Normal file
56
apps/backend/src/migrate.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import * as path from 'path';
|
||||
import { Pool } from 'pg';
|
||||
import { promises as fs } from 'fs';
|
||||
import {
|
||||
Kysely,
|
||||
Migrator,
|
||||
PostgresDialect,
|
||||
FileMigrationProvider,
|
||||
} from 'kysely';
|
||||
import { ZodUnknownDef } from 'zod';
|
||||
|
||||
async function migrateToLatest() {
|
||||
const db = new Kysely<ZodUnknownDef>({
|
||||
dialect: new PostgresDialect({
|
||||
pool: new Pool({
|
||||
database: 'cowsi',
|
||||
host: 'localhost',
|
||||
user: 'postgres',
|
||||
password: 'postgres',
|
||||
port: 5432,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
const migrator = new Migrator({
|
||||
db,
|
||||
provider: new FileMigrationProvider({
|
||||
fs,
|
||||
path,
|
||||
// This needs to be an absolute path.
|
||||
migrationFolder: path.join(__dirname, './migrations'),
|
||||
}),
|
||||
});
|
||||
|
||||
const { error, results } = await migrator.migrateToLatest();
|
||||
|
||||
results?.forEach((it) => {
|
||||
if (it.status === 'Success') {
|
||||
console.log(`migration "${it.migrationName}" was executed successfully`);
|
||||
} else if (it.status === 'Error') {
|
||||
console.error(`failed to execute migration "${it.migrationName}"`);
|
||||
}
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error('failed to migrate');
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('Done migrating');
|
||||
}
|
||||
|
||||
await db.destroy();
|
||||
}
|
||||
|
||||
void migrateToLatest();
|
||||
30
apps/backend/src/migrations/2023-07-28_07-38-38_init_db.ts
Normal file
30
apps/backend/src/migrations/2023-07-28_07-38-38_init_db.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Kysely, sql } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<unknown>): Promise<void> {
|
||||
await db.schema
|
||||
.createTable('users')
|
||||
.addColumn('id', 'bigserial', (col) => col.primaryKey())
|
||||
.addColumn('first_name', 'varchar(255)', (col) => col.notNull())
|
||||
.addColumn('last_name', 'varchar(255)', (col) => col.notNull())
|
||||
.addColumn('email', 'varchar(255)', (col) => col.notNull().unique())
|
||||
.addColumn('hash', 'text')
|
||||
.addColumn('created_at', 'timestamptz', (col) =>
|
||||
col.notNull().defaultTo(sql`now()`),
|
||||
)
|
||||
.addColumn('updated_at', 'timestamptz', (col) =>
|
||||
col.notNull().defaultTo(sql`now()`),
|
||||
)
|
||||
.addColumn('deleted_at', 'timestamptz')
|
||||
.execute();
|
||||
|
||||
// You can also add indexes, foreign keys, etc. here
|
||||
await db.schema
|
||||
.createIndex('users_email_index')
|
||||
.on('users')
|
||||
.column('email')
|
||||
.execute();
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<unknown>): Promise<void> {
|
||||
await db.schema.dropTable('users').execute();
|
||||
}
|
||||
Reference in New Issue
Block a user