Folder structure for PandaLib

This commit is contained in:
Marc Baloup 2021-03-21 12:41:43 +01:00
parent 3c3ba8bca3
commit 4da86314c8
Signed by: marcbal
GPG Key ID: BBC0FE3ABC30B893
80 changed files with 1668 additions and 1668 deletions

View File

View File

@ -1,391 +1,391 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.javatuples.Pair; import org.javatuples.Pair;
import fr.pandacube.util.Log; import fr.pandacube.util.Log;
/** /**
* <b>ORM = Object-Relational Mapping</b> * <b>ORM = Object-Relational Mapping</b>
* *
* @author Marc Baloup * @author Marc Baloup
* *
*/ */
public final class ORM { public final class ORM {
private static List<Class<? extends SQLElement<?>>> tables = new ArrayList<>(); private static List<Class<? extends SQLElement<?>>> tables = new ArrayList<>();
private static Map<Class<? extends SQLElement<?>>, String> tableNames = new HashMap<>(); private static Map<Class<? extends SQLElement<?>>, String> tableNames = new HashMap<>();
private static DBConnection connection; private static DBConnection connection;
public static DBConnection getConnection() { public static DBConnection getConnection() {
return connection; return connection;
} }
public synchronized static <E extends SQLElement<E>> void init(DBConnection conn) { public synchronized static <E extends SQLElement<E>> void init(DBConnection conn) {
connection = conn; connection = conn;
} }
public static synchronized <E extends SQLElement<E>> void initTable(Class<E> elemClass) throws ORMInitTableException { public static synchronized <E extends SQLElement<E>> void initTable(Class<E> elemClass) throws ORMInitTableException {
if (tables.contains(elemClass)) return; if (tables.contains(elemClass)) return;
try { try {
tables.add(elemClass); tables.add(elemClass);
Log.debug("[ORM] Start Init SQL table "+elemClass.getSimpleName()); Log.debug("[ORM] Start Init SQL table "+elemClass.getSimpleName());
E instance = elemClass.getConstructor().newInstance(); E instance = elemClass.getConstructor().newInstance();
String tableName = instance.tableName(); String tableName = instance.tableName();
tableNames.put(elemClass, tableName); tableNames.put(elemClass, tableName);
if (!tableExistInDB(tableName)) createTable(instance); if (!tableExistInDB(tableName)) createTable(instance);
Log.debug("[ORM] End init SQL table "+elemClass.getSimpleName()); Log.debug("[ORM] End init SQL table "+elemClass.getSimpleName());
} catch (Exception|ExceptionInInitializerError e) { } catch (Exception|ExceptionInInitializerError e) {
throw new ORMInitTableException(elemClass, e); throw new ORMInitTableException(elemClass, e);
} }
} }
private static <E extends SQLElement<E>> void createTable(E elem) throws SQLException { private static <E extends SQLElement<E>> void createTable(E elem) throws SQLException {
String sql = "CREATE TABLE IF NOT EXISTS " + elem.tableName() + " ("; String sql = "CREATE TABLE IF NOT EXISTS " + elem.tableName() + " (";
List<Object> params = new ArrayList<>(); List<Object> params = new ArrayList<>();
Collection<SQLField<E, ?>> tableFields = elem.getFields().values(); Collection<SQLField<E, ?>> tableFields = elem.getFields().values();
boolean first = true; boolean first = true;
for (SQLField<E, ?> f : tableFields) { for (SQLField<E, ?> f : tableFields) {
Pair<String, List<Object>> statementPart = f.forSQLPreparedStatement(); Pair<String, List<Object>> statementPart = f.forSQLPreparedStatement();
params.addAll(statementPart.getValue1()); params.addAll(statementPart.getValue1());
if (!first) sql += ", "; if (!first) sql += ", ";
first = false; first = false;
sql += statementPart.getValue0(); sql += statementPart.getValue0();
} }
sql += ", PRIMARY KEY id(id))"; sql += ", PRIMARY KEY id(id))";
try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) { try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) {
int i = 1; int i = 1;
for (Object val : params) for (Object val : params)
ps.setObject(i++, val); ps.setObject(i++, val);
Log.info("Creating table " + elem.tableName() + ":\n" + ps.toString()); Log.info("Creating table " + elem.tableName() + ":\n" + ps.toString());
ps.executeUpdate(); ps.executeUpdate();
} }
} }
public static <E extends SQLElement<E>> String getTableName(Class<E> elemClass) throws ORMException { public static <E extends SQLElement<E>> String getTableName(Class<E> elemClass) throws ORMException {
initTable(elemClass); initTable(elemClass);
return tableNames.get(elemClass); return tableNames.get(elemClass);
} }
private static boolean tableExistInDB(String tableName) throws SQLException { private static boolean tableExistInDB(String tableName) throws SQLException {
boolean exist = false; boolean exist = false;
try (ResultSet set = connection.getNativeConnection().getMetaData().getTables(null, null, tableName, null)) { try (ResultSet set = connection.getNativeConnection().getMetaData().getTables(null, null, tableName, null)) {
exist = set.next(); exist = set.next();
} }
return exist; return exist;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <E extends SQLElement<E>> SQLField<E, Integer> getSQLIdField(Class<E> elemClass) public static <E extends SQLElement<E>> SQLField<E, Integer> getSQLIdField(Class<E> elemClass)
throws ORMInitTableException { throws ORMInitTableException {
initTable(elemClass); initTable(elemClass);
return (SQLField<E, Integer>) SQLElement.fieldsCache.get(elemClass).get("id"); return (SQLField<E, Integer>) SQLElement.fieldsCache.get(elemClass).get("id");
} }
public static <E extends SQLElement<E>> SQLElementList<E> getByIds(Class<E> elemClass, Integer... ids) throws ORMException { public static <E extends SQLElement<E>> SQLElementList<E> getByIds(Class<E> elemClass, Integer... ids) throws ORMException {
return getByIds(elemClass, Arrays.asList(ids)); return getByIds(elemClass, Arrays.asList(ids));
} }
public static <E extends SQLElement<E>> SQLElementList<E> getByIds(Class<E> elemClass, Collection<Integer> ids) public static <E extends SQLElement<E>> SQLElementList<E> getByIds(Class<E> elemClass, Collection<Integer> ids)
throws ORMException { throws ORMException {
return getAll(elemClass, getSQLIdField(elemClass).in(ids), SQLOrderBy.asc(getSQLIdField(elemClass)), 1, null); return getAll(elemClass, getSQLIdField(elemClass).in(ids), SQLOrderBy.asc(getSQLIdField(elemClass)), 1, null);
} }
public static <E extends SQLElement<E>> E getById(Class<E> elemClass, int id) throws ORMException { public static <E extends SQLElement<E>> E getById(Class<E> elemClass, int id) throws ORMException {
return getFirst(elemClass, getSQLIdField(elemClass).eq(id)); return getFirst(elemClass, getSQLIdField(elemClass).eq(id));
} }
public static <E extends SQLElement<E>> E getFirst(Class<E> elemClass, SQLWhere<E> where) public static <E extends SQLElement<E>> E getFirst(Class<E> elemClass, SQLWhere<E> where)
throws ORMException { throws ORMException {
return getFirst(elemClass, where, null, null); return getFirst(elemClass, where, null, null);
} }
public static <E extends SQLElement<E>> E getFirst(Class<E> elemClass, SQLOrderBy<E> orderBy) public static <E extends SQLElement<E>> E getFirst(Class<E> elemClass, SQLOrderBy<E> orderBy)
throws ORMException { throws ORMException {
return getFirst(elemClass, null, orderBy, null); return getFirst(elemClass, null, orderBy, null);
} }
public static <E extends SQLElement<E>> E getFirst(Class<E> elemClass, SQLWhere<E> where, SQLOrderBy<E> orderBy) public static <E extends SQLElement<E>> E getFirst(Class<E> elemClass, SQLWhere<E> where, SQLOrderBy<E> orderBy)
throws ORMException { throws ORMException {
return getFirst(elemClass, where, orderBy, null); return getFirst(elemClass, where, orderBy, null);
} }
public static <E extends SQLElement<E>> E getFirst(Class<E> elemClass, SQLWhere<E> where, SQLOrderBy<E> orderBy, Integer offset) public static <E extends SQLElement<E>> E getFirst(Class<E> elemClass, SQLWhere<E> where, SQLOrderBy<E> orderBy, Integer offset)
throws ORMException { throws ORMException {
SQLElementList<E> elts = getAll(elemClass, where, orderBy, 1, offset); SQLElementList<E> elts = getAll(elemClass, where, orderBy, 1, offset);
return (elts.size() == 0) ? null : elts.get(0); return (elts.size() == 0) ? null : elts.get(0);
} }
public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass) throws ORMException { public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass) throws ORMException {
return getAll(elemClass, null, null, null, null); return getAll(elemClass, null, null, null, null);
} }
public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass, SQLWhere<E> where) throws ORMException { public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass, SQLWhere<E> where) throws ORMException {
return getAll(elemClass, where, null, null, null); return getAll(elemClass, where, null, null, null);
} }
public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass, SQLWhere<E> where, public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass, SQLWhere<E> where,
SQLOrderBy<E> orderBy) throws ORMException { SQLOrderBy<E> orderBy) throws ORMException {
return getAll(elemClass, where, orderBy, null, null); return getAll(elemClass, where, orderBy, null, null);
} }
public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass, SQLWhere<E> where, public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass, SQLWhere<E> where,
SQLOrderBy<E> orderBy, Integer limit) throws ORMException { SQLOrderBy<E> orderBy, Integer limit) throws ORMException {
return getAll(elemClass, where, orderBy, limit, null); return getAll(elemClass, where, orderBy, limit, null);
} }
public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass, SQLWhere<E> where, public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass, SQLWhere<E> where,
SQLOrderBy<E> orderBy, Integer limit, Integer offset) throws ORMException { SQLOrderBy<E> orderBy, Integer limit, Integer offset) throws ORMException {
SQLElementList<E> elmts = new SQLElementList<>(); SQLElementList<E> elmts = new SQLElementList<>();
forEach(elemClass, where, orderBy, limit, offset, elmts::add); forEach(elemClass, where, orderBy, limit, offset, elmts::add);
return elmts; return elmts;
} }
public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, Consumer<E> action) throws ORMException { public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, Consumer<E> action) throws ORMException {
forEach(elemClass, null, null, null, null, action); forEach(elemClass, null, null, null, null, action);
} }
public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, SQLWhere<E> where, public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, SQLWhere<E> where,
Consumer<E> action) throws ORMException { Consumer<E> action) throws ORMException {
forEach(elemClass, where, null, null, null, action); forEach(elemClass, where, null, null, null, action);
} }
public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, SQLWhere<E> where, public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, SQLWhere<E> where,
SQLOrderBy<E> orderBy, Consumer<E> action) throws ORMException { SQLOrderBy<E> orderBy, Consumer<E> action) throws ORMException {
forEach(elemClass, where, orderBy, null, null, action); forEach(elemClass, where, orderBy, null, null, action);
} }
public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, SQLWhere<E> where, public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, SQLWhere<E> where,
SQLOrderBy<E> orderBy, Integer limit, Consumer<E> action) throws ORMException { SQLOrderBy<E> orderBy, Integer limit, Consumer<E> action) throws ORMException {
forEach(elemClass, where, orderBy, limit, null, action); forEach(elemClass, where, orderBy, limit, null, action);
} }
public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, SQLWhere<E> where, public static <E extends SQLElement<E>> void forEach(Class<E> elemClass, SQLWhere<E> where,
SQLOrderBy<E> orderBy, Integer limit, Integer offset, Consumer<E> action) throws ORMException { SQLOrderBy<E> orderBy, Integer limit, Integer offset, Consumer<E> action) throws ORMException {
initTable(elemClass); initTable(elemClass);
try { try {
String sql = "SELECT * FROM " + getTableName(elemClass); String sql = "SELECT * FROM " + getTableName(elemClass);
List<Object> params = new ArrayList<>(); List<Object> params = new ArrayList<>();
if (where != null) { if (where != null) {
Pair<String, List<Object>> ret = where.toSQL(); Pair<String, List<Object>> ret = where.toSQL();
sql += " WHERE " + ret.getValue0(); sql += " WHERE " + ret.getValue0();
params.addAll(ret.getValue1()); params.addAll(ret.getValue1());
} }
if (orderBy != null) sql += " ORDER BY " + orderBy.toSQL(); if (orderBy != null) sql += " ORDER BY " + orderBy.toSQL();
if (limit != null) sql += " LIMIT " + limit; if (limit != null) sql += " LIMIT " + limit;
if (offset != null) sql += " OFFSET " + offset; if (offset != null) sql += " OFFSET " + offset;
sql += ";"; sql += ";";
try (ResultSet set = customQueryStatement(sql, params)) { try (ResultSet set = customQueryStatement(sql, params)) {
while (set.next()) { while (set.next()) {
E elm = getElementInstance(set, elemClass); E elm = getElementInstance(set, elemClass);
action.accept(elm); action.accept(elm);
} }
} }
} catch (SQLException e) { } catch (SQLException e) {
throw new ORMException(e); throw new ORMException(e);
} }
} }
public static <E extends SQLElement<E>> long count(Class<E> elemClass) throws ORMException { public static <E extends SQLElement<E>> long count(Class<E> elemClass) throws ORMException {
return count(elemClass, null); return count(elemClass, null);
} }
public static <E extends SQLElement<E>> long count(Class<E> elemClass, SQLWhere<E> where) throws ORMException { public static <E extends SQLElement<E>> long count(Class<E> elemClass, SQLWhere<E> where) throws ORMException {
initTable(elemClass); initTable(elemClass);
try { try {
String sql = "SELECT COUNT(*) as count FROM " + getTableName(elemClass); String sql = "SELECT COUNT(*) as count FROM " + getTableName(elemClass);
List<Object> params = new ArrayList<>(); List<Object> params = new ArrayList<>();
if (where != null) { if (where != null) {
Pair<String, List<Object>> ret = where.toSQL(); Pair<String, List<Object>> ret = where.toSQL();
sql += " WHERE " + ret.getValue0(); sql += " WHERE " + ret.getValue0();
params.addAll(ret.getValue1()); params.addAll(ret.getValue1());
} }
sql += ";"; sql += ";";
try (ResultSet set = customQueryStatement(sql, params)) { try (ResultSet set = customQueryStatement(sql, params)) {
if (set.next()) { if (set.next()) {
return set.getLong(1); return set.getLong(1);
} }
} }
} catch (SQLException e) { } catch (SQLException e) {
throw new ORMException(e); throw new ORMException(e);
} }
throw new ORMException("Cant retrieve element count from database (The ResultSet may be empty)"); throw new ORMException("Cant retrieve element count from database (The ResultSet may be empty)");
} }
public static ResultSet customQueryStatement(String sql, List<Object> params) throws ORMException { public static ResultSet customQueryStatement(String sql, List<Object> params) throws ORMException {
try { try {
PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql); PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql);
int i = 1; int i = 1;
for (Object val : params) { for (Object val : params) {
if (val instanceof Enum<?>) val = ((Enum<?>) val).name(); if (val instanceof Enum<?>) val = ((Enum<?>) val).name();
ps.setObject(i++, val); ps.setObject(i++, val);
} }
Log.debug(ps.toString()); Log.debug(ps.toString());
ResultSet rs = ps.executeQuery(); ResultSet rs = ps.executeQuery();
ps.closeOnCompletion(); ps.closeOnCompletion();
return rs; return rs;
} catch (SQLException e) { } catch (SQLException e) {
throw new ORMException(e); throw new ORMException(e);
} }
} }
public static <E extends SQLElement<E>> SQLUpdate<E> update(Class<E> elemClass, SQLWhere<E> where) throws ORMException { public static <E extends SQLElement<E>> SQLUpdate<E> update(Class<E> elemClass, SQLWhere<E> where) throws ORMException {
return new SQLUpdate<>(elemClass, where); return new SQLUpdate<>(elemClass, where);
} }
/* package */ static <E extends SQLElement<E>> int update(Class<E> elemClass, SQLWhere<E> where, Map<SQLField<E, ?>, Object> values) throws ORMException { /* package */ static <E extends SQLElement<E>> int update(Class<E> elemClass, SQLWhere<E> where, Map<SQLField<E, ?>, Object> values) throws ORMException {
return new SQLUpdate<>(elemClass, where, values).execute(); return new SQLUpdate<>(elemClass, where, values).execute();
} }
/** /**
* Delete the elements of the table represented by {@code elemClass} which meet the condition {@code where}. * Delete the elements of the table represented by {@code elemClass} which meet the condition {@code where}.
* @param elemClass the SQLElement representing the table. * @param elemClass the SQLElement representing the table.
* @param where the condition to meet for an element to be deleted from the table. If null, the table is truncated using {@link #truncateTable(Class)}. * @param where the condition to meet for an element to be deleted from the table. If null, the table is truncated using {@link #truncateTable(Class)}.
* @return The return value of {@link PreparedStatement#executeUpdate()}, for an SQL query {@code DELETE}. * @return The return value of {@link PreparedStatement#executeUpdate()}, for an SQL query {@code DELETE}.
* @throws ORMException * @throws ORMException
*/ */
public static <E extends SQLElement<E>> int delete(Class<E> elemClass, SQLWhere<E> where) throws ORMException { public static <E extends SQLElement<E>> int delete(Class<E> elemClass, SQLWhere<E> where) throws ORMException {
initTable(elemClass); initTable(elemClass);
if (where == null) { if (where == null) {
return truncateTable(elemClass); return truncateTable(elemClass);
} }
Pair<String, List<Object>> whereData = where.toSQL(); Pair<String, List<Object>> whereData = where.toSQL();
String sql = "DELETE FROM " + getTableName(elemClass) String sql = "DELETE FROM " + getTableName(elemClass)
+ " WHERE " + whereData.getValue0() + " WHERE " + whereData.getValue0()
+ ";"; + ";";
List<Object> params = new ArrayList<>(whereData.getValue1()); List<Object> params = new ArrayList<>(whereData.getValue1());
return customUpdateStatement(sql, params); return customUpdateStatement(sql, params);
} }
public static int customUpdateStatement(String sql, List<Object> params) throws ORMException { public static int customUpdateStatement(String sql, List<Object> params) throws ORMException {
try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) { try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) {
int i = 1; int i = 1;
for (Object val : params) { for (Object val : params) {
if (val instanceof Enum<?>) val = ((Enum<?>) val).name(); if (val instanceof Enum<?>) val = ((Enum<?>) val).name();
ps.setObject(i++, val); ps.setObject(i++, val);
} }
Log.debug(ps.toString()); Log.debug(ps.toString());
return ps.executeUpdate(); return ps.executeUpdate();
} catch (SQLException e) { } catch (SQLException e) {
throw new ORMException(e); throw new ORMException(e);
} }
} }
public static <E extends SQLElement<E>> int truncateTable(Class<E> elemClass) throws ORMException { public static <E extends SQLElement<E>> int truncateTable(Class<E> elemClass) throws ORMException {
try (Statement stmt = connection.getNativeConnection().createStatement()) { try (Statement stmt = connection.getNativeConnection().createStatement()) {
return stmt.executeUpdate("TRUNCATE `" + getTableName(elemClass) + "`"); return stmt.executeUpdate("TRUNCATE `" + getTableName(elemClass) + "`");
} catch(SQLException e) { } catch(SQLException e) {
throw new ORMException(e); throw new ORMException(e);
} }
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static <E extends SQLElement<E>> E getElementInstance(ResultSet set, Class<E> elemClass) throws ORMException { private static <E extends SQLElement<E>> E getElementInstance(ResultSet set, Class<E> elemClass) throws ORMException {
try { try {
E instance = elemClass.getConstructor(int.class).newInstance(set.getInt("id")); E instance = elemClass.getConstructor(int.class).newInstance(set.getInt("id"));
int fieldCount = set.getMetaData().getColumnCount(); int fieldCount = set.getMetaData().getColumnCount();
for (int c = 1; c <= fieldCount; c++) { for (int c = 1; c <= fieldCount; c++) {
String fieldName = set.getMetaData().getColumnLabel(c); String fieldName = set.getMetaData().getColumnLabel(c);
// ignore when field is present in database but not handled by SQLElement instance // ignore when field is present in database but not handled by SQLElement instance
if (!instance.getFields().containsKey(fieldName)) continue; if (!instance.getFields().containsKey(fieldName)) continue;
SQLField<E, Object> sqlField = (SQLField<E, Object>) instance.getFields().get(fieldName); SQLField<E, Object> sqlField = (SQLField<E, Object>) instance.getFields().get(fieldName);
boolean customType = sqlField.type instanceof SQLCustomType; boolean customType = sqlField.type instanceof SQLCustomType;
Object val = set.getObject(c, Object val = set.getObject(c,
(Class<?>)(customType ? ((SQLCustomType<?, ?>)sqlField.type).intermediateJavaType (Class<?>)(customType ? ((SQLCustomType<?, ?>)sqlField.type).intermediateJavaType
: sqlField.type.getJavaType())); : sqlField.type.getJavaType()));
if (val == null || set.wasNull()) { if (val == null || set.wasNull()) {
instance.set(sqlField, null, false); instance.set(sqlField, null, false);
} }
else { else {
if (customType) { if (customType) {
try { try {
val = ((SQLCustomType<Object, Object>)sqlField.type).dbToJavaConv.apply(val); val = ((SQLCustomType<Object, Object>)sqlField.type).dbToJavaConv.apply(val);
} catch (Exception e) { } catch (Exception e) {
throw new ORMException("Error while converting value of field '"+sqlField.getName()+"' with SQLCustomType from "+((SQLCustomType<Object, Object>)sqlField.type).intermediateJavaType throw new ORMException("Error while converting value of field '"+sqlField.getName()+"' with SQLCustomType from "+((SQLCustomType<Object, Object>)sqlField.type).intermediateJavaType
+"(jdbc source) to "+sqlField.type.getJavaType()+"(java destination). The original value is '"+val.toString()+"'", e); +"(jdbc source) to "+sqlField.type.getJavaType()+"(java destination). The original value is '"+val.toString()+"'", e);
} }
} }
instance.set(sqlField, val, false); instance.set(sqlField, val, false);
// la valeur venant de la BDD est marqué comme "non modifié" // la valeur venant de la BDD est marqué comme "non modifié"
// dans l'instance car le constructeur de l'instance met // dans l'instance car le constructeur de l'instance met
// tout les champs comme modifiés // tout les champs comme modifiés
instance.modifiedSinceLastSave.remove(sqlField.getName()); instance.modifiedSinceLastSave.remove(sqlField.getName());
} }
} }
if (!instance.isValidForSave()) throw new ORMException( if (!instance.isValidForSave()) throw new ORMException(
"This SQLElement representing a database entry is not valid for save : " + instance.toString()); "This SQLElement representing a database entry is not valid for save : " + instance.toString());
return instance; return instance;
} catch (ReflectiveOperationException | IllegalArgumentException | SecurityException | SQLException e) { } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException | SQLException e) {
throw new ORMException("Can't instanciate " + elemClass.getName(), e); throw new ORMException("Can't instanciate " + elemClass.getName(), e);
} }
} }
private ORM() {} // rend la classe non instanciable private ORM() {} // rend la classe non instanciable
} }

