datanucleus / datanucleus-rdbms

DataNucleus support for persistence to RDBMS Datastores
30 stars 66 forks source link

Add support for persisting PostgreSQL `JSON` and `JSONB` fields #494

Closed nscuro closed 4 months ago

nscuro commented 4 months ago

Feature Request

PostgreSQL has dedicated types for JSON: JSON and JSONB.

To clients, both behave pretty much like TEXT.

At the moment, DataNucleus can correctly fetch JSON and JSONB values as String, but it cannot persist them. I published test cases here: https://github.com/nscuro/datanucleus-test-jdo/blob/postgres-json-jsonb/src/test/java/org/datanucleus/test/SimpleTest.java

To summarize the tests: Trying to persist an object with JSON or JSONB columns currently yields the following exception:

javax.jdo.JDODataStoreException: Insert of object "mydomain.model.PersonJsonb@6edcad64" using statement "INSERT INTO "PERSON_JSONB" ("DATA","NAME") VALUES (?,?)" failed : ERROR: column "DATA" is of type jsonb but expression is of type character varying

In raw SQL, this would be addressed by type casting, i.e.:

INSERT INTO "PERSON_JSONB" ("DATA","NAME") VALUES (?::JSONB,?)

In JDBC, the same can be achieved with:

PGobject pgObject = new PGobject();
pgObject.setType("JSONB");
pgObject.setValue("{\"foo\":\"bar\"");

preparedStatement.setObject(1, pgObject);

I'd be happy to contribute a PR for this, but I'd very much appreciate a nudge as to what would need to be done.

nscuro commented 4 months ago

Just learned about the insert-function and update-function extensions, which make the tests pass:

@Persistent
@Column(name = "DATA", jdbcType = "CLOB")
@Extensions({
        @Extension(vendorName = "datanucleus", key = "insert-function", value = "(?::JSONB)"),
        @Extension(vendorName = "datanucleus", key = "update-function", value = "(?::JSONB)")
})
private String data;

I think this is sufficient.