Skip to content

Commit

Permalink
Migrate from MySQL to PostgreSQL (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
drishit96 authored Mar 17, 2024
1 parent 62708f8 commit f3c65ea
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 116 deletions.
15 changes: 0 additions & 15 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,6 @@ jobs:
- name: Find and Replace UI_ENV
run: find -name "ui.config.ts" -type f -exec sed -i ''s/#{UI_ENV}#/test/g'' {} \;

- name: Find and Replace TEST_DB_ORG - Using Secret
run: find -name "playwright.config.ts" -type f -exec sed -i ''s/#{TEST_DB_ORG}#/${{ secrets.TEST_DB_ORG }}/g'' {} \;

- name: Find and Replace TEST_DB_SERVICE_TOKEN - Using Secret
run: find -name "playwright.config.ts" -type f -exec sed -i ''s/#{TEST_DB_SERVICE_TOKEN}#/${{ secrets.TEST_DB_SERVICE_TOKEN }}/g'' {} \;

- name: Find and Replace TEST_DB_TOKEN_ID - Using Secret
run: find -name "playwright.config.ts" -type f -exec sed -i ''s/#{TEST_DB_TOKEN_ID}#/${{ secrets.TEST_DB_TOKEN_ID }}/g'' {} \;

- name: Find and Replace TEST_LOGIN_USERNAME - Using Secret
run: find -name "auth.setup.ts" -type f -exec sed -i ''s/#{TEST_LOGIN_USERNAME}#/${{ secrets.TEST_LOGIN_USERNAME }}/g'' {} \;

Expand All @@ -91,12 +82,6 @@ jobs:
- name: Install dependencies
run: npm ci --legacy-peer-deps

- name: Install Planetscale CLI
run: |
mkdir pscaledir
wget -O pscalecli.tar.gz https://github.com/planetscale/cli/releases/download/v0.145.0/pscale_0.145.0_linux_amd64.tar.gz
tar -xvf pscalecli.tar.gz -C ./pscaledir
- name: Set DEBUG=pw:webserver
run: echo "DEBUG=pw:webserver" >> $GITHUB_ENV

Expand Down
2 changes: 1 addition & 1 deletion app/lib/prisma.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PrismaClient } from "@prisma/client";

const prisma = global.prisma || new PrismaClient();
const prisma = global.prisma || new PrismaClient({ log: ["error", "warn"] });
if (process.env.NODE_ENV === "development") global.prisma = prisma;

