Открытый урок MSA Postgres
- Поднимаем контейнер с PostgreSQL (см. docker-compose.yaml)
docker compose up -d - Устанавливаем goose:
go install github.com/pressly/goose/v3/cmd/goose@latest
goose -version- Создаем миграцию создания таблицы пользователей:
goose create create_table_users sql -dir=./migrations-- +goose Up
-- +goose StatementBegin
CREATE TABLE IF NOT EXISTS users (
id UUID NOT NULL DEFAULT gen_random_uuid(), -- Уникальный идентификатор ползователя
email TEXT NOT NULL CHECK (email = lower(email)), -- email ползователя
username TEXT NOT NULL, -- username ползователя
full_name TEXT, -- Полное имя ползователя
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), -- Когда создан
last_login TIMESTAMP WITH TIME ZONE, -- Последний вход
is_active BOOLEAN NOT NULL DEFAULT true, -- Активный пользователь
PRIMARY KEY(id),
UNIQUE(email)
);
COMMENT ON TABLE users IS 'Таблица пользователей';
COMMENT ON COLUMN users.id IS 'Уникальный идентификатор ползователя';
COMMENT ON COLUMN users.email IS 'email ползователя';
COMMENT ON COLUMN users.username IS 'username ползователя';
COMMENT ON COLUMN users.full_name IS 'Полное имя ползователя';
COMMENT ON COLUMN users.created_at IS 'Когда создан';
COMMENT ON COLUMN users.last_login IS 'Последний вход';
COMMENT ON COLUMN users.is_active IS 'Активный пользователь';
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS users;
-- +goose StatementEndgoose create create_indexes_table_users sql -dir=./migrations-- +goose Up
-- +goose NO TRANSACTION
-- CREATE INDEX CONCURRENTLY cannot run inside a transaction block (SQLSTATE 25001)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_username
ON users (username);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_full_name_gin
ON users USING gin (to_tsvector('simple', full_name));
-- +goose Down
-- +goose StatementBegin
DROP INDEX IF EXISTS idx_users_username, idx_users_full_name_gin;
-- +goose StatementEnd- Проверяем статус миграций
goose postgres "user=${POSTGRES_USER} password=${POSTGRES_PASSWORD} dbname=${POSTGRES_DB} host=127.0.0.1 port=5432 sslmode=disable" status -dir ./migrations2025/08/17 14:26:22 Applied At Migration
2025/08/17 14:26:22 =======================================
2025/08/17 14:26:22 Pending -- 20250817104252_create_table_users.sql
2025/08/17 14:26:22 Pending -- 20250817104936_create_indexes_table_users.sql
- Накатываем миграции
goose postgres "user=${POSTGRES_USER} password=${POSTGRES_PASSWORD} dbname=${POSTGRES_DB} host=127.0.0.1 port=5432 sslmode=disable" up -dir ./migrations2025/08/17 14:29:14 OK 20250817104252_create_table_users.sql (10.5ms)
2025/08/17 14:29:14 OK 20250817104936_create_indexes_table_users.sql (11.68ms)
2025/08/17 14:29:14 goose: successfully migrated database to version: 20250817104936
- Повторно проверяем статус миграций
goose postgres "user=${POSTGRES_USER} password=${POSTGRES_PASSWORD} dbname=${POSTGRES_DB} host=127.0.0.1 port=5432 sslmode=disable" status -dir ./migrations2025/08/17 14:32:51 Applied At Migration
2025/08/17 14:32:51 =======================================
2025/08/17 14:32:51 Sun Aug 17 11:29:14 2025 -- 20250817104252_create_table_users.sql
2025/08/17 14:32:51 Sun Aug 17 11:29:14 2025 -- 20250817104936_create_indexes_table_users.sql
- Устанавливаем
bobgen-psql
go get -tool github.com/stephenafamo/bob/gen/bobgen-psql@latest - Создадим файл bobgen.yaml:
# Подробнее: https://bob.stephenafamo.com/docs/code-generation/psql#driver-configuration
psql:
dsn: "postgres://example_user:example_password@127.0.0.1:5432/example?sslmode=disable"
driver: "github.com/jackc/pgx/v5/stdlib"
schemas:
- "public"
uuid_pkg: "google"
except:
goose_db_version: []
# Подробнее: https://bob.stephenafamo.com/docs/code-generation/configuration#plugins-configuration
plugins:
dbinfo: # Генерирует код для получения информации о каждой базе данных: схемах, таблицах, столбцах, индексах, первичных ключах, внешних ключах, уникальных ограничениях и проверочных ограничениях.
disabled: false
pkgname: "dbinfo"
destination: "internal/gen/bob/dbinfo"
enums: # Генерирует код для перечислений в отдельном пакете, если таковые имеются.
disabled: false
pkgname: "enums"
destination: "internal/gen/bob/enums"
models: # Генерирует код для моделей. Зависит от перечислений.
disabled: false
pkgname: "schema"
destination: "internal/gen/bob/schema"
factory: # Генерирует код для фабрик. Зависит от моделей.
disabled: false
pkgname: "factory"
destination: "internal/gen/bob/factory"
dberrors: # Генерирует код для ошибок уникальных ограничений. Зависит от моделей.
disabled: false
pkgname: "dberrors"
destination: "internal/gen/bob/dberrors"
where: # Добавляет шаблоны в пакет моделей для генерации кода для предложений WHERE, например
disabled: false
loaders: # Добавляет шаблоны в пакет моделей для генерации кода для загрузчиков, например models.SelectThenLoad.Table.Rel()
disabled: false
joins:
disabled: false- Запустим утиллиту bobgen-psql
go tool github.com/stephenafamo/bob/gen/bobgen-psql -c ./config/bobgen.yaml- в пакете
internal/gen/bobпоявятся сгенерированные файлы
- Создадим файл queries.sql:
-- FindUserByEmail
SELECT * FROM users WHERE email = $1;- В bobgen.yaml укажем путь до файла с запросами:
psql:
# ...
queries:
- ./internal/repository/users/bob/sql- Запустим утиллиту bobgen-psql
go tool github.com/stephenafamo/bob/gen/bobgen-psql -c ./config/bobgen.yaml- В директории
/internal/repository/users/bob/sqlпоявятся сгенерированные файлы