From 15a36cbe6382ab54fefc4537761c6a6f0d0d3b5a Mon Sep 17 00:00:00 2001 From: Arman Date: Sat, 15 Jun 2024 16:40:16 +0700 Subject: [PATCH 1/6] feat(db): update schema & seeder --- .../migration.sql | 6 +++ .../migration.sql | 2 + prisma/schema.prisma | 17 ++++++- prisma/seed/users.seed.js | 45 +++++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/20240615093224_add_field_on_profile/migration.sql create mode 100644 prisma/migrations/20240615093721_add_about_field_on_profile/migration.sql diff --git a/prisma/migrations/20240615093224_add_field_on_profile/migration.sql b/prisma/migrations/20240615093224_add_field_on_profile/migration.sql new file mode 100644 index 0000000..3b95f0d --- /dev/null +++ b/prisma/migrations/20240615093224_add_field_on_profile/migration.sql @@ -0,0 +1,6 @@ +-- AlterTable +ALTER TABLE `profiles` ADD COLUMN `incomePerMonth` INTEGER NULL, + ADD COLUMN `insurance` ENUM('Saham', 'Reksadana', 'Obligasi', 'Emas', 'Cryptocurrency') NULL, + ADD COLUMN `investment` ENUM('Saham', 'Reksadana', 'Obligasi', 'Emas', 'Cryptocurrency') NULL, + ADD COLUMN `totalDebt` INTEGER NULL, + ADD COLUMN `totalSaving` INTEGER NULL; diff --git a/prisma/migrations/20240615093721_add_about_field_on_profile/migration.sql b/prisma/migrations/20240615093721_add_about_field_on_profile/migration.sql new file mode 100644 index 0000000..2cd2b6a --- /dev/null +++ b/prisma/migrations/20240615093721_add_about_field_on_profile/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `profiles` ADD COLUMN `about` VARCHAR(191) NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7bb2333..f658901 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -31,7 +31,7 @@ model User { profile Profile? - UserChatRoom ChatRoom[] @relation("UserChatRoom") + UserChatRoom ChatRoom[] @relation("UserChatRoom") ExpertChatRoom ChatRoom[] @relation("ExpertChatRoom") @@map("users") @@ -51,6 +51,7 @@ model Role { model Profile { id String @id @default(uuid()) avatar String? + about String? maritalStatus ProfileMarital? certifiedStatus String? createdAt DateTime @default(now()) @@ -62,6 +63,12 @@ model Profile { education Education? @relation(fields: [educationId], references: [id]) educationId String? + investment ProfileInvestmentAndInsurance? + insurance ProfileInvestmentAndInsurance? + incomePerMonth Int? + totalSaving Int? + totalDebt Int? + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String @unique @@ -117,6 +124,14 @@ enum ProfileMarital { Cerai } +enum ProfileInvestmentAndInsurance { + Saham + Reksadana + Obligasi + Emas + Cryptocurrency +} + enum ChatRoomType { Expert AI diff --git a/prisma/seed/users.seed.js b/prisma/seed/users.seed.js index 293d192..1af749a 100644 --- a/prisma/seed/users.seed.js +++ b/prisma/seed/users.seed.js @@ -33,6 +33,7 @@ const seedUsers = async (count) => { gender === "Laki_laki" ? getPublicUrl("male.png") : getPublicUrl("female.png"); + const about = faker.lorem.paragraph(); const maritalStatus = faker.helpers.arrayElement([ "Lajang", @@ -47,6 +48,37 @@ const seedUsers = async (count) => { const randomWork = works[Math.floor(Math.random() * works.length)]; const workId = randomWork.id; + const investment = faker.helpers.arrayElement([ + "Saham", + "Reksadana", + "Obligasi", + "Emas", + "Cryptocurrency", + ]); + + const insurance = faker.helpers.arrayElement([ + "Saham", + "Reksadana", + "Obligasi", + "Emas", + "Cryptocurrency", + ]); + + const incomePerMonth = faker.datatype.number({ + min: 0, + max: 25000000, + }); + + const totalSaving = faker.datatype.number({ + min: 0, + max: 144000000, + }); + + const totalDebt = faker.datatype.number({ + min: 0, + max: 144000000, + }); + await prisma.user.create({ data: { fullName, @@ -59,6 +91,7 @@ const seedUsers = async (count) => { profile: { create: { avatar: avatarDefault, + about, maritalStatus, certifiedStatus: randomRole.name === "Expert" @@ -74,6 +107,18 @@ const seedUsers = async (count) => { id: educationId, }, }, + investment: + randomRole.name === "User" ? investment : null, + insurance: + randomRole.name === "User" ? insurance : null, + incomePerMonth: + randomRole.name === "User" + ? incomePerMonth + : null, + totalSaving: + randomRole.name === "User" ? totalSaving : null, + totalDebt: + randomRole.name === "User" ? totalDebt : null, }, }, }, From 51e7425f8a8da02b118b859ef025e760bbba6719 Mon Sep 17 00:00:00 2001 From: Arman Date: Sat, 15 Jun 2024 17:42:16 +0700 Subject: [PATCH 2/6] feat(db): update schema --- .../20240615101729_change_int_to_bigint/migration.sql | 4 ++++ .../20240615103211_change_bigint_to_decimal/migration.sql | 4 ++++ prisma/schema.prisma | 6 +++--- 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 prisma/migrations/20240615101729_change_int_to_bigint/migration.sql create mode 100644 prisma/migrations/20240615103211_change_bigint_to_decimal/migration.sql diff --git a/prisma/migrations/20240615101729_change_int_to_bigint/migration.sql b/prisma/migrations/20240615101729_change_int_to_bigint/migration.sql new file mode 100644 index 0000000..89b64f5 --- /dev/null +++ b/prisma/migrations/20240615101729_change_int_to_bigint/migration.sql @@ -0,0 +1,4 @@ +-- AlterTable +ALTER TABLE `profiles` MODIFY `incomePerMonth` BIGINT NULL, + MODIFY `totalDebt` BIGINT NULL, + MODIFY `totalSaving` BIGINT NULL; diff --git a/prisma/migrations/20240615103211_change_bigint_to_decimal/migration.sql b/prisma/migrations/20240615103211_change_bigint_to_decimal/migration.sql new file mode 100644 index 0000000..2d2d262 --- /dev/null +++ b/prisma/migrations/20240615103211_change_bigint_to_decimal/migration.sql @@ -0,0 +1,4 @@ +-- AlterTable +ALTER TABLE `profiles` MODIFY `incomePerMonth` DECIMAL(65, 30) NULL, + MODIFY `totalDebt` DECIMAL(65, 30) NULL, + MODIFY `totalSaving` DECIMAL(65, 30) NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index f658901..d19397e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -65,9 +65,9 @@ model Profile { investment ProfileInvestmentAndInsurance? insurance ProfileInvestmentAndInsurance? - incomePerMonth Int? - totalSaving Int? - totalDebt Int? + incomePerMonth Decimal? + totalSaving Decimal? + totalDebt Decimal? user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String @unique From 3ce0fd82fde8c71e27d812ea6ca49ff1d8e3db05 Mon Sep 17 00:00:00 2001 From: Arman Date: Sat, 15 Jun 2024 17:43:20 +0700 Subject: [PATCH 3/6] feat(api): update schema validation, controller, and repository for model user profile --- src/controller/users.controller.js | 13 +++++++ src/repository/users.repository.js | 54 ++++++++++++++++++++++++++++++ src/schema/users.schema.js | 10 ++++++ 3 files changed, 77 insertions(+) diff --git a/src/controller/users.controller.js b/src/controller/users.controller.js index bf78e52..47fc5ea 100644 --- a/src/controller/users.controller.js +++ b/src/controller/users.controller.js @@ -23,6 +23,7 @@ import { getFileNameFromUrl, getPublicUrl, } from "../utils/bucket.util.js"; +import { Decimal } from "@prisma/client/runtime/library"; export const getAllUsersHandler = async (req, res) => { try { @@ -153,6 +154,18 @@ export const editUserProfilePartialFieldByUserIdHandler = async (req, res) => { req.body ); + if (req.body.incomePerMonth) { + req.body.incomePerMonth = new Decimal(req.body.incomePerMonth); + } + + if (req.body.totalSaving) { + req.body.totalSaving = new Decimal(req.body.totalSaving); + } + + if (req.body.totalDebt) { + req.body.totalDebt = new Decimal(req.body.totalDebt); + } + const user = await editUserProfileByUserId(userId, validateData, res); res.status(200).send({ diff --git a/src/repository/users.repository.js b/src/repository/users.repository.js index 511c9f3..ea32469 100644 --- a/src/repository/users.repository.js +++ b/src/repository/users.repository.js @@ -29,6 +29,7 @@ export const findUsers = async (filters) => { profile: { select: { id: true, + about: true, avatar: true, maritalStatus: true, certifiedStatus: true, @@ -48,6 +49,11 @@ export const findUsers = async (filters) => { updatedAt: true, }, }, + investment: true, + insurance: true, + incomePerMonth: true, + totalSaving: true, + totalDebt: true, createdAt: true, updatedAt: true, }, @@ -77,6 +83,7 @@ export const findUserById = async (userId) => { select: { id: true, avatar: true, + about: true, maritalStatus: true, certifiedStatus: true, work: { @@ -95,6 +102,11 @@ export const findUserById = async (userId) => { updatedAt: true, }, }, + investment: true, + insurance: true, + incomePerMonth: true, + totalSaving: true, + totalDebt: true, createdAt: true, updatedAt: true, }, @@ -125,6 +137,7 @@ export const findUserByEmail = async (email) => { select: { id: true, avatar: true, + about: true, maritalStatus: true, certifiedStatus: true, work: { @@ -143,6 +156,11 @@ export const findUserByEmail = async (email) => { updatedAt: true, }, }, + investment: true, + insurance: true, + incomePerMonth: true, + totalSaving: true, + totalDebt: true, createdAt: true, updatedAt: true, }, @@ -173,6 +191,7 @@ export const findUserByRefreshToken = async (refreshToken) => { select: { id: true, avatar: true, + about: true, maritalStatus: true, certifiedStatus: true, work: { @@ -191,6 +210,11 @@ export const findUserByRefreshToken = async (refreshToken) => { updatedAt: true, }, }, + investment: true, + insurance: true, + incomePerMonth: true, + totalSaving: true, + totalDebt: true, createdAt: true, updatedAt: true, }, @@ -229,11 +253,17 @@ export const findUserProfileByUserId = async (userId) => { }, select: { id: true, + about: true, avatar: true, maritalStatus: true, certifiedStatus: true, work: true, education: true, + investment: true, + insurance: true, + incomePerMonth: true, + totalSaving: true, + totalDebt: true, createdAt: true, updatedAt: true, }, @@ -248,6 +278,9 @@ export const updateUserProfileByUserId = async (userId, userData) => { userId, }, data: { + ...(userData.about && { + about: userData.about, + }), ...(userData.maritalStatus && { maritalStatus: userData.maritalStatus, }), @@ -260,6 +293,21 @@ export const updateUserProfileByUserId = async (userId, userData) => { ...(userData.educationId && { education: { connect: { id: userData.educationId } }, }), + ...(userData.investment && { + investment: userData.investment, + }), + ...(userData.insurance && { + insurance: userData.insurance, + }), + ...(userData.incomePerMonth && { + incomePerMonth: userData.incomePerMonth, + }), + ...(userData.totalSaving && { + totalSaving: userData.totalSaving, + }), + ...(userData.totalDebt && { + totalDebt: userData.totalDebt, + }), }, }); @@ -272,10 +320,16 @@ export const deleteUserProfileByUserId = async (userId) => { userId, }, data: { + about: null, maritalStatus: null, certifiedStatus: null, workId: null, educationId: null, + investment: null, + insurance: null, + incomePerMonth: null, + totalSaving: null, + totalDebt: null, }, }); diff --git a/src/schema/users.schema.js b/src/schema/users.schema.js index a1fb1ac..ed86462 100644 --- a/src/schema/users.schema.js +++ b/src/schema/users.schema.js @@ -19,9 +19,19 @@ export const UpdatePartialFieldUserSchema = z export const UpdatePartialFieldUserProfileSchema = z .object({ + about: z.string().optional(), maritalStatus: z.enum(["Lajang", "Menikah", "Cerai"]).optional(), certifiedStatus: z.string().nullable().optional(), workId: z.string().optional(), educationId: z.string().optional(), + investment: z + .enum(["Saham", "Reksadana", "Obligasi", "Emas", "Cryptocurrency"]) + .optional(), + insurance: z + .enum(["Saham", "Reksadana", "Obligasi", "Emas", "Cryptocurrency"]) + .optional(), + incomePerMonth: z.union([z.string(), z.number()]).optional(), + totalSaving: z.union([z.string(), z.number()]).optional(), + totalDebt: z.union([z.string(), z.number()]).optional(), }) .strict(); From e185c39a8ebaa19fd6adeb833990e224d7f5141a Mon Sep 17 00:00:00 2001 From: Arman Date: Sat, 15 Jun 2024 17:56:59 +0700 Subject: [PATCH 4/6] feat(db): update schema formatting decimal --- .../20240615105605_formatting_decimal/migration.sql | 12 ++++++++++++ prisma/schema.prisma | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 prisma/migrations/20240615105605_formatting_decimal/migration.sql diff --git a/prisma/migrations/20240615105605_formatting_decimal/migration.sql b/prisma/migrations/20240615105605_formatting_decimal/migration.sql new file mode 100644 index 0000000..b3f6e12 --- /dev/null +++ b/prisma/migrations/20240615105605_formatting_decimal/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - You are about to alter the column `incomePerMonth` on the `profiles` table. The data in that column could be lost. The data in that column will be cast from `Decimal(65,30)` to `Decimal(25,2)`. + - You are about to alter the column `totalDebt` on the `profiles` table. The data in that column could be lost. The data in that column will be cast from `Decimal(65,30)` to `Decimal(25,2)`. + - You are about to alter the column `totalSaving` on the `profiles` table. The data in that column could be lost. The data in that column will be cast from `Decimal(65,30)` to `Decimal(25,2)`. + +*/ +-- AlterTable +ALTER TABLE `profiles` MODIFY `incomePerMonth` DECIMAL(25, 2) NULL, + MODIFY `totalDebt` DECIMAL(25, 2) NULL, + MODIFY `totalSaving` DECIMAL(25, 2) NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d19397e..896b890 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -65,9 +65,9 @@ model Profile { investment ProfileInvestmentAndInsurance? insurance ProfileInvestmentAndInsurance? - incomePerMonth Decimal? - totalSaving Decimal? - totalDebt Decimal? + incomePerMonth Decimal? @db.Decimal(25, 2) + totalSaving Decimal? @db.Decimal(25, 2) + totalDebt Decimal? @db.Decimal(25, 2) user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String @unique From e998ddc7e717b18092ab2c4b99cc0765bb64724f Mon Sep 17 00:00:00 2001 From: Arman Date: Sat, 15 Jun 2024 18:25:26 +0700 Subject: [PATCH 5/6] feat(db): update seeder --- prisma/seed/users.seed.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/prisma/seed/users.seed.js b/prisma/seed/users.seed.js index 1af749a..8d4a566 100644 --- a/prisma/seed/users.seed.js +++ b/prisma/seed/users.seed.js @@ -26,14 +26,14 @@ const seedUsers = async (count) => { "Laki_laki", "Perempuan", ]); - const age = faker.datatype.number({ min: 18, max: 80 }); + const age = faker.number.int({ min: 18, max: 80 }); const phoneNumber = faker.phone.number(); const password = hashPassword; const avatarDefault = gender === "Laki_laki" ? getPublicUrl("male.png") : getPublicUrl("female.png"); - const about = faker.lorem.paragraph(); + const about = faker.lorem.paragraph(1); const maritalStatus = faker.helpers.arrayElement([ "Lajang", @@ -64,17 +64,17 @@ const seedUsers = async (count) => { "Cryptocurrency", ]); - const incomePerMonth = faker.datatype.number({ + const incomePerMonth = faker.number.int({ min: 0, max: 25000000, }); - const totalSaving = faker.datatype.number({ + const totalSaving = faker.number.int({ min: 0, max: 144000000, }); - const totalDebt = faker.datatype.number({ + const totalDebt = faker.number.int({ min: 0, max: 144000000, }); From 6cbbef19fbdc7920cf70b59740fa9d8c4e89af0d Mon Sep 17 00:00:00 2001 From: Arman Date: Sat, 15 Jun 2024 18:25:45 +0700 Subject: [PATCH 6/6] feat(docs): update response example and schema --- openapi.json | 60 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/openapi.json b/openapi.json index 4303dd8..669a1dc 100644 --- a/openapi.json +++ b/openapi.json @@ -1144,6 +1144,7 @@ "data": { "profile": { "id": "de5b1599-b1b7-4633-8a5d-331690ee9413", + "about": "Sophismata tum crur tabgo angulus. Certe statua adfero statua talis aveho aspicio. Pel voluptatum strenuus.", "avatar": "https://storage.googleapis.com/finboost/example.png", "maritalStatus": "Lajang", "certifiedStatus": null, @@ -1154,7 +1155,12 @@ "education": { "id": "7fe46a1f-fb32-4e36-9741-d96f22cf4b4b", "name": "SMA / Sederajat" - } + }, + "investment": "Saham", + "insurance": "Obligasi", + "incomePerMonth": "9211156", + "totalSaving": "111138960", + "totalDebt": "10000000" } } } @@ -1167,6 +1173,7 @@ "data": { "profile": { "id": "36429cef-96d1-41a7-b579-c2dc8d4f2beb", + "about": null, "avatar": "https://storage.googleapis.com/finboost/example2.png", "maritalStatus": "Menikah", "certifiedStatus": "Certified Financial Planner", @@ -1177,7 +1184,12 @@ "education": { "id": "b5fbeaee-812f-4ec3-b807-22dd2794e09a", "name": "S1" - } + }, + "investment": null, + "insurance": null, + "incomePerMonth": null, + "totalSaving": null, + "totalDebt": null } } } @@ -1225,10 +1237,16 @@ "User 1": { "description": "Example request to partially update user profile", "value": { + "about": "Testing About", "maritalStatus": "Lajang", "certifiedStatus": null, "workId": "319defd8-1836-4b9d-af2d-655a43a60bde", - "educationId": "7fe46a1f-fb32-4e36-9741-d96f22cf4b4b" + "educationId": "7fe46a1f-fb32-4e36-9741-d96f22cf4b4b", + "investment": "Saham", + "insurance": "Obligasi", + "incomePerMonth": "2400000", + "totalSaving": "5000000", + "totalDebt": "10000000" } }, "User 2": { @@ -3343,6 +3361,9 @@ "id": { "type": "string" }, + "about": { + "type": "string" + }, "avatar": { "type": "string" }, @@ -3357,6 +3378,21 @@ }, "educationId": { "type": "string" + }, + "investment": { + "type": "string" + }, + "insurance": { + "type": "string" + }, + "incomePerMonth": { + "type": "string" + }, + "totalSaving": { + "type": "string" + }, + "totalDebt": { + "type": "string" } } }, @@ -3424,6 +3460,9 @@ "UpdatePartialFieldProfile": { "type": "object", "properties": { + "about": { + "type": "string" + }, "maritalStatus": { "type": "string" }, @@ -3435,6 +3474,21 @@ }, "educationId": { "type": "string" + }, + "investment": { + "type": "string" + }, + "insurance": { + "type": "string" + }, + "incomePerMonth": { + "type": "string" + }, + "totalSaving": { + "type": "string" + }, + "totalDebt": { + "type": "string" } } },