-
Notifications
You must be signed in to change notification settings - Fork 1k
Fix problem when model maps integer id to a GoType #2657
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
Conversation
giautm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR look good to merge.
| if strings.HasPrefix(t.Name(), "TestPostgres/") { | ||
| require.Equal(t, sid.ID("2"), iSIDChildren[0].ID) | ||
| require.Equal(t, sid.ID("3"), iSIDChildren[1].ID) | ||
| } else { | ||
| require.Equal(t, sid.ID("101"), iSIDChildren[0].ID) | ||
| require.Equal(t, sid.ID("102"), iSIDChildren[1].ID) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate on why we have this TestPostgres check? Why it's different than the rest?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, the purpose of these tests is to check return values from ent whether they are set returned values from DB.
The reasons why the code of each RDB is different as follows.
Mysql and sqlite assign value greater than maximum value of the column when auto increment.
https://dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html
"When you insert any other value into an AUTO_INCREMENT column, the column is set to that value and the sequence is reset so that the next automatically generated value follows sequentially from the largest column value. "
https://www.sqlite.org/autoinc.html
"The ROWID chosen for the new row is at least one larger than the largest ROWID"
Auto-increment of Postgres is provided as a type named Serial. ( of course, you know. ) And it behaves as a function nextval('tablename_colname_seq') internally.
https://www.postgresql.org/docs/13/datatype-numeric.html#DATATYPE-SERIAL
https://www.postgresql.org/docs/13/functions-sequence.html
Ent creates a table by SQL below when test of IntSID run.
CREATE TABLE "int_si_ds" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"int_sid_parent" bigint NULL, PRIMARY KEY ("id"),
CONSTRAINT "int_si_ds_int_si_ds_parent" FOREIGN KEY ("int_sid_parent") REFERENCES "int_si_ds" ("id") ON DELETE SET NULL
)https://www.geeksforgeeks.org/postgresql-identity-column/#:~:text=The%20GENERATED%20ALWAYS%20instructs%20PostgreSQL,value%20for%20the%20identity%20column.
"The GENERATED AS IDENTITY constraint is the SQL standard-conforming variant of the PostgreSQL’s SERIAL column."
Unfortunately, Serial will not associate with column value user inserted.
Therefore, SaveX() will not return "101" or "102" as ID after insertion of sid.ID("100") on Postgres.
Even worse, Postgres will occer an error if insert ID "2" instead of "100". Because it will conflict between sequence and exsisting value.
panic: ent: constraint failed: insert nodes to table "int_si_ds": pq: duplicate key value violates unique constraint "int_si_ds_pkey"
Therefore, I cannot unify the test Postgres and the others.
↓↓↓ edited ↓↓↓
A way to unify these tests, I will move "children id test" to before "ID assignment test".
However, it will spoil bit of robustness in test. It means that it lacks some states of the test are after user assignment id.
Additionally, this code has attention calling for developers about difference of each RDBs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I unified the tests by rearranging the tests.
Because, fundamental purpose is just checking children IDs. This if-statement is noisy.
94163af
| iSID := client.IntSID.Create().SaveX(ctx) | ||
| require.Equal(t, sid.ID("1"), iSID.ID) | ||
| iSIDChildID := sid.ID("100") | ||
| iSIDChild := client.IntSID.Create().SetID(iSIDChildID).SetParent(iSID).SaveX(ctx) | ||
| require.Equal(t, iSIDChildID, iSIDChild.ID) | ||
| require.Equal(t, iSID.ID, iSIDChild.QueryParent().OnlyX(ctx).ID) | ||
| iSIDBulk := make([]*ent.IntSIDCreate, 2) | ||
| iSIDBulk[0] = client.IntSID.Create().SetParent(iSID) | ||
| iSIDBulk[1] = client.IntSID.Create().SetParent(iSID) | ||
| iSIDChildren := client.IntSID.CreateBulk(iSIDBulk...).SaveX(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| iSID := client.IntSID.Create().SaveX(ctx) | |
| require.Equal(t, sid.ID("1"), iSID.ID) | |
| iSIDChildID := sid.ID("100") | |
| iSIDChild := client.IntSID.Create().SetID(iSIDChildID).SetParent(iSID).SaveX(ctx) | |
| require.Equal(t, iSIDChildID, iSIDChild.ID) | |
| require.Equal(t, iSID.ID, iSIDChild.QueryParent().OnlyX(ctx).ID) | |
| iSIDBulk := make([]*ent.IntSIDCreate, 2) | |
| iSIDBulk[0] = client.IntSID.Create().SetParent(iSID) | |
| iSIDBulk[1] = client.IntSID.Create().SetParent(iSID) | |
| iSIDChildren := client.IntSID.CreateBulk(iSIDBulk...).SaveX(ctx) | |
| root := client.IntSID.Create().SaveX(ctx) | |
| require.EqualValues(t, "1", root.ID) | |
| cid := sid.ID("100") | |
| child := client.IntSID.Create().SetID(cid).SetParent(root).SaveX(ctx) | |
| require.Equal(t, cid, child.ID) | |
| require.Equal(t, rott.ID, child.QueryParent().OnlyX(ctx).ID) | |
| children := client.IntSID.CreateBulk( | |
| client.IntSID.Create().SetParent(root), | |
| client.IntSID.Create().SetParent(root) | |
| ).SaveX(ctx) |
Give these variables shorter names, please 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, but some variable names will conflict.
I'll wrap it by sub test.
in this way.
stoikheia@a6f4dbd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed a commit.
5f5b11a
thanks
|
Looks great! Last minor comments, please. |
Co-authored-by: Ariel Mashraki <[email protected]>
…to 20220608_fix_templates2
Wrapped tests of IntSID for avoid conflicts.
ebae19f to
abfb905
Compare
Order of tests was changed. As a result, if-statement for difference in RDB is deleted. + force pushing same commit to invoke ci.
abfb905 to
3085e25
Compare
a8m
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
Amazing @stoikheia! Thanks for working on it and I'll love to see you on our Discord server.
Two errors occurred when I use integer PK in a DB and associate GoType in a model.
sidhas been decrared in/ent/entc/integration/customid/sid/sid.go.Errors
1.
intsid_create.go : (*IntSidCreateBulk) Save()2.
intsid.go : (*IntSid) assignValues()Fix
1.
I took a way is similar to sqlSave() in *_create.go below to fix this problem.
ent/entc/gen/template/dialect/sql/create.tmpl
Line 23 in 7017cbc
ent/entc/gen/template/dialect/sql/create.tmpl
Lines 33 to 35 in 7017cbc
Because, Code generator will check GoType implements ValueScanner.
ent/schema/field/field.go
Lines 1177 to 1182 in 7017cbc
2.
I fixed it so that it is assigned as the value of the column type of model when it is GoType.
It has the same behavior as String, Bytes, UUID and Other.
And I aggregated check condition IsUUID() and IsOther() into HasGoType().
Because it indicates true when HasGoType() is called if the column is set field.Other and field.UUID.