View File

@ -1,201 +1,201 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import fr.pandacube.util.Log; import fr.pandacube.util.Log;
/** /**
* *
* @param <E> * @param <E>
*/ */
public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> { public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Map<SQLField<E, ?>, Object> modifiedValues = new LinkedHashMap<>(); private final Map<SQLField<E, ?>, Object> modifiedValues = new LinkedHashMap<>();
@Override @Override
public synchronized boolean add(E e) { public synchronized boolean add(E e) {
if (e == null || !e.isStored()) return false; if (e == null || !e.isStored()) return false;
return super.add(e); return super.add(e);
} }
/** /**
* Défini une valeur à un champ qui sera appliquée dans la base de données à * Défini une valeur à un champ qui sera appliquée dans la base de données à
* tous les * tous les
* entrées présente dans cette liste lors de l'appel à {@link #saveCommon()} * entrées présente dans cette liste lors de l'appel à {@link #saveCommon()}
* . * .
* Les valeurs stockés dans chaque élément de cette liste ne seront affectés * Les valeurs stockés dans chaque élément de cette liste ne seront affectés
* que lors de * que lors de
* l'appel à {@link #saveCommon()} * l'appel à {@link #saveCommon()}
* *
* @param <T> * @param <T>
* @param field le champs à modifier * @param field le champs à modifier
* @param value la valeur à lui appliquer * @param value la valeur à lui appliquer
*/ */
public synchronized <T> void setCommon(SQLField<E, T> field, T value) { public synchronized <T> void setCommon(SQLField<E, T> field, T value) {
if (field == null) if (field == null)
throw new IllegalArgumentException("field can't be null"); throw new IllegalArgumentException("field can't be null");
if (field.getName() == "id") if (field.getName() == "id")
throw new IllegalArgumentException("Can't modify id field in a SQLElementList"); throw new IllegalArgumentException("Can't modify id field in a SQLElementList");
Class<E> elemClass = field.getSQLElementType(); Class<E> elemClass = field.getSQLElementType();
try { try {
E emptyElement = elemClass.getConstructor().newInstance(); E emptyElement = elemClass.getConstructor().newInstance();
emptyElement.set(field, value, false); emptyElement.set(field, value, false);
} catch (Exception e) { } catch (Exception e) {
throw new IllegalArgumentException("Illegal field or value or can't instanciante an empty instance of " throw new IllegalArgumentException("Illegal field or value or can't instanciante an empty instance of "
+ elemClass.getName() + ". (the instance is only created to test validity of field and value)", e); + elemClass.getName() + ". (the instance is only created to test validity of field and value)", e);
} }
// ici, la valeur est bonne // ici, la valeur est bonne
modifiedValues.put(field, value); modifiedValues.put(field, value);
} }
/** /**
* Applique toutes les valeurs défini avec * Applique toutes les valeurs défini avec
* {@link #setCommon(SQLField, Object)} à toutes * {@link #setCommon(SQLField, Object)} à toutes
* les entrées dans la base de données correspondants aux entrées de cette * les entrées dans la base de données correspondants aux entrées de cette
* liste. Les nouvelles * liste. Les nouvelles
* valeurs sont aussi mises à jour dans les objets contenus dans cette * valeurs sont aussi mises à jour dans les objets contenus dans cette
* liste, si la valeur n'a pas été modifiée individuellement avec * liste, si la valeur n'a pas été modifiée individuellement avec
* {@link SQLElement#set(SQLField, Object)}.<br/> * {@link SQLElement#set(SQLField, Object)}.<br/>
* Les objets de cette liste qui n'ont pas leur données en base de données * Les objets de cette liste qui n'ont pas leur données en base de données
* sont ignorées. * sont ignorées.
* *
* @throws SQLException * @throws SQLException
*/ */
public synchronized int saveCommon() throws ORMException { public synchronized int saveCommon() throws ORMException {
List<E> storedEl = getStoredEl(); List<E> storedEl = getStoredEl();
if (storedEl.isEmpty()) return 0; if (storedEl.isEmpty()) return 0;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Class<E> classEl = (Class<E>)storedEl.get(0).getClass(); Class<E> classEl = (Class<E>)storedEl.get(0).getClass();
int ret = ORM.update(classEl, int ret = ORM.update(classEl,
storedEl.get(0).getFieldId().in(storedEl.stream().map(SQLElement::getId).collect(Collectors.toList()) storedEl.get(0).getFieldId().in(storedEl.stream().map(SQLElement::getId).collect(Collectors.toList())
), ),
modifiedValues); modifiedValues);
applyNewValuesToElements(storedEl); applyNewValuesToElements(storedEl);
return ret; return ret;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void applyNewValuesToElements(List<E> storedEl) { private void applyNewValuesToElements(List<E> storedEl) {
// applique les valeurs dans chaques objets de la liste // applique les valeurs dans chaques objets de la liste
for (E el : storedEl) for (E el : storedEl)
for (@SuppressWarnings("rawtypes") for (@SuppressWarnings("rawtypes")
SQLField entry : modifiedValues.keySet()) SQLField entry : modifiedValues.keySet())
if (!el.isModified(entry)) el.set(entry, modifiedValues.get(entry), false); if (!el.isModified(entry)) el.set(entry, modifiedValues.get(entry), false);
} }
private List<E> getStoredEl() { private List<E> getStoredEl() {
return stream().filter(SQLElement::isStored).collect(Collectors.toCollection(() -> new ArrayList<>())); return stream().filter(SQLElement::isStored).collect(Collectors.toCollection(() -> new ArrayList<>()));
} }
/** /**
* @deprecated please use {@link ORM#delete(Class, SQLWhere)} instead, * @deprecated please use {@link ORM#delete(Class, SQLWhere)} instead,
* except if you really want to fetch the data before removing them from database. * except if you really want to fetch the data before removing them from database.
*/ */
@Deprecated @Deprecated
public synchronized void removeFromDB() { public synchronized void removeFromDB() {
List<E> storedEl = getStoredEl(); List<E> storedEl = getStoredEl();
if (storedEl.isEmpty()) return; if (storedEl.isEmpty()) return;
try { try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Class<E> classEl = (Class<E>)storedEl.get(0).getClass(); Class<E> classEl = (Class<E>)storedEl.get(0).getClass();
ORM.delete(classEl, ORM.delete(classEl,
storedEl.get(0).getFieldId().in(storedEl.stream().map(SQLElement::getId).collect(Collectors.toList())) storedEl.get(0).getFieldId().in(storedEl.stream().map(SQLElement::getId).collect(Collectors.toList()))
); );
for (E el : storedEl) for (E el : storedEl)
el.markAsNotStored(); el.markAsNotStored();
} catch (ORMException e) { } catch (ORMException e) {
Log.severe(e); Log.severe(e);
} }
} }
public <T, P extends SQLElement<P>> SQLElementList<P> getReferencedEntries(SQLFKField<E, T, P> foreignKey, SQLOrderBy<P> orderBy) throws ORMException { public <T, P extends SQLElement<P>> SQLElementList<P> getReferencedEntries(SQLFKField<E, T, P> foreignKey, SQLOrderBy<P> orderBy) throws ORMException {
Set<T> values = new HashSet<>(); Set<T> values = new HashSet<>();
forEach(v -> { forEach(v -> {
T val = v.get(foreignKey); T val = v.get(foreignKey);
if (val != null) if (val != null)
values.add(val); values.add(val);
}); });
if (values.isEmpty()) { if (values.isEmpty()) {
return new SQLElementList<>(); return new SQLElementList<>();
} }
return ORM.getAll(foreignKey.getForeignElementClass(), foreignKey.getPrimaryField().in(values), orderBy, null, null); return ORM.getAll(foreignKey.getForeignElementClass(), foreignKey.getPrimaryField().in(values), orderBy, null, null);
} }
public <T, P extends SQLElement<P>> Map<T, P> getReferencedEntriesInGroups(SQLFKField<E, T, P> foreignKey) throws ORMException { public <T, P extends SQLElement<P>> Map<T, P> getReferencedEntriesInGroups(SQLFKField<E, T, P> foreignKey) throws ORMException {
SQLElementList<P> foreignElemts = getReferencedEntries(foreignKey, null); SQLElementList<P> foreignElemts = getReferencedEntries(foreignKey, null);
Map<T, P> ret = new HashMap<>(); Map<T, P> ret = new HashMap<>();
foreignElemts.forEach(foreignVal -> ret.put(foreignVal.get(foreignKey.getPrimaryField()), foreignVal)); foreignElemts.forEach(foreignVal -> ret.put(foreignVal.get(foreignKey.getPrimaryField()), foreignVal));
return ret; return ret;
} }
public <T, F extends SQLElement<F>> SQLElementList<F> getReferencingForeignEntries(SQLFKField<F, T, E> foreignKey, SQLOrderBy<F> orderBy, Integer limit, Integer offset) throws ORMException { public <T, F extends SQLElement<F>> SQLElementList<F> getReferencingForeignEntries(SQLFKField<F, T, E> foreignKey, SQLOrderBy<F> orderBy, Integer limit, Integer offset) throws ORMException {
Set<T> values = new HashSet<>(); Set<T> values = new HashSet<>();
forEach(v -> { forEach(v -> {
T val = v.get(foreignKey.getPrimaryField()); T val = v.get(foreignKey.getPrimaryField());
if (val != null) if (val != null)
values.add(val); values.add(val);
}); });
if (values.isEmpty()) { if (values.isEmpty()) {
return new SQLElementList<>(); return new SQLElementList<>();
} }
return ORM.getAll(foreignKey.getSQLElementType(), foreignKey.in(values), orderBy, limit, offset); return ORM.getAll(foreignKey.getSQLElementType(), foreignKey.in(values), orderBy, limit, offset);
} }
public <T, F extends SQLElement<F>> Map<T, SQLElementList<F>> getReferencingForeignEntriesInGroups(SQLFKField<F, T, E> foreignKey, SQLOrderBy<F> orderBy, Integer limit, Integer offset) throws ORMException { public <T, F extends SQLElement<F>> Map<T, SQLElementList<F>> getReferencingForeignEntriesInGroups(SQLFKField<F, T, E> foreignKey, SQLOrderBy<F> orderBy, Integer limit, Integer offset) throws ORMException {
SQLElementList<F> foreignElements = getReferencingForeignEntries(foreignKey, orderBy, limit, offset); SQLElementList<F> foreignElements = getReferencingForeignEntries(foreignKey, orderBy, limit, offset);
Map<T, SQLElementList<F>> map = new HashMap<>(); Map<T, SQLElementList<F>> map = new HashMap<>();
foreignElements.forEach(foreignVal -> { foreignElements.forEach(foreignVal -> {
SQLElementList<F> subList = map.getOrDefault(foreignVal.get(foreignKey), new SQLElementList<>()); SQLElementList<F> subList = map.getOrDefault(foreignVal.get(foreignKey), new SQLElementList<>());
subList.add(foreignVal); subList.add(foreignVal);
map.put(foreignVal.get(foreignKey), subList); map.put(foreignVal.get(foreignKey), subList);
}); });
return map; return map;
} }
public JsonArray asJsonArray() { public JsonArray asJsonArray() {
JsonArray json = new JsonArray(); JsonArray json = new JsonArray();
forEach(el -> json.add(el.asJsonObject())); forEach(el -> json.add(el.asJsonObject()));
return json; return json;
} }
} }

