https://github.com/reforms/reforms
Reforms is repository for framework that help in development with SQL and ORM technics
https://github.com/reforms/reforms
jdbc jdbc-framework jdbc-orm jdbc-orm-framework orm-framework sql sql-parser
Last synced: 11 days ago
JSON representation
Reforms is repository for framework that help in development with SQL and ORM technics
- Host: GitHub
- URL: https://github.com/reforms/reforms
- Owner: reforms
- Created: 2017-01-16T10:23:21.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2017-12-03T13:18:22.000Z (about 8 years ago)
- Last Synced: 2024-04-28T04:15:56.217Z (over 1 year ago)
- Topics: jdbc, jdbc-framework, jdbc-orm, jdbc-orm-framework, orm-framework, sql, sql-parser
- Language: Java
- Size: 1.15 MB
- Stars: 7
- Watchers: 1
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: Readme.asciidoc
Awesome Lists containing this project
README
////
License is free for everything
////
RefOrms
-------
Hello, its RefOrms framework.
RefOrms is SQL-oriented JDBC framework, similar to Spring Framework JDBC but having several advantages over it.
See link:https://htmlpreview.github.io/?https://github.com/reforms/ReformsDoc/blob/master/doc.html[RefOrms Manual] with html preview.
What the project does:
~~~~~~~~~~~~~~~~~~~~~
[square]
* Project helps you map your SQL query to your ORM data.
* Project contains SQL-92 parser to select, update, insert and delete queries.
Why the project is useful:
~~~~~~~~~~~~~~~~~~~~~~~~~
[square]
* 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.
How users can get started with the project:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[source,xml]
----
com.github.reforms
reforms
2017.08.17
----
Short example usaging reforms framework in interface programming style:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[source,java]
----
// Your IClientDao dao interface
public interface IClientDao {
@TargetQuery("SELECT id, name, state FROM clients WHERE name = ?")
public Client findClientByName(String clientName);
}
// Your needs
public class ClientHelper {
public void doSomeWork(java.sql.Connection connection) throws Exception {
// ... code before
IClientDao clientdao = com.reforms.orm.OrmDao.createDao(IClientDao.class, connection);
Client client = clientdao.findClientByName("Gaius Iulius Caesar");
// ... code after
}
}
----
Concept of Usage as Best Practices:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[square]
* 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
Job for You and Job for RefOrms:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[options="header,middle,autowidth"]
|===
| 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_
|===
Strengths and Features:
~~~~~~~~~~~~~~~~~~~~~~~
[square]
* 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 are supporting _BEAN way_, _DIRECT way_ or _MAP way_
* Paging data for some dialect of sql
Sintax rules for mapping selecting columns to orm fields inside your SQL query:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
At first, take a look at SQL query below
[source,sql]
----
SELECT client_id, CNAME, state AS client_state FROM clients
----
Column name map to orm field name use next rules:
[start]
1. _Under_score_ column to camelCase field: _client_id_ -> clientId
2. _UPPERCASE_ column to lowercase field: _CNAME_ -> cname
3. _AS clause statement_ has highest priority then column: pass:q[state] _client_state_ -> clientState. Be careful, as clause _name_ converting to field name using _under_score_ to _camelCase_ rule *only*
[end]
Adapting column type to orm field type goes through next phases:
[start]
1. Determination of type to reading value from ResultSet - base on syntax rules in select statement
2. Converting value of this type to the relevant field type of orm - base on syntax rules in select statement
[end]
And
[start=3]
3. Always base on syntax rules in select statement inside _AS clause_
4. Аbsolutely ignoring of column type in your db
5. Only depends on orm field type
[end]
Example? At first, take a look at SQL query below
[source,sql]
----
SELECT client_id, client_id AS id, act_time AS t#logTime FROM clients
----
and orm class
[source,java]
----
class Client {
// ....
int clientId;
long id;
java.util.Date logTime;
// ....
}
----
[start]
1. Column expression '_client_id_' will reading from ResultSet using clientId field type - int. Java code equivalent: _rs.getInt(1);_
2. Column expression '_client_id AS id_' will reading from ResultSet using id field type - long. Java code equivalent: _rs.getLong(2);_
3. 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());_
[end]
All directives see in table below
[options="header,middle,autowidth"]
|===
| 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.
Sintax rules for filters:
~~~~~~~~~~~~~~~~~~~~~~~~~
At first, take a look at SQL query below
[source,sql]
----
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:
[source,sql]
----
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?
[source,sql]
----
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.
[source,sql]
----
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
[source,sql]
----
SELECT id, name, state, act_time FROM clients WHERE act_time <= ?
----
If both will absent?
[source,sql]
----
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
[source,sql]
----
-- 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
----
Full Example of usage
~~~~~~~~~~~~~~~~~~~~~
[[E1]]*1. Your ORM*
[source,java]
----
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)*
[source,java]
----
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)*
[source,java]
----
package com.reforms.example;
import com.reforms.orm.dao.bobj.model.OrmHandler;
public class ClientHandler implements OrmHandler {
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);
}
}
----
[[E4]]*4. Your DAO*
[source,java]
----
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 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 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);
}
}
----
Any Examples
~~~~~~~~~~~~
*1. Mapping selecting column values to orm fields, in case, all orm field names differ from column names*
[source,sql]
----
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
----