diff --git a/backend/cmd/api/main.go b/backend/cmd/api/main.go index 036c15c..a8900c8 100644 --- a/backend/cmd/api/main.go +++ b/backend/cmd/api/main.go @@ -50,6 +50,9 @@ func main() { queries, pool := db.Connect(cfg) defer pool.Close() + // Run Migrations + db.Migrate(pool) + // Initialize services profissionaisService := profissionais.NewService(queries) authService := auth.NewService(queries, profissionaisService, cfg) diff --git a/backend/internal/db/db.go b/backend/internal/db/db.go index 4ba229b..a082aee 100644 --- a/backend/internal/db/db.go +++ b/backend/internal/db/db.go @@ -1,41 +1,58 @@ package db import ( - "context" - "log" + "context" + "embed" + "log" - "photum-backend/internal/config" - "photum-backend/internal/db/generated" + "photum-backend/internal/config" + "photum-backend/internal/db/generated" - "github.com/jackc/pgx/v5/pgxpool" + "github.com/jackc/pgx/v5/pgxpool" ) +//go:embed schema.sql +var schemaFS embed.FS + func Connect(cfg *config.Config) (*generated.Queries, *pgxpool.Pool) { - log.Printf("Connecting to database with DSN: %#v", cfg.DBDsn) - poolConfig, err := pgxpool.ParseConfig(cfg.DBDsn) - if err != nil { - log.Fatalf("Unable to parse DB DSN: %v", err) - } + log.Printf("Connecting to database with DSN: %#v", cfg.DBDsn) + poolConfig, err := pgxpool.ParseConfig(cfg.DBDsn) + if err != nil { + log.Fatalf("Unable to parse DB DSN: %v", err) + } - // Diagnostic log (password presence only) - if poolConfig != nil && poolConfig.ConnConfig != nil { - hasPassword := poolConfig.ConnConfig.Password != "" - log.Printf("DB config user=%s host=%s port=%d password_set=%t", - poolConfig.ConnConfig.User, - poolConfig.ConnConfig.Host, - poolConfig.ConnConfig.Port, - hasPassword, - ) - } + // Diagnostic log (password presence only) + if poolConfig != nil && poolConfig.ConnConfig != nil { + hasPassword := poolConfig.ConnConfig.Password != "" + log.Printf("DB config user=%s host=%s port=%d password_set=%t", + poolConfig.ConnConfig.User, + poolConfig.ConnConfig.Host, + poolConfig.ConnConfig.Port, + hasPassword, + ) + } - pool, err := pgxpool.NewWithConfig(context.Background(), poolConfig) - if err != nil { - log.Fatalf("Unable to connect to database: %v", err) - } + pool, err := pgxpool.NewWithConfig(context.Background(), poolConfig) + if err != nil { + log.Fatalf("Unable to connect to database: %v", err) + } - if err := pool.Ping(context.Background()); err != nil { - log.Fatalf("Database ping failed: %v", err) - } + if err := pool.Ping(context.Background()); err != nil { + log.Fatalf("Database ping failed: %v", err) + } - return generated.New(pool), pool + return generated.New(pool), pool +} + +func Migrate(pool *pgxpool.Pool) { + log.Println("Applying database migration...") + schema, err := schemaFS.ReadFile("schema.sql") + if err != nil { + log.Fatalf("Failed to read schema file: %v", err) + } + + if _, err := pool.Exec(context.Background(), string(schema)); err != nil { + log.Fatalf("Failed to execute migration: %v", err) + } + log.Println("Database migration applied successfully.") } diff --git a/backend/internal/db/schema.sql b/backend/internal/db/schema.sql index d7f8ac1..d85144b 100644 --- a/backend/internal/db/schema.sql +++ b/backend/internal/db/schema.sql @@ -1,6 +1,6 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -CREATE TABLE usuarios ( +CREATE TABLE IF NOT EXISTS usuarios ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), email VARCHAR(255) UNIQUE NOT NULL, senha_hash VARCHAR(255) NOT NULL, @@ -10,7 +10,7 @@ CREATE TABLE usuarios ( atualizado_em TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -CREATE TABLE funcoes_profissionais ( +CREATE TABLE IF NOT EXISTS funcoes_profissionais ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), nome VARCHAR(50) UNIQUE NOT NULL, criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW(), @@ -22,9 +22,10 @@ INSERT INTO funcoes_profissionais (nome) VALUES ('Cinegrafista'), ('Recepcionista'), ('Fixo Photum'), -('Controle'); +('Controle') +ON CONFLICT (nome) DO NOTHING; -CREATE TABLE cadastro_profissionais ( +CREATE TABLE IF NOT EXISTS cadastro_profissionais ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), usuario_id UUID REFERENCES usuarios(id) ON DELETE SET NULL, nome VARCHAR(255) NOT NULL, @@ -54,7 +55,7 @@ CREATE TABLE cadastro_profissionais ( atualizado_em TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -CREATE TABLE refresh_tokens ( +CREATE TABLE IF NOT EXISTS refresh_tokens ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), usuario_id UUID NOT NULL REFERENCES usuarios(id) ON DELETE CASCADE, token_hash VARCHAR(255) NOT NULL, @@ -66,7 +67,7 @@ CREATE TABLE refresh_tokens ( ); -- Cursos Table -CREATE TABLE cursos ( +CREATE TABLE IF NOT EXISTS cursos ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), nome VARCHAR(100) UNIQUE NOT NULL, criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW() @@ -79,10 +80,11 @@ INSERT INTO cursos (nome) VALUES ('Farmácia'), ('Fisioterapia'), ('Gastronomia'), ('Historia'), ('Jornalismo'), ('Med. Veterinária'), ('Medicina'), ('Nutrição'), ('Odontologia'), ('Outro'), ('Pedagogia'), ('Publicidade'), ('Superior Diversos'), ('Tec. Diversos'), ('Termomecânica'), ('Unificados'), ('Tec. Enfermagem'), ('Quimica'), ('EFI / EF II / EM'), ('Psicologia'), -('Terapia Ocupacinal'), ('R.I'); +('Terapia Ocupacinal'), ('R.I') +ON CONFLICT (nome) DO NOTHING; -- Empresas Table -CREATE TABLE empresas ( +CREATE TABLE IF NOT EXISTS empresas ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), nome VARCHAR(100) UNIQUE NOT NULL, criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW() @@ -92,10 +94,11 @@ INSERT INTO empresas (nome) VALUES ('Arte Formaturas'), ('JR Formaturas'), ('Perfil'), ('Photum'), ('Populi Formaturas'), ('Prime'), ('Smart'), ('Viva SP'), ('Antares'), ('Forcamp'), ('PNI'), ('Fábio Ribeiro'), ('Told - B2_(CAMPINAS)'), ('Told - B2_(RECIFE)'), ('NOVO - Told - B2_(SP)'), ('NOVO - Told - RUB_(SP)'), ('NOVO - TOLD'), ('Alpha Digital'), ('Golden'), ('Festa da Beca'), -('Ponta Eventos'), ('Toy SP'), ('MVP Formaturas'), ('RUB'); +('Ponta Eventos'), ('Toy SP'), ('MVP Formaturas'), ('RUB') +ON CONFLICT (nome) DO NOTHING; -- Anos Formaturas Table -CREATE TABLE anos_formaturas ( +CREATE TABLE IF NOT EXISTS anos_formaturas ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), ano_semestre VARCHAR(20) UNIQUE NOT NULL, -- Ex: 2019.2 criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW() @@ -104,10 +107,11 @@ CREATE TABLE anos_formaturas ( INSERT INTO anos_formaturas (ano_semestre) VALUES ('2019.2'), ('2020.1'), ('2020.2'), ('2021.1'), ('2021.2'), ('2022.1'), ('2022.2'), ('2023.1'), ('2023.2'), ('2024.1'), ('2024.2'), ('2025.1'), ('2025.2'), ('2026.1'), ('2026.2'), ('2027.1'), ('2027.2'), ('2028.1'), -('2028.2'), ('2029.1'), ('2029.2'); +('2028.2'), ('2029.1'), ('2029.2') +ON CONFLICT (ano_semestre) DO NOTHING; -- Tipos Servicos Table -CREATE TABLE tipos_servicos ( +CREATE TABLE IF NOT EXISTS tipos_servicos ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), nome VARCHAR(50) UNIQUE NOT NULL, criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW() @@ -115,10 +119,11 @@ CREATE TABLE tipos_servicos ( INSERT INTO tipos_servicos (nome) VALUES ('Fotógrafo'), ('Recepcionista'), ('Cinegrafista'), ('Coordenação'), ('Ponto de Foto'), ('Ponto de ID'), ('Estúdio'), -('Outro'), ('Controle'); +('Outro'), ('Controle') +ON CONFLICT (nome) DO NOTHING; -- Tipos Eventos Table -CREATE TABLE tipos_eventos ( +CREATE TABLE IF NOT EXISTS tipos_eventos ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), nome VARCHAR(100) UNIQUE NOT NULL, criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW() @@ -127,10 +132,11 @@ CREATE TABLE tipos_eventos ( INSERT INTO tipos_eventos (nome) VALUES ('Identificação'), ('Baile'), ('Colação'), ('Col/Baile (mesmo local)'), ('Col/Baile (local diferente)'), ('Missa / Culto'), ('Churrasco'), ('Trote'), ('Outro'), ('Balada'), ('Jantar'), ('Festa Junina'), ('Colação Oficial'), ('Family Day'), -('Refeição'), ('Estudio ID e Family Day'), ('Estudio Colação / Baile'); +('Refeição'), ('Estudio ID e Family Day'), ('Estudio Colação / Baile') +ON CONFLICT (nome) DO NOTHING; -- Precos Tipos Eventos Table (Junction Table for Pricing) -CREATE TABLE precos_tipos_eventos ( +CREATE TABLE IF NOT EXISTS precos_tipos_eventos ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), tipo_evento_id UUID REFERENCES tipos_eventos(id) ON DELETE CASCADE, funcao_profissional_id UUID REFERENCES funcoes_profissionais(id) ON DELETE CASCADE,