-
Notifications
You must be signed in to change notification settings - Fork 10
Java Language Support
Most of syntax is supported. Easier to list what is not:
- Conditional logic (
if
or?:
) - useCASE\WHEN
orIIF
instead. - Loops (
for
orwhile
), since there is no corresponding SQL construct. See Dynamic Queries for dynamic scenarios. -
switch
statement. -
try/catch/finally
constructs. - Some operators. FluentJPA translates most operators "as is", therefore if your database does not support e.g.
>>
operator, you cannot use it.
Functions that can be called are either:
- "mapped" (provided by the DB vendor or custom stored procedures) - those are marked with
@Function
annotation - Directives - FluentJPA special functions
- Library - actually those are builtin Custom Functions
- Builtin Mappings and Custom Mappings
Just works with a small constraint: functions must be either static or interface default. Once your function meets the Java Language Support standards above, you can have them as many as you want; call one another etc.
Example (refactoring the Builtin Mappings):
public List<X> myMethod(List<String> names) {
FluentQuery query = FluentJPA.SQL((Table1 t1) -> {
//custom function call
customFunction(t1, names);
// variables and expressions can be used here as well
});
...
}
// custom function - ordinary Java function...
private static void customFunction(Table1 t1, List<String> names) {
selectAll(t1); // nested custom function call
boolean containsName = names.contains(t1.getName()); // variable
WHERE(t1.getP1() + 5 < t1.getP2() || containsName); // type-safe expression
// of any complexity
}
Understand what it mean from SQL translation perspective: since there is no general concept of a "local" function in SQL, FluentJPA will duplicate the expression produced by the function (or stored in a variable) as many times as it is used. If the function accepts parameters, the produced expressions will be different with regard to the arguments.
Just works. Simply use parameters inside your code and FluentJPA will do the rest - identify them and register using Query.setParameter(). See an example with names
parameter in Builtin Mappings below.
Note, FluentJPA does not differentiate between parameters and local variables declared before the call to
FluentJPA.SQL()
and used inside it.
To enhance Java integration, there are several Java methods/constructs mapped to the SQL counterparts:
- String concatenation: expression like
x.firstName() + " " + x.lastName()
will be converted to correspondingCONCAT
SQL function call. -
Collection.contains()
: mapped toIN
operator. Works on any type implementingCollection
interface. Especially useful in the following scenarios:-
Collection parameters, e.g.
public List<X> myMethod(List<String> names) { FluentQuery query = FluentJPA.SQL((Table1 t1) -> { selectAll(t1); WHERE(names.contains(t1.getName()); // ^^^^^^^^^^^^^^ // will be translated to something like `t1.name IN (?1)`. // But looks more natural with Java `contains` }); ... }
-
WHERE
clause with sub-select involving 2 tables, e.g.FluentQuery query = FluentJPA.SQL((Table1 t1, Table2 t2) -> { selectAll(t1); WHERE(collect(t2, t2.getCol1()).contains(t1.getCol1())); // ^^^^^^^ collect using Library, and then contains });
-
Collection.size()
andCollection.isEmpty()
are mapped to respectiveCOUNT
andEXISTS
constructs. -
String.concat()
,String.length()
,String.toLowerCase()
,String.toUpperCase()
,String.replace()
,String.trim()
- all mapped to respective SQL functions. -
Most
Math.*
methods are mapped as well.
-
You can register a custom mapping between any Java method and a custom or mapped function. So any time FluentJPA encounters a call to that Java method, it will "call" the mapping instead. In fact all the Builtin Mappings above are mapped by this technique. E.g.:
// substitute String::concat with mapped ScalarFunctions::CONCAT
FluentJPA.SQLConfig().registerMethodSubstitution(String::concat, ScalarFunctions::CONCAT);
// substitute Collection::contains with a custom function (lambda)
// that invokes a mapped operator IN.
// This mapping "powers" the examples above
FluentJPA.SQLConfig().registerMethodSubstitution(
(Function2<Collection<Comparable>, Comparable, Boolean>)
Collection::contains,
(collection, item) -> IN(item, collection));
Getting Started
- Introduction
- Setup
- Data Types
- Entities & Tuples
- Sub Queries
- JPA Integration
- Java Language Support
- Directives
- Library
- Returning Results
- JPA Repositories
Examples
Basic SQL DML Statements
Advanced SQL DML Statements
- Common Table Expressions (WITH Clause)
- Window Functions (OVER Clause)
- Aggregate Expressions
- MERGE
- Temporal Tables
Advanced Topics