What is fieldIndex about in JOOQ - java

I read JOOQ API documentation about following APIs, but still couldn't understand what is fieldIndex about.
fetchAny(int fieldIndex, java.lang.Class<? extends T> type)
For example, in the following code I already knows which column to select, why do we need filedIndex of 0? What does 0 mean?
String name = getDslContext().select(TESTB.STU_NAME)
.from(TESTB)
.where(TESTB.ID.eq(studentId))
.fetchAny(0, String.class);

jOOQ mostly operates on Record types. For instance, when you create the following query:
.select(TESTB.STU_NAME)
.from(TESTB)
.where(TESTB.ID.eq(studentId));
You're really operating on a ResultQuery<Record1<String>>. By calling fetchAny(0, String.class) on that type, you're telling jOOQ that you want to fetch any record, and from that record, you want to get only the value at index 0, converted to String.
This may feel like repeating the same information twice (using TESTB.STU_NAME, and fetching the column at index 0). This is because fetchign a single value is quite a special case in the jOOQ API. Unfortunately, the ResultQuery API doesn't really "know" that you're selecting only one column even if that type information is present via generics.
One alternative would be to use DSLContext.fetchValue(ResultQuery):
String name = getDslContext().fetchValue(
DSL.select(TESTB.STU_NAME)
.from(TESTB)
.where(TESTB.ID.eq(studentId))
);

Related

JOOQ SUM in Kotlin with custom types

currently I have a converter to work with value objects in JOOQ with Kotlin.
My database has a table called transactions with a field type decimal(10, 2) called billing _amount and on my Kotlin code I have a simple ValueObject from DDD to wrap it up, called BillingAmount defined as following
data class BillingAmount(val value: BigDecimal)
As for my jooq custom converter I have the following code:
public final TableField<TransactionsRecord, BillingAmount> BILLING_AMOUNT =
createField(
DSL.name("billing_amount"),
org.jooq.impl.SQLDataType.NUMERIC(10, 2).nullable(false),
this,
"",
org.jooq.Converter.ofNullable(
java.math.BigDecimal.class,
okano.dev.jooqtesting.BillingAmount.class,
t -> new okano.dev.jooqtesting.BillingAmount(t),
u -> u.getValue()
)
);
On my repository, I'm just trying to retrieve a sum a billing amounts, but jooq is complaining that BillingAmount doesn't extend a Number class. I know that is a Java generic validation that is preventing my code from working, but there's any way around, except by extending the Number class, for solving this problem? I thought that the converter should be enough, but for sure I'm wrong about this.
Here's the simple query I'm trying to achieve:
// jooq is an instance of DSLContext
return jooq.select(sum(TABLE.BILLING_AMOUNT))
.from(TABLE)
.fetchSingle()
Any thoughts on this question? Thanks in advance.
I assume that problems you're experiencing is just due to Java's type system.
If so, you can simply coerce the field to a different type for a query, like so (admittedly, muddying the query defining code):
BillingAmount sum = jooq
.select(sum(TABLE.BILLING_AMOUNT.coerce(BigDecimal.class)))
.from(TABLE)
.fetchSingle(TABLE.BILLING_AMOUNT);
It's not quite the same type of result as in original query, though, because it materializes BillingAmount directly, and not a Record<BillingAmount> (because after coercion the query return type would be Record<BigDecimal>.
As a workaround, you can always resort to using plain SQL templating in jOOQ
fun alternativeSum(field: Field<*>) = DSL.field("{0}", field.getDataType(), field)

Should I just disable UInteger type on JOOQ?

