Querying by value in JSONB field in h2/postgresql - postgresql

I have following json field in entity:
{"uuid", "uuid2"}
and I want to use #Query to find an entity which contains given uuid in this field. I have found a solution for postgresql (which we are using), but when I try to test it using h2 I get Function JSONB_EXISTS not found exception.
Is it possible to make it work with both postgresql and h2 using same query?
How I am creating a query (this works fine for postgresql, but not for h2):
#Query(
nativeQuery = true,
value = "SELECT * FROM patient_person WHERE jsonb_exists(patient_reference_ids, :patientReferenceId)"
)
fun findByPatientReferenceId(#Param("patientReferenceId") patientReferenceId: String): PatientPersonEntity?
How is field defined in entity:
#Type(type = "jsonb")
#Column(columnDefinition = "jsonb")
var patientReferenceIds: emptyList()
Error during test run
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Function "JSONB_EXISTS" not found; SQL statement:
SELECT * FROM patient_person WHERE jsonb_exists(patient_reference_ids, ?) [90022-200]

Related

JPA Criteria on PostgreSQL boolean type creates invalid query

I have a regular JPA Entity which has a boolean field:
#Entity("UserAccount")
public class UserAccount {
...
#Column(name = "isActive")
private boolean isActive = false;
...
}
This is backed by a table in PostgreSQL 15. In the table definition, the field is of type BOOLEAN (not integer!):
CREATE TABLE UserAccount(
...
isActive BOOLEAN NOT NULL,
...
)
When I attempt to use the JPA Criteria API with it:
criteriaBuilder.isTrue(root.get("isActive"))
... then it will be rendered as = 1 in the SQL query which is sent to PostgreSQL:
SELECT ...
FROM UserAccount
WHERE isActive = 1
PostgreSQL rejects this query with the following error (which is pretty clear):
PSQLException: ERROR: operator does not exist: boolean = integer
Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
My question is: how can I tell Hibernate that I'm using an actual PostgreSQL-native BOOLEAN type in my table instead of encoding the boolean as a number?

How to JPA Query for Postgresql #Type list-array?

I have column in a database in which data are stored in this way {type1,type2,...}. I want to get elements from CARS table which are in Set carTypes.
#Type(type = "list-array")
#Column(name = "TYPES")
private final List<String> types;
Not working:
#Query("SELECT * FROM cars c WHERE (:carTypes) IN (c.types)")
List<Object[]> findCars(#Nullable #Param("carTypes") Set<String> carTypes);
Error:
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: bytea = character varying[]
I don't know what the Spring Data abstraction for this (or if there is any), but with plain Hibernate you can do something like this:
BasicType type = (BasicType) session.getFactory()
.getMappingMetamodel()
.getEntityDescriptor(Car.class)
.getPropertyType("types");
List<Car> list = session.createQuery(
"SELECT * FROM cars c WHERE (:carTypes) IN (c.types)",
Car.class
)
.setParameter("carTypes", carTypes, type)
.getResultList();

How can I make some change on spring data underlying query

I am using spring data in my project with Postgres as the Database. I have an entity that has a JSON field and I want to keep it as a String in the java context, but a jsonb in the database. Whenever I want to persist an instance of my entity the problem arises since hibernate is treating the JSON property as a Basic type and the underlying query does not change the String type to jsonb type.
#Entity
#Table(name = "a", catalog = "")
#TypeDef(name = "jsonb", typeClass = String.class)
public class A {
#Type(type = "jsonb")
#Column(name = "json-data", columnDefinition = "jsonb")
private String myJsonData;
}
I find the solution for this problem here, but it needs to change the parameters of the underlying PreparedStatement query. So, I need to change the query and add ::jsonb to make Postgres cast the parameter to jsonb. Is there any Annotation related to #Type to make it work?
You can use #ColumnTransformer for this purpose.

Postgresql jsonb column with spring jpa nativequery issue

I have a native query defined in a spring JpaRepositroy as:
#Query(value="Select * from Employee WHERE....", nativeQuery=true)
List<Employee> getEmployees(....)
In entity, I have a jsonb field defined as:
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
....
#Type(type = "jsonb")
#Column(name = "properties", columnDefinition = "jsonb")
private ObjectNode properties;
This setup works perfect, and it fetches the records for me correctly.
But if I try to fetch only some specific columns by changing query as:
#Query(value="Select emp_name, properties from Employee WHERE....", nativeQuery=true)
List<Object[]> getEmployees(....)
This gives me error as:
Caused by: org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111
And I get this error only if properties field is in SELECT clause, else this too works fine.
What is the reason? And how to get it working with properties field?

JPQL Query working in testing, not in production

I have two Entities related by a ManyToMany and I want to select them via a named Query. This works in my test (with a H2 DB set up) and throws exceptions at runtime (with postgresql set up). Other than the H2 and PG I am hard pressed to find differences between test and production.
The Entities and the Query look like so (abbreviated):
#Entity(name = "Enrichment")
#Table(name = "mh_Enrichment")
NamedQueries({
#NamedQuery(name = "findByLink",
query = "SELECT e FROM Enrichment e INNER JOIN e.links l WHERE l.link in (:links)") })
public class EnrichmentImpl {
#Id
#Column(name = "enrichmentId")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#ManyToMany
#JoinTable(name = "mh_EnrichmentLinks", joinColumns = { #JoinColumn(name = "EnrichmentId",
referencedColumnName = "enrichmentId") }, inverseJoinColumns = { #JoinColumn(name = "Link",
referencedColumnName = "link") })
private List<Link> links;
}
#Entity(name = "Link")
#Table(name = "mh_enrichment_link")
public class LinksImpl {
#Id
#Column(name = "link", length = 1024)
private String link;
}
Upon running the query with a String value in production I get:
Internal Exception: org.postgresql.util.PSQLException: ERROR: operator does not exist: character varying = bigint
Hinweis: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Position: 215
Error Code: 0
Call: SELECT t1.enrichmentId FROM mh_enrichment_link t0, mh_EnrichmentLinks t2, mh_Enrichment t1 WHERE ((t0.link IN (?)) AND ((t2.EnrichmentId = t1.enrichmentId) AND (t0.link = t2.Link)))
Any ideas what's wrong? It is the query, isn't it?
The query is supposed to retrieve a list of Enrichments that are related to the given link.
Update #1
As requested: the tables in the DB look as follows:
For entity Link
CREATE TABLE mh_enrichment_link
(
link character varying(1024) NOT NULL,
CONSTRAINT mh_enrichment_link_pkey PRIMARY KEY (link)
)
For entity Enrichment
CREATE TABLE mh_enrichment
(
enrichmentid bigint NOT NULL,
CONSTRAINT mh_enrichment_pkey PRIMARY KEY (enrichmentid)
)
For the relation (See answer, this was where it went wrong)
CREATE TABLE mh_enrichmentlinks
(
link character varying(1024) NOT NULL,
CONSTRAINT mh_enrichment_link_pkey PRIMARY KEY (link)
)
The issue was fixed by dropping all related tables and having JPA regenerate them. Table definitions didn't match Entity definitions.
Thats also the quite obviously the reason why the test worked and the production didn't. In testing the tables are generated on runtime, in production they existed already (with an outdated definition).
Side note: The query is correct and does what it should.