bun
bun copied to clipboard
Error default NullZero
when inserting or updating, the value is equal to the default value, then it is replaced with null
tag.option "default" set NullZero = true. Because of this, we get that value null https://github.com/uptrace/bun/blob/master/schema/table.go#L380
https://github.com/uptrace/bun/blob/master/schema/field.go#L96
example
type Item struct {
bun.BaseModel `bun:"item"`
ID int `bun:"id,pk,autoincrement"`
NomenclatureGUID uuid.UUID `bun:"nomenclature_guid,type:binary(36)"`
Count int `bun:"count,type:int,notnull,default:0"`
Url string `bun:"url,type:varchar(100),notnull,default:''"`
}
item := error2.Item{
Count: 5,
Url: "www.test.ru",
}
_, err = db.NewInsert().Model(&item).Exec(context.Background())
item.Url = ""
_, err = db.NewUpdate().Model(&item).WherePK().Exec(context.Background())
waiting
UPDATE `item` SET `nomenclature_guid` = '00000000-0000-0000-0000-000000000000', `count` = 5, `url` = '' WHERE (`item`.`id` = 1)
actual
UPDATE `item` SET `nomenclature_guid` = '00000000-0000-0000-0000-000000000000', `count` = 5, `url` = NULL WHERE (`item`.`id` = 1)
item.Count = 0
_, err = db.NewUpdate().Model(&item).WherePK().Exec(context.Background())
waiting
UPDATE `item` SET `nomenclature_guid` = '00000000-0000-0000-0000-000000000000', `count` = 0, `url` = '' WHERE (`item`.`id` = 1)
actual
UPDATE `item` SET `nomenclature_guid` = '00000000-0000-0000-0000-000000000000', `count` = NULL, `url` = NULL WHERE (`item`.`id` = 1)
The problem appeared after fixing issue 512 It was enough to pass the uuid=nil to be executed uuid_generate_v4()
https://github.com/uptrace/bun/pull/515/files#diff-abecd8d935ca8952a3554e15fa6989972dd0cea6de3410b6541931883b0d6d84R377
I just noticed I had the same problem when migrating an application from go-pg/pg to bun.
Thanks @dlarin for reporting this!
To clarify the issue: it is currently impossible to update a field having a default value to the zero value (should we update the title of the issue to clarify?).
Note that this is not an issue when inserting an item, since a zero value would be translated either to DEFAULT
or to the default value set via the default
tag (see query_insert.go#L322-L330).
Elaborating on your example, the following:
item := Item{
Count: 5,
Url: "",
}
_, err = db.NewInsert().Model(&item).Exec(ctx)
would generate:
-- Using PostgreSQL, where DEFAULT placeholder is supported:
INSERT INTO "item" ("nomenclature_guid", "count", "url") VALUES (NULL, 5, DEFAULT);
-- Using a database where DEFAULT placeholder is not supported, e.q. sqlite:
INSERT INTO "item" ("nomenclature_guid", "count", "url") VALUES (NULL, 5 , '');
In both cases, the url
column is set to the empty string (either by the database itself, applying the column's default, or by the query explicitly), as expected.
Then, as @dlarin showed previously, an update to the zero value is impossible as it is translated to NULL (see query_update.go#L313 which calls schema/field.go#L96-L98), since the default
tag implies nullzero
(see schema/table.go#L378-L381):
item.Url = ""
_, err = db.NewUpdate().Model(&item).Column("url").WherePK().Exec(context.Background())
UPDATE "item" SET "url" = NULL WHERE ("item"."id" = 1)
This is unexpected and seems like a bug.
A short-term workaround would be to use Set()
or SetColumn()
(see Update API) instead, but this can be tedious to implement.
same to me.
Also having this issue. Had to remove all default values, which is obviously highly problematic. Is it specific to Postgres?