View File

@ -1,69 +1,69 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import fr.pandacube.util.Log; import fr.pandacube.util.Log;
/** /**
* *
* @author Marc * @author Marc
* *
* @param <F> the table class of this current foreign key field * @param <F> the table class of this current foreign key field
* @param <T> the Java type of this field * @param <T> the Java type of this field
* @param <P> the table class of the targeted primary key * @param <P> the table class of the targeted primary key
*/ */
public class SQLFKField<F extends SQLElement<F>, T, P extends SQLElement<P>> extends SQLField<F, T> { public class SQLFKField<F extends SQLElement<F>, T, P extends SQLElement<P>> extends SQLField<F, T> {
private SQLField<P, T> sqlPrimaryKeyField; private SQLField<P, T> sqlPrimaryKeyField;
private Class<P> sqlForeignKeyElemClass; private Class<P> sqlForeignKeyElemClass;
protected SQLFKField(SQLType<T> t, boolean nul, T deflt, Class<P> fkEl, SQLField<P, T> fkF) { protected SQLFKField(SQLType<T> t, boolean nul, T deflt, Class<P> fkEl, SQLField<P, T> fkF) {
super(t, nul, deflt); super(t, nul, deflt);
construct(fkEl, fkF); construct(fkEl, fkF);
} }
/* package */ static <E extends SQLElement<E>, F extends SQLElement<F>> SQLFKField<E, Integer, F> idFK(boolean nul, Class<F> fkEl) { /* package */ static <E extends SQLElement<E>, F extends SQLElement<F>> SQLFKField<E, Integer, F> idFK(boolean nul, Class<F> fkEl) {
return idFK(nul, null, fkEl); return idFK(nul, null, fkEl);
} }
/* package */ static <E extends SQLElement<E>, F extends SQLElement<F>> SQLFKField<E, Integer, F> idFK(boolean nul, Integer deflt, Class<F> fkEl) { /* package */ static <E extends SQLElement<E>, F extends SQLElement<F>> SQLFKField<E, Integer, F> idFK(boolean nul, Integer deflt, Class<F> fkEl) {
if (fkEl == null) throw new IllegalArgumentException("foreignKeyElement can't be null"); if (fkEl == null) throw new IllegalArgumentException("foreignKeyElement can't be null");
try { try {
SQLField<F, Integer> f = ORM.getSQLIdField(fkEl); SQLField<F, Integer> f = ORM.getSQLIdField(fkEl);
return new SQLFKField<>(f.type, nul, deflt, fkEl, f); return new SQLFKField<>(f.type, nul, deflt, fkEl, f);
} catch (ORMInitTableException e) { } catch (ORMInitTableException e) {
Log.severe("Can't create Foreign key Field targetting id field of '"+fkEl+"'", e); Log.severe("Can't create Foreign key Field targetting id field of '"+fkEl+"'", e);
return null; return null;
} }
} }
/* package */ static <E extends SQLElement<E>, T, F extends SQLElement<F>> SQLFKField<E, T, F> customFK(boolean nul, Class<F> fkEl, SQLField<F, T> fkF) { /* package */ static <E extends SQLElement<E>, T, F extends SQLElement<F>> SQLFKField<E, T, F> customFK(boolean nul, Class<F> fkEl, SQLField<F, T> fkF) {
return customFK(nul, null, fkEl, fkF); return customFK(nul, null, fkEl, fkF);
} }
/* package */ static <E extends SQLElement<E>, T, F extends SQLElement<F>> SQLFKField<E, T, F> customFK(boolean nul, T deflt, Class<F> fkEl, SQLField<F, T> fkF) { /* package */ static <E extends SQLElement<E>, T, F extends SQLElement<F>> SQLFKField<E, T, F> customFK(boolean nul, T deflt, Class<F> fkEl, SQLField<F, T> fkF) {
if (fkEl == null) throw new IllegalArgumentException("foreignKeyElement can't be null"); if (fkEl == null) throw new IllegalArgumentException("foreignKeyElement can't be null");
return new SQLFKField<>(fkF.type, nul, deflt, fkEl, fkF); return new SQLFKField<>(fkF.type, nul, deflt, fkEl, fkF);
} }
private void construct(Class<P> fkEl, SQLField<P, T> fkF) { private void construct(Class<P> fkEl, SQLField<P, T> fkF) {
if (fkF == null) throw new IllegalArgumentException("foreignKeyField can't be null"); if (fkF == null) throw new IllegalArgumentException("foreignKeyField can't be null");
try { try {
ORM.initTable(fkEl); ORM.initTable(fkEl);
} catch (ORMInitTableException e) { } catch (ORMInitTableException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if (fkF.getSQLElementType() == null) if (fkF.getSQLElementType() == null)
throw new RuntimeException("Can't initialize foreign key. The primary key in the table " + fkEl.getName() + " is not properly initialized and can't be targetted by a forein key"); throw new RuntimeException("Can't initialize foreign key. The primary key in the table " + fkEl.getName() + " is not properly initialized and can't be targetted by a forein key");
sqlPrimaryKeyField = fkF; sqlPrimaryKeyField = fkF;
sqlForeignKeyElemClass = fkEl; sqlForeignKeyElemClass = fkEl;
} }
public SQLField<P, T> getPrimaryField() { public SQLField<P, T> getPrimaryField() {
return sqlPrimaryKeyField; return sqlPrimaryKeyField;
} }
public Class<P> getForeignElementClass() { public Class<P> getForeignElementClass() {
return sqlForeignKeyElemClass; return sqlForeignKeyElemClass;
} }
} }

View File

@ -1,141 +1,141 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.javatuples.Pair; import org.javatuples.Pair;
import fr.pandacube.util.orm.SQLWhereComp.SQLComparator; import fr.pandacube.util.orm.SQLWhereComp.SQLComparator;
public class SQLField<E extends SQLElement<E>, T> { public class SQLField<E extends SQLElement<E>, T> {
private Class<E> sqlElemClass; private Class<E> sqlElemClass;
private String name = null; private String name = null;
public final SQLType<T> type; public final SQLType<T> type;
public final boolean canBeNull; public final boolean canBeNull;
public final boolean autoIncrement; public final boolean autoIncrement;
/* package */ final T defaultValue; /* package */ final T defaultValue;
/* package */ SQLField(SQLType<T> t, boolean nul, boolean autoIncr, T deflt) { /* package */ SQLField(SQLType<T> t, boolean nul, boolean autoIncr, T deflt) {
type = t; type = t;
canBeNull = nul; canBeNull = nul;
autoIncrement = autoIncr; autoIncrement = autoIncr;
defaultValue = deflt; defaultValue = deflt;
} }
/* package */ SQLField(SQLType<T> t, boolean nul) { /* package */ SQLField(SQLType<T> t, boolean nul) {
this(t, nul, false, null); this(t, nul, false, null);
} }
/* package */ SQLField(SQLType<T> t, boolean nul, boolean autoIncr) { /* package */ SQLField(SQLType<T> t, boolean nul, boolean autoIncr) {
this(t, nul, autoIncr, null); this(t, nul, autoIncr, null);
} }
/* package */ SQLField(SQLType<T> t, boolean nul, T deflt) { /* package */ SQLField(SQLType<T> t, boolean nul, T deflt) {
this(t, nul, false, deflt); this(t, nul, false, deflt);
} }
/* package */ Pair<String, List<Object>> forSQLPreparedStatement() { /* package */ Pair<String, List<Object>> forSQLPreparedStatement() {
List<Object> params = new ArrayList<>(1); List<Object> params = new ArrayList<>(1);
if (defaultValue != null && !autoIncrement) params.add(defaultValue); if (defaultValue != null && !autoIncrement) params.add(defaultValue);
return new Pair<>("`" + getName() + "` " + type.toString() + (canBeNull ? " NULL" : " NOT NULL") return new Pair<>("`" + getName() + "` " + type.toString() + (canBeNull ? " NULL" : " NOT NULL")
+ (autoIncrement ? " AUTO_INCREMENT" : "") + (autoIncrement ? " AUTO_INCREMENT" : "")
+ ((defaultValue == null || autoIncrement) ? "" : " DEFAULT ?"), params); + ((defaultValue == null || autoIncrement) ? "" : " DEFAULT ?"), params);
} }
/* package */ void setSQLElementType(Class<E> elemClass) { /* package */ void setSQLElementType(Class<E> elemClass) {
sqlElemClass = elemClass; sqlElemClass = elemClass;
} }
public Class<E> getSQLElementType() { public Class<E> getSQLElementType() {
return sqlElemClass; return sqlElemClass;
} }
/* package */ void setName(String n) { /* package */ void setName(String n) {
name = n; name = n;
} }
public String getName() { public String getName() {
return name; return name;
} }
/** /**
* <b>Don't use this {@link #toString()} method in a SQL query, because * <b>Don't use this {@link #toString()} method in a SQL query, because
* the default value is not escaped correctly</b> * the default value is not escaped correctly</b>
* *
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */
@Override @Override
public String toString() { public String toString() {
return forSQLPreparedStatement().getValue0().replaceFirst("\\?", return forSQLPreparedStatement().getValue0().replaceFirst("\\?",
(defaultValue != null && !autoIncrement) ? defaultValue.toString() : ""); (defaultValue != null && !autoIncrement) ? defaultValue.toString() : "");
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null) return false; if (obj == null) return false;
if (!(obj instanceof SQLField)) return false; if (!(obj instanceof SQLField)) return false;
SQLField<?, ?> f = (SQLField<?, ?>) obj; SQLField<?, ?> f = (SQLField<?, ?>) obj;
if (!f.getName().equals(getName())) return false; if (!f.getName().equals(getName())) return false;
if (!f.sqlElemClass.equals(sqlElemClass)) return false; if (!f.sqlElemClass.equals(sqlElemClass)) return false;
return true; return true;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return getName().hashCode() + sqlElemClass.hashCode(); return getName().hashCode() + sqlElemClass.hashCode();
} }
public SQLWhere<E> eq(T r) { public SQLWhere<E> eq(T r) {
return comp(SQLComparator.EQ, r); return comp(SQLComparator.EQ, r);
} }
public SQLWhere<E> geq(T r) { public SQLWhere<E> geq(T r) {
return comp(SQLComparator.GEQ, r); return comp(SQLComparator.GEQ, r);
} }
public SQLWhere<E> gt(T r) { public SQLWhere<E> gt(T r) {
return comp(SQLComparator.GT, r); return comp(SQLComparator.GT, r);
} }
public SQLWhere<E> leq(T r) { public SQLWhere<E> leq(T r) {
return comp(SQLComparator.LEQ, r); return comp(SQLComparator.LEQ, r);
} }
public SQLWhere<E> lt(T r) { public SQLWhere<E> lt(T r) {
return comp(SQLComparator.LT, r); return comp(SQLComparator.LT, r);
} }
public SQLWhere<E> neq(T r) { public SQLWhere<E> neq(T r) {
return comp(SQLComparator.NEQ, r); return comp(SQLComparator.NEQ, r);
} }
private SQLWhere<E> comp(SQLComparator c, T r) { private SQLWhere<E> comp(SQLComparator c, T r) {
if (r == null) if (r == null)
throw new IllegalArgumentException("The value cannot be null. Use SQLField#isNull(value) or SQLField#isNotNull(value) to check for null values"); throw new IllegalArgumentException("The value cannot be null. Use SQLField#isNull(value) or SQLField#isNotNull(value) to check for null values");
return new SQLWhereComp<>(this, c, r); return new SQLWhereComp<>(this, c, r);
} }
public SQLWhere<E> like(String like) { public SQLWhere<E> like(String like) {
return new SQLWhereLike<>(this, like); return new SQLWhereLike<>(this, like);
} }
public SQLWhere<E> in(Collection<T> v) { public SQLWhere<E> in(Collection<T> v) {
return new SQLWhereIn<>(this, v); return new SQLWhereIn<>(this, v);
} }
public SQLWhere<E> isNull() { public SQLWhere<E> isNull() {
return new SQLWhereNull<>(this, true); return new SQLWhereNull<>(this, true);
} }
public SQLWhere<E> isNotNull() { public SQLWhere<E> isNotNull() {
return new SQLWhereNull<>(this, false); return new SQLWhereNull<>(this, false);
} }
} }

View File

@ -1,97 +1,97 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class SQLOrderBy<E extends SQLElement<E>> { public class SQLOrderBy<E extends SQLElement<E>> {
private List<OBField> orderByFields = new ArrayList<>(); private List<OBField> orderByFields = new ArrayList<>();
/** /**
* Construit une nouvelle clause ORDER BY * Construit une nouvelle clause ORDER BY
*/ */
private SQLOrderBy() {} private SQLOrderBy() {}
/** /**
* Ajoute un champ dans la clause ORDER BY en construction * Ajoute un champ dans la clause ORDER BY en construction
* *
* @param field le champ SQL à ordonner * @param field le champ SQL à ordonner
* @param d le sens de tri (croissant ASC ou décroissant DESC) * @param d le sens de tri (croissant ASC ou décroissant DESC)
* @return l'objet courant (permet de chainer les ajouts de champs) * @return l'objet courant (permet de chainer les ajouts de champs)
*/ */
private SQLOrderBy<E> add(SQLField<E, ?> field, Direction d) { private SQLOrderBy<E> add(SQLField<E, ?> field, Direction d) {
orderByFields.add(new OBField(field, d)); orderByFields.add(new OBField(field, d));
return this; return this;
} }
/** /**
* Ajoute un champ dans la clause ORDER BY en construction avec pour direction ASC * Ajoute un champ dans la clause ORDER BY en construction avec pour direction ASC
* *
* @param field le champ SQL à ordonner * @param field le champ SQL à ordonner
* @return l'objet courant (permet de chainer les ajouts de champs) * @return l'objet courant (permet de chainer les ajouts de champs)
*/ */
public SQLOrderBy<E> thenAsc(SQLField<E, ?> field) { public SQLOrderBy<E> thenAsc(SQLField<E, ?> field) {
return add(field, Direction.ASC); return add(field, Direction.ASC);
} }
/** /**
* Ajoute un champ dans la clause ORDER BY en construction avec pour direction DESC * Ajoute un champ dans la clause ORDER BY en construction avec pour direction DESC
* *
* @param field le champ SQL à ordonner * @param field le champ SQL à ordonner
* @return l'objet courant (permet de chainer les ajouts de champs) * @return l'objet courant (permet de chainer les ajouts de champs)
*/ */
public SQLOrderBy<E> thenDesc(SQLField<E, ?> field) { public SQLOrderBy<E> thenDesc(SQLField<E, ?> field) {
return add(field, Direction.DESC); return add(field, Direction.DESC);
} }
/* package */ String toSQL() { /* package */ String toSQL() {
String ret = ""; String ret = "";
boolean first = true; boolean first = true;
for (OBField f : orderByFields) { for (OBField f : orderByFields) {
if (!first) ret += ", "; if (!first) ret += ", ";
first = false; first = false;
ret += "`" + f.field.getName() + "` " + f.direction.name(); ret += "`" + f.field.getName() + "` " + f.direction.name();
} }
return ret; return ret;
} }
@Override @Override
public String toString() { public String toString() {
return toSQL(); return toSQL();
} }
private class OBField { private class OBField {
public final SQLField<E, ?> field; public final SQLField<E, ?> field;
public final Direction direction; public final Direction direction;
public OBField(SQLField<E, ?> f, Direction d) { public OBField(SQLField<E, ?> f, Direction d) {
field = f; field = f;
direction = d; direction = d;
} }
} }
private enum Direction { private enum Direction {
ASC, DESC; ASC, DESC;
} }
public static <E extends SQLElement<E>> SQLOrderBy<E> asc(SQLField<E, ?> field) { public static <E extends SQLElement<E>> SQLOrderBy<E> asc(SQLField<E, ?> field) {
return new SQLOrderBy<E>().thenAsc(field); return new SQLOrderBy<E>().thenAsc(field);
} }
public static <E extends SQLElement<E>> SQLOrderBy<E> desc(SQLField<E, ?> field) { public static <E extends SQLElement<E>> SQLOrderBy<E> desc(SQLField<E, ?> field) {
return new SQLOrderBy<E>().thenDesc(field); return new SQLOrderBy<E>().thenDesc(field);
} }
} }

View File

@ -1,39 +1,39 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
public class SQLType<T> { public class SQLType<T> {
protected final String sqlDeclaration; protected final String sqlDeclaration;
private final Class<T> javaTypes; private final Class<T> javaTypes;
/* package */ SQLType(String sqlD, Class<T> javaT) { /* package */ SQLType(String sqlD, Class<T> javaT) {
sqlDeclaration = sqlD; sqlDeclaration = sqlD;
javaTypes = javaT; javaTypes = javaT;
} }
@Override @Override
public String toString() { public String toString() {
return sqlDeclaration; return sqlDeclaration;
} }
public boolean isAssignableFrom(Object val) { public boolean isAssignableFrom(Object val) {
if (javaTypes.isInstance(val)) return true; if (javaTypes.isInstance(val)) return true;
return false; return false;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return toString().hashCode(); return toString().hashCode();
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null || !(obj instanceof SQLType)) return false; if (obj == null || !(obj instanceof SQLType)) return false;
return toString().equals(((SQLType<?>) obj).toString()); return toString().equals(((SQLType<?>) obj).toString());
} }
public Class<T> getJavaType() { public Class<T> getJavaType() {
return javaTypes; return javaTypes;
} }
} }

