Проблема, которую решает pgxWrappy

Как разработчик на Go, я долгое время использовал pgx - безусловно, лучший драйвер для PostgreSQL. Но каждый раз, когда нужно было сканировать результаты запроса в структуры, особенно со сложной вложенностью, приходилось писать много шаблонного кода. Это отнимало время и делало код менее читаемым.

После десятков проектов с pgx я решил создать решение, которое сохраняет все преимущества оригинального драйвера, но избавляет от рутинных операций.

Ключевые возможности pgxWrappy

1. Интуитивное сканирование результатов

Больше не нужно вручную перебирать строки и вызывать Scan():

// Вместо этого:
rows, _ := conn.Query(ctx, "SELECT id, name FROM users")
defer rows.Close()
var users []User
for rows.Next() {
    var u User
    rows.Scan(&u.ID, &u.Name)
    users = append(users, u)
}

// Делаем так:
var users []User
db.Select(ctx, &users, "SELECT id, name FROM users")

2. Поддержка сложных структур

Работа с вложенными структурами становится простой:

type Address struct {
    City   string `db:"city"`
    Street string `db:"street"`
}

type User struct {
    ID      int     `db:"id"`
    Name    string  `db:"name"`
    Address Address `db:"address"` // Автоматическое сканирование вложенной структуры
}

// Запрос должен содержать поля address_city и address_street
db.Get(ctx, &user, "SELECT id, name, city as address_city, street as address_street FROM users WHERE id=$1", 1)

3. Гибкие варианты именования полей

Поддерживаются разные стили тегов:

type User struct {
    UserID  int    `db:"user_id"`  // явное указание имени столбца
    Name    string `db:"name"`     // простое соответствие
    Email   string                // если тег отсутствует, используется имя поля в snake_case
    Address Address `db:"-"`       // игнорирование поля при сканировании
}

4. Полноценная работа с транзакциями

Упрощенное управление транзакциями:

tx, err := db.Begin(ctx)
if err != nil {
    return err
}
defer tx.Rollback(ctx)

// Работаем как с обычным wrapper'ом
err = tx.Exec(ctx, "UPDATE accounts SET balance = balance - $1 WHERE id = $2", amount, fromID)
err = tx.Exec(ctx, "UPDATE accounts SET balance = balance + $1 WHERE id = $2", amount, toID)

return tx.Commit(ctx)

Производительность

pgxWrappy добавляет минимальные накладные расходы по сравнению с чистым pgx. В тестах на сканирование 10,000 строк разница составляет менее 5%. Это плата за удобство, которое во многих случаях окупается сокращением времени разработки.

Когда стоит использовать?

pgxWrappy идеально подходит для:

  • Проектов, где важна чистота и читаемость кода

  • Приложений со сложными domain-моделями

  • Команд, которые хотят сократить boilerplate-код

  • Разработчиков, переходящих с database/sql на pgx

Установка и начало работы

go get -u github.com/Arlandaren/pgxWrappy

Пример подключения:

import (
    "context"
    "github.com/jackc/pgx/v5/pgxpool"
    "github.com/Arlandaren/pgxWrappy/pkg/postgres"
)

func main() {
    ctx := context.Background()
    pool, _ := pgxpool.New(ctx, "postgres://user:pass@localhost:5432/db")
    db := pgxwrappy.NewWrapper(pool)
    
    // Готово к работе!
}

Сообщество и вклад

Проект активно развивается. Приветствуются:

  • Отзывы и предложения

  • Bug reports

  • Pull requests

  • Примеры использования из реальных проектов

⭐ Поддержите проект звездой на GitHub: https://github.com/Arlandaren/pgxWrappy

Альтернативы и сравнение

Особенность

pgx (чистый)

pgxWrappy

database/sql

GORM

Производительность

⭐⭐⭐⭐⭐

⭐⭐⭐⭐

⭐⭐⭐

⭐⭐

Удобство работы

⭐⭐

⭐⭐⭐⭐⭐

⭐⭐

⭐⭐⭐⭐

Сложные структуры

⭐⭐⭐⭐⭐

⭐⭐⭐⭐

Контроль запросов

⭐⭐⭐⭐⭐

⭐⭐⭐⭐

⭐⭐⭐⭐

⭐⭐

PostgreSQL фичи

⭐⭐⭐⭐⭐

⭐⭐⭐⭐

⭐⭐

⭐⭐

pgxWrappy занимает идеальную нишу между чистым pgx и тяжелыми ORM, предлагая баланс производительности и удобства.

Попробуйте pgxWrappy в своем следующем проекте и ощутите разницу! Ваши звёзды и отзывы помогут сделать библиотеку лучше для всего Go-сообщества.

Комментарии (7)


  1. anaxita
    30.07.2025 22:12

    Пожалуйста, не выкладывайте пост с кодом претендующим на что то продакшен реди, без тестов.

    А так же задумайтесь, почему до сих пор нет такой обертки, которую вы изобрели. Или есть?


    1. qeeveex
      30.07.2025 22:12

      Согласен. Не стоит пренебрегать тестами. К тому же они выступают частью документации. В golang даже есть Example выполняющиеся как тесты.