From 7497787ae4191aaec758a6f3a10b177643bf2630 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sat, 14 Dec 2024 16:11:53 +0100 Subject: [PATCH] query store CRUD --- src/command/queryStoreCommand.ts | 12 +++ src/command/queryStoreCommandHandler.ts | 66 ++++++++++++++ .../admin/queryBuilderController.ts | 8 +- src/controller/admin/queryStoreController.ts | 91 +++++++++++++++++++ src/data-source.ts | 4 + src/entity/query.ts | 10 ++ src/factory/admin/queryStore.ts | 25 +++++ src/migrations/1734187754677-queryStore.ts | 25 +++++ src/routes/admin/index.ts | 2 + src/routes/admin/queryStore.ts | 45 +++++++++ src/service/queryStoreService.ts | 40 ++++++++ src/viewmodel/admin/queryStore.models.ts | 4 + 12 files changed, 327 insertions(+), 5 deletions(-) create mode 100644 src/command/queryStoreCommand.ts create mode 100644 src/command/queryStoreCommandHandler.ts create mode 100644 src/controller/admin/queryStoreController.ts create mode 100644 src/entity/query.ts create mode 100644 src/factory/admin/queryStore.ts create mode 100644 src/migrations/1734187754677-queryStore.ts create mode 100644 src/routes/admin/queryStore.ts create mode 100644 src/service/queryStoreService.ts create mode 100644 src/viewmodel/admin/queryStore.models.ts diff --git a/src/command/queryStoreCommand.ts b/src/command/queryStoreCommand.ts new file mode 100644 index 0000000..4404fbe --- /dev/null +++ b/src/command/queryStoreCommand.ts @@ -0,0 +1,12 @@ +export interface CreateQueryStoreCommand { + query: string; +} + +export interface UpdateQueryStoreCommand { + id: number; + query: string; +} + +export interface DeleteQueryStoreCommand { + id: number; +} diff --git a/src/command/queryStoreCommandHandler.ts b/src/command/queryStoreCommandHandler.ts new file mode 100644 index 0000000..7981204 --- /dev/null +++ b/src/command/queryStoreCommandHandler.ts @@ -0,0 +1,66 @@ +import { dataSource } from "../data-source"; +import { query } from "../entity/query"; +import InternalException from "../exceptions/internalException"; +import { CreateQueryStoreCommand, DeleteQueryStoreCommand, UpdateQueryStoreCommand } from "./queryStoreCommand"; + +export default abstract class QueryStoreCommandHandler { + /** + * @description create queryStore + * @param CreateQueryStoreCommand + * @returns {Promise} + */ + static async create(createQueryStore: CreateQueryStoreCommand): Promise { + return await dataSource + .createQueryBuilder() + .insert() + .into(query) + .values({ + query: createQueryStore.query, + }) + .execute() + .then((result) => { + return result.identifiers[0].id; + }) + .catch((err) => { + throw new InternalException("Failed creating queryStore", err); + }); + } + + /** + * @description update queryStore + * @param UpdateQueryStoreCommand + * @returns {Promise} + */ + static async update(updateQueryStore: UpdateQueryStoreCommand): Promise { + return await dataSource + .createQueryBuilder() + .update(query) + .set({ + queryStore: updateQueryStore.query, + }) + .where("id = :id", { id: updateQueryStore.id }) + .execute() + .then(() => {}) + .catch((err) => { + throw new InternalException("Failed updating queryStore", err); + }); + } + + /** + * @description delete queryStore + * @param DeleteQueryStoreCommand + * @returns {Promise} + */ + static async delete(deletQueryStore: DeleteQueryStoreCommand): Promise { + return await dataSource + .createQueryBuilder() + .delete() + .from(query) + .where("id = :id", { id: deletQueryStore.id }) + .execute() + .then(() => {}) + .catch((err) => { + throw new InternalException("Failed deleting queryStore", err); + }); + } +} diff --git a/src/controller/admin/queryBuilderController.ts b/src/controller/admin/queryBuilderController.ts index ccab8df..cd08b8d 100644 --- a/src/controller/admin/queryBuilderController.ts +++ b/src/controller/admin/queryBuilderController.ts @@ -37,13 +37,11 @@ export async function executeQuery(req: Request, res: Response): Promise { let count = parseInt((req.query.count as string) ?? "25"); const query = req.body.query; - //build query to sql - //verify sql or return error - //let [rows, total] = await executeQuery(query, offset, count); + let [rows, total] = await DynamicQueryBuilder.buildQuery(query, offset, count).getManyAndCount(); res.json({ - rows: [], - total: 0, + rows: rows, + total: total, offset: offset, count: count, }); diff --git a/src/controller/admin/queryStoreController.ts b/src/controller/admin/queryStoreController.ts new file mode 100644 index 0000000..6207e97 --- /dev/null +++ b/src/controller/admin/queryStoreController.ts @@ -0,0 +1,91 @@ +import { Request, Response } from "express"; +import QueryStoreFactory from "../../factory/admin/queryStore"; +import QueryStoreService from "../../service/queryStoreService"; +import { + CreateQueryStoreCommand, + DeleteQueryStoreCommand, + UpdateQueryStoreCommand, +} from "../../command/queryStoreCommand"; +import QueryStoreCommandHandler from "../../command/queryStoreCommandHandler"; + +/** + * @description get all queryStores + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getAllQueryStores(req: Request, res: Response): Promise { + let queryStores = await QueryStoreService.getAll(); + + res.json(QueryStoreFactory.mapToBase(queryStores)); +} + +/** + * @description get queryStore by id + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getQueryStoreById(req: Request, res: Response): Promise { + const id = parseInt(req.params.id); + + let queryStore = await QueryStoreService.getById(id); + + res.json(QueryStoreFactory.mapToSingle(queryStore)); +} + +/** + * @description create new queryStore + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function createQueryStore(req: Request, res: Response): Promise { + const query = req.body.query; + + let createQueryStore: CreateQueryStoreCommand = { + query: query, + }; + + await QueryStoreCommandHandler.create(createQueryStore); + + res.sendStatus(204); +} + +/** + * @description update queryStore + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function updateQueryStore(req: Request, res: Response): Promise { + const id = parseInt(req.params.id); + const query = req.body.query; + + let updateQueryStore: UpdateQueryStoreCommand = { + id: id, + query: query, + }; + + await QueryStoreCommandHandler.update(updateQueryStore); + + res.sendStatus(204); +} + +/** + * @description delete queryStore + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function deleteQueryStore(req: Request, res: Response): Promise { + const id = parseInt(req.params.id); + + let deleteQueryStore: DeleteQueryStoreCommand = { + id: id, + }; + + await QueryStoreCommandHandler.delete(deleteQueryStore); + + res.sendStatus(204); +} diff --git a/src/data-source.ts b/src/data-source.ts index 5271c7c..e4bb7af 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -44,6 +44,8 @@ import { reset } from "./entity/reset"; import { ResetToken1732358596823 } from "./migrations/1732358596823-resetToken"; import { SMSAlarming1732696919191 } from "./migrations/1732696919191-SMSAlarming"; import { SecuringCalendarType1733249553766 } from "./migrations/1733249553766-securingCalendarType"; +import { query } from "./entity/query"; +import { QueryStore1734187754677 } from "./migrations/1734187754677-queryStore"; const dataSource = new DataSource({ type: DB_TYPE as any, @@ -82,6 +84,7 @@ const dataSource = new DataSource({ protocolPrintout, calendar, calendarType, + query, ], migrations: [ Initial1724317398939, @@ -98,6 +101,7 @@ const dataSource = new DataSource({ ResetToken1732358596823, SMSAlarming1732696919191, SecuringCalendarType1733249553766, + QueryStore1734187754677, ], migrationsRun: true, migrationsTransactionMode: "each", diff --git a/src/entity/query.ts b/src/entity/query.ts new file mode 100644 index 0000000..b03d4e2 --- /dev/null +++ b/src/entity/query.ts @@ -0,0 +1,10 @@ +import { Column, Entity, PrimaryColumn } from "typeorm"; + +@Entity() +export class query { + @PrimaryColumn({ generated: "increment", type: "int" }) + id: number; + + @Column({ type: "text", default: "" }) + query: string; +} diff --git a/src/factory/admin/queryStore.ts b/src/factory/admin/queryStore.ts new file mode 100644 index 0000000..478e48b --- /dev/null +++ b/src/factory/admin/queryStore.ts @@ -0,0 +1,25 @@ +import { query } from "../../entity/query"; +import { QueryStoreViewModel } from "../../viewmodel/admin/queryStore.models"; + +export default abstract class QueryStoreFactory { + /** + * @description map record to queryStore + * @param {queryStore} record + * @returns {QueryStoreViewModel} + */ + public static mapToSingle(record: query): QueryStoreViewModel { + return { + id: record.id, + query: record.query, + }; + } + + /** + * @description map records to queryStore + * @param {Array} records + * @returns {Array} + */ + public static mapToBase(records: Array): Array { + return records.map((r) => this.mapToSingle(r)); + } +} diff --git a/src/migrations/1734187754677-queryStore.ts b/src/migrations/1734187754677-queryStore.ts new file mode 100644 index 0000000..b86fa23 --- /dev/null +++ b/src/migrations/1734187754677-queryStore.ts @@ -0,0 +1,25 @@ +import { MigrationInterface, QueryRunner, Table } from "typeorm"; +import { DB_TYPE } from "../env.defaults"; + +export class QueryStore1734187754677 implements MigrationInterface { + name = "QueryStore1734187754677"; + + public async up(queryRunner: QueryRunner): Promise { + const variableType_int = DB_TYPE == "mysql" ? "int" : "integer"; + + await queryRunner.createTable( + new Table({ + name: "query", + columns: [ + { name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" }, + { name: "query", type: "text", isNullable: false, default: "''" }, + ], + }), + true + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable("query"); + } +} diff --git a/src/routes/admin/index.ts b/src/routes/admin/index.ts index 2a292f3..193213e 100644 --- a/src/routes/admin/index.ts +++ b/src/routes/admin/index.ts @@ -7,6 +7,7 @@ import executivePosition from "./executivePosition"; import membershipStatus from "./membershipStatus"; import qualification from "./qualification"; import calendarType from "./calendarType"; +import queryStore from "./queryStore"; import member from "./member"; import protocol from "./protocol"; @@ -37,6 +38,7 @@ router.use( ); router.use("/qualification", PermissionHelper.passCheckMiddleware("read", "settings", "qualification"), qualification); router.use("/calendartype", PermissionHelper.passCheckMiddleware("read", "settings", "calendar_type"), calendarType); +router.use("/querystore", PermissionHelper.passCheckMiddleware("read", "settings", "query_store"), queryStore); router.use("/member", PermissionHelper.passCheckMiddleware("read", "club", "member"), member); router.use("/protocol", PermissionHelper.passCheckMiddleware("read", "club", "protocol"), protocol); diff --git a/src/routes/admin/queryStore.ts b/src/routes/admin/queryStore.ts new file mode 100644 index 0000000..e160187 --- /dev/null +++ b/src/routes/admin/queryStore.ts @@ -0,0 +1,45 @@ +import express, { Request, Response } from "express"; +import PermissionHelper from "../../helpers/permissionHelper"; +import { + createQueryStore, + deleteQueryStore, + getAllQueryStores, + getQueryStoreById, + updateQueryStore, +} from "../../controller/admin/queryStoreController"; + +var router = express.Router({ mergeParams: true }); + +router.get("/", async (req: Request, res: Response) => { + await getAllQueryStores(req, res); +}); + +router.get("/:id", async (req: Request, res: Response) => { + await getQueryStoreById(req, res); +}); + +router.post( + "/", + PermissionHelper.passCheckMiddleware("create", "settings", "query_store"), + async (req: Request, res: Response) => { + await createQueryStore(req, res); + } +); + +router.patch( + "/:id", + PermissionHelper.passCheckMiddleware("update", "settings", "query_store"), + async (req: Request, res: Response) => { + await updateQueryStore(req, res); + } +); + +router.delete( + "/:id", + PermissionHelper.passCheckMiddleware("delete", "settings", "query_store"), + async (req: Request, res: Response) => { + await deleteQueryStore(req, res); + } +); + +export default router; diff --git a/src/service/queryStoreService.ts b/src/service/queryStoreService.ts new file mode 100644 index 0000000..93145f9 --- /dev/null +++ b/src/service/queryStoreService.ts @@ -0,0 +1,40 @@ +import { dataSource } from "../data-source"; +import { query } from "../entity/query"; +import InternalException from "../exceptions/internalException"; + +export default abstract class QueryStoreService { + /** + * @description get all queryStores + * @returns {Promise>} + */ + static async getAll(): Promise> { + return await dataSource + .getRepository(query) + .createQueryBuilder("queryStore") + .getMany() + .then((res) => { + return res; + }) + .catch((err) => { + throw new InternalException("queryStores not found", err); + }); + } + + /** + * @description get queryStore by id + * @returns {Promise} + */ + static async getById(id: number): Promise { + return await dataSource + .getRepository(query) + .createQueryBuilder("queryStore") + .where("queryStore.id = :id", { id: id }) + .getOneOrFail() + .then((res) => { + return res; + }) + .catch((err) => { + throw new InternalException("queryStore not found by id", err); + }); + } +} diff --git a/src/viewmodel/admin/queryStore.models.ts b/src/viewmodel/admin/queryStore.models.ts new file mode 100644 index 0000000..10d547b --- /dev/null +++ b/src/viewmodel/admin/queryStore.models.ts @@ -0,0 +1,4 @@ +export interface QueryStoreViewModel { + id: number; + query: string; +}