I thought the problem was me and my code and so I tried to reproduce the problem with sqlx example directly.
I only made minor changes by adding an Option<>
to simulate my real problem.
- async fn add_person(pool: &PgPool, person: Person) -> anyhow::Result<i64> {
+ async fn add_person(pool: &PgPool, person: Option<Person>) -> anyhow::Result<i64> {
and in migrations
:
- person JSONB NOT NULL
+ person JSONB
If I run it it is saved in the DB:
and instead I expect this:
Where am I doing wrong?
https://github.com/frederikhors/iss-sqlx-option-null
"0.7.4"
"macros", "postgres", "runtime-tokio", "chrono", "uuid"
Postgres 16
Windows
rustc --version
: rustc 1.79.0 (129f3b996 2024-06-10)
So the function (from official example with your changes) looks like this:
async fn add_person(pool: &PgPool, person: Option<Person>) -> anyhow::Result<i64> {
let rec = sqlx::query!(
r#"
INSERT INTO people ( person )
VALUES ( $1 )
RETURNING id
"#,
Json(person) as _
)
.fetch_one(pool)
.await?;
Ok(rec.id)
}
This isn't passing an Option<Json<_>>
, its passing a Json<_>
. So the person
will be used as a JSON value. If you pass None
as a person
, that is interpreted as a JSON null
value rather than an SQL NULL. You instead want to express that a None
person should not have a JSON value.
Try this:
sqlx::query!(
r#"
INSERT INTO people ( person )
VALUES ( $1 )
RETURNING id
"#,
person.map(Json) as _
)
This is now passing an Option<Json<_>>
instead.