From 55270d30abfcabc8e29513d4e7017c6c88f83db9 Mon Sep 17 00:00:00 2001 From: Vermium Sifell Date: Wed, 19 Oct 2022 17:04:30 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Fixed=20an?= =?UTF-8?q?=20transfer=20transaction=20helper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20221019142757_modules/migration.sql | 16 ++++ prisma/schema.prisma | 7 +- src/helpers/transferCredits.ts | 93 +++++++++++++++++++ 3 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 prisma/migrations/20221019142757_modules/migration.sql create mode 100644 src/helpers/transferCredits.ts diff --git a/prisma/migrations/20221019142757_modules/migration.sql b/prisma/migrations/20221019142757_modules/migration.sql new file mode 100644 index 0000000..ec153f0 --- /dev/null +++ b/prisma/migrations/20221019142757_modules/migration.sql @@ -0,0 +1,16 @@ +-- RedefineTables +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_GuildMember" ( + "userId" TEXT NOT NULL, + "guildId" TEXT NOT NULL, + "creditsEarned" INTEGER NOT NULL DEFAULT 0, + "pointsEarned" INTEGER NOT NULL DEFAULT 0, + CONSTRAINT "GuildMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "GuildMember_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_GuildMember" ("creditsEarned", "guildId", "pointsEarned", "userId") SELECT coalesce("creditsEarned", 0) AS "creditsEarned", "guildId", coalesce("pointsEarned", 0) AS "pointsEarned", "userId" FROM "GuildMember"; +DROP TABLE "GuildMember"; +ALTER TABLE "new_GuildMember" RENAME TO "GuildMember"; +CREATE UNIQUE INDEX "GuildMember_userId_guildId_key" ON "GuildMember"("userId", "guildId"); +PRAGMA foreign_key_check; +PRAGMA foreign_keys=ON; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a1ab624..7b621c1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -2,7 +2,8 @@ // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" + previewFeatures = ["interactiveTransactions"] } datasource db { @@ -86,8 +87,8 @@ model GuildMember { // Settings // Modules - creditsEarned Int? - pointsEarned Int? + creditsEarned Int @default(0) + pointsEarned Int @default(0) // Unique Identifier @@unique([userId, guildId]) diff --git a/src/helpers/transferCredits.ts b/src/helpers/transferCredits.ts new file mode 100644 index 0000000..538eee9 --- /dev/null +++ b/src/helpers/transferCredits.ts @@ -0,0 +1,93 @@ +import { Guild, User } from "discord.js"; +import prisma from "../prisma"; + +export default async (guild: Guild, from: User, to: User, amount: number) => { + return await prisma.$transaction(async (tx) => { + // 1. Decrement amount from the sender. + const sender = await tx.guildMember.upsert({ + update: { + creditsEarned: { + decrement: amount, + }, + }, + create: { + user: { + connectOrCreate: { + create: { + id: from.id, + }, + where: { + id: from.id, + }, + }, + }, + guild: { + connectOrCreate: { + create: { + id: guild.id, + }, + where: { + id: guild.id, + }, + }, + }, + creditsEarned: -amount, + }, + where: { + userId_guildId: { + userId: from.id, + guildId: guild.id, + }, + }, + }); + + if (!sender) throw new Error("No sender available"); + + if (!sender.creditsEarned) throw new Error("No credits available"); + + // 2. Verify that the sender's balance didn't go below zero. + if (sender.creditsEarned < 0) { + throw new Error(`${from} doesn't have enough to send ${amount}`); + } + + // 3. Increment the recipient's balance by amount + const recipient = await tx.guildMember.upsert({ + update: { + creditsEarned: { + increment: amount, + }, + }, + create: { + user: { + connectOrCreate: { + create: { + id: to.id, + }, + where: { + id: to.id, + }, + }, + }, + guild: { + connectOrCreate: { + create: { + id: guild.id, + }, + where: { + id: guild.id, + }, + }, + }, + creditsEarned: +amount, + }, + where: { + userId_guildId: { + userId: to.id, + guildId: guild.id, + }, + }, + }); + + return recipient; + }); +};