pgx icon indicating copy to clipboard operation
pgx copied to clipboard

RowToStructByName does not scan into embedded structures

Open SemenKuzmichevWork opened this issue 1 year ago • 9 comments

Describe the bug I get "struct doesn't have corresponding row field id" error when I try to do RowToStructByName because I have another field in nested structure with db:"id" tag To Reproduce

type Subscription struct {
	ID          int       `db:"id"`
	TariffAlias string    `db:"tariff_alias"`
	Tariff
}

type Tariff struct {
	ID          int        `db:"id"`
	Alias       string     `db:"alias"`
}

pgx.CollectOneRow(rows, pgx.RowToStructByName[Subscription])
select * from subscription as s join tariff t on t.alias = s.tariff_alias;

Expected behavior I get the completed structure Subscription Actual behavior struct doesn't have corresponding row field id

Version

  • Go: go version go1.21 darwin/amd64
  • pgx: github.com/jackc/pgx/v5.3.1

Additional context The problem can be corrected by adding zeroing of the field name in the fieldPosByName function, as a mark that it has already found a match in the structure fldDescs[i].Name = ""

SemenKuzmichevWork avatar Aug 18 '23 13:08 SemenKuzmichevWork

Perhaps we should have a better error message, but I don't think that your example should work. The *StructByName* helpers are supposed to work independently of column order. There is no way to safely scan multiple columns with the same name.

The problem can be corrected by adding zeroing of the field name in the fieldPosByName function, as a mark that it has already found a match in the structure fldDescs[i].Name = ""

That might happen to work for your particular example query:

select * from subscription as s join tariff t on t.alias = s.tariff_alias;

But it could silently fail with data corruption if the column order was changed.

select * from tariff t join subscription as s on t.alias = s.tariff_alias;

jackc avatar Aug 19 '23 21:08 jackc

Tell me, are there any changes on this topic? Is it possible to assemble this structure with one database query?

type Role struct {
	ID   int64   `db:"role_id"`
	Name string  `db:"role_name"`
}

type Permission struct {
	ID     int64   `db:"permission_id"`
	Name   string  `db:"permission_name"`
}

type User struct {
	ID       int64  `db:"user_id"`
	Email    string
	Password string
	Role
	Permissions []Permission
}

Now, using pgx.CollectOneRow(rows, pgx.RowToStructByName[User]), I can join the user with the role, but not the permissions. I think this is because permissions is a slice.

Error: There is no corresponding permission_id string field in the structure.

eliofery avatar Apr 02 '24 20:04 eliofery

+1

ivanpetrovs avatar Sep 27 '24 13:09 ivanpetrovs

+1

filipencopav avatar Oct 03 '24 14:10 filipencopav

Now, using pgx.CollectOneRow(rows, pgx.RowToStructByName[User]), I can join the user with the role

Is that so? I have an embedded struct into which I scan, and it doesn't see any embedded fields.

filipencopav avatar Oct 04 '24 08:10 filipencopav