bun
bun copied to clipboard
Update operation sets boolean fields to NULL instead of false, violating non-null constraint
Hello,
I'm currently using bun in a project and I've encountered an issue with boolean fields defaulting to NULL instead of false during updates.
Here's the bun model struct I'm using:
type Entity struct {
ID int `bun:"id,autoincrement"`
IsActive bool `bun:"is_active,notnull,default:true"` // corresponds to is_active BOOLEAN NOT NULL DEFAULT TRUE in the schema
}
And here's the function I'm using to update the Entity:
func (r *EntityRepository) UpdateEntity(ctx context.Context, id int, isActive bool) (*Entity, error) {
// ...
entity := &Entity{
ID: id,
IsActive: isActive,
}
_, err := r.DB.NewUpdate().Model(entity).Column("is_active").WherePK().Exec(ctx)
// ...
}
In my test case, when I'm setting IsActive
to false
explicitly and try to update the record, I get an error: null value in column "is_active" violates not-null constraint error, which indicates that the is_active column is being set to NULL.
I've checked/debugged my code and can confirm that IsActive
is being set to false and not NULL.
This issue seems to occur only during updates when the boolean value is explicitly set to false
.
Thank you.
tl;dr: Try using .Value()
method to control which value gets appended to the query.
The following should work:
db.NewUpdate().
Model(entity).
Column("is_active").
Value("is_active", "false"). // will substitute to is_active = false
WherePK().
Exec(ctx)
This is a workaround, because the behaviour you've described looks buggy. For more about that, read on.
This happens because any field that has a bun:"default:x"
tag also gets a "nullzero"
tag.:
https://github.com/uptrace/bun/blob/8a4383505d7e954897b23811a412b9cdafaf41eb/schema/table.go#L378-L381
Why? Because for INSERT
queries bun
needs to be able to correctly decide to append DEFAULT
placeholder for a field that has a zero value:
https://github.com/uptrace/bun/blob/8a4383505d7e954897b23811a412b9cdafaf41eb/query_insert.go#L335-L338
That's helpful, even though not all dialects support this feature (looking at you, SQLite).
But then, once we try to set a field that has a default value to false
(zero boolean value) in UpdateQuery
we get the bug you've described. It happens here:
https://github.com/uptrace/bun/blob/8a4383505d7e954897b23811a412b9cdafaf41eb/schema/field.go#L97-L99
I think ~~adding a HasDefault bool
field to schema.Field
and using it~~ checking for SQLDefault != ""
in the InsertQuery
instead would be a good long-term solution.