Neye ihtiyacınız var
- TypeScript ile yazılmış bir discord.js botu. Node.js Bot türümüz,
.ts ile biten ana dosyayı tsx ile çalıştırır, yani önceden hiçbir şeyin derlenmesi gerekmez: TypeScript Discord botu nasıl çalıştırılır.
- PlayNHost bot planı, tür olarak Node.js Bot seçili. Her plan bir veritabanı içerir.
- Migration'ı bir kez yazmak için kendi bilgisayarınızda Node.js ve npm.
1. Veritabanını ve değişkenleri oluşturun
- Bot sunucunuzu panelde açın, Veritabanları'na, sonra Yeni veritabanı ve Veritabanı oluştur'a tıklayın.
- Yeni veritabanının sayfası açılır (daha sonra Veritabanlarınız içinden ona tıklarsınız). Açık tutun ve Hazır yapılandırma altında Şunun için yapılandırma alanından Generic URL'yi seçin: Prisma komut satırının ihtiyaç duyduğu
mysql://... bağlantı dizesi budur.
- Bot sayfasını, Ortam bölmesini açın, .env dosyası yapıştır'a tıklayın ve değerlerinizle altı satır yapıştırın.
DATABASE_URL için Generic URL'yi gösterildiği gibi yapıştırın: veritabanı parolalarımız @ ve + gibi karakterler içerebilir, Prisma bunların bir URL içinde yüzde kodlamalı olmasını ister ve Generic URL zaten kodlanmıştır.
DB_HOST=your-host
DB_PORT=3306
DB_NAME=your-database
DB_USER=your-username
DB_PASSWORD=your-password
DATABASE_URL=mysql://your-username:your-password@your-host:3306/your-database
DB_PASSWORD ve DATABASE_URL bir Gizli rozeti alır: yalnızca yazılabilir olarak saklanırlar. 6 değişkeni içe aktar'a tıklayın.
Botun kendisi, Prisma'nın quickstart'ındaki gibi adaptöre tek tek verilen beş DB_ değeriyle bağlanır. DATABASE_URL yalnızca kurulum sırasında çalışan prisma komutları içindir.
2. Proje dosyaları
package.json
{
"name": "my-discord-bot",
"private": true,
"type": "module",
"scripts": {
"postinstall": "prisma generate && prisma migrate deploy"
},
"dependencies": {
"@prisma/adapter-mariadb": "^7",
"@prisma/client": "^7",
"discord.js": "^14"
},
"devDependencies": {
"prisma": "^7"
}
}
prisma7.config.ts (Prisma 7.10 ve sonrası bu adı kullanır, böylece Prisma 8'in prisma.config.ts dosyasıyla çakışmaz)
import { defineConfig } from "prisma/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
},
datasource: {
url: process.env.DATABASE_URL,
},
});
prisma/schema.prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
datasource db {
provider = "mysql"
}
model Warning {
id Int @id @default(autoincrement())
guildId String @db.VarChar(20)
userId String @db.VarChar(20)
reason String @db.VarChar(200)
createdAt DateTime @default(now())
@@index([guildId, userId])
}
index.ts
import { Client, Events, GatewayIntentBits, InteractionContextType, MessageFlags, REST, Routes, SlashCommandBuilder } from "discord.js";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
import { PrismaClient } from "./generated/prisma/client";
// One client for the whole bot. The values come from the Environment pane.
const adapter = new PrismaMariaDb({
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT),
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
connectionLimit: 5,
});
const prisma = new PrismaClient({ adapter });
const commands = [
new SlashCommandBuilder()
.setName("warn")
.setDescription("Warn a member and count their warnings")
.setContexts(InteractionContextType.Guild)
.addUserOption((o) => o.setName("user").setDescription("Who to warn").setRequired(true))
.addStringOption((o) => o.setName("reason").setDescription("Why").setRequired(true).setMaxLength(200))
.toJSON(),
];
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.once(Events.ClientReady, async (c) => {
await new REST().setToken(process.env.DISCORD_TOKEN!).put(Routes.applicationCommands(c.user.id), { body: commands });
console.log(`Logged in as ${c.user.tag}`);
});
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand() || interaction.commandName !== "warn" || !interaction.guildId) return;
const user = interaction.options.getUser("user", true);
const reason = interaction.options.getString("reason", true);
try {
await prisma.warning.create({ data: { guildId: interaction.guildId, userId: user.id, reason } });
const total = await prisma.warning.count({ where: { guildId: interaction.guildId, userId: user.id } });
await interaction.reply(`${user} has ${total} warning(s).`);
} catch (err) {
console.error(err);
if (!interaction.replied) await interaction.reply({ content: "Could not save the warning. Try again later.", flags: MessageFlags.Ephemeral }).catch(console.error);
}
});
client.login(process.env.DISCORD_TOKEN);
setContexts(InteractionContextType.Guild) ve !interaction.guildId kontrolü, /warn komutunu özel mesajlardan uzak tutar. try/catch önemlidir: o olmadan discord.js başarısız bir sorguyu kendi error olayına verir ve orada kimse dinlemiyorsa Node.js botu durdurur.
3. İlk migration'ı kendi bilgisayarınızda yazın
Kendi bilgisayarınızdaki proje klasöründe (Windows'ta prisma\migrations\0_init klasörlerini mkdir -p yerine elle oluşturun):
npm install --ignore-scripts
mkdir -p prisma/migrations/0_init
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
migrate diff boş bir veritabanını şemanızla karşılaştırır ve hiçbir veritabanına bağlanmadan SQL'i yazar. --ignore-scripts, bir veritabanına ulaşmaya çalışacak olan postinstall'ı atlar. Dosya -- CreateTable ve CREATE TABLE `Warning` ile başlar.
4. Yükleyin ve başlatın
- Dosyalar'da
package.json, prisma7.config.ts, index.ts dosyalarını ve prisma klasörünü (içinde schema.prisma ve migrations olacak) yükleyin. node_modules ve generated klasörlerini yüklemeyin: sunucu ikisini de oluşturur.
- Bot sayfasında, Kod bölmesinde Giriş dosyası değerini
index.ts yapın.
- Başlat'a basın ve Konsol'u açın. Kurulum
postinstall'ınızı çalıştırır: önce Generated Prisma Client (7.10.1), sonra All migrations have been successfully applied., sonra [PlayNHost] Starting your bot ve Logged in as ... satırlarını görürsünüz.
Konsol ayrıca npm warn install-scripts 2 packages had install scripts blocked mesajını gösterir; bu mesaj prisma ve @prisma/engines içindir. Node.js 22 imajımızdaki npm sürümü, izin verilmedikçe bağımlılıkların kurulum betiklerini engeller. Kendi postinstall'ınız yine de çalışır ve testimizde Prisma bu betikler olmadan da üretti, migrate etti ve sorgu çalıştırdı.
Neden prisma migrate dev değil?
prisma migrate dev, migration'larınızı denetlemek için önce geçici bir shadow veritabanı oluşturur. Botunuzun veritabanı kullanıcısı kendi veritabanı içinde çalışabilir ama yenilerini oluşturamaz, bu yüzden sunucularımızda şu hatayla durur:
Prisma Migrate could not create the shadow database. Please make sure the database user has permission to create databases. Read more about the shadow database (and workarounds) at https://pris.ly/d/migrate-shadow
Original error: Error code: P1010
User was denied access on the database `prisma_migrate_shadow_db_...`
prisma migrate deploy yalnızca migration dosyalarını uygular ve shadow veritabanı gerektirmez, postinstall bu yüzden onu kullanır. migrate dev'i kendi bilgisayarınızdan botun veritabanına da yönlendiremezsiniz: veritabanı yalnızca PlayNHost sunucularından ve phpMyAdmin'den bağlantı kabul eder.
Şemayı sonradan değiştirmek
- Bilgisayarınızda, kendi MySQL veya MariaDB'nize (örneğin Docker'daki birine) karşı
npx prisma migrate dev --name ve değişikliğe bir ad vererek çalıştırın: terminalinizde DATABASE_URL'yi o veritabanına ayarlayın, çünkü prisma7.config.ts onu ortamdan okur. prisma/migrations içine yeni bir klasör yazar.
- Yeni migration klasörünü ve değişen
schema.prisma'yı yükleyin.
- Sunucu
npm install'ı ve onunla birlikte postinstall'ınızı yalnızca package.json, package-lock.json veya Node.js sürümü değiştiğinde, node_modules eksik olduğunda ya da son kurulumdan bir günden fazla sonraki ilk başlatmada çalıştırır. Migration'ı hemen uygulamak için package.json'ı değiştirin (örneğin version alanını) veya node_modules klasörünü Dosyalar içinden silin, sonra yeniden başlatın.
Bellek: ağır kısım kurulumdur
Bu projeyi sıfırdan, en küçük bot planımız gibi 512 MB ile sınırlanmış bir konteynerde kurduk. prisma generate ve prisma migrate deploy dahil kurulum 41 saniye sürdü ve bir çalıştırmada 386 MB bellek (dosya önbelleği sayılmadan), ikincisinde 417 MB tepe değere ulaştı; ikisinde de bellek yetersizliğinden kaynaklanan bir sonlandırma olmadı. 100 MB'tan az boşlukla 512 MB'lık plana sığar, bu yüzden daha büyük bir proje veya daha fazla paket sınırı aşabilir. Aynı kurulum Prisma olmadan (yalnızca discord.js ve mysql2) 147 MB'a çıktı.
Sınırlar ve hatalar
- Veritabanı kullanıcısı başına aynı anda 20 bağlantı, aynı girişi kullanan tüm süreçler toplamında.
connectionLimit değerini düşük tutun; bir bot için 5 fazlasıyla yeter.
- 120 saniyeden uzun süren bir sorgu durdurulur, 1969 hata koduyla:
Query execution was interrupted (max_statement_time exceeded).
- Veritabanı başına 500 MB: 500 MB'a ulaşınca, siz satır silene kadar yazma işlemleri durdurulur. Sunucu yedekleri veritabanını içermez. Arada bir phpMyAdmin'den dışa aktarın.
- Bağlantı sorunlarının nedenleri mysql2'dekilerle aynıdır (yanlış parola, yanlış ana makine veya port, Ortam içinde eksik bir değişken, kendi bilgisayarınızdan bağlanma), ama mesajlar farklıdır: MariaDB adaptörü mysql2'yi değil
mariadb sürücüsünü kullanır ve onun mesajlarını kaydetmedik. Nedenler discord.js botuyla MySQL veritabanı nasıl kullanılır yazısında listelenmiştir.
Bunun yerine mysql2 veya aiomysql ile düz SQL mi istiyorsunuz? discord.js (mysql2), discord.py (aiomysql). Genel bakış: Discord botunuzla veritabanı nasıl kullanılır. Veritabanı dahil bir bot sunucusu mu lazım? Bot planlarına bakın.