View File

@ -1,43 +1,43 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import java.util.List; import java.util.List;
import org.javatuples.Pair; import org.javatuples.Pair;
import fr.pandacube.util.Log; import fr.pandacube.util.Log;
public abstract class SQLWhere<E extends SQLElement<E>> { public abstract class SQLWhere<E extends SQLElement<E>> {
public abstract Pair<String, List<Object>> toSQL() throws ORMException; public abstract Pair<String, List<Object>> toSQL() throws ORMException;
@Override @Override
public String toString() { public String toString() {
try { try {
return toSQL().getValue0(); return toSQL().getValue0();
} catch (ORMException e) { } catch (ORMException e) {
Log.warning(e); Log.warning(e);
return "[SQLWhere.toString() error (see logs)]"; return "[SQLWhere.toString() error (see logs)]";
} }
} }
public SQLWhereAnd<E> and(SQLWhere<E> other) { public SQLWhereAnd<E> and(SQLWhere<E> other) {
return new SQLWhereAnd<E>().and(this).and(other); return new SQLWhereAnd<E>().and(this).and(other);
} }
public SQLWhereOr<E> or(SQLWhere<E> other) { public SQLWhereOr<E> or(SQLWhere<E> other) {
return new SQLWhereOr<E>().or(this).or(other); return new SQLWhereOr<E>().or(this).or(other);
} }
public static <E extends SQLElement<E>> SQLWhereAnd<E> and() { public static <E extends SQLElement<E>> SQLWhereAnd<E> and() {
return new SQLWhereAnd<>(); return new SQLWhereAnd<>();
} }
public static <E extends SQLElement<E>> SQLWhereOr<E> or() { public static <E extends SQLElement<E>> SQLWhereOr<E> or() {
return new SQLWhereOr<>(); return new SQLWhereOr<>();
} }
public static String escapeLike(String str) { public static String escapeLike(String str) {
return str.replace("\\", "\\\\").replace("_", "\\_").replace("%", "\\%"); return str.replace("\\", "\\\\").replace("_", "\\_").replace("%", "\\%");
} }
} }

