Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arbitrary struct field name for belongs_to relation leads to error with eager creation. #469

Closed
aeneasr opened this issue Nov 25, 2019 · 1 comment

Comments

@aeneasr
Copy link
Member

aeneasr commented Nov 25, 2019

Description

When using a has_many relation, it seems to be impossible to set the child's struct field name of the foreign key, instead <name>ID is apparently required.

Steps to Reproduce the Problem

type Request struct {
	ID            uuid.UUID `json:"id" db:"id" rw:"r"`
	CreatedAt     time.Time `json:"created_at" db:"created_at"`
	UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
	Methods    Methods               `json:"-" has_many:"methods"`
}

type Method struct {
	ID        uuid.UUID `json:"id" db:"id" rw:"r"`

	CreatedAt time.Time `json:"created_at" db:"created_at"`
	UpdatedAtF time.Time `json:"updated_at" db:"updated_at"`

	
	RequestFoo  uuid.UUID  `json:"-" db:"request_id"`
	
	Request   *Request  `json:"request" belongs_to:"request" fk_id:"RequestFoo"`

	// Doesn't work either:
	// Request   *Request  `json:"request" belongs_to:"request" fk_id:"request_id"`
}

func TestRequest(t *testing.T) {
	req := models.Request{
		Methods: []models.Method{{}},
	}
	_, err = tx.Eager().ValidateAndSave(&req)
	require.NoError(t, err)
}

With fizz

create_table("requests") {
	t.Column("id", "uuid", {primary: true})
	t.Timestamps()
}

create_table("methods") {
	t.Column("id", "uuid", {primary: true})
	t.Timestamps()
	t.Column("request_id", "uuid")
       t.ForeignKey("request_id", {"requests": ["id"]}, {"on_delete": "cascade"})
}

Will always result in: could not set '3aecf318-0fb6-43b3-b3fe-a0de91042f65' in '<invalid reflect.Value>' (or some other uuid value).

Only changing RequestFoo to RequestID resolves the issue:

Expected Behavior

I would expect the struct field name to be customizable. I would also expect this to work if RequestID was missing from the struct:

type Method struct {
	ID        uuid.UUID `json:"id" db:"id" rw:"r"`

	CreatedAt time.Time `json:"created_at" db:"created_at"`
	UpdatedAt time.Time `json:"updated_at" db:"updated_at"`

	Request   *Request  `json:"request" belongs_to:"request" fk_id:"request_id"`
}

I would also expect the behavior to reflect other struct fields with db tags. This works with eager fetching, but not eager creation.

Actual Behavior

It seems like this is some fixed behavior. This is also not explained in the docs.

Info

Using pop latest master without buffalo.

aeneasr added a commit to ory/kratos that referenced this issue Dec 1, 2019
This is a major refactoring of the internal DBAL. After a successful proof of concept and evaluation of gobuffalo/pop, we believe this to be the best DBAL for Go at the moment. It abstracts a lot of boilerplate code away.

As with all sophisticated DBALs, pop too has its quirks. There are several issues that have been discovered during testing and adoption: gobuffalo/pop#136 gobuffalo/pop#476 gobuffalo/pop#473 gobuffalo/pop#469 gobuffalo/pop#466

However, the upside of moving much of the hard database/sql plumbing into another library cleans up the code base significantly and reduces complexity.

As part of this change, the "ephermal" DBAL ("in memory") will be removed and sqlite will be used instead. This further reduces complexity of the code base and code-duplication.

To support sqlite, CGO is required, which means that we need to run tests with `go test -tags sqlite` on a machine that has g++ installed. This also means that we need a Docker Image with `alpine` as opposed to pure `scratch`. While this is certainly a downside, the upside of less maintenance and "free" support for SQLite, PostgreSQL, MySQL, and CockroachDB simply outweighs any downsides that come with CGO.
aeneasr added a commit to ory/kratos that referenced this issue Dec 1, 2019
This is a major refactoring of the internal DBAL. After a successful proof of concept and evaluation of gobuffalo/pop, we believe this to be the best DBAL for Go at the moment. It abstracts a lot of boilerplate code away.

As with all sophisticated DBALs, pop too has its quirks. There are several issues that have been discovered during testing and adoption: gobuffalo/pop#136 gobuffalo/pop#476 gobuffalo/pop#473 gobuffalo/pop#469 gobuffalo/pop#466

However, the upside of moving much of the hard database/sql plumbing into another library cleans up the code base significantly and reduces complexity.

As part of this change, the "ephermal" DBAL ("in memory") will be removed and sqlite will be used instead. This further reduces complexity of the code base and code-duplication.

To support sqlite, CGO is required, which means that we need to run tests with `go test -tags sqlite` on a machine that has g++ installed. This also means that we need a Docker Image with `alpine` as opposed to pure `scratch`. While this is certainly a downside, the upside of less maintenance and "free" support for SQLite, PostgreSQL, MySQL, and CockroachDB simply outweighs any downsides that come with CGO.
@stanislas-m
Copy link
Member

Fixed with #546.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants