Escrevendo o primeiro schema do banco
Se abrir o arquivo prisma/schema.prisma
você vai ver que ele tem algumas coisas já ali, vamos fazer algumas alterações pontuais, mas não se preocupe, vou explicar o que cada coisa faz.
Vamos remover a parte de post que vem por padrão e vamos alterar os Ids para serem do tipo Int
e não String
como vem por padrão.
Vai ficar assim
Voce pode remover a tabela Post não vamos precisar dela
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
// Necessary for Next auth
model Account {
id Int @id @default(autoincrement())
userId Int
type String
provider String
providerAccountId String
refresh_token String? // @db.Text
access_token String? // @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? // @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id Int @id @default(autoincrement())
sessionToken String @unique
userId Int
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model User {
id Int @id @default(autoincrement())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
Porque estamos mudando o tipo do Id?
No geral não faz muita diferença se você usa Int ou String, mas caso você queira usar funções do banco como Count, Sum, Avg, etc usar o Int vai dar menos trabalho pro banco, aqui estamos usando o SQlite que é um banco bem simples, mas se você estiver usando um banco mais robusto como o Postgres, usar o Int vai ser mais performático.
Adicionando tabelas do MMO
Primeiro vamos criar a tabela de Classes, ela vai ser responsavel por guardar as classes que nosso jogo vai possuir.
model Class {
id int @id @default(autoincrement())
name String // Nome da classe
description String // Descrição que vamos exibir para o usuario
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Por padrão o prisma só vai atualizar nossa base de dados quando executarmos o comando db:push que fizemos antes, esse comando vai criar as tabelas que não existem e atualizar as que já existem, mas caso você ja tenha algum dado na tabela, é possivel que o prisma não consiga atualizar a tabela, para esses casos você vai ter que recriar a tabela, mas não se preocupe, vamos ver como fazer isso mais pra frente.
Por enquanto vamos continuar criando sem rodar o comando, agora vamos criar a tabela de Character que vai ser responsavel por guardar os personagens dos usuarios.
model Character {
id int @id @default(autoincrement())
name String // Nome do personagem
classId Int // Id da classe do personagem
level Int // Level do personagem
class Class @relation(fields: [classId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Agora precisamos adicionar a referencia no model de Classes para que o prisma saiba que existe uma relação entre as tabelas.
model Class {
id Int @id @default(autoincrement())
name String // Nome da classe
description String // Descrição que vamos exibir para o usuario
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
characters Character[] // <- Adcionamos essa linha
}
Todo personagem no nosso jogo pertence a um usuario, então vamos adicionar a tabela de User, sempre que for criar uma relação entre tabelas você precisa adicionar a referencia nos dois models. Ou seja se adicionarmos a referencia no model de Character, precisamos adicionar a referencia no model de User também.
model User {
id Int @id @default(autoincrement())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
characters Character[] // <- Adcionamos essa linha
}
model Character {
id Int @id @default(autoincrement())
name String // Nome do personagem
classId Int // Id da classe do personagem
userId Int // Id do usuario que criou o personagem <- Adcionamos essa linha
level Int // Level do personagem
class Class @relation(fields: [classId], references: [id])
user User @relation(fields: [userId], references: [id]) // <- Adcionamos essa linha
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
O ideal seria a gente limitar o tamanho dos dados do tipo String
, por default ele vai usar o tipo text que não tem um limite de tamanho, mas estamos usando o SQlite
que não tem um tipo de dado que limita o tamanho do texto, então vamos usar o tipo String
mesmo.
Lembre-se de dar uma olhada na referencia do Prisma para saber quais tipos são mais adequados para cada caso. https://www.prisma.io/docs/concepts/components/prisma-schema/data-model#scalar-types
O schema final do prisma fica assim
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
// NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below
// Further reading:
// https://next-auth.js.org/adapters/prisma#create-the-prisma-schema
// https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
url = env("DATABASE_URL")
}
// Necessary for Next auth
model Account {
id Int @id @default(autoincrement())
type String
provider String
providerAccountId String
refresh_token String? // @db.Text
access_token String? // @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? // @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId Int
@@unique([provider, providerAccountId])
}
model Session {
id Int @id @default(autoincrement())
sessionToken String @unique
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId Int
}
model User {
id Int @id @default(autoincrement())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
characters Character[]
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
// MMORPG Models
model Skill {
id Int @id @default(autoincrement())
name String @unique
description String
emoji String
manaCost Int @default(1)
level Int @default(1)
DPS Int @default(0)
defense Int @default(0)
health Int @default(0)
RNG Int @default(0)
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
classId Int
characters CharSkill[]
}
model Class {
id Int @id @default(autoincrement())
name String @unique
emoji String
description String
characters Character[]
skills Skill[]
}
model CharStats {
id Int @id @default(autoincrement())
strength Int @default(1)
agility Int @default(1)
faith Int @default(1)
intelligence Int @default(1)
luck Int @default(1)
DPS Int @default(1)
defense Int @default(1)
health Int @default(50)
mana Int @default(10)
stamina Int @default(100)
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
characterId Int @unique
}
model Item {
id Int @id @default(autoincrement())
name String @unique
description String
type String
level Int @default(1)
DPS Int?
defense Int?
health Int?
RNG Int?
inventories ItemInventory[]
drops MonsterDrop[]
}
model ItemInventory {
equipped Boolean @default(false)
type String
quantity Int @default(1)
item Item @relation(fields: [itemId], references: [id], onDelete: Cascade)
itemId Int
inventory Inventory @relation(fields: [inventoryId], references: [id], onDelete: Cascade)
inventoryId Int
@@id([itemId, inventoryId])
}
model Inventory {
id Int @id @default(autoincrement())
character Character @relation(fields: [characterId], references: [id])
characterId Int @unique
items ItemInventory[]
}
model CharSkill {
level Int @default(1)
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
characterId Int
skill Skill @relation(fields: [skillId], references: [id])
skillId Int
@@id([characterId, skillId])
}
model Monster {
id Int @id @default(autoincrement())
name String @unique
level Int @default(1)
health Int @default(1)
DPS Int @default(1)
defense Int @default(1)
map Map @relation(fields: [mapId], references: [id], onDelete: Cascade)
mapId Int
drops MonsterDrop[]
quests Quest[]
}
model MonsterDrop {
quantity Int @default(1)
dropChance Int @default(100)
monster Monster @relation(fields: [monsterId], references: [id], onDelete: Cascade)
monsterId Int
item Item @relation(fields: [itemId], references: [id])
itemId Int
@@id([monsterId, itemId])
}
model Quest {
id Int @id @default(autoincrement())
name String @unique
description String
level Int @default(1)
experience Int @default(0)
image String @default("/coin.png")
map Map @relation(fields: [mapId], references: [id], onDelete: Cascade)
mapId Int
monsters Monster[]
characters CharQuest[]
}
model CharQuest {
completed Boolean @default(false)
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
characterId Int
quest Quest @relation(fields: [questId], references: [id])
questId Int
@@id([characterId, questId])
}
model Map {
id Int @id @default(autoincrement())
name String @unique
description String
level Int @default(1)
monsters Monster[]
quests Quest[]
characters Character[]
}
model ExperienceTable {
id Int @id @default(autoincrement())
level Int @unique
experience Int @default(0)
}
model CharLog {
id Int @id @default(autoincrement())
message String
createdAt DateTime @default(now())
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
characterId Int
}
model Character {
id Int @id @default(autoincrement())
name String @unique
level Int @default(1)
experience Int @default(0)
points Int @default(0)
pkPoints Int @default(0)
isDead Boolean @default(false)
map Map @relation(fields: [mapId], references: [id], onDelete: SetDefault)
mapId Int @default(1)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId Int
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
classId Int
charStats CharStats?
inventory Inventory?
skills CharSkill[]
logs CharLog[]
quests CharQuest[]
}
```
</details>
## Criando as tabelas
Agora vamos rodar o comando db:push para atualizar nosso banco de dados.
```bash
npm run db:push
Como dito anteriormente, o prisma não vai conseguir atualizar a tabela de Character porque já temos dados nela.
Como estamos em desenvolvimento vou apagar o arquivo db.sqlite e rodar o comando novamente, em bases como Postgres e Mysql o prisma consegue converter os dados automaticamente, como estamos usando o Sqlite vamos apagar o arquivo por enquanto.
Depois de apagar o arquivo vamos rodar o npm run db:push
novamente.
PS mmorpg-nextjs> npm run db:push
> mmorpg-text-menthor@0.1.0 db:push
> prisma db push
Environment variables loaded from .env
Prisma schema loaded from prisma\schema.prisma
Datasource "db": SQLite database "db.sqlite" at "file:./db.sqlite"
The database is already in sync with the Prisma schema.
✔ Generated Prisma Client (v5.8.1) to .\node_modules\@prisma\client in 95ms
Pronto ele criou pra gente o db.sqlite novamente agora podemos continuar.