I've been trying to write some queries (for MySQL) and I'm not sure how to write this particular one that involves Integer and UInteger types:
DSL.position(T1.FIELD, ":", -1).eq(T2.UINTFIELD)
position returns a Field<Integer>, so I can't simply compare this result to my Field<UInteger>. Is there a simple way to achieve it? I'd like to keep the correct field types for further validation.
You can use DSL.cast() or DSL.coerce() for this. I recommend coerce.
DSL.cast() produces a SQL cast expression and a jOOQ field reference of the desired type
DSL.coerce() does not affect the generated SQL but still produces a jOOQ filed reference of the desired type.
For example:
position(T1.FIELD, ":", -1).eq(coerce(T2.UINTFIELD, SQLDataType.INTEGER))

Update more than 22 values in Jooq [duplicate]

I have two functions: one returns a list of fields, the other returns a select query (which selects the corresponding values of the fields).
private List<Field<?>> fields() {
....
}
private Select<?> select() {
...
}
Note that the degree is determined at runtime, it depends on the user input. Hence List<Field<?>> and Select<?>.
It is possible to insert into a table:
context.insertInto(table, fields()).select(select()))
It is not possible to update a table:
context.update(table).set(DSL.row(fields()), select())
Could this functionality be added to jOOQ 3.7?
Which workaround can we use for now?
Nice catch, there's a missing method on the UpdateSetFirstStep DSL API, which accepts RowN as a first argument, the type returned from DSL.row(Collection). This should be fixed for jOOQ 3.7:
https://github.com/jOOQ/jOOQ/issues/4475
As a workaround, and if you can live with the guilt of the hack, you could cast to raw types:
context.update(table).set((Row1) DSL.row(fields()), (Select) select())
You can cast DSL.row(fields()) to Row1, because the internal implementation type returned by DSL.row(fields()) implements all Row[N] types.

Spring Data JPA Repository Queries - How to map #Param value to multiple parameter types

I have implemented following JPA Repository query for some common search functionality.
But with that query, due to age is a Integer value and mapping Parameter is String value I got some exception as follow. Is there any mechanism to implicitly casting parameter to relevant data type instead of we do that. Thanks.
Query with common parameter
#Query("select u from User u where u.firstname = :searchText or u.age = :searchText")
List<User> findBySearchText(#Param("searchText") String searchText);
Exception
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: integer = character varying
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
The issue you see has nothing to do with the binding itself. Spring Data basically binds the value you give to the named parameter searchText.
It looks like what happens next is that your persistence provider builds some SQL from it where there's a type mismatch apparently. Age doesn't seem to be of type String, is it? That said, I think trying to bind an arbitrary String to an integer (which it is I guess) is a very weird approach in the first place.
SQL is not really built to support arbitrary text search features and schema is helping you to detect invalid criterias (which it does in this case). Have you thought about adding a full-text search store (Elasticsearch, Solr or the like) and do the text searches in those?

Retrieving the value of selectCount in jooq

I have some code that looks like this:
Record record = jooq
.selectCount()
.from(USERS)
.fetchOne();
Currently I'm doing the following to get the count:
Integer count = (Integer) record.getValue(0);
But it seems like there must be a better solution (that's type-safe...since that's the whole point of using jooq). Any suggestions?
Unfortunately, for this particular query, there aren't many "better" ways to typesafely get the count() value. What you could do, to add type-safety, is this:
Field<Integer> f = count();
Integer count = jooq.
.select(f) // Or selectCount(). Replaced it to illustrate the case
.from(USERS)
.fetchOne(f);
The problem is that most of the type information about the projection has been "lost" to the Java compiler, by the time the fetch() methods are "reached". There is no way that a ResultQuery.fetchXXX() method could recover it from the SELECT clause, and produce it to you.
On the jOOQ user group, some users have argued to move the projection into the fetch() methods, entirely, the way C#'s LINQ, or Scala's SLICK do it. This would greatly complicate the expression of more advanced SELECT statements. An more elaborate explanation is documented here.
With jOOQ 3.0, additional record-level typesafety has been introduced. In jOOQ 3.3, it will thus be possible to fetch a single value as such (has been registered as #2246):
<T> T fetchValue(Select<Record1<T>> select);

Categories

Resources