View File

@ -1,58 +1,58 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.javatuples.Pair; import org.javatuples.Pair;
public abstract class SQLWhereChain<E extends SQLElement<E>> extends SQLWhere<E> { public abstract class SQLWhereChain<E extends SQLElement<E>> extends SQLWhere<E> {
private SQLBoolOp operator; private SQLBoolOp operator;
protected List<SQLWhere<E>> conditions = new ArrayList<>(); protected List<SQLWhere<E>> conditions = new ArrayList<>();
/* package */ SQLWhereChain(SQLBoolOp op) { /* package */ SQLWhereChain(SQLBoolOp op) {
if (op == null) throw new IllegalArgumentException("op can't be null"); if (op == null) throw new IllegalArgumentException("op can't be null");
operator = op; operator = op;
} }
protected void add(SQLWhere<E> sqlWhere) { protected void add(SQLWhere<E> sqlWhere) {
if (sqlWhere == null) throw new IllegalArgumentException("sqlWhere can't be null"); if (sqlWhere == null) throw new IllegalArgumentException("sqlWhere can't be null");
conditions.add(sqlWhere); conditions.add(sqlWhere);
} }
@Override @Override
public Pair<String, List<Object>> toSQL() throws ORMException { public Pair<String, List<Object>> toSQL() throws ORMException {
if (conditions.isEmpty()) { if (conditions.isEmpty()) {
throw new ORMException("SQLWhereChain needs at least one element inside !"); throw new ORMException("SQLWhereChain needs at least one element inside !");
} }
String sql = ""; String sql = "";
List<Object> params = new ArrayList<>(); List<Object> params = new ArrayList<>();
boolean first = true; boolean first = true;
for (SQLWhere<E> w : conditions) { for (SQLWhere<E> w : conditions) {
if (!first) sql += " " + operator.sql + " "; if (!first) sql += " " + operator.sql + " ";
first = false; first = false;
Pair<String, List<Object>> ret = w.toSQL(); Pair<String, List<Object>> ret = w.toSQL();
sql += "(" + ret.getValue0() + ")"; sql += "(" + ret.getValue0() + ")";
params.addAll(ret.getValue1()); params.addAll(ret.getValue1());
} }
return new Pair<>(sql, params); return new Pair<>(sql, params);
} }
/* package */ enum SQLBoolOp { /* package */ enum SQLBoolOp {
/** Equivalent to SQL "<code>AND</code>" */ /** Equivalent to SQL "<code>AND</code>" */
AND("AND"), AND("AND"),
/** Equivalent to SQL "<code>OR</code>" */ /** Equivalent to SQL "<code>OR</code>" */
OR("OR"); OR("OR");
/* package */ final String sql; /* package */ final String sql;
private SQLBoolOp(String s) { private SQLBoolOp(String s) {
sql = s; sql = s;
} }
} }
} }