export default prisma;
20 changes: 9 additions & 11 deletions app/modules/recurring/recurring.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,17 +228,15 @@ export async function markTransactionAsDone(

export async function markAsNotified(userIds: string[], startDate: Date, endDate: Date) {
try {
//Used raw query due to issue: https://github.com/prisma/prisma/issues/5043
const result = await prisma.$executeRaw(
Prisma.sql`UPDATE RecurringTransaction SET isNotified = 1 WHERE userId IN (${Prisma.join(
userIds
)}) AND executionDate > ${formatDate_DD_MMMM_YYYY_hh_mm(
startDate
)} AND executionDate <= ${formatDate_DD_MMMM_YYYY_hh_mm(
endDate
)} AND isNotified = 0`
);
return result > 0;
const result = await prisma.recurringTransaction.updateMany({
where: {
userId: { in: userIds },
executionDate: { gt: startDate, lte: endDate },
isNotified: false,
},
data: { isNotified: true },
});
return result.count > 0;
} catch (error) {
logError(error);
return false;
Expand Down
5 changes: 4 additions & 1 deletion app/modules/subscriptions/gpb.subscriptions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ export async function createGPBSubscription(
}

// reset isLatest flag for all purchaseTokens of current user
await prisma.$executeRaw`UPDATE GPBSubscription SET isLatest = 0 WHERE userId = ${userId} AND isLatest = 1;`;
await prisma.gPBSubscription.updateMany({
where: { userId, isLatest: true },
data: { isLatest: false },
});

let expiry = 0;
if (
Expand Down
1 change: 1 addition & 0 deletions app/modules/transaction/transaction.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export type MonthlyTargetInput = z.infer<typeof MonthlyTargetInputSchema>;
export type MonthlyCategoryWiseTargetInput = z.infer<
typeof MonthlyCategoryWiseTargetInputSchema
>;

export type TransactionType = "income" | "expense" | "investment";

export function parseTransactionInput(transaction: unknown) {
Expand Down
6 changes: 3 additions & 3 deletions app/modules/transaction/transaction.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ export async function editMonthlyTarget(
valuesArr.push(
Prisma.sql`(${Prisma.join([
userId,
formatDate_YYYY_MM_DD(date),
Prisma.sql`CAST(${formatDate_YYYY_MM_DD(date)} AS DATE)`,
"expense",
category,
0,
Expand All @@ -657,9 +657,9 @@ export async function editMonthlyTarget(
}

const categoryBudgetUpdate = prisma.$executeRaw(
Prisma.sql`INSERT INTO CategoryAmount (userId, date, type, category, amount, budget) VALUES ${Prisma.join(
Prisma.sql`INSERT INTO "CategoryAmount" ("userId", "date", "type", "category", "amount", "budget") VALUES ${Prisma.join(
valuesArr
)} ON DUPLICATE KEY UPDATE budget = VALUES(budget)`
)} ON CONFLICT ("userId", "date", "type", "category") DO UPDATE SET budget = EXCLUDED.budget`
);
tasks.push(categoryBudgetUpdate);

Expand Down
9 changes: 2 additions & 7 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const config: PlaywrightTestConfig = {
// globalSetup: require.resolve("./global-setup"),
testDir: "./tests",
/* Maximum time one test can run for. */
timeout: 30 * 1000,
globalTimeout: 120 * 1000,
timeout: 45 * 1000,
globalTimeout: 0,
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
Expand Down Expand Up @@ -113,11 +113,6 @@ const config: PlaywrightTestConfig = {

/* Run your local dev server before starting the tests */
webServer: [
{
command: `./pscaledir/pscale connect expense-manager dev --org #{TEST_DB_ORG}# --service-token #{TEST_DB_SERVICE_TOKEN}# --service-token-id #{TEST_DB_TOKEN_ID}#`,
port: 3306,
reuseExistingServer: true,
},
{
command: "npm run testserver",
port: 3000,
Expand Down
126 changes: 48 additions & 78 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ generator client {
}

datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
provider = "postgresql"
url = env("DATABASE_URL")
relationMode = "prisma"
}

model User {
Expand Down Expand Up @@ -49,20 +49,14 @@ model MonthlyTarget {
@@id([userId, date])
}

enum TransactionType {
expense
income
investment
}

model CategoryAmount {
userId String
date DateTime
category String
type TransactionType
amount Decimal @db.Decimal(22, 4)
budget Decimal? @db.Decimal(16, 4)
user User @relation(fields: [userId], references: [id])
type String @db.VarChar(10)
amount Decimal @db.Decimal(22, 4)
budget Decimal? @db.Decimal(16, 4)
user User @relation(fields: [userId], references: [id])
@@id([userId, date, type, category])
@@index([userId, date, type, amount])
Expand All @@ -71,120 +65,96 @@ model CategoryAmount {
model PaymentModeAmount {
userId String
date DateTime
transactionType TransactionType
transactionType String @db.VarChar(10)
paymentMode String
amount Decimal @db.Decimal(22, 4)
budget Decimal? @db.Decimal(16, 4)
user User @relation(fields: [userId], references: [id])
@@id([userId, date, transactionType, paymentMode])
@@index([userId, date, transactionType, paymentMode, amount])
@@index([userId, date, transactionType, paymentMode, amount], map: "PaymentModeAmount_userId_d6310b-342e-4566-9d91-4c4bdd285dbc_idx")
}

model Transaction {
id String @id @default(nanoid(18))
createdAt DateTime @default(now())
id String @id @default(nanoid(18))
createdAt DateTime @default(now())
createdAtLocal DateTime
description String? @db.VarChar(250)
amount Decimal @db.Decimal(22, 4)
type TransactionType
description String? @db.VarChar(250)
amount Decimal @db.Decimal(22, 4)
type String @db.VarChar(10)
category String
category2 String?
category3 String?
paymentMode String
user User @relation(fields: [userId], references: [id])
user User @relation(fields: [userId], references: [id])
userId String
@@index([userId, createdAtLocal, type, category])
}

enum PaymentGateway {
GPB // Google Play Billing
STR // Stripe
}

model UserPreference {
userId String @unique
currency String? @db.VarChar(3)
timezone String @db.VarChar(64)
locale String @db.VarChar(15)
paymentGateway PaymentGateway?
isActiveSubscription Boolean @default(false)
isMFAOn Boolean @default(false)
collectAnalytics Boolean?
lastModified Float @default(0) @db.Double()
user User? @relation(fields: [userId], references: [id])
userId String @unique(map: "UserPreference_userId_idx")
currency String? @db.VarChar(3)
timezone String @db.VarChar(64)
locale String @db.VarChar(15)
paymentGateway String? @db.VarChar(3)
isActiveSubscription Boolean @default(false)
isMFAOn Boolean @default(false)
collectAnalytics Boolean?
lastModified Float @default(0)
user User? @relation(fields: [userId], references: [id])
@@index([userId, lastModified])
}

model RecurringTransaction {
id String @id @default(nanoid(12))
occurrence String @db.VarChar(5)
interval Int @db.UnsignedSmallInt
amount Decimal @db.Decimal(22, 4)
type TransactionType
id String @id @default(nanoid(12))
occurrence String @db.VarChar(5)
interval Int @db.SmallInt
amount Decimal @db.Decimal(22, 4)
type String @db.VarChar(10)
category String
category2 String?
category3 String?
paymentMode String
description String? @db.VarChar(250)
description String? @db.VarChar(250)
executionDate DateTime
isNotified Boolean @default(false)
user User? @relation(fields: [userId], references: [id])
isNotified Boolean @default(false)
userId String
user User? @relation(fields: [userId], references: [id])
@@index([userId, executionDate])
@@index([executionDate, isNotified])
}

model CustomCategory {
userId String
type TransactionType
value String @db.VarChar(250)
user User? @relation(fields: [userId], references: [id])
userId String
type String @db.VarChar(10)
value String @db.VarChar(250)
user User? @relation(fields: [userId], references: [id])
@@id([userId, type, value])
}

enum GPBSubscriptionState {
SUBSCRIPTION_STATE_ACTIVE
SUBSCRIPTION_STATE_CANCELED
SUBSCRIPTION_STATE_IN_GRACE_PERIOD
SUBSCRIPTION_STATE_ON_HOLD
SUBSCRIPTION_STATE_PAUSED
SUBSCRIPTION_STATE_EXPIRED
}

model GPBSubscription {
purchaseToken String @id @db.VarChar(250)
purchaseToken String @id @db.VarChar(250)
userId String
isLatest Boolean @default(false)
state GPBSubscriptionState
expiry Float? @db.Double()
isLatest Boolean @default(false)
state String @db.VarChar(40)
expiry Float?
cancelReason String?
@@index([userId, isLatest])
}

enum STRSubscriptionState {
trialing
active
past_due
incomplete
incomplete_expired
canceled
unpaid
paused
}

model STRSubscription {
userId String @id
customerId String
subscriptionId String
state STRSubscriptionState
expiry Float
cancelAtExpiry Boolean @default(false)
userId String @id
customerId String
subscriptionId String
state String @db.VarChar(20)
expiry Float
cancelAtExpiry Boolean @default(false)
@@index([subscriptionId])
}
}

0 comments on commit f3c65ea

Please sign in to comment.