-
Notifications
You must be signed in to change notification settings - Fork 10
Data Types
SQL data types are a tricky thing, especially when considering mapping them to Java.
- Supported types and names are different between vendors.
- Some types have variable length, scale and precision. There is actually a countless number of sub types.
- Finally, different projects choose to map database types differently. Even worse, in the same project same SQL type can be mapped to Java type differently depending on the context.
There are 2 primary use cases involving data types:
- CASTs - we want to be able to use SQL CAST operator.
- Literals - we want to be able to write a string constant, e.g.
2016-03-04
, and treat it as aDate
type in SQL. Intervals are commonly used as hard-coded literals, see usage examples here.
In both cases, when used in FluentJPA, we want that after CASTing or using a literal, the result would be of the correct Java type, making the compiler happy.
FluentJPA aims support all the use cases and creates a statically typed dynamic type system. The following explains how this is achieved and how to use it.
- Per vendor FluentJPA defines an
enum DataTypeNames
that contains all the vendor type names and provides convenientcreate()
methods (more on them below). - Defines a
DataType<T>
interface:
-
T
is the mapped Java type, e.g.Integer
. - This interface defines
cast()
andof()
(type literal) methods, which both returnT
in Java and produce the typed SQL during translation. Also there is araw()
method which outputs the expression as is, letting the Database to decide about the required conversion.
SQL Server does not support string literals. Use
cast()
orraw()
methods instead.
Per vendor there is DataTypes interface, containing declarations like these:
// Java type Timestamp is mapped to SQL type TIMESTAMP (cast and literal work correctly)
final DataType<Timestamp> TIMESTAMP = DataTypeNames.TIMESTAMP.create();
// Java type BigDecimal is mapped to SQL type NUMERIC
final DataType<BigDecimal> DECIMAL = DataTypeNames.NUMERIC.create();
It contains the most obvious type declarations with naming convention following the vendor names. Of course any "varying" types are missing.
All this is a preparation for creating your own, project specific types set! E.g.:
// this is supposed to be written in the customer project
public interface MyProjectDataTypes {
final DataType<String> SHORT_STRING = DataTypeNames.VARCHAR.create(255);
final DataType<String> MEDIUM_STRING = DataTypeNames.VARCHAR.create(1024);
final DataType<String> LONG_STRING = DataTypeNames.VARCHAR.create(4096);
// refer a "standard type"
final DataType<Timestamp> TIMESTAMP = DataTypes.TIMESTAMP;
// refer a "standard type" and provide a domain specific name
final DataType<Integer> INTERVAL = DataTypes.INT;
...
}
Now, provided MyProjectDataTypes
is added to static imports, we can write a query like this:
FluentQuery query = FluentJPA.SQL((CrunchbaseCompany c) -> {
Date foundedAgo = subtract(NOW(), TIMESTAMP.cast(c.getFoundedAtClean()));
// foundedAtClean is a String -------------------^^^^^^^^^^^^^^^^^^^
SELECT(c.getPermalink(), c.getFoundedAtClean(), foundedAgo);
FROM(c);
WHERE(c.getFoundedAtClean() != null);
});
Or
SELECT DATE_ADD(c.getFoundedAt(), INTERVAL.of(1, TimeUnit.DAY)); // MySQL
SELECT add(c.getFoundedAt(), INTERVAL.of(1, DatePart.WEEK)); // PostgreSQL
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