View File

@ -1,58 +1,58 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.javatuples.Pair; import org.javatuples.Pair;
/* package */ class SQLWhereComp<E extends SQLElement<E>> extends SQLWhere<E> { /* package */ class SQLWhereComp<E extends SQLElement<E>> extends SQLWhere<E> {
private SQLField<E, ?> left; private SQLField<E, ?> left;
private SQLComparator comp; private SQLComparator comp;
private Object right; private Object right;
/** /**
* Compare a field with a value * Compare a field with a value
* *
* @param l the field at left of the comparison operator. Can't be null * @param l the field at left of the comparison operator. Can't be null
* @param c the comparison operator, can't be null * @param c the comparison operator, can't be null
* @param r the value at right of the comparison operator. Can't be null * @param r the value at right of the comparison operator. Can't be null
*/ */
/* package */ <T> SQLWhereComp(SQLField<E, T> l, SQLComparator c, T r) { /* package */ <T> SQLWhereComp(SQLField<E, T> l, SQLComparator c, T r) {
if (l == null || r == null || c == null) if (l == null || r == null || c == null)
throw new IllegalArgumentException("All arguments for SQLWhereComp constructor can't be null"); throw new IllegalArgumentException("All arguments for SQLWhereComp constructor can't be null");
left = l; left = l;
comp = c; comp = c;
right = r; right = r;
} }
@Override @Override
public Pair<String, List<Object>> toSQL() throws ORMException { public Pair<String, List<Object>> toSQL() throws ORMException {
List<Object> params = new ArrayList<>(); List<Object> params = new ArrayList<>();
SQLElement.addValueToSQLObjectList(params, left, right); SQLElement.addValueToSQLObjectList(params, left, right);
return new Pair<>("`" + left.getName() + "` " + comp.sql + " ? ", params); return new Pair<>("`" + left.getName() + "` " + comp.sql + " ? ", params);
} }
/* package */ enum SQLComparator { /* package */ enum SQLComparator {
/** Equivalent to SQL "<code>=</code>" */ /** Equivalent to SQL "<code>=</code>" */
EQ("="), EQ("="),
/** Equivalent to SQL "<code>></code>" */ /** Equivalent to SQL "<code>></code>" */
GT(">"), GT(">"),
/** Equivalent to SQL "<code>>=</code>" */ /** Equivalent to SQL "<code>>=</code>" */
GEQ(">="), GEQ(">="),
/** Equivalent to SQL "<code>&lt;</code>" */ /** Equivalent to SQL "<code>&lt;</code>" */
LT("<"), LT("<"),
/** Equivalent to SQL "<code>&lt;=</code>" */ /** Equivalent to SQL "<code>&lt;=</code>" */
LEQ("<="), LEQ("<="),
/** Equivalent to SQL "<code>!=</code>" */ /** Equivalent to SQL "<code>!=</code>" */
NEQ("!="); NEQ("!=");
/* package */ final String sql; /* package */ final String sql;
private SQLComparator(String s) { private SQLComparator(String s) {
sql = s; sql = s;
} }
} }
} }

