Я использую драйвер jackc/pgx вместе с библиотекой GORM для взаимодействия с базой данных PostgreSQL.
У меня есть случай, когда мне нужно проверить код ошибки PostgreSQL и по-разному обработать определенный тип ошибки. При использовании драйвера pgx
методы GORM возвращают тип *pgconn.PgError
в качестве error
, который содержит поле с конкретным кодом ошибки.
Чтобы получить доступ к этому полю, я должен привести error
к *pgconn.PgError
, но по какой-то причине это не удается:
res := tx.Take(&f, "id = ?", id)
if res.Error != nil {
if pqErr, ok := res.Error.(*pgconn.PgError); ok {
// does not reach here
} else {
fmt.Printf("Error type: %T\n", res.Error)
// Output: "Error type: *pgconn.PgError"
}
}
Примечания:
pgx
и pgconn
находятся внутри одного и того же проекта, поэтому дело не в том, что они возвращают разные версии типа с одним и тем же именем. Другими словами, у меня есть только один импорт в моем go.mod.*pgconn.PgError
.🤔 А знаете ли вы, что...
Go имеет средства для создания и использования модулей (modules) для управления зависимостями.
Как правильно указал @HymnsForDisco в комментариях, существуют и github.com/jackc/pgconn
, и github.com/jackc/pgx/pgconn
. Оказывается, возвращенная ошибка была из первого, тогда как я импортировал последний в свой код.
Для подтверждения я добавил следующую строку:
fmt.Println("Error path: ", reflect.TypeOf(res.Error).Elem().PkgPath())
// Output: "Error path: github.com/jackc/pgconn"
Изменение моего импорта на «github.com/jackc/pgconn» решило проблему.
Вы решили свою собственную проблему, но вот, возможно, полезная информация и то, как я нашел источник.
Пакеты с одинаковыми именами могут существовать в одной и той же программе, если у них разные пути импорта. Например, в стандартной библиотеке есть как math/rand
, так и crypto/rand
, каждая из которых называется rand
. Это первый намек на то, что *pgconn.PgError
и *pgconn.PgError
не одно и то же: они происходят из разных путей импорта.
Когда модули в Go вносят серьезные изменения , они должны изменить свой путь импорта. Это необходимо для сохранения обратной совместимости в отношении путей импорта. Обратите внимание, что обычно это делается путем обновления объявления module
в файле go.mod
, а не путем фактического перемещения кода в подкаталог. Например, посмотрите этот коммит, где pgx
был перемещен с v4
на v5
. Это вторая подсказка: код из проекта pgx
доступен по нескольким путям импорта (из-за нескольких основных версий).
Имея это в виду, я использовал теги git для просмотра репозитория в последней версии v4.x.x
. Я заметил, что, как ни странно, пакета pgconn
не существовало в v4
. Это, казалось, исключало идею конфликта github.com/jackc/pgx/v4/pgconn
vs github.com/jackc/pgx/v5/pgconn
. Затем я поискал в Google «pgconn» и нашел репозиторий github.com/jackc/pgconn
, где я увидел в README:
Эта версия используется с pgx v4. В pgx v5 он является частью репозитория https://github.com/jackc/pgx.
Судя по другой информации, которую вы предоставили, ваша ошибка могла заключаться в использовании пути импорта "github.com/jackc/pgx/pgconn"
. Как показано в примере кода для pgx
, текущий путь импорта, который вы должны использовать для базового модуля, — "github.com/jackc/pgx/v5"
, и пакеты внутри него будут указываться аналогичным образом, например, "github.com/jackc/pgx/v5/pgconn"
.