From 9b5a75300a71aa168b1532f002d83e444bbfc2db Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Tue, 30 Dec 2025 08:02:18 -0600 Subject: [PATCH] feat(datamart): intial setup to datamart migrations --- backend/src/datamart/datamartAdd.route.ts | 18 ++++++++++++++ backend/src/db/db.controller.ts | 16 ++++++++++++ backend/src/db/schema/datamart.schema.ts | 30 +++++++++++++++++++++++ backend/src/logger/db.transport.ts | 2 +- backend/src/routeHandler.routes.ts | 15 ++++++------ backend/src/utils/trycatch.utils.ts | 28 +++++++++++++++++++++ 6 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 backend/src/datamart/datamartAdd.route.ts create mode 100644 backend/src/db/db.controller.ts create mode 100644 backend/src/db/schema/datamart.schema.ts create mode 100644 backend/src/utils/trycatch.utils.ts diff --git a/backend/src/datamart/datamartAdd.route.ts b/backend/src/datamart/datamartAdd.route.ts new file mode 100644 index 0000000..ff18d86 --- /dev/null +++ b/backend/src/datamart/datamartAdd.route.ts @@ -0,0 +1,18 @@ +import { Router } from "express"; +import { apiReturn } from "../utils/returnHelper.utils.js"; + +const r = Router(); + +r.post("/add", async (_, res) => { + apiReturn(res, { + success: true, + level: "info", + module: "routes", + subModule: "prodSql", + message: "connect.message", + data: [{ connect: "" }], + status: 200, + }); +}); + +export default r; diff --git a/backend/src/db/db.controller.ts b/backend/src/db/db.controller.ts new file mode 100644 index 0000000..4b27765 --- /dev/null +++ b/backend/src/db/db.controller.ts @@ -0,0 +1,16 @@ +import { drizzle } from "drizzle-orm/postgres-js"; +import postgres from "postgres"; + +const dbURL = `postgres://${process.env.DATABASE_USER}:${process.env.DATABASE_PASSWORD}@${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_DB}`; + +const queryClient = postgres(dbURL, { + max: 10, + idle_timeout: 60, + connect_timeout: 30, + max_lifetime: 1000 * 6 * 5, + onnotice: (n) => { + console.info("PG notice: ", n.message); + }, +}); + +export const db = drizzle({ client: queryClient }); diff --git a/backend/src/db/schema/datamart.schema.ts b/backend/src/db/schema/datamart.schema.ts new file mode 100644 index 0000000..421445b --- /dev/null +++ b/backend/src/db/schema/datamart.schema.ts @@ -0,0 +1,30 @@ +import { + boolean, + integer, + pgTable, + text, + timestamp, + uuid, +} from "drizzle-orm/pg-core"; +import { createInsertSchema, createSelectSchema } from "drizzle-zod"; +import type { z } from "zod"; + +export const datamart = pgTable("datamart", { + id: uuid("id").defaultRandom().primaryKey(), + name: text("name"), + description: text("description").notNull(), + query: text("query"), + version: integer("version").notNull(), + active: boolean("active").default(true), + options: text("checked").default(""), + add_date: timestamp("add_date").defaultNow(), + add_user: text("add_user").default("lst-system"), + upd_date: timestamp("upd_date").defaultNow(), + upd_user: text("upd_date").default("lst-system"), +}); + +export const datamartSchema = createSelectSchema(datamart); +export const newDataMartSchema = createInsertSchema(datamart); + +export type Datamart = z.infer; +export type NewDatamart = z.infer; diff --git a/backend/src/logger/db.transport.ts b/backend/src/logger/db.transport.ts index a040a7d..feed38b 100644 --- a/backend/src/logger/db.transport.ts +++ b/backend/src/logger/db.transport.ts @@ -1,7 +1,7 @@ import build from "pino-abstract-transport"; import { db } from "../db/db.controller.js"; import { logs } from "../db/schema/logs.schema.js"; -import { tryCatch } from "../utils/trycatch.utlis.js"; +import { tryCatch } from "../utils/trycatch.utils.js"; const pinoLogLevels: Record = { 10: "trace", diff --git a/backend/src/routeHandler.routes.ts b/backend/src/routeHandler.routes.ts index a8fb6de..01862bc 100644 --- a/backend/src/routeHandler.routes.ts +++ b/backend/src/routeHandler.routes.ts @@ -1,16 +1,15 @@ import type { Express } from "express"; // import the routes and route setups -import { setupApiDocsRoutes } from "./configs/scaler.config.js"; -import { setupDatamartRoutes } from "./datamart/datamart.routes.js"; -import { setupProdSqlRoutes } from "./prodSql/prodSql.routes.js"; +// import { setupApiDocsRoutes } from "./configs/scaler.config.js"; +// import { setupDatamartRoutes } from "./datamart/datamart.routes.js"; +// import { setupProdSqlRoutes } from "./prodSql/prodSql.routes.js"; import stats from "./system/stats.route.js"; export const setupRoutes = (baseUrl: string, app: Express) => { - //setup all the routes - setupApiDocsRoutes(baseUrl, app); - setupProdSqlRoutes(baseUrl, app); - setupDatamartRoutes(baseUrl, app); - app.use(`${baseUrl}/api/stats`, stats); + //setup all the routes + // setupApiDocsRoutes(baseUrl, app); + // setupProdSqlRoutes(baseUrl, app); + // setupDatamartRoutes(baseUrl, app); }; diff --git a/backend/src/utils/trycatch.utils.ts b/backend/src/utils/trycatch.utils.ts new file mode 100644 index 0000000..b0d57cf --- /dev/null +++ b/backend/src/utils/trycatch.utils.ts @@ -0,0 +1,28 @@ +type Success = { data: T; error: null }; +type Failure = { data: null; error: E }; + +export type Result = Success | Failure; + +/** + * A universal tryCatch wrapper that: + * - Never throws + * - Always resolves to Result + * - Allows optional error mapping function for strong typing + */ + +export async function tryCatch( + promise: Promise, + onError?: (error: unknown) => E, +): Promise> { + try { + const data = await promise; + return { data, error: null }; + } catch (err: unknown) { + const error = onError + ? onError(err) + : err instanceof Error + ? (err as E) + : (new Error(String(err)) as E); + return { data: null, error }; + } +}