View File

@ -1,33 +1,33 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.javatuples.Pair; import org.javatuples.Pair;
/* package */ class SQLWhereLike<E extends SQLElement<E>> extends SQLWhere<E> { /* package */ class SQLWhereLike<E extends SQLElement<E>> extends SQLWhere<E> {
private SQLField<E, ?> field; private SQLField<E, ?> field;
private String likeExpr; private String likeExpr;
/** /**
* Compare a field with a value * Compare a field with a value
* *
* @param f the field at left of the LIKE keyword. Can't be null * @param f the field at left of the LIKE keyword. Can't be null
* @param like the like expression. * @param like the like expression.
*/ */
/* package */ SQLWhereLike(SQLField<E, ?> f, String like) { /* package */ SQLWhereLike(SQLField<E, ?> f, String like) {
if (f == null || like == null) if (f == null || like == null)
throw new IllegalArgumentException("All arguments for SQLWhereLike constructor can't be null"); throw new IllegalArgumentException("All arguments for SQLWhereLike constructor can't be null");
field = f; field = f;
likeExpr = like; likeExpr = like;
} }
@Override @Override
public Pair<String, List<Object>> toSQL() { public Pair<String, List<Object>> toSQL() {
ArrayList<Object> params = new ArrayList<>(); ArrayList<Object> params = new ArrayList<>();
params.add(likeExpr); params.add(likeExpr);
return new Pair<>("`" + field.getName() + "` LIKE ? ", params); return new Pair<>("`" + field.getName() + "` LIKE ? ", params);
} }
} }

