? Запарило ручное сканирование в pgx? Встречайте pgxWrappy - супер-удобную обертку для PostgreSQL в Golang! ??

? Больше никакого boilerplate-кода!

// ? БЫЛО (кошмар на 10 строк):
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)
}

// ✅ СТАЛО (магия в 1 строку!):
var users []User
db.Select(ctx, &users, "SELECT id, name FROM users") // ✨ Волшебство!

✨ Главные фишки pgxWrappy

? Автомагическое сканирование во что угодно!

  • Структуры ?

  • Вложенные структуры ?➡?

  • Слайсы ?

  • Указатели ?

  • Кастомные типы ?

� Пример с вложенностью:

type Profile struct {
    Bio  string `db:"bio"`
    Pic  string `db:"avatar_url"`
}

type User struct {
    ID      int     `db:"id"`
    Name    string  `db:"name"`
    Profile Profile `db:"profile"` // ? Автораскрытие вложенности!
}

// Запрос просто должен содержать profile_bio и profile_avatar_url
db.Get(ctx, &user, "SELECT ..., bio AS profile_bio, avatar_url AS profile_avatar_url ...")

? Три причины выбрать pgxWrappy:

  1. ⏱ Экономия 30% времени на рутинном коде

  2. ? Сохраняем всю мощь pgx под капотом

  3. ? Простота миграции - подходит к существующим проектам

⚡ Быстрый старт

go get -u github.com/Arlandaren/pgxWrappy # ⬇️ Одна команда - и готово!
// ? Настройка за 5 секунд:
db := pgxwrappy.NewWrapper(pool) // ? Вот и всё!

// ? Пример CRUD:
db.Get(ctx, &user, "SELECT * FROM users WHERE id=$1", 42)       // READ
db.Exec(ctx, "UPDATE users SET name=$1 WHERE id=$2", "Bob", 42) // UPDATE

? Сравнение с аналогами

pgxWrappy

Чистый pgx

GORM

sqlx

Удобство

?

?

?

?

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

???

????

?

??

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

PostgreSQL фичи

✅✅

✅✅✅

✅✅

? Идеальный баланс между производительностью и удобством!

? Бонусы:

  • ? Потокобезопасность из коробки

  • ? Поддержка context.Context

  • ? Ясные ошибки с stack trace

  • ? Простое расширение функционала

?

? Нравится идея? Поставьте звезду на GitHub:
https://github.com/Arlandaren/pgxWrappy

? Хотите помочь? Присылайте PR и идеи!
? Нашли баг? Открывайте issue!

pgxWrappy - потому что жизнь слишком коротка для ручного сканирования! ?

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


  1. xakep666
    25.07.2025 21:00

    А в чем принципиальное отличие от связки Collect* и RowTo* (например, RowToStructByName) функций прямо из самого pgx v5?


    1. alrn Автор
      25.07.2025 21:00

      Встроенные функции pgx (RowToStructByName, CollectOneRow, CollectRows) не поддерживают автоматическое разворачивание вложенных структур.

      Ключевые отличия:
      Уровень абстракции:
      1)pgxWrappy предоставляет более высокоуровневый API
      2)Встроенные функции pgx требуют больше ручной работы

      Сканирование вложенных структур:
      1)pgxWrappy автоматически обрабатывает вложенные структуры
      2)В pgx вам нужно вручную обрабатывать каждое поле вложенной структуры

      Работа со срезами:
      1)pgxWrappy предоставляет простые методы Select для получения срезов
      2)В pgx нужно использовать CollectRows с RowToStructByName

      Поддержка транзакций:
      1)pgxWrappy предоставляет обёртки для удобной работы с транзакциями
      2)В pgx транзакции нужно обрабатывать вручную

      Сравнение:

      Для обычной структуры)

      // pgxWrappy
      err := dbWrapper.Get(ctx, &user, "SELECT id, name FROM users WHERE id=$1", userID)
      
      // pgx
      row := conn.QueryRow(ctx, "SELECT id, name FROM users WHERE id=$1", userID)
      err := pgx.RowToStructByName(row, &user)
      

      Для вложенной)

      type Address struct {
          Street string `db:"street"`
          City   string `db:"city"`
      }
      
      type User struct {
          ID      int     `db:"id"`
          Name    string  `db:"name"`
          Address Address `db:"address"` // автоматически разберёт address_street, address_city
      }
      
      var user User
      err := dbWrapper.Get(ctx, &user, "SELECT id, name, street as address_street, city as address_city FROM users WHERE id=$1", userID)
      
      //pgx
      rows, _ := conn.Query(ctx, "SELECT id, name, street, city FROM users WHERE id=$1", userID)
      user, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[User])
      
      // Что получим?
      // user.Address.Street и user.Address.City будут пустыми
      // Потому что pgx не знает, как мапить плоские поля на вложенную структуру.
      

      Даже либа pgxScan не справляется с этим также просто как PgxWrappy - вложенные структуры его главная суть.


  1. bromzh
    25.07.2025 21:00

    Запарило ручное сканирование в pgx?

    Используйте выразительные языки, а не это вот!


  1. yellow79
    25.07.2025 21:00

    То есть вместо кошмара из 10 строк(которых в примере 8) я получаю "суперудобную обёртку", которая вынуждает меня постоянно думать о структурных мета-тегах при написании запросов? Очень удобно! (сарказм)


  1. noRoman
    25.07.2025 21:00

    https://jmoiron.github.io/sqlx/
    Пользуйтесь на здоровье!


  1. DasMeister
    25.07.2025 21:00

    А тесты для кода с рефлектом вы забыли закомитить или что произошло с ними?