diff --git a/.github/workflows/nepal.yml b/.github/workflows/nepal.yml index 9af5d6f..3e42031 100644 --- a/.github/workflows/nepal.yml +++ b/.github/workflows/nepal.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - nepal jobs: build: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6210922 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +version: "3.8" + +services: + postgres_db: + image: postgres:latest + container_name: postgres + restart: always + environment: + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres123 + - POSTGRES_DB=coachnpdb + ports: + - "5432:5432" + volumes: + - ./database:/var/lib/postgresql/data diff --git a/src/database/migrations/1701434781415-migrations.ts b/src/database/migrations/1701434781415-migrations.ts new file mode 100644 index 0000000..3f95725 --- /dev/null +++ b/src/database/migrations/1701434781415-migrations.ts @@ -0,0 +1,20 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class migrations1701434781415 implements MigrationInterface { + name = 'migrations1701434781415' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "region" ADD "parent_id" uuid`); + await queryRunner.query(`ALTER TABLE "region" ALTER COLUMN "updated_at" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "region" ALTER COLUMN "updated_at" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "region" ADD CONSTRAINT "FK_2547f55866c0274d35fdd9a29c0" FOREIGN KEY ("parent_id") REFERENCES "region"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "region" DROP CONSTRAINT "FK_2547f55866c0274d35fdd9a29c0"`); + await queryRunner.query(`ALTER TABLE "region" ALTER COLUMN "updated_at" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "region" ALTER COLUMN "updated_at" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "region" DROP COLUMN "parent_id"`); + } + +} diff --git a/src/database/migrations/1701624768823-migrations.ts b/src/database/migrations/1701624768823-migrations.ts new file mode 100644 index 0000000..04e760f --- /dev/null +++ b/src/database/migrations/1701624768823-migrations.ts @@ -0,0 +1,18 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class migrations1701624768823 implements MigrationInterface { + name = 'migrations1701624768823' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "region" DROP CONSTRAINT "FK_2547f55866c0274d35fdd9a29c0"`); + await queryRunner.query(`ALTER TABLE "region" ADD "level" integer`); + await queryRunner.query(`ALTER TABLE "region" ADD CONSTRAINT "FK_2547f55866c0274d35fdd9a29c0" FOREIGN KEY ("parent_id") REFERENCES "region"("id") ON DELETE CASCADE ON UPDATE CASCADE`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "region" DROP CONSTRAINT "FK_2547f55866c0274d35fdd9a29c0"`); + await queryRunner.query(`ALTER TABLE "region" DROP COLUMN "level"`); + await queryRunner.query(`ALTER TABLE "region" ADD CONSTRAINT "FK_2547f55866c0274d35fdd9a29c0" FOREIGN KEY ("parent_id") REFERENCES "region"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + +} diff --git a/src/modules/dashboard/controller/index.ts b/src/modules/dashboard/controller/index.ts index 0a4572e..fb19c95 100644 --- a/src/modules/dashboard/controller/index.ts +++ b/src/modules/dashboard/controller/index.ts @@ -3,8 +3,7 @@ import { DashboardService } from "../service"; import { constants } from "http2"; import { SchoolService } from "../../school/service"; -import { School } from "../../school/entity/school.entity"; -import { Region } from "../../school/entity/region.entity"; +import { Region } from "../../region/entity/region.entity"; const { HTTP_STATUS_OK, HTTP_STATUS_INTERNAL_SERVER_ERROR } = constants; diff --git a/src/modules/region/controller/index.ts b/src/modules/region/controller/index.ts index 1929789..0579152 100644 --- a/src/modules/region/controller/index.ts +++ b/src/modules/region/controller/index.ts @@ -46,7 +46,7 @@ export default class SchoolController { } }; - public static findAll = async ( + public static findAllParents = async ( _req: Request, res: Response ): Promise => { @@ -61,4 +61,36 @@ export default class SchoolController { }); } }; + + public static findAllByParent = async ( + req: Request, + res: Response + ): Promise => { + try { + const list = await RegionService.findByParentId(req.params.id); + return res.status(HTTP_STATUS_OK).send(list); + } catch (error) { + console.log({ error }); + res.status(HTTP_STATUS_INTERNAL_SERVER_ERROR).send({ + error: HTTP_STATUS_INTERNAL_SERVER_ERROR, + message: (error as any).message, + }); + } + }; + + public static findById = async ( + req: Request, + res: Response + ): Promise => { + try { + const item = await RegionService.findById(req.params.id); + return res.status(HTTP_STATUS_OK).send(item); + } catch (error) { + console.log({ error }); + res.status(HTTP_STATUS_INTERNAL_SERVER_ERROR).send({ + error: HTTP_STATUS_INTERNAL_SERVER_ERROR, + message: (error as any).message, + }); + } + }; } diff --git a/src/modules/region/entity/region.entity.ts b/src/modules/region/entity/region.entity.ts index 8eb6e2b..49908b2 100644 --- a/src/modules/region/entity/region.entity.ts +++ b/src/modules/region/entity/region.entity.ts @@ -1,6 +1,8 @@ import { Column, Entity, + JoinColumn, + ManyToOne, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn, @@ -19,7 +21,27 @@ export class Region { @Column({ nullable: true }) name?: string; - schoolsCount?: number; + @Column({ nullable: true }) + level?: number; + + @Column({ nullable: true }) + parent_id?: string; + + @ManyToOne(() => Region, (region) => region.children, { + onDelete: "CASCADE", + onUpdate: "CASCADE", + orphanedRowAction: "delete", + }) + @JoinColumn({ name: "parent_id" }) + parent?: Region; + + @OneToMany(() => Region, (region) => region.parent, { + cascade: true, + onDelete: "CASCADE", + onUpdate: "CASCADE", + orphanedRowAction: "delete", + }) + children?: Region[]; @OneToMany(() => School, (school) => school.region) schools?: School[]; @@ -30,4 +52,6 @@ export class Region { @Column({ nullable: true }) deleted_at?: Date; + + schoolsCount?: number; } diff --git a/src/modules/region/routes.ts b/src/modules/region/routes.ts index 23458a4..636add4 100644 --- a/src/modules/region/routes.ts +++ b/src/modules/region/routes.ts @@ -22,7 +22,22 @@ const schoolRouter = (app: Application): void => { app.get( `/${config.country}/api/region`, Authentication.authenticate, - RegionController.findAll + RegionController.findAllParents + ); + app.get( + `/${config.country}/api/region/parent/:id`, + Authentication.authenticate, + RegionController.findAllByParent + ); + app.get( + `/${config.country}/api/region/parent`, + Authentication.authenticate, + RegionController.findAllByParent + ); + app.get( + `/${config.country}/api/region/:id`, + Authentication.authenticate, + RegionController.findById ); }; diff --git a/src/modules/region/service/index.ts b/src/modules/region/service/index.ts index c649f40..a13f658 100644 --- a/src/modules/region/service/index.ts +++ b/src/modules/region/service/index.ts @@ -1,7 +1,6 @@ -import { DeleteResult, UpdateResult } from "typeorm"; +import { DeleteResult, IsNull, UpdateResult } from "typeorm"; import dataSource from "../../../database/config/ormconfig"; import { Region } from "../entity/region.entity"; -import { School } from "../../school/entity/school.entity"; export class RegionService { static create = async (data: Region): Promise => { @@ -12,26 +11,57 @@ export class RegionService { static update = async ( id: string, - { name }: Region - ): Promise => { + { name, children }: Region + ): Promise => { const regionRepository = await dataSource.getRepository(Region); - return regionRepository.update(id, { name }); + return regionRepository.save({ id, name, children }); }; static delete = async (id: string): Promise => { - const schoolRepository = await dataSource.getRepository(Region); + const regionRepository = await dataSource.getRepository(Region); + + return regionRepository.delete(id); + }; + + static findById = async (id: string): Promise => { + const regionRepository = await dataSource.getRepository(Region); + + return regionRepository.findOne({ + where: { id }, + relations: { parent: true, children: { children: true } }, + order: { + name: "ASC", + children: { name: "ASC", children: { name: "ASC" } }, + }, + }); + }; + + static findByParentId = async (parent_id?: string): Promise => { + const regionRepository = await dataSource.getRepository(Region); - return schoolRepository.delete(id); + if (parent_id) { + return regionRepository.find({ + where: { parent_id }, + relations: { children: true }, + order: { name: "ASC" }, + }); + } else { + return regionRepository.find({ + where: { parent_id: IsNull() }, + relations: { children: true }, + order: { name: "ASC" }, + }); + } }; static findAll = async (): Promise => { const regionRepository = await dataSource.getRepository(Region); - return regionRepository - .createQueryBuilder("region") - .leftJoinAndSelect(School, "school", "school.region_id = region.id") - .loadRelationCountAndMap("region.schoolsCount", "region.schools") - .getMany(); + return regionRepository.find({ + where: { parent_id: IsNull() }, + relations: { children: true }, + order: { name: "ASC" }, + }); }; } diff --git a/src/modules/school/entity/region.entity.ts b/src/modules/school/entity/region.entity.ts deleted file mode 100644 index fda1e81..0000000 --- a/src/modules/school/entity/region.entity.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm"; -import { School } from "./school.entity"; - -@Entity() -export class Region { - constructor(school?: Partial) { - Object.assign(this, school); - } - - @PrimaryGeneratedColumn("uuid") - id?: string; - - @Column({ nullable: true }) - name?: string; - - @OneToMany(() => School, (school) => school.region) - schools?: School[]; - - @Column({ nullable: true }) - updated_at?: Date; - - @Column({ nullable: true }) - deleted_at?: Date; -} diff --git a/src/modules/school/entity/school.entity.ts b/src/modules/school/entity/school.entity.ts index a698ce2..5f309fd 100644 --- a/src/modules/school/entity/school.entity.ts +++ b/src/modules/school/entity/school.entity.ts @@ -8,7 +8,7 @@ import { } from "typeorm"; import { CoachSchool } from "../../coach/entity/coach-school.entity"; import { Teacher } from "../../teacher/entity/teacher.entity"; -import { Region } from "./region.entity"; +import { Region } from "../../region/entity/region.entity"; @Entity() export class School { @@ -29,17 +29,6 @@ export class School { @Column({ nullable: true }) name?: string; - @Column({ nullable: true }) - region_old?: - | "EASTERN" - | "NORTHERN" - | "NORTH WESTERN" - | "WESTERN" - | "SOUTHERN"; - - @Column({ nullable: true }) - district?: string; - @Column({ nullable: true }) emis_number?: string; diff --git a/src/modules/school/service/index.ts b/src/modules/school/service/index.ts index 5c6387f..da823fe 100644 --- a/src/modules/school/service/index.ts +++ b/src/modules/school/service/index.ts @@ -3,7 +3,7 @@ import dataSource from "../../../database/config/ormconfig"; import { School } from "../entity/school.entity"; import crypto from "crypto"; import config from "../../../config"; -import { Region } from "../entity/region.entity"; +import { Region } from "../../region/entity/region.entity"; const algorithm = "aes-256-ecb"; @@ -14,10 +14,13 @@ export class SchoolService { return schoolRepository.save(data); }; - static update = async (id: string, data: School): Promise => { + static update = async ( + id: string, + { name, emis_number, region_id }: School + ): Promise => { const schoolRepository = await dataSource.getRepository(School); - return schoolRepository.update(id, data); + return schoolRepository.save({ id, region_id, emis_number, name }); }; static delete = async (id: string): Promise => {