Some ORM refactoring
This commit is contained in:
parent
ccaf9bf26c
commit
ea9bfd1270
@ -6,7 +6,9 @@ import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.javatuples.Pair;
|
||||
@ -24,6 +26,7 @@ import fr.pandacube.util.orm.SQLWhereComp.SQLComparator;
|
||||
public final class ORM {
|
||||
|
||||
private static List<Class<? extends SQLElement<?>>> tables = new ArrayList<>();
|
||||
private static Map<Class<? extends SQLElement<?>>, String> tableNames = new HashMap<>();
|
||||
|
||||
private static DBConnection connection;
|
||||
|
||||
@ -45,7 +48,8 @@ public final class ORM {
|
||||
Log.debug("[ORM] Start Init SQL table "+elemClass.getSimpleName());
|
||||
E instance = elemClass.newInstance();
|
||||
String tableName = instance.tableName();
|
||||
if (!tableExist(tableName)) createTable(instance);
|
||||
tableNames.put(elemClass, tableName);
|
||||
if (!tableExistInDB(tableName)) createTable(instance);
|
||||
Log.debug("[ORM] End init SQL table "+elemClass.getSimpleName());
|
||||
} catch (Exception|ExceptionInInitializerError e) {
|
||||
throw new ORMInitTableException(elemClass, e);
|
||||
@ -78,8 +82,13 @@ public final class ORM {
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public static <E extends SQLElement<E>> String getTableName(Class<E> elemClass) throws ORMException {
|
||||
initTable(elemClass);
|
||||
return tableNames.get(elemClass);
|
||||
}
|
||||
|
||||
private static boolean tableExist(String tableName) throws SQLException {
|
||||
private static boolean tableExistInDB(String tableName) throws SQLException {
|
||||
boolean exist = false;
|
||||
try (ResultSet set = connection.getNativeConnection().getMetaData().getTables(null, null, tableName, null)) {
|
||||
exist = set.next();
|
||||
@ -176,7 +185,7 @@ public final class ORM {
|
||||
initTable(elemClass);
|
||||
|
||||
try {
|
||||
String sql = "SELECT * FROM " + elemClass.newInstance().tableName();
|
||||
String sql = "SELECT * FROM " + getTableName(elemClass);
|
||||
|
||||
List<Object> params = new ArrayList<>();
|
||||
|
||||
@ -189,67 +198,20 @@ public final class ORM {
|
||||
if (limit != null) sql += " LIMIT " + limit;
|
||||
if (offset != null) sql += " OFFSET " + offset;
|
||||
sql += ";";
|
||||
|
||||
try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) {
|
||||
|
||||
int i = 1;
|
||||
for (Object val : params) {
|
||||
if (val instanceof Enum<?>) val = ((Enum<?>) val).name();
|
||||
ps.setObject(i++, val);
|
||||
}
|
||||
Log.debug(ps.toString());
|
||||
|
||||
try (ResultSet set = ps.executeQuery()) {
|
||||
while (set.next()) {
|
||||
E elm = getElementInstance(set, elemClass);
|
||||
action.accept(elm);
|
||||
}
|
||||
|
||||
try (ResultSet set = customQueryStatement(sql, params)) {
|
||||
while (set.next()) {
|
||||
E elm = getElementInstance(set, elemClass);
|
||||
action.accept(elm);
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException | SQLException e) {
|
||||
} catch (SQLException e) {
|
||||
throw new ORMException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the elements of the table represented by {@code elemClass} which meet the condition {@code where}.
|
||||
* @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)}.
|
||||
* @return The return value of {@link PreparedStatement#executeUpdate()}, for an SQL query {@code DELETE}.
|
||||
* @throws ORMException
|
||||
*/
|
||||
public static <E extends SQLElement<E>> int delete(Class<E> elemClass, SQLWhere where) throws ORMException {
|
||||
initTable(elemClass);
|
||||
|
||||
if (where == null) {
|
||||
return truncateTable(elemClass);
|
||||
}
|
||||
|
||||
try {
|
||||
Pair<String, List<Object>> whereData = where.toSQL();
|
||||
|
||||
String sql = "DELETE FROM " + elemClass.newInstance().tableName()
|
||||
+ " WHERE " + whereData.getValue0()
|
||||
+ ";";
|
||||
List<Object> params = new ArrayList<>(whereData.getValue1());
|
||||
|
||||
try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) {
|
||||
|
||||
int i = 1;
|
||||
for (Object val : params) {
|
||||
if (val instanceof Enum<?>) val = ((Enum<?>) val).name();
|
||||
ps.setObject(i++, val);
|
||||
}
|
||||
Log.debug(ps.toString());
|
||||
|
||||
return ps.executeUpdate();
|
||||
}
|
||||
} catch (ReflectiveOperationException | SQLException e) {
|
||||
throw new ORMException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static <E extends SQLElement<E>> long count(Class<E> elemClass) throws ORMException {
|
||||
return count(elemClass, null);
|
||||
@ -259,7 +221,7 @@ public final class ORM {
|
||||
initTable(elemClass);
|
||||
|
||||
try {
|
||||
String sql = "SELECT COUNT(*) as count FROM " + elemClass.newInstance().tableName();
|
||||
String sql = "SELECT COUNT(*) as count FROM " + getTableName(elemClass);
|
||||
|
||||
List<Object> params = new ArrayList<>();
|
||||
|
||||
@ -269,23 +231,13 @@ public final class ORM {
|
||||
params.addAll(ret.getValue1());
|
||||
}
|
||||
sql += ";";
|
||||
|
||||
try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) {
|
||||
|
||||
int i = 1;
|
||||
for (Object val : params) {
|
||||
if (val instanceof Enum<?>) val = ((Enum<?>) val).name();
|
||||
ps.setObject(i++, val);
|
||||
}
|
||||
Log.debug(ps.toString());
|
||||
|
||||
try (ResultSet set = ps.executeQuery()) {
|
||||
while (set.next()) {
|
||||
return set.getLong(1);
|
||||
}
|
||||
|
||||
try (ResultSet set = customQueryStatement(sql, params)) {
|
||||
if (set.next()) {
|
||||
return set.getLong(1);
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException | SQLException e) {
|
||||
} catch (SQLException e) {
|
||||
throw new ORMException(e);
|
||||
}
|
||||
|
||||
@ -295,16 +247,8 @@ public final class ORM {
|
||||
|
||||
|
||||
|
||||
public static <E extends SQLElement<E>> int truncateTable(Class<E> elemClass) throws ORMException {
|
||||
try (Statement stmt = connection.getNativeConnection().createStatement()) {
|
||||
return stmt.executeUpdate("TRUNCATE `" + elemClass.newInstance().tableName() + "`");
|
||||
} catch(SQLException | ReflectiveOperationException e) {
|
||||
throw new ORMException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static ResultSet getCustomResult(String sql, List<Object> params) throws ORMException {
|
||||
public static ResultSet customQueryStatement(String sql, List<Object> params) throws ORMException {
|
||||
try {
|
||||
PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql);
|
||||
int i = 1;
|
||||
@ -325,6 +269,71 @@ public final class ORM {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static <E extends SQLElement<E>> SQLUpdate<E> update(Class<E> elemClass, SQLWhere where) throws ORMException {
|
||||
return new SQLUpdate<>(elemClass, where);
|
||||
}
|
||||
|
||||
/* package */ static <E extends SQLElement<E>> int update(Class<E> elemClass, SQLWhere where, Map<SQLField<E, ?>, Object> values) throws ORMException {
|
||||
return new SQLUpdate<>(elemClass, where, values).execute();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete the elements of the table represented by {@code elemClass} which meet the condition {@code where}.
|
||||
* @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)}.
|
||||
* @return The return value of {@link PreparedStatement#executeUpdate()}, for an SQL query {@code DELETE}.
|
||||
* @throws ORMException
|
||||
*/
|
||||
public static <E extends SQLElement<E>> int delete(Class<E> elemClass, SQLWhere where) throws ORMException {
|
||||
initTable(elemClass);
|
||||
|
||||
if (where == null) {
|
||||
return truncateTable(elemClass);
|
||||
}
|
||||
|
||||
Pair<String, List<Object>> whereData = where.toSQL();
|
||||
|
||||
String sql = "DELETE FROM " + getTableName(elemClass)
|
||||
+ " WHERE " + whereData.getValue0()
|
||||
+ ";";
|
||||
List<Object> params = new ArrayList<>(whereData.getValue1());
|
||||
|
||||
return customUpdateStatement(sql, params);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static int customUpdateStatement(String sql, List<Object> params) throws ORMException {
|
||||
try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) {
|
||||
|
||||
int i = 1;
|
||||
for (Object val : params) {
|
||||
if (val instanceof Enum<?>) val = ((Enum<?>) val).name();
|
||||
ps.setObject(i++, val);
|
||||
}
|
||||
Log.debug(ps.toString());
|
||||
|
||||
return ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
throw new ORMException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static <E extends SQLElement<E>> int truncateTable(Class<E> elemClass) throws ORMException {
|
||||
try (Statement stmt = connection.getNativeConnection().createStatement()) {
|
||||
return stmt.executeUpdate("TRUNCATE `" + getTableName(elemClass) + "`");
|
||||
} catch(SQLException e) {
|
||||
throw new ORMException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <E extends SQLElement<E>> E getElementInstance(ResultSet set, Class<E> elemClass) throws ORMException {
|
||||
try {
|
||||
@ -379,23 +388,4 @@ public final class ORM {
|
||||
|
||||
private ORM() {} // rend la classe non instanciable
|
||||
|
||||
/*
|
||||
* public static void main(String[] args) throws Throwable {
|
||||
* ORM.init(new DBConnection("localhost", 3306, "pandacube", "pandacube",
|
||||
* "pandacube"));
|
||||
* List<SQLPlayer> players = ORM.getAll(SQLPlayer.class,
|
||||
* new SQLWhereChain(SQLBoolOp.AND)
|
||||
* .add(new SQLWhereNull(SQLPlayer.banTimeout, true))
|
||||
* .add(new SQLWhereChain(SQLBoolOp.OR)
|
||||
* .add(new SQLWhereComp(SQLPlayer.bambou, SQLComparator.EQ, 0L))
|
||||
* .add(new SQLWhereComp(SQLPlayer.grade, SQLComparator.EQ, "default"))
|
||||
* ),
|
||||
* new SQLOrderBy().addField(SQLPlayer.playerDisplayName), null, null);
|
||||
* for(SQLPlayer p : players) {
|
||||
* System.out.println(p.get(SQLPlayer.playerDisplayName));
|
||||
* }
|
||||
* // TODO mise à jour relative d'un champ (incrément / décrément)
|
||||
* }
|
||||
*/
|
||||
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
private boolean stored = false;
|
||||
private int id;
|
||||
|
||||
private final String tableName;
|
||||
private final SQLFieldMap<E> fields;
|
||||
|
||||
private final Map<SQLField<E, ?>, Object> values;
|
||||
@ -40,7 +39,6 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public SQLElement() {
|
||||
tableName = tableName();
|
||||
|
||||
try {
|
||||
ORM.initTable((Class<E>)getClass());
|
||||
@ -230,7 +228,6 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
throw new IllegalStateException(toString() + " has at least one undefined value and can't be saved.");
|
||||
|
||||
ORM.initTable((Class<E>)getClass());
|
||||
String toStringStatement = "";
|
||||
try {
|
||||
|
||||
if (stored) { // mettre à jour les valeurs dans la base
|
||||
@ -243,27 +240,8 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
Map<SQLField<E, ?>, Object> modifiedValues = getOnlyModifiedValues();
|
||||
|
||||
if (modifiedValues.isEmpty()) return;
|
||||
|
||||
String sql = "";
|
||||
List<Object> psValues = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<SQLField<E, ?>, Object> entry : modifiedValues.entrySet()) {
|
||||
sql += "`" + entry.getKey().getName() + "` = ? ,";
|
||||
addValueToSQLObjectList(psValues, entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
if (sql.length() > 0) sql = sql.substring(0, sql.length() - 1);
|
||||
|
||||
try (PreparedStatement ps = db.getNativeConnection()
|
||||
.prepareStatement("UPDATE " + tableName + " SET " + sql + " WHERE id=" + id)) {
|
||||
|
||||
int i = 1;
|
||||
for (Object val : psValues)
|
||||
ps.setObject(i++, val);
|
||||
|
||||
toStringStatement = ps.toString();
|
||||
ps.executeUpdate();
|
||||
}
|
||||
|
||||
ORM.update((Class<E>)getClass(), new SQLWhereComp(getFieldId(), SQLComparator.EQ, getId()), modifiedValues);
|
||||
}
|
||||
else { // ajouter dans la base
|
||||
|
||||
@ -286,16 +264,15 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
concat_fields += "`" + entry.getKey().getName() + "`";
|
||||
addValueToSQLObjectList(psValues, entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
|
||||
try (PreparedStatement ps = db.getNativeConnection().prepareStatement(
|
||||
"INSERT INTO " + tableName + " (" + concat_fields + ") VALUES (" + concat_vals + ")",
|
||||
"INSERT INTO " + tableName() + " (" + concat_fields + ") VALUES (" + concat_vals + ")",
|
||||
Statement.RETURN_GENERATED_KEYS)) {
|
||||
|
||||
int i = 1;
|
||||
for (Object val : psValues)
|
||||
ps.setObject(i++, val);
|
||||
|
||||
toStringStatement = ps.toString();
|
||||
ps.executeUpdate();
|
||||
|
||||
try (ResultSet rs = ps.getGeneratedKeys()) {
|
||||
@ -308,9 +285,8 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
|
||||
modifiedSinceLastSave.clear();
|
||||
} catch (SQLException e) {
|
||||
throw new ORMException("Error while executing SQL statement " + toStringStatement, e);
|
||||
throw new ORMException("Error while saving data", e);
|
||||
}
|
||||
Log.debug(toStringStatement);
|
||||
}
|
||||
|
||||
|
||||
@ -344,7 +320,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
|
||||
if (stored) { // supprimer la ligne de la base
|
||||
try (PreparedStatement st = db.getNativeConnection()
|
||||
.prepareStatement("DELETE FROM " + tableName + " WHERE id=" + id)) {
|
||||
.prepareStatement("DELETE FROM " + tableName() + " WHERE id=" + id)) {
|
||||
Log.debug(st.toString());
|
||||
st.executeUpdate();
|
||||
markAsNotStored();
|
||||
|
@ -78,42 +78,22 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
|
||||
*
|
||||
* @throws SQLException
|
||||
*/
|
||||
public synchronized void saveCommon() throws ORMException {
|
||||
public synchronized int saveCommon() throws ORMException {
|
||||
List<E> storedEl = getStoredEl();
|
||||
if (storedEl.isEmpty()) return;
|
||||
if (storedEl.isEmpty()) return 0;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<E> classEl = (Class<E>)storedEl.get(0).getClass();
|
||||
|
||||
int ret = ORM.update(classEl,
|
||||
new SQLWhereIn(storedEl.get(0).getFieldId(),
|
||||
storedEl.stream().map(SQLElement::getId).collect(Collectors.toList())
|
||||
),
|
||||
modifiedValues);
|
||||
|
||||
String sqlSet = "";
|
||||
List<Object> psValues = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<SQLField<E, ?>, Object> entry : modifiedValues.entrySet()) {
|
||||
sqlSet += "`" + entry.getKey().getName() + "` = ? ,";
|
||||
SQLElement.addValueToSQLObjectList(psValues, entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
if (sqlSet.length() > 0) sqlSet = sqlSet.substring(0, sqlSet.length() - 1);
|
||||
|
||||
String sqlWhere = "";
|
||||
boolean first = true;
|
||||
for (E el : storedEl) {
|
||||
if (!first) sqlWhere += " OR ";
|
||||
first = false;
|
||||
sqlWhere += "id = " + el.getId();
|
||||
}
|
||||
|
||||
try(PreparedStatement ps = ORM.getConnection().getNativeConnection()
|
||||
.prepareStatement("UPDATE " + storedEl.get(0).tableName() + " SET " + sqlSet + " WHERE " + sqlWhere)) {
|
||||
|
||||
int i = 1;
|
||||
for (Object val : psValues)
|
||||
ps.setObject(i++, val);
|
||||
|
||||
Log.debug(ps.toString());
|
||||
ps.executeUpdate();
|
||||
|
||||
applyNewValuesToElements(storedEl);
|
||||
} catch (SQLException e) {
|
||||
throw new ORMException(e);
|
||||
}
|
||||
applyNewValuesToElements(storedEl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
70
src/main/java/fr/pandacube/util/orm/SQLUpdate.java
Normal file
70
src/main/java/fr/pandacube/util/orm/SQLUpdate.java
Normal file
@ -0,0 +1,70 @@
|
||||
package fr.pandacube.util.orm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.javatuples.Pair;
|
||||
|
||||
import fr.pandacube.util.Log;
|
||||
|
||||
public class SQLUpdate<E extends SQLElement<E>> {
|
||||
|
||||
private final Class<E> elemClass;
|
||||
private final SQLWhere where;
|
||||
private final Map<SQLField<E, ?>, Object> values;
|
||||
|
||||
/* package */ SQLUpdate(Class<E> el, SQLWhere w) {
|
||||
elemClass = el;
|
||||
where = w;
|
||||
values = new HashMap<>();
|
||||
}
|
||||
|
||||
/* package */ SQLUpdate(Class<E> el, SQLWhere w, Map<SQLField<E, ?>, Object> v) {
|
||||
elemClass = el;
|
||||
where = w;
|
||||
values = v;
|
||||
}
|
||||
|
||||
public <T> SQLUpdate<E> set(SQLField<E, T> field, T value) {
|
||||
values.put(field, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLUpdate<E> setUnsafe(SQLField<E, ?> field, Object value) {
|
||||
values.put(field, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int execute() throws ORMException {
|
||||
|
||||
if (values.isEmpty()) {
|
||||
Log.warning(new ORMException("Trying to do an UPDATE with no values to SET. Query aborted."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
String sql = "UPDATE " + ORM.getTableName(elemClass) + " SET ";
|
||||
List<Object> params = new ArrayList<>();
|
||||
|
||||
boolean first = true;
|
||||
for (Map.Entry<SQLField<E, ?>, Object> entry : values.entrySet()) {
|
||||
if (!first)
|
||||
sql += ", ";
|
||||
sql += "`" + entry.getKey().getName() + "` = ? ";
|
||||
SQLElement.addValueToSQLObjectList(params, entry.getKey(), entry.getValue());
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (where != null) {
|
||||
Pair<String, List<Object>> ret = where.toSQL();
|
||||
sql += " WHERE " + ret.getValue0();
|
||||
params.addAll(ret.getValue1());
|
||||
}
|
||||
|
||||
sql += ";";
|
||||
|
||||
return ORM.customUpdateStatement(sql, params);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user