[FIX-DOC] update migration and some docs
This commit is contained in:
parent
c3d2eff5be
commit
3d526aaede
@ -36,7 +36,7 @@ public class AnnotationTools {
|
||||
return element.getSimpleName();
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more than 1 element @SQLTableName on " + element.getClass().getCanonicalName());
|
||||
throw new Exception("Must not have more than 1 element @Table on " + element.getClass().getCanonicalName());
|
||||
}
|
||||
final String tmp = ((Table) annotation[0]).name();
|
||||
if (tmp == null) {
|
||||
@ -51,7 +51,7 @@ public class AnnotationTools {
|
||||
return null;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more than 1 element @SQLComment on " + element.getClass().getCanonicalName());
|
||||
throw new Exception("Must not have more than 1 element @DataComment on " + element.getClass().getCanonicalName());
|
||||
}
|
||||
return ((DataComment) annotation[0]).value();
|
||||
}
|
||||
@ -62,7 +62,7 @@ public class AnnotationTools {
|
||||
return null;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more than 1 element @SQLDefault on " + element.getClass().getCanonicalName());
|
||||
throw new Exception("Must not have more than 1 element @DataDefault on " + element.getClass().getCanonicalName());
|
||||
}
|
||||
return ((DataDefault) annotation[0]).value();
|
||||
}
|
||||
@ -70,12 +70,13 @@ public class AnnotationTools {
|
||||
public static Integer getLimitSize(final Field element) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
|
||||
if (annotation.length == 0) {
|
||||
return null;
|
||||
return 255;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more than 1 element @SQLLimitSize on " + element.getClass().getCanonicalName());
|
||||
throw new Exception("Must not have more than 1 element @Column on " + element.getClass().getCanonicalName());
|
||||
}
|
||||
return ((Column) annotation[0]).length();
|
||||
final int length = ((Column) annotation[0]).length();
|
||||
return length <= 0 ? null : length;
|
||||
}
|
||||
|
||||
public static boolean isAnnotationGroup(final Field field, final Class<?> annotationType) {
|
||||
|
@ -40,8 +40,20 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import jakarta.ws.rs.InternalServerErrorException;
|
||||
|
||||
/* TODO list:
|
||||
- useful code to manage external query: List<T> query<T>(class<T> clazz, String query, List<Object> parameters);
|
||||
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
|
||||
ResultSetMetaData rsmd = rs.getMetaData();
|
||||
String name = rsmd.getColumnName(1);
|
||||
- Manage to group of SQL action to permit to commit only at the end.
|
||||
|
||||
*/
|
||||
|
||||
/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite
|
||||
* back-end. */
|
||||
public class DataAccess {
|
||||
static final Logger LOGGER = LoggerFactory.getLogger(DataAccess.class);
|
||||
// by default we manage some add-on that permit to manage non-native model (like json serialization, List of external key as String list...)
|
||||
static final List<DataAccessAddOn> addOn = new ArrayList<>();
|
||||
|
||||
static {
|
||||
@ -51,20 +63,12 @@ public class DataAccess {
|
||||
addOn.add(new AddOnDataJson());
|
||||
}
|
||||
|
||||
/** Add a new add-on on the current management.
|
||||
* @param addOn instantiate object on the Add-on */
|
||||
public static void addAddOn(final DataAccessAddOn addOn) {
|
||||
DataAccess.addOn.add(addOn);
|
||||
}
|
||||
|
||||
public static class ExceptionDBInterface extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public int errorID;
|
||||
|
||||
public ExceptionDBInterface(final int errorId, final String message) {
|
||||
super(message);
|
||||
this.errorID = errorId;
|
||||
}
|
||||
}
|
||||
|
||||
public DataAccess() {
|
||||
|
||||
}
|
||||
@ -777,7 +781,6 @@ public class DataAccess {
|
||||
}
|
||||
}
|
||||
whereInjectValue(ps, condition, iii);
|
||||
|
||||
return ps.executeUpdate();
|
||||
} catch (final SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
@ -805,8 +808,6 @@ public class DataAccess {
|
||||
ps.setDouble(iii.value, tmp);
|
||||
} else if (value instanceof final Boolean tmp) {
|
||||
ps.setBoolean(iii.value, tmp);
|
||||
} else if (value instanceof final Boolean tmp) {
|
||||
ps.setBoolean(iii.value, tmp);
|
||||
} else if (value instanceof final Timestamp tmp) {
|
||||
ps.setTimestamp(iii.value, tmp);
|
||||
} else if (value instanceof final Date tmp) {
|
||||
@ -822,8 +823,7 @@ public class DataAccess {
|
||||
}
|
||||
}
|
||||
|
||||
public static void whereAppendQuery(final StringBuilder query, final String tableName, final QueryItem condition, final QueryOptions options, final String deletedFieldName)
|
||||
throws ExceptionDBInterface {
|
||||
public static void whereAppendQuery(final StringBuilder query, final String tableName, final QueryItem condition, final QueryOptions options, final String deletedFieldName) {
|
||||
boolean exclude_deleted = true;
|
||||
if (options != null) {
|
||||
exclude_deleted = !options.exist(AccessDeletedItems.class);
|
||||
@ -1058,6 +1058,12 @@ public class DataAccess {
|
||||
return delete(clazz, id, null);
|
||||
}
|
||||
|
||||
/** Delete items with the specific Id (cf @Id) and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before).
|
||||
* @param <ID_TYPE> Type of the reference @Id
|
||||
* @param clazz Data model that might remove element
|
||||
* @param id Unique Id of the model
|
||||
* @param options (Optional) Options of the request
|
||||
* @return Number of element that is removed. */
|
||||
public static <ID_TYPE> int delete(final Class<?> clazz, final ID_TYPE id, final QueryOptions options) throws Exception {
|
||||
final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
|
||||
if (hasDeletedFieldName != null) {
|
||||
@ -1067,6 +1073,11 @@ public class DataAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/** Delete items with the specific condition and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before).
|
||||
* @param clazz Data model that might remove element.
|
||||
* @param condition Condition to remove elements.
|
||||
* @param options (Optional) Options of the request.
|
||||
* @return Number of element that is removed. */
|
||||
public static int deleteWhere(final Class<?> clazz, final QueryItem condition, final QueryOptions options) throws Exception {
|
||||
final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
|
||||
if (hasDeletedFieldName != null) {
|
||||
@ -1107,13 +1118,6 @@ public class DataAccess {
|
||||
return deleteSoftWhere(clazz, getTableIdCondition(clazz, id), options);
|
||||
}
|
||||
|
||||
public static String getDBNow() {
|
||||
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
|
||||
return "now(3)";
|
||||
}
|
||||
return "DATE()";
|
||||
}
|
||||
|
||||
public static int deleteSoftWhere(final Class<?> clazz, final QueryItem condition, final QueryOptions options) throws Exception {
|
||||
final String tableName = AnnotationTools.getTableName(clazz, options);
|
||||
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
|
||||
@ -1163,7 +1167,6 @@ public class DataAccess {
|
||||
query.append("` SET `");
|
||||
query.append(deletedFieldName);
|
||||
query.append("`=false ");
|
||||
/* is is needed only for SQLite ??? query.append("`modify_date`="); query.append(getDBNow()); query.append(", "); */
|
||||
// need to disable the deleted false because the model must be unselected to be updated.
|
||||
options.add(QueryOptions.ACCESS_DELETED_ITEMS);
|
||||
whereAppendQuery(query, tableName, condition, options, deletedFieldName);
|
||||
|
@ -48,13 +48,20 @@ public class MigrationEngine {
|
||||
}
|
||||
|
||||
/** Get the current version/migration name
|
||||
* @return Model represent the last migration. If null then no migration has been done. */
|
||||
public Migration getCurrentVersion() {
|
||||
* @return Model represent the last migration. If null then no migration has been done.
|
||||
* @throws MigrationException */
|
||||
public Migration getCurrentVersion() throws MigrationException {
|
||||
if (!DataAccess.isTableExist("KAR_migration")) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final List<Migration> data = DataAccess.gets(Migration.class, new QueryOptions(QueryOptions.READ_ALL_COLOMN));
|
||||
List<Migration> data = null;
|
||||
try {
|
||||
data = DataAccess.gets(Migration.class, new QueryOptions(QueryOptions.READ_ALL_COLOMN));
|
||||
} catch (final Exception e) {
|
||||
// Previous version does not have the same timeCode...
|
||||
data = DataAccess.gets(Migration.class);
|
||||
}
|
||||
if (data == null) {
|
||||
LOGGER.error("Can not collect the migration table in the DB:{}");
|
||||
return null;
|
||||
@ -63,16 +70,16 @@ public class MigrationEngine {
|
||||
LOGGER.error("Fail to Request migration table in the DB: empty size");
|
||||
return null;
|
||||
}
|
||||
LOGGER.debug("List of migrations:");
|
||||
LOGGER.info("List of migrations:");
|
||||
for (final Migration elem : data) {
|
||||
LOGGER.debug(" - date={} name={} end={}", elem.updatedAt, elem.name, elem.terminated);
|
||||
LOGGER.info(" - date={} name={} end={}", elem.updatedAt, elem.name, elem.terminated);
|
||||
}
|
||||
return data.get(data.size() - 1);
|
||||
} catch (final Exception ex) {
|
||||
LOGGER.error("Fail to Request migration table in the DB:{}", ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
throw new MigrationException("Can not retreive Migration model");
|
||||
}
|
||||
|
||||
/** Process the automatic migration of the system The function wait the Administrator intervention to correct the bug.
|
||||
@ -99,10 +106,13 @@ public class MigrationEngine {
|
||||
public void migrateErrorThrow(final DBConfig config) throws MigrationException {
|
||||
LOGGER.info("Execute migration ... [BEGIN]");
|
||||
// check the integrity of the migrations:
|
||||
LOGGER.info("List of availlable Migration: ");
|
||||
for (final MigrationInterface elem : this.datas) {
|
||||
if (elem == null) {
|
||||
LOGGER.info(" - null");
|
||||
throw new MigrationException("Add a null migration");
|
||||
}
|
||||
LOGGER.info(" - {}", elem.getName());
|
||||
if (elem == this.init) {
|
||||
throw new MigrationException("Add a migration that is the initialization migration");
|
||||
}
|
||||
@ -142,6 +152,7 @@ public class MigrationEngine {
|
||||
LOGGER.info("DB '{}' exist.", config.getDbName());
|
||||
// STEP 2: Check migration table exist:
|
||||
LOGGER.info("Verify existance of migration table '{}'", "KAR_migration");
|
||||
// TODO: set the class in parameters instead of string...
|
||||
exist = DataAccess.isTableExist("KAR_migration");
|
||||
if (!exist) {
|
||||
LOGGER.info("'{}' Does not exist create a new one...", "KAR_migration");
|
||||
@ -180,18 +191,22 @@ public class MigrationEngine {
|
||||
throw new MigrationException("An error occured in the last migration: '" + currentVersion.name + "' defect @" + currentVersion.stepId + "/" + currentVersion.count);
|
||||
}
|
||||
LOGGER.info("Upgrade the system Current version: {}", currentVersion.name);
|
||||
boolean find = this.init != null && this.init.getName() == currentVersion.name;
|
||||
if (currentVersion.name.equals(this.init.getName())) {
|
||||
boolean find = this.init != null && this.init.getName().equals(currentVersion.name);
|
||||
if (find) {
|
||||
toApply = this.datas;
|
||||
} else {
|
||||
for (int iii = 0; iii < this.datas.size(); iii++) {
|
||||
LOGGER.info(" ===> Check what must be apply:");
|
||||
for (final MigrationInterface elem : this.datas) {
|
||||
LOGGER.info(" - {}", elem.getName());
|
||||
if (!find) {
|
||||
if (this.datas.get(iii).getName() == currentVersion.name) {
|
||||
if (currentVersion.name.equals(elem.getName())) {
|
||||
LOGGER.info(" == current version");
|
||||
find = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
toApply.add(this.datas.get(iii));
|
||||
LOGGER.info(" ++ add ");
|
||||
toApply.add(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -241,13 +256,18 @@ public class MigrationEngine {
|
||||
migrationResult.name = elem.getName();
|
||||
migrationResult.stepId = 0;
|
||||
migrationResult.terminated = false;
|
||||
migrationResult.count = elem.getNumberOfStep();
|
||||
try {
|
||||
migrationResult.count = elem.getNumberOfStep();
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new MigrationException("Fail to get number of migration step (maybe generation fail): " + e.getLocalizedMessage());
|
||||
}
|
||||
migrationResult.log = log.toString();
|
||||
try {
|
||||
migrationResult = DataAccess.insert(migrationResult);
|
||||
} catch (final Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
throw new MigrationException("Fail to insert migration Log in the migration table: " + e.getLocalizedMessage());
|
||||
}
|
||||
boolean ret = true;
|
||||
try {
|
||||
@ -256,7 +276,7 @@ public class MigrationEngine {
|
||||
log.append("\nFail in the migration apply ");
|
||||
log.append(e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
throw new MigrationException("Migration fial: '" + migrationResult.name + "' defect @" + migrationResult.stepId + "/" + migrationResult.count);
|
||||
throw new MigrationException("Migration fail: '" + migrationResult.name + "' defect @" + migrationResult.stepId + "/" + migrationResult.count);
|
||||
}
|
||||
if (ret) {
|
||||
migrationResult.terminated = true;
|
||||
@ -264,6 +284,7 @@ public class MigrationEngine {
|
||||
DataAccess.update(migrationResult, migrationResult.id, List.of("terminated"));
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new MigrationException("Fail to update migration Log in the migration table: " + e.getLocalizedMessage());
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@ -272,13 +293,15 @@ public class MigrationEngine {
|
||||
DataAccess.update(migrationResult, migrationResult.id, List.of("log"));
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new MigrationException("Fail to update migration Log in the migration table: " + e.getLocalizedMessage() + " WITH: An error occured in the migration (OUTSIDE detection): '"
|
||||
+ migrationResult.name + "' defect @" + migrationResult.stepId + "/" + migrationResult.count);
|
||||
}
|
||||
throw new MigrationException("An error occured in the migration (OUTSIDE detection): '" + migrationResult.name + "' defect @" + migrationResult.stepId + "/" + migrationResult.count);
|
||||
}
|
||||
LOGGER.info("Migrate: [{}/{}] {} [ END ]", id, count, elem.getName());
|
||||
}
|
||||
|
||||
public void revertTo(final DBEntry entry, final String migrationName) {
|
||||
public void revertTo(final DBEntry entry, final String migrationName) throws MigrationException {
|
||||
final Migration currentVersion = getCurrentVersion();
|
||||
final List<MigrationInterface> toApply = new ArrayList<>();
|
||||
boolean find = false;
|
||||
|
@ -23,5 +23,5 @@ public interface MigrationInterface {
|
||||
|
||||
/** Get the number of step in the migration process.
|
||||
* @return count of SQL access. */
|
||||
int getNumberOfStep();
|
||||
int getNumberOfStep() throws Exception;
|
||||
}
|
||||
|
@ -26,13 +26,18 @@ record Action(String action, List<String> filterDB) {
|
||||
public class MigrationSqlStep implements MigrationInterface {
|
||||
final static Logger LOGGER = LoggerFactory.getLogger(MigrationSqlStep.class);
|
||||
private final List<Action> actions = new ArrayList<>();
|
||||
private boolean isGenerated = false;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getClass().getCanonicalName();
|
||||
}
|
||||
|
||||
public void display() {
|
||||
public void display() throws Exception {
|
||||
if (!this.isGenerated) {
|
||||
this.isGenerated = true;
|
||||
generateStep();
|
||||
}
|
||||
for (int iii = 0; iii < this.actions.size(); iii++) {
|
||||
final Action action = this.actions.get(iii);
|
||||
LOGGER.info(" >>>> SQL ACTION : {}/{} ==> filter='{}'\n{}", iii, this.actions.size(), action.filterDB(), action.action());
|
||||
@ -49,7 +54,10 @@ public class MigrationSqlStep implements MigrationInterface {
|
||||
|
||||
@Override
|
||||
public boolean applyMigration(final DBEntry entry, final StringBuilder log, final Migration model) throws Exception {
|
||||
generateStep();
|
||||
if (!this.isGenerated) {
|
||||
this.isGenerated = true;
|
||||
generateStep();
|
||||
}
|
||||
for (int iii = 0; iii < this.actions.size(); iii++) {
|
||||
log.append("action [" + (iii + 1) + "/" + this.actions.size() + "]\n");
|
||||
LOGGER.info(" >>>> SQL ACTION : {}/{}", iii + 1, this.actions.size());
|
||||
@ -128,7 +136,11 @@ public class MigrationSqlStep implements MigrationInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfStep() {
|
||||
public int getNumberOfStep() throws Exception {
|
||||
if (!this.isGenerated) {
|
||||
this.isGenerated = true;
|
||||
generateStep();
|
||||
}
|
||||
return this.actions.size();
|
||||
}
|
||||
|
||||
|
@ -29,5 +29,6 @@ public class Migration extends GenericDataSoftDelete {
|
||||
@DataComment("number of element in the migration")
|
||||
public Integer count;
|
||||
@DataComment("Log generate by the migration")
|
||||
@Column(length = 0)
|
||||
public String log = "";
|
||||
}
|
||||
|
@ -15,10 +15,10 @@ import jakarta.persistence.Table;
|
||||
public class GenericToken extends GenericDataSoftDelete {
|
||||
@Column(nullable = false)
|
||||
public Long parentId;
|
||||
@Column(nullable = false)
|
||||
@Column(nullable = false, length = 0)
|
||||
public String name;
|
||||
@Column(nullable = false)
|
||||
public Timestamp endValidityTime = null;
|
||||
@Column(nullable = false)
|
||||
@Column(nullable = false, length = 0)
|
||||
public String token;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user