Hello, its RefOrms framework.
-
Project helps you map your SQL query to your ORM data.
-
Project contains SQL-92 parser to select, update, insert and delete queries.
-
It’s powerfull instrument which helps you to take all from SQL and map it to ORM.
-
It’s not hibernate, it’s not DDL (like JOOQ) it’s only SQL to ORM.
Download reforms.jar and include it to your project.
// 1. Common dao style: Inside your client ClintDao class
public Client findClientById(long clientId) throws Exception {
com.reforms.orm.OrmDao ormDao = new com.reforms.orm.OrmDao(connection);
return ormDao.select(Client.class,
"SELECT id, name, state FROM clients WHERE id = ?",
clientId);
}
/** OR */
// 2. Interface programming style: Inside your IClientDao dao interface
@TargetQuery(query = "SELECT id, name, state FROM clients WHERE name = ?", type = QT_SELECT)
public Client findClientByName(String clientName);
-
One dependency: reforms.jar for all needs
-
One class com.reforms.orm.OrmDao for most of needs
-
Usaging annotated code as little as possible
-
Simple, but powerfull sintaxes for mapping selecting columns to orm fields
-
Reusable SQL query for difference filters
-
Usaging Interface programming style as technic of coding
N | Task | Your job | RefOrms job | Example and Details |
---|---|---|---|---|
1 |
ORM class |
+ |
- |
|
2 |
SQL query |
+ |
- |
SELECT, INSERT, UPDATE, DELETE queries |
3 |
DAO class or DAO interface |
+ |
- |
|
4 |
Parse SQL query |
- |
+ |
Building tree expressions for analysis |
5 |
Setting values to PreparedStatement |
- |
+ |
ps.setLong("id", 1L); |
6 |
Reading values from ResultSet |
- |
+ |
rs.getLong("id"); |
7 |
Map ResultSet to ORM class |
- |
+ |
Using tree expressions convert rs to ORM |
-
Selectable columns:
-
Filtering selectable columns in SELECT clause before SQL query execute
-
Mapping selectable columns to orm fields inside your SQL query, using framework rules
-
Mapping selectable columns to orm fields inside your SQL query, using your custom rules
-
Mapping selectable columns to map data inside your SQL query, using framework rules
-
Mapping selectable columns to map data inside your SQL query, using your custom rules
-
-
Managing of schema inside your SQL query
-
Filtering data in WHERE/HAVING clause
-
Static filters - required filters inside your SQL query: if filter values absent exception will occure
-
Dynamic filters - optional filters inside your SQL query: if filter values absent SQL query will be changed and SQL expressions for missing filter values will be cut from SQL query
-
Filters can be base on BEAN way, DIRECT way or MAP way
-
-
Paging data for some dialect of sql
At first, take a look at SQL query below
SELECT client_id, CNAME, state AS client_state FROM clients
Column name map to orm field name use next rules:
-
Under_score column to camelCase field: client_id → clientId
-
UPPERCASE column to lowercase field: CNAME → cname
-
AS clause statement has highest priority then column:
stateclient_state → clientState. Be careful, as clause name converting to field name using under_score to camelCase rule only
Adapting column type to orm field type goes through next phases:
-
Determination of type to reading value from ResultSet - base on syntax rules in select statement
-
Converting value of this type to the relevant field type of orm - base on syntax rules in select statement
And
-
Always base on syntax rules in select statement inside AS clause
-
Аbsolutely ignoring of column type in your db
-
Only depends on orm field type
Example? At first, take a look at SQL query below
SELECT client_id, client_id AS id, act_time AS t#logTime FROM clients
and orm class
class Client {
// ....
int clientId;
long id;
java.util.Date logTime;
// ....
}
-
Column expression 'client_id' will reading from ResultSet using clientId field type - int. Java code equivalent: rs.getInt(1);
-
Column expression 'client_id AS id' will reading from ResultSet using id field type - long. Java code equivalent: rs.getLong(2);
-
Column expression 'act_time AS t#logTime' will reading from ResultSet using t# directive wich mean 'read as java.sql.Timestamp' and convert read value to java.util.Date, because logTime field declared with this type. Java code equivalent: new java.util.Date(rs.getTimestamp(3).getTime());
All directives see in table below
Directive | Java Type |
---|---|
z |
boolean |
y |
byte |
x |
short |
i |
int |
f |
float |
w |
double |
l |
long |
e |
java.lang.Enum (user data concrete type) |
s or nothing |
java.lang.String (default type for reporting) |
n |
java.math.BigDecimal |
I |
java.math.BigInteger |
d |
java.sql.Date |
v |
java.sql.Time |
t |
java.sql.Timestamp |
a |
java.io.InputStream as AsciiStream |
b |
java.io.InputStream as BinaryStream |
u |
User Custome Type, need Registry IReportValueConverter |
Expected that directive will rarely be used and mainly for date, stream and user types.
At first, take a look at SQL query below
SELECT id, name, state FROM clients WHERE id = ?
Its SQL query in common style for filtering result by id. If we use RefOrms framework terminology we can say that query contains static (required) filter by id. And if we use RefOrms framework we can (although not necessarily) rewrite SQL query like this:
SELECT id, name, state FROM clients WHERE id = :id
It’s like Hibernate or Spring way. What happens, if :id filter value will be absent? Exception occur. And it’s correct. But, if we have filter that can be or not to be?
SELECT id, name, state, act_time FROM clients WHERE act_time >= ? AND act_time <= ?
What then? Then the game enters the dynamic filters. How? Easy.
SELECT id, name, state, act_time FROM clients WHERE act_time >= ::begin_from AND act_time <= ::end_to
Double colon is way to use dynamic filters. What happens, if :begin_from will be absent, but :end_to will present? Like below
SELECT id, name, state, act_time FROM clients WHERE act_time <= ?
If both will absent?
SELECT id, name, state, act_time FROM clients
Yes. SQL query was modifed. And it’s powerfull side of RefOrms framework. You don’t need to construct your sql query using if statement in java code. You only declare dynamic or static filters inside SQL query. RefOrms framework supports all SQL-92 predicates (excluding OVERLAPS and MATCH) with dynamic filters. Few examples
-- 1. IN predicate will be removed if states filter will be absent
SELECT id, name, state FROM clients WHERE state IN (::states)
-- 2. LIKE predicate will be removed if name filter will be absent
SELECT id, name, state FROM clients WHERE name LIKE ::name
-- 3. VALUES block predicate will be narrowed down if some filters will be absent OR removed if all filters will be absent
SELECT id, name, state FROM clients WHERE (id, name) = (::id, ::name)
-- and so on
package com.reforms.example;
public class Client {
private long id;
private String name;
private ClientState state;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ClientState getState() {
return state;
}
public void setState(ClientState state) {
this.state = state;
}
}
2. Your ENUM (part of orm)
package com.reforms.example;
import com.reforms.ann.TargetField;
import com.reforms.ann.TargetMethod;
public enum ClientState {
NEW(0),
ACTIVE(1),
BLOCKED(2);
@TargetField
private int state;
private ClientState(int state) {
this.state = state;
}
public int getState() {
return state;
}
@TargetMethod
public static ClientState getClientState(int state) {
for (ClientState clientState : values()) {
if (clientState.state == state) {
return clientState;
}
}
throw new IllegalStateException("Unknown client with state " + state);
}
}
3. Your ORM Handler (if need)
package com.reforms.example;
import com.reforms.orm.dao.bobj.model.OrmHandler;
public class ClientHandler implements OrmHandler<Client> {
private int index;
@Override
public void startHandle() {
index = 0;
System.out.println("beging...");
}
@Override
public boolean handleOrm(Client dbClient) {
index++;
System.out.println("Load client: " + dbClient);
return true;
}
@Override
public void endHandle() {
System.out.println("end... Total: " + index);
}
}
package com.reforms.example;
import com.reforms.orm.OrmDao;
import com.reforms.orm.dao.bobj.model.OrmIterator;
import java.sql.Connection;
import java.util.List;
public class ClientDao {
// Reform api - dao
private OrmDao ormDao;
public ClientDao(Connection connection) {
ormDao = new OrmDao(connection);
}
// Load all active clients
private static final String SELECT_ACTIVE_CLIENTS_QUERY = "SELECT id, name, state FROM clients WHERE state = ?";
public List<Client> loadActiveClients() throws Exception {
return ormDao.selectList(Client.class, SELECT_ACTIVE_CLIENTS_QUERY, ClientState.ACTIVE);
}
// Load all clients
private static final String SELECT_ALL_CLIENTS_QUERY = "SELECT id, name, state FROM clients";
public OrmIterator<Client> loadClients() throws Exception {
return ormDao.selectIterator(Client.class, SELECT_ALL_CLIENTS_QUERY);
}
public void processClients(ClientHandler clientHandler) throws Exception {
ormDao.selectAndHandle(Client.class, SELECT_ALL_CLIENTS_QUERY, clientHandler);
}
// Find client using id
private static final String FIND_CLIENT_QUERY = "SELECT id, name, state FROM clients WHERE id = ?";
public Client findClient(long clientId) throws Exception {
return ormDao.select(Client.class, FIND_CLIENT_QUERY, clientId);
}
// Update client name and state
private static final String UPDATE_CLIENT_QUERY = "UPDATE clients SET name = ?, state = ? WHERE id = ?";
public int updateClientNameAndState(long clientId, String clientName, ClientState clientState) throws Exception {
return ormDao.update(UPDATE_CLIENT_QUERY, clientName, clientState, clientId);
}
// Delete client using id
private static final String DELETE_CLIENT_QUERY = "DELETE FROM clients WHERE id = ?";
public int deleteClient(long clientId) throws Exception {
return ormDao.delete(DELETE_CLIENT_QUERY, clientId);
}
// Insert new client
private static final String INSERT_CLIENT_QUERY = "INSERT INTO clients (id, name, state) VALUES(?, ?, ?)";
public void saveClient(long clientId, String clientName, ClientState clientState) throws Exception {
ormDao.insert(INSERT_CLIENT_QUERY, clientId, clientName, clientState);
}
}
1. Mapping selecting column values to orm fields, in case, all orm field names differ from column names
SELECT cl.id AS cid:clientId, -- map column 'cl.id' to 'clientId' orm field
-- client.setClientId(cl.id);
-- cid - as clause name in result SQL query: SELECT cl.id AS cid,...
cl.name AS clientName, -- map column 'cl.name' to 'clientName' orm field
-- client.setClientName(cl.name);
addr.id AS clientAddress.addressId, -- map column 'addr.id' to 'addressId' orm field inside of clientAddress orm
-- client.getClientAddress().setAddressId(addr.id);
addr.city AS clientAddress.refCity, -- map column 'addr.city' to 'refCity' orm field inside of clientAddress orm
-- client.getClientAddress().setCity(addr.city)
addr.street AS clientAddress.refStreet, -- map column 'addr.street' to 'refStreet' orm field inside of clientAddress orm
-- client.getClientAddress().setRefstreet(addr.street)
cl.act_time AS t#logDate -- map column 'cl.act_time' to 'logDate' orm field
-- client.setLogDate(cl.act_time);
-- t# - direct type of act_time - java.util.Date based on java.sql.Timestamp
FROM client AS cl,
address AS addr