From 54eb4544f79baa85aee07772301492b39c693646 Mon Sep 17 00:00:00 2001 From: Kan-A-Pesh Date: Fri, 25 Oct 2024 10:08:18 +0200 Subject: [PATCH 1/6] chore: create db schema --- database/migrations/0000_light_tinkerer.sql | 4 - .../0000_organic_fantastic_four.sql | 48 +++ database/migrations/meta/0000_snapshot.json | 278 +++++++++++++++++- database/migrations/meta/_journal.json | 4 +- database/schema/acquired.ts | 34 +++ database/schema/challeges.ts | 29 ++ database/schema/clubs.ts | 20 ++ database/schema/granters.ts | 17 ++ database/schema/users.ts | 40 ++- 9 files changed, 458 insertions(+), 16 deletions(-) delete mode 100644 database/migrations/0000_light_tinkerer.sql create mode 100644 database/migrations/0000_organic_fantastic_four.sql create mode 100644 database/schema/acquired.ts create mode 100644 database/schema/challeges.ts create mode 100644 database/schema/clubs.ts create mode 100644 database/schema/granters.ts diff --git a/database/migrations/0000_light_tinkerer.sql b/database/migrations/0000_light_tinkerer.sql deleted file mode 100644 index e121419..0000000 --- a/database/migrations/0000_light_tinkerer.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE TABLE IF NOT EXISTS "users" ( - "id" serial PRIMARY KEY NOT NULL, - "first_name" text NOT NULL -); diff --git a/database/migrations/0000_organic_fantastic_four.sql b/database/migrations/0000_organic_fantastic_four.sql new file mode 100644 index 0000000..af31052 --- /dev/null +++ b/database/migrations/0000_organic_fantastic_four.sql @@ -0,0 +1,48 @@ +CREATE TABLE IF NOT EXISTS "acquired" ( + "user_uuid" uuid PRIMARY KEY NOT NULL, + "challenge_id" serial PRIMARY KEY NOT NULL, + "created_by" serial NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "challenges" ( + "id" serial PRIMARY KEY NOT NULL, + "club_id" serial NOT NULL, + "score" integer NOT NULL, + "name" text NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "clubs" ( + "id" serial PRIMARY KEY NOT NULL, + "avatar_url" text NOT NULL, + "name" text NOT NULL, + "description" text NOT NULL, + "daily_date" date NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "granters" ( + "id" serial PRIMARY KEY NOT NULL, + "club_id" serial NOT NULL, + "email" text NOT NULL, + "password" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "users" ( + "uuid" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "club_id" serial NOT NULL, + "email" text NOT NULL, + "hashpass" text NOT NULL, + "username" text NOT NULL, + "quote" text, + "updated_at" timestamp DEFAULT now() NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "name_unique_idx" ON "clubs" USING btree ("name");--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "email_unique_idx" ON "users" USING btree ("email");--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "username_unique_idx" ON "users" USING btree ("username"); \ No newline at end of file diff --git a/database/migrations/meta/0000_snapshot.json b/database/migrations/meta/0000_snapshot.json index ecf6519..7078def 100644 --- a/database/migrations/meta/0000_snapshot.json +++ b/database/migrations/meta/0000_snapshot.json @@ -1,11 +1,54 @@ { - "id": "85674a8b-3f8c-476f-9ce2-8635c80b2d04", + "id": "0e004108-39e1-4d32-b380-d66778f5ed70", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { - "public.users": { - "name": "users", + "public.acquired": { + "name": "acquired", + "schema": "", + "columns": { + "user_uuid": { + "name": "user_uuid", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "challenge_id": { + "name": "challenge_id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "public.challenges": { + "name": "challenges", "schema": "", "columns": { "id": { @@ -14,11 +57,37 @@ "primaryKey": true, "notNull": true }, - "first_name": { - "name": "first_name", + "club_id": { + "name": "club_id", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", "type": "text", "primaryKey": false, "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" } }, "indexes": {}, @@ -26,6 +95,205 @@ "compositePrimaryKeys": {}, "uniqueConstraints": {}, "checkConstraints": {} + }, + "public.clubs": { + "name": "clubs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "avatar_url": { + "name": "avatar_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "daily_date": { + "name": "daily_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "name_unique_idx": { + "name": "name_unique_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "public.granters": { + "name": "granters", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "club_id": { + "name": "club_id", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "uuid": { + "name": "uuid", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "club_id": { + "name": "club_id", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hashpass": { + "name": "hashpass", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "quote": { + "name": "quote", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "email_unique_idx": { + "name": "email_unique_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "username_unique_idx": { + "name": "username_unique_idx", + "columns": [ + { + "expression": "username", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} } }, "enums": {}, diff --git a/database/migrations/meta/_journal.json b/database/migrations/meta/_journal.json index fccfd13..7f17554 100644 --- a/database/migrations/meta/_journal.json +++ b/database/migrations/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "7", - "when": 1729680286443, - "tag": "0000_light_tinkerer", + "when": 1729840120930, + "tag": "0000_organic_fantastic_four", "breakpoints": true } ] diff --git a/database/schema/acquired.ts b/database/schema/acquired.ts new file mode 100644 index 0000000..ee7abc2 --- /dev/null +++ b/database/schema/acquired.ts @@ -0,0 +1,34 @@ +import { relations } from "drizzle-orm"; +import { pgTable, serial, timestamp, uuid } from "drizzle-orm/pg-core"; +import { users } from "./users"; +import { challenges } from "./challeges"; + +export const acquired = pgTable("acquired", { + userUuid: uuid("user_uuid").primaryKey(), + challengeId: serial("challenge_id").primaryKey(), + createdBy: serial("created_by"), + updatedAt: timestamp("updated_at") + .defaultNow() + .notNull() + .$onUpdate(() => new Date()), + createdAt: timestamp("created_at").defaultNow().notNull() +}); + +export const acquiredRelations = relations(acquired, ({ many }) => ({ + user: many(users), + challenge: many(challenges) +})); + +export const acquiredUser = relations(acquired, ({ one }) => ({ + user: one(users, { + fields: [acquired.userUuid], + references: [users.uuid] + }) +})); + +export const acquiredChallenge = relations(acquired, ({ one }) => ({ + challenge: one(challenges, { + fields: [acquired.challengeId], + references: [challenges.id] + }) +})); diff --git a/database/schema/challeges.ts b/database/schema/challeges.ts new file mode 100644 index 0000000..abd1698 --- /dev/null +++ b/database/schema/challeges.ts @@ -0,0 +1,29 @@ +import { relations } from "drizzle-orm"; +import { integer, pgTable, serial, text, timestamp } from "drizzle-orm/pg-core"; +import { acquired } from "./acquired"; +import { clubs } from "./clubs"; +import { granters } from "./granters"; + +export const challenges = pgTable("challenges", { + id: serial("id").primaryKey(), + clubId: serial("club_id"), + score: integer("score").notNull(), + name: text("name").notNull(), + updatedAt: timestamp("updated_at") + .defaultNow() + .notNull() + .$onUpdate(() => new Date()), + createdAt: timestamp("created_at").defaultNow().notNull() +}); + +export const challengesRelations = relations(challenges, ({ many }) => ({ + acquired: many(acquired), + granters: many(granters) +})); + +export const challengesClub = relations(challenges, ({ one }) => ({ + club: one(clubs, { + fields: [challenges.clubId], + references: [clubs.id] + }) +})); diff --git a/database/schema/clubs.ts b/database/schema/clubs.ts new file mode 100644 index 0000000..56c1aa9 --- /dev/null +++ b/database/schema/clubs.ts @@ -0,0 +1,20 @@ +import { date, pgTable, serial, text, timestamp, uniqueIndex } from "drizzle-orm/pg-core"; + +export const clubs = pgTable( + "clubs", + { + id: serial("id").primaryKey(), + avatarUrl: text("avatar_url").notNull(), + name: text("name").notNull(), + description: text("description").notNull(), + dailyDate: date("daily_date").notNull(), + updatedAt: timestamp("updated_at") + .defaultNow() + .notNull() + .$onUpdate(() => new Date()), + createdAt: timestamp("created_at").defaultNow().notNull() + }, + (clubs) => ({ + nameUniqueIdx: uniqueIndex("name_unique_idx").on(clubs.name) + }) +); diff --git a/database/schema/granters.ts b/database/schema/granters.ts new file mode 100644 index 0000000..000fae4 --- /dev/null +++ b/database/schema/granters.ts @@ -0,0 +1,17 @@ +import { relations } from "drizzle-orm"; +import { pgTable, serial, text } from "drizzle-orm/pg-core"; +import { clubs } from "./clubs"; + +export const granters = pgTable("granters", { + id: serial("id").primaryKey(), + clubId: serial("club_id").notNull(), + email: text("email").notNull(), + password: text("password").notNull() +}); + +export const grantersClub = relations(granters, ({ one }) => ({ + club: one(clubs, { + fields: [granters.clubId], + references: [clubs.id] + }) +})); diff --git a/database/schema/users.ts b/database/schema/users.ts index 6ec5a55..2aa93d8 100644 --- a/database/schema/users.ts +++ b/database/schema/users.ts @@ -1,6 +1,36 @@ -import { pgTable, serial, text } from "drizzle-orm/pg-core"; +import { relations } from "drizzle-orm"; +import { pgTable, serial, text, timestamp, uniqueIndex, uuid } from "drizzle-orm/pg-core"; +import { acquired } from "./acquired"; +import { clubs } from "./clubs"; -export const users = pgTable("users", { - id: serial("id").primaryKey(), - firstName: text("first_name").notNull() -}); +export const users = pgTable( + "users", + { + uuid: uuid("uuid").primaryKey().defaultRandom(), + clubId: serial("club_id"), + email: text("email").notNull(), + hashpass: text("hashpass").notNull(), + username: text("username").notNull(), + quote: text("quote"), + updatedAt: timestamp("updated_at") + .defaultNow() + .notNull() + .$onUpdate(() => new Date()), + createdAt: timestamp("created_at").defaultNow().notNull() + }, + (users) => ({ + emailUniqueIdx: uniqueIndex("email_unique_idx").on(users.email), + usernameUniqueIdx: uniqueIndex("username_unique_idx").on(users.username) + }) +); + +export const usersRelations = relations(users, ({ many }) => ({ + acquired: many(acquired) +})); + +export const usersClub = relations(users, ({ one }) => ({ + club: one(clubs, { + fields: [users.clubId], + references: [clubs.id] + }) +})); From 3edd759c06aa43c000df8e60c55e9f1f1f49e4bb Mon Sep 17 00:00:00 2001 From: Kan-A-Pesh Date: Fri, 25 Oct 2024 10:10:18 +0200 Subject: [PATCH 2/6] fix: disabled test --- .../{users.test.ts => example.test.disabled} | 0 tests/e2e/routes.test.ts | 42 ------------------- tests/unit/error.test.ts | 27 ------------ tests/unit/index.test.ts | 21 ---------- 4 files changed, 90 deletions(-) rename tests/e2e/{users.test.ts => example.test.disabled} (100%) delete mode 100644 tests/e2e/routes.test.ts delete mode 100644 tests/unit/error.test.ts delete mode 100644 tests/unit/index.test.ts diff --git a/tests/e2e/users.test.ts b/tests/e2e/example.test.disabled similarity index 100% rename from tests/e2e/users.test.ts rename to tests/e2e/example.test.disabled diff --git a/tests/e2e/routes.test.ts b/tests/e2e/routes.test.ts deleted file mode 100644 index 395f131..0000000 --- a/tests/e2e/routes.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import request from "supertest"; -import createApp from "@/app"; - -const app = createApp("e2e-routes"); - -describe("Test multiple routes", () => { - test("should send an empty response on GET /", async () => { - const res = await request(app).get("/").expect("Content-Type", /json/).expect(200); - - expect(res.body).toStrictEqual({ - masterStatus: 204, - sentAt: expect.any(Number), - response: [ - { - status: 204, - success: true - } - ] - }); - }); - - test("should send an empty response GET /error", async () => { - const res = await request(app) - .get("/error") - .set("Accept-Language", "en") - .expect("Content-Type", /json/) - .expect(400); - - expect(res.body).toStrictEqual({ - masterStatus: 400, - sentAt: expect.any(Number), - response: [ - { - status: 400, - success: false, - error: "errors.template", - translatedError: "This is a template error message" - } - ] - }); - }); -}); diff --git a/tests/unit/error.test.ts b/tests/unit/error.test.ts deleted file mode 100644 index 2455d52..0000000 --- a/tests/unit/error.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import request from "supertest"; -import createApp from "@/app"; - -const app = createApp("unit-error"); - -describe("GET /error", () => { - it("should send an empty response", async () => { - const res = await request(app) - .get("/error") - .set("Accept-Language", "en") - .expect("Content-Type", /json/) - .expect(400); - - expect(res.body).toStrictEqual({ - masterStatus: 400, - sentAt: expect.any(Number), - response: [ - { - status: 400, - success: false, - error: "errors.template", - translatedError: "This is a template error message" - } - ] - }); - }); -}); diff --git a/tests/unit/index.test.ts b/tests/unit/index.test.ts deleted file mode 100644 index 1960968..0000000 --- a/tests/unit/index.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import request from "supertest"; -import createApp from "@/app"; - -const app = createApp("unit-index"); - -describe("GET /", () => { - it("should send an empty response", async () => { - const res = await request(app).get("/").expect("Content-Type", /json/).expect(200); - - expect(res.body).toStrictEqual({ - masterStatus: 204, - sentAt: expect.any(Number), - response: [ - { - status: 204, - success: true - } - ] - }); - }); -}); From 28fd7c2e332fc7329cfe2d3bf5660f965396e0e5 Mon Sep 17 00:00:00 2001 From: Kan-A-Pesh Date: Fri, 25 Oct 2024 10:48:14 +0200 Subject: [PATCH 3/6] ci: added lint check --- .github/workflows/lint.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..0d16111 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,24 @@ +name: Check lint + +on: + push: + branches: + - main + - master + - develop + pull_request: + branches: + - main + - master + - develop + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + name: Check lint + steps: + - uses: actions/checkout@v3 + + - name: Check lint + run: npm run lint From 73cebd625ccd53d8b5dd6ef34a0cd091cc406ce2 Mon Sep 17 00:00:00 2001 From: Kan-A-Pesh Date: Fri, 25 Oct 2024 10:48:35 +0200 Subject: [PATCH 4/6] fix: removed unused routes & added status check --- database/schema/acquired.ts | 30 +++++++++++++++++++----------- routes.ts | 7 ------- routes/error.ts | 9 --------- routes/unhandled.ts | 3 --- routes/users/getUsers.ts | 13 ------------- routes/users/postUsers.ts | 36 ------------------------------------ routes/users/routes.ts | 10 ---------- tests/unit/status.test.ts | 21 +++++++++++++++++++++ 8 files changed, 40 insertions(+), 89 deletions(-) delete mode 100644 routes/error.ts delete mode 100644 routes/unhandled.ts delete mode 100644 routes/users/getUsers.ts delete mode 100644 routes/users/postUsers.ts delete mode 100644 routes/users/routes.ts create mode 100644 tests/unit/status.test.ts diff --git a/database/schema/acquired.ts b/database/schema/acquired.ts index ee7abc2..a94b12f 100644 --- a/database/schema/acquired.ts +++ b/database/schema/acquired.ts @@ -1,18 +1,26 @@ import { relations } from "drizzle-orm"; -import { pgTable, serial, timestamp, uuid } from "drizzle-orm/pg-core"; +import { index, pgTable, primaryKey, serial, timestamp, uuid } from "drizzle-orm/pg-core"; import { users } from "./users"; import { challenges } from "./challeges"; -export const acquired = pgTable("acquired", { - userUuid: uuid("user_uuid").primaryKey(), - challengeId: serial("challenge_id").primaryKey(), - createdBy: serial("created_by"), - updatedAt: timestamp("updated_at") - .defaultNow() - .notNull() - .$onUpdate(() => new Date()), - createdAt: timestamp("created_at").defaultNow().notNull() -}); +export const acquired = pgTable( + "acquired", + { + userUuid: uuid("user_uuid"), + challengeId: serial("challenge_id"), + createdBy: serial("created_by"), + updatedAt: timestamp("updated_at") + .defaultNow() + .notNull() + .$onUpdate(() => new Date()), + createdAt: timestamp("created_at").defaultNow().notNull() + }, + (acquired) => ({ + pk: primaryKey({ columns: [acquired.userUuid, acquired.challengeId] }), + userUuidIdx: index("user_uuid_idx").on(acquired.userUuid), + challengeIdIdx: index("challenge_id_idx").on(acquired.challengeId) + }) +); export const acquiredRelations = relations(acquired, ({ many }) => ({ user: many(users), diff --git a/routes.ts b/routes.ts index b2af139..98d4f13 100644 --- a/routes.ts +++ b/routes.ts @@ -1,15 +1,8 @@ import { Router } from "express"; -import Route_Error from "./routes/error"; import Route_Index from "./routes/index"; -import Route_UnhandledError from "./routes/unhandled"; -import usersRouter from "./routes/users/routes"; const router = Router(); router.get("/", Route_Index); -router.get("/error", Route_Error); -router.get("/unhandled", Route_UnhandledError); - -router.use("/users", usersRouter); export default router; diff --git a/routes/error.ts b/routes/error.ts deleted file mode 100644 index 6e1eb5d..0000000 --- a/routes/error.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Status from "@/models/status"; -import { NextFunction, Request, Response } from "express"; - -export default function Route_Error(req: Request, res: Response, next: NextFunction) { - return Status.send(req, next, { - status: 400, - error: "errors.template" - }); -} diff --git a/routes/unhandled.ts b/routes/unhandled.ts deleted file mode 100644 index 3cf0729..0000000 --- a/routes/unhandled.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default function Route_UnhandledError() { - throw new Error("This is an unhandled error"); -} diff --git a/routes/users/getUsers.ts b/routes/users/getUsers.ts deleted file mode 100644 index 3587478..0000000 --- a/routes/users/getUsers.ts +++ /dev/null @@ -1,13 +0,0 @@ -import DB from "@/database/config"; -import { users } from "@/database/schema/users"; -import Status from "@/models/status"; -import { NextFunction, Request, Response } from "express"; - -export default async function Route_GetUsers(req: Request, res: Response, next: NextFunction) { - const allUsers = await DB.instance.select().from(users); - - return Status.send(req, next, { - status: 200, - data: allUsers - }); -} diff --git a/routes/users/postUsers.ts b/routes/users/postUsers.ts deleted file mode 100644 index 7f0296e..0000000 --- a/routes/users/postUsers.ts +++ /dev/null @@ -1,36 +0,0 @@ -import DB from "@/database/config"; -import { users } from "@/database/schema/users"; -import Status from "@/models/status"; -import { NextFunction, Request, Response } from "express"; -import { z } from "zod"; - -const body = z.object({ - firstName: z.string() -}); - -export default async function Route_PostUsers(req: Request, res: Response, next: NextFunction) { - const payload = body.safeParse(req.body); - if (!payload.success) { - return Status.send(req, next, { - status: 400, - error: "errors.validation" - }); - } - - const user = await DB.instance - .insert(users) - .values(payload.data) - .returning({ id: users.id, firstName: users.firstName }); - - if (user.length !== 1) { - return Status.send(req, next, { - status: 500, - error: "errors.database" - }); - } - - return Status.send(req, next, { - status: 200, - data: user[0] - }); -} diff --git a/routes/users/routes.ts b/routes/users/routes.ts deleted file mode 100644 index ee38ed2..0000000 --- a/routes/users/routes.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Router } from "express"; -import Route_GetUsers from "./getUsers"; -import Route_PostUsers from "./postUsers"; - -const usersRouter = Router(); - -usersRouter.get("/", Route_GetUsers); -usersRouter.post("/", Route_PostUsers); - -export default usersRouter; diff --git a/tests/unit/status.test.ts b/tests/unit/status.test.ts new file mode 100644 index 0000000..75aa5f1 --- /dev/null +++ b/tests/unit/status.test.ts @@ -0,0 +1,21 @@ +import request from "supertest"; +import createApp from "@/app"; + +const app = createApp("e2e-users"); + +describe("Test status page", () => { + test("should send a 200", async () => { + const res = await request(app).get("/").set("Accept-Language", "en").expect("Content-Type", /json/).expect(200); + + expect(res.body).toStrictEqual({ + masterStatus: 204, + sentAt: expect.any(Number), + response: [ + { + status: 204, + success: true + } + ] + }); + }); +}); From 47f5b16a5363000594d85fccb233a1c78b338353 Mon Sep 17 00:00:00 2001 From: Kan-A-Pesh Date: Fri, 25 Oct 2024 10:49:32 +0200 Subject: [PATCH 5/6] ci: fix lint ci --- .github/workflows/lint.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0d16111..34f6aa0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,5 +20,13 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: Install dependencies + run: npm ci + - name: Check lint run: npm run lint From f3600935637efb6085f347f40259bf0b75372692 Mon Sep 17 00:00:00 2001 From: Kan-A-Pesh Date: Fri, 25 Oct 2024 11:11:12 +0200 Subject: [PATCH 6/6] ci: regenerated migrations --- ...ntastic_four.sql => 0000_smart_jackal.sql} | 9 ++-- database/migrations/meta/0000_snapshot.json | 51 ++++++++++++++++--- database/migrations/meta/_journal.json | 4 +- 3 files changed, 53 insertions(+), 11 deletions(-) rename database/migrations/{0000_organic_fantastic_four.sql => 0000_smart_jackal.sql} (79%) diff --git a/database/migrations/0000_organic_fantastic_four.sql b/database/migrations/0000_smart_jackal.sql similarity index 79% rename from database/migrations/0000_organic_fantastic_four.sql rename to database/migrations/0000_smart_jackal.sql index af31052..ac66955 100644 --- a/database/migrations/0000_organic_fantastic_four.sql +++ b/database/migrations/0000_smart_jackal.sql @@ -1,9 +1,10 @@ CREATE TABLE IF NOT EXISTS "acquired" ( - "user_uuid" uuid PRIMARY KEY NOT NULL, - "challenge_id" serial PRIMARY KEY NOT NULL, + "user_uuid" uuid, + "challenge_id" serial NOT NULL, "created_by" serial NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL + "created_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "acquired_user_uuid_challenge_id_pk" PRIMARY KEY("user_uuid","challenge_id") ); --> statement-breakpoint CREATE TABLE IF NOT EXISTS "challenges" ( @@ -43,6 +44,8 @@ CREATE TABLE IF NOT EXISTS "users" ( "created_at" timestamp DEFAULT now() NOT NULL ); --> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_uuid_idx" ON "acquired" USING btree ("user_uuid");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "challenge_id_idx" ON "acquired" USING btree ("challenge_id");--> statement-breakpoint CREATE UNIQUE INDEX IF NOT EXISTS "name_unique_idx" ON "clubs" USING btree ("name");--> statement-breakpoint CREATE UNIQUE INDEX IF NOT EXISTS "email_unique_idx" ON "users" USING btree ("email");--> statement-breakpoint CREATE UNIQUE INDEX IF NOT EXISTS "username_unique_idx" ON "users" USING btree ("username"); \ No newline at end of file diff --git a/database/migrations/meta/0000_snapshot.json b/database/migrations/meta/0000_snapshot.json index 7078def..fab077b 100644 --- a/database/migrations/meta/0000_snapshot.json +++ b/database/migrations/meta/0000_snapshot.json @@ -1,5 +1,5 @@ { - "id": "0e004108-39e1-4d32-b380-d66778f5ed70", + "id": "b0e99e73-e2d8-4775-a232-6adac633f175", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", @@ -11,13 +11,13 @@ "user_uuid": { "name": "user_uuid", "type": "uuid", - "primaryKey": true, - "notNull": true + "primaryKey": false, + "notNull": false }, "challenge_id": { "name": "challenge_id", "type": "serial", - "primaryKey": true, + "primaryKey": false, "notNull": true }, "created_by": { @@ -41,9 +41,48 @@ "default": "now()" } }, - "indexes": {}, + "indexes": { + "user_uuid_idx": { + "name": "user_uuid_idx", + "columns": [ + { + "expression": "user_uuid", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "challenge_id_idx": { + "name": "challenge_id_idx", + "columns": [ + { + "expression": "challenge_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, "foreignKeys": {}, - "compositePrimaryKeys": {}, + "compositePrimaryKeys": { + "acquired_user_uuid_challenge_id_pk": { + "name": "acquired_user_uuid_challenge_id_pk", + "columns": [ + "user_uuid", + "challenge_id" + ] + } + }, "uniqueConstraints": {}, "checkConstraints": {} }, diff --git a/database/migrations/meta/_journal.json b/database/migrations/meta/_journal.json index 7f17554..1f2ee93 100644 --- a/database/migrations/meta/_journal.json +++ b/database/migrations/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "7", - "when": 1729840120930, - "tag": "0000_organic_fantastic_four", + "when": 1729847426779, + "tag": "0000_smart_jackal", "breakpoints": true } ]