View File

@ -1,37 +1,37 @@
package fr.pandacube.util.orm; package fr.pandacube.util.orm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.javatuples.Pair; import org.javatuples.Pair;
import fr.pandacube.util.Log; import fr.pandacube.util.Log;
/* package */ class SQLWhereNull<E extends SQLElement<E>> extends SQLWhere<E> { /* package */ class SQLWhereNull<E extends SQLElement<E>> extends SQLWhere<E> {
private SQLField<E, ?> fild; private SQLField<E, ?> fild;
private boolean nulll; private boolean nulll;
/** /**
* Init a IS NULL / IS NOT NULL expression for a SQL WHERE condition. * Init a IS NULL / IS NOT NULL expression for a SQL WHERE condition.
* *
* @param field the field to check null / not null state * @param field the field to check null / not null state
* @param isNull true if we want to ckeck if "IS NULL", or false to check if * @param isNull true if we want to ckeck if "IS NULL", or false to check if
* "IS NOT NULL" * "IS NOT NULL"
*/ */
/* package */ SQLWhereNull(SQLField<E, ?> field, boolean isNull) { /* package */ SQLWhereNull(SQLField<E, ?> field, boolean isNull) {
if (field == null) throw new IllegalArgumentException("field can't be null"); if (field == null) throw new IllegalArgumentException("field can't be null");
if (!field.canBeNull) Log.getLogger().log(Level.WARNING, if (!field.canBeNull) Log.getLogger().log(Level.WARNING,
"Useless : Trying to check IS [NOT] NULL on the field " + field.getSQLElementType().getName() + "#" "Useless : Trying to check IS [NOT] NULL on the field " + field.getSQLElementType().getName() + "#"
+ field.getName() + " which is declared in the ORM as 'can't be null'"); + field.getName() + " which is declared in the ORM as 'can't be null'");
fild = field; fild = field;
nulll = isNull; nulll = isNull;
} }
@Override @Override
public Pair<String, List<Object>> toSQL() { public Pair<String, List<Object>> toSQL() {
return new Pair<>("`" + fild.getName() + "` IS " + ((nulll) ? "NULL" : "NOT NULL"), new ArrayList<>()); return new Pair<>("`" + fild.getName() + "` IS " + ((nulll) ? "NULL" : "NOT NULL"), new ArrayList<>());
} }
} }