Перенос.

This commit is contained in:
2023-09-17 22:13:42 +03:00
parent dd2e0ca7e0
commit 629d8b8477
1239 changed files with 61161 additions and 1 deletions

View File

@@ -0,0 +1,31 @@
package Common.Database;
public enum ColumnType {
UNDEFINED,
INT,
LONG,
DOUBLE,
STRING;
public static ColumnType valueOf(Class<?> type) {
ColumnType res = UNDEFINED;
try {
res = valueOf(type.getSimpleName().toUpperCase());
} catch (Exception ignored) {
}
return res;
}
public String getSQLType() {
String res = "";
switch (this) {
case INT:
case LONG:
res = "INTEGER";
break;
case DOUBLE:
res = "REAL";
break;
case STRING:
res = "VARCHAR";
}
return res;
}
}

View File

@@ -0,0 +1,64 @@
package Common.Database;
import Common.UI.Selectable;
import Common.Utils.Index;
import Common.Utils.Utils;
import com.sun.org.glassfish.gmbal.Description;
import java.io.Serializable;
import java.util.Objects;
public abstract class DBObject implements Selectable, Serializable {
//<editor-fold desc="Selectable">
@Description("IGNORE")
private boolean selected = false;
@Override
public boolean isSelected() {
return selected;
}
@Override
public void select(boolean flag) {
if (selected != flag) {
selected = flag;
Index counter = getSelectionCounter();
if (Objects.nonNull(counter)) {
if (selected) counter.Inc();
else counter.Dec();
}
}
}
//</editor-fold>
public Index getSelectionCounter() {
return null;
}
public boolean isVisible() {
return true;
}
public abstract Object getPK();
public String getBDialogName() {
return Utils.Brackets(getDialogName());
}
public String getDialogName() {
return getPK().toString();
}
//статус. например завершенность багрепорта или состояние задачи на запуск. как правило обладает цветным шрифтом.
//как объект будут называть по внешним ключам.
public String getFKName() {
return null;
}
public Object getEmptyFK() {
return null;
}
@Override
public String toString() {
return getBDialogName();
}
//---
public void SynchronizeFields(DBObject src){
selected = src.selected;
}
//------
public DBObject(){}
public DBObject(DBObject src){
this.SynchronizeFields(src);
}
//---------
}

View File

@@ -0,0 +1,34 @@
package Common.Database;
import java.lang.reflect.Field;
public abstract class DBTable<K, D extends DBObject> extends DataSet<K, D> {
//-
public DBTableColumn PK = null;
private Database db = null; //база данных - владелец таблицы.
public DBTable(Class<K> k_in, Class<D> d_in) {
super(k_in, d_in);
for (Field field : d.getFields()) {
DBTableColumn column = new DBTableColumn(field);
if ((!column.Ignore) && !columns.containsKey(column.Name)) {
columns.put(column.Name, column);
if (column.PrimaryKey) PK = column;
}
}
}
public Database getDb() {
return db;
}
public void setDb(Database db_in) {
db = db_in;
}
@Override
public String getPKName() {
return PK.Name;
}
@Override
public String toString() {
StringBuilder res = new StringBuilder(Name + "\n");
for (DBTableColumn c : columns.values())
res.append(c).append("\n");
return res.toString();
}
}

View File

@@ -0,0 +1,50 @@
package Common.Database;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Vector;
public class DBTableColumn {
public String Name = "";
public ColumnType type = ColumnType.UNDEFINED;
public Vector<String> attributes = new Vector<String>();
public boolean Ignore = false;
public boolean PrimaryKey = false;
public boolean AutoIncrement = false;
public Object default_value = null;
public DBTableColumn(Field field) {
ExtractAttributes(field);
PrimaryKey = attributes.contains("PRIMARY KEY");
AutoIncrement = attributes.contains("AUTOINCREMENT");
Name = field.getName();
type = (field.getType().isEnum()) ? ColumnType.STRING : ColumnType.valueOf(field.getType());
Ignore = ((Modifier.isStatic(field.getModifiers()) ||
type.equals(ColumnType.UNDEFINED) ||
attributes.contains("IGNORE")
)
);
}
public String QName() {
return "\"" + Name + "\"";
}
public void ExtractAttributes(Field field) {
attributes = new Vector<String>();
Annotation[] annotations = field.getAnnotations();
for (Annotation a : annotations) {
String[] data = a.toString().split("value=");
if (data.length > 1) {
String[] attributes_ = data[1].split("[,\")]");
for (String attribute : attributes_) {
if (attribute.length() > 0)
attributes.add(attribute);
}
}
}
}
@Override
public String toString() {
String res = QName() + " " + type.getSQLType();
if (attributes.size() > 0)
res += " " + String.join(" ", attributes);
return res;
}
}

View File

@@ -0,0 +1,253 @@
package Common.Database;
import Common.Current;
import Common.UI.DataSetControlForm;
import Common.UI.Menus_2023.DataMenuBar;
import Common.UI.Tables.ColumnFilter;
import Common.UI.UI;
import Common.UI.Windows.Dialog.DBObjectDialog;
import Common.UI.Windows.Dialog.DialogFields;
import Common.Utils.TextLog;
import Visual_DVM_2021.UI.Interface.FilterWindow;
import javax.swing.*;
import java.awt.*;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Vector;
import java.util.stream.Collectors;
public class DataSet<K, D extends DBObject> extends DataSetAnchestor {
//-
public static LinkedHashMap<Class, Object> selections = new LinkedHashMap<>();
//-
public String Name;
public Class<K> k; //класс первичного ключа.
public Class<D> d; //класс объектов.
public LinkedHashMap<K, D> Data = new LinkedHashMap<>(); //наполнение
//-
//<editor-fold desc="UI таблица">
public DataSetControlForm ui_;
protected FilterWindow f_ui;
//</editor-fold>
//-
public LinkedHashMap<Integer, ColumnFilter> columnsFilters = new LinkedHashMap<>();
public DataSet(Class<K> k_in, Class<D> d_in) {
k = k_in;
d = d_in;
Name = d.getSimpleName();
}
public void mountUI(JPanel content_in) {
UI.Clear(content_in);
//-->
ui_ = createUI();
ui_.setContent(content_in);
//-->
if (UI.menuBars.containsKey(getClass())) {
DataMenuBar bar = UI.menuBars.get(getClass());
content_in.add(bar, BorderLayout.NORTH);
setFilterUI(count -> UI.menuBars.get(getClass()).countLabel.setText(String.valueOf(count)));
if (ui_.hasCheckBox())
bar.createSelectionButtons(this);
}
content_in.add(ui_.getDataPanel(), BorderLayout.CENTER);
}
public DataSetControlForm getUi() {
return ui_;
}
public void setFilterUI(FilterWindow ui_in) {
f_ui = ui_in;
}
public void ShowUI() {
if (ui_ != null) {
ui_.Show();
if (f_ui != null)
f_ui.ShowMatchesCount(getRowCountUI());
}
}
public void ShowUI(Object key) {
if (ui_ != null) {
ui_.Show(key);
if (f_ui != null)
f_ui.ShowMatchesCount(getRowCountUI());
}
}
public void ClearUI() {
if ((ui_ != null) && ui_.isShown()) {
ui_.ClearSelection();
ui_.Clear();
if (f_ui != null)
f_ui.ShowNoMatches();
}
}
public void RefreshUI() {
if (ui_ != null) ui_.Refresh();
}
public int getRowCountUI() {
return ui_.getRowCount();
}
public void SetCurrentObjectUI(Object pk) {
if (ui_ != null) {
//todo возможно проверить, что текущий объект уже соответствует ключу, и если да, то ничего делать.
ui_.ClearSelection(); //сброс текущего объекта и всего что с ним связано.
ui_.Select(pk);
}
}
//столбы/ потом переименовать обратно в getUIColumnNames.сейчас так для скорости переноса.
public String[] getUIColumnNames() {
return new String[]{};
}
protected DataSetControlForm createUI() {
return null;
}
public boolean hasUI() {
return ui_ != null;
}
public void CheckAll(boolean flag) {
for (D object : Data.values()) {
if (object.isVisible())
object.Select(flag);
}
RefreshUI();
}
public D getFirstRecord() {
return Data.values().stream().findFirst().orElse(null);
}
public Vector<D> getOrderedRecords(Comparator<D> comparator) {
Vector<D> res = new Vector<>(Data.values());
res.sort(comparator);
return res;
}
@SuppressWarnings("unchecked")
public DBObjectDialog<D, ? extends DialogFields> getDialog() {
return null;
}
public boolean ShowAddObjectDialog(DBObject object) {
return getDialog().ShowDialog(getSingleDescription() + ": добавление", object);
}
public boolean ShowEditObjectDialog(DBObject object) {
DBObjectDialog dialog = getDialog();
dialog.edit = true;
dialog.SetEditLimits();
return dialog.ShowDialog(getSingleDescription() + ": редактирование", object);
}
public boolean ViewObject(DBObject object) {
DBObjectDialog dialog = getDialog();
dialog.SetReadonly();
dialog.ShowDialog(getSingleDescription() + ": просмотр", object);
return false;
}
public boolean ShowDeleteObjectDialog(DBObject object) {
return UI.Warning(getSingleDescription() + " " + object.getBDialogName() + " будет удален(а)");
}
public String QName() {
return "\"" + Name + "\"";
}
public String getPKName() {
return "";
} //получить имя ключевого поля. нужно для таблиц.
public String getPluralDescription() {
return "";
}
public String getSingleDescription() {
return "";
}
//времянки
public Current CurrentName() {
return Current.Undefined;
}
public boolean CheckCurrent(TextLog log) {
return Current.Check(log, CurrentName());
}
public boolean hasCurrent() {
return Current.get(CurrentName()) != null;
}
public void dropCurrent() {
Current.set(CurrentName(), null);
}
public D getCurrent() {
return (D) Current.get(CurrentName());
}
public void setCurrent(D o) {
Current.set(CurrentName(), o);
}
//-
public void put(Object key, D object) {
Data.put((K) key, object);
}
public D get(Object key) {
return Data.get(key);
}
public Object getFieldAt(D object, int columnIndex) {
return null;
}
public void clear() {
Data.clear();
}
public int size() {
return Data.size();
}
public boolean containsKey(Object key) {
return Data.containsKey(key);
}
//-
public Vector<K> getVisibleKeys() {
Comparator<D> comparator = getComparator();
Vector<K> res = new Vector<>();
if (comparator == null) {
for (K key : Data.keySet())
if (Data.get(key).isVisible())
res.add(key);
} else {
Vector<D> raw = new Vector<>();
for (D object : Data.values()) {
if (object.isVisible())
raw.add(object);
}
raw.sort(comparator);
for (D object : raw)
res.add((K) object.getPK());
}
return res;
}
protected Comparator<D> getComparator() {
return null;
}
public int getCheckedCount() {
return (int) Data.values().stream().filter(d -> d.isVisible() && d.isSelected()).count();
}
public Vector<D> getCheckedItems() {
return Data.values().stream().filter(d -> d.isVisible() && d.isSelected()).collect(Collectors.toCollection(Vector::new));
}
public Vector<K> getCheckedKeys() {
return Data.values().stream().filter(DBObject::isSelected).map(d -> (K) d.getPK()).collect(Collectors.toCollection(Vector::new));
}
//--
public void SaveLastSelections() {
if (hasUI()) {
Object lastPk = null;
if ((CurrentName() != Current.Undefined) && (getCurrent() != null))
lastPk = getCurrent().getPK();
if (!selections.containsKey(getClass()))
selections.put(getClass(), lastPk);
else selections.replace(getClass(), lastPk);
}
}
public void RestoreLastSelections() {
if (hasUI()) {
Object lastPk = selections.get(getClass());
// if (lastPk != null) UI.Info(this.getClass() + ":" + lastPk.toString());
if ((CurrentName() != Current.Undefined) && (lastPk != null)) {
// UI.Info(lastPk.toString());
// System.out.println(ui);
// UI.Info("+");
ui_.Select(lastPk);
}
}
}
//---
// применить значение фильтра к фильру объекта напирмер Message.filterValue = text;
public void changeColumnFilterValue(int columnIndex, String text) {
}
public Object getColumnFilterValue(int columnIndex) {
return "";
}
}

View File

@@ -0,0 +1,11 @@
package Common.Database;
import java.util.LinkedHashMap;
public abstract class DataSetAnchestor {
//чтобы обмануть стирание типов во всех параметризованных полях. используется не во всех потомках.
//ибо не все наборы данных относятся к базам.
public LinkedHashMap<String, DBTableColumn> columns = new LinkedHashMap<>();
//то же самое. на самом деле внешние ключи бывают только у таблиц бд
public LinkedHashMap<Class<? extends DBObject>, FKBehaviour> getFKDependencies() {
return new LinkedHashMap<>();
}
}

View File

@@ -0,0 +1,274 @@
package Common.Database;
import Common.Global;
import Common.Utils.Utils;
import Repository.RepositoryRefuseException;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.Vector;
//самый общий интерфейс базы данных, независимо от реализации.
public abstract class Database {
//------------------------------
public LinkedHashMap<Class<? extends DBObject>, DBTable> tables = new LinkedHashMap<>(); //таблицы
protected File file = null;
public Database(File file_in) {
file = file_in;
}
public File getFile() {
return file;
}
public void setFile(File file_in) {
file = file_in;
}
//<editor-fold desc="Общая часть">
public void Connect() throws Exception {
// UI.Print(DebugPrintLevel.Database, "соединение с базой данных " + file.getAbsolutePath());
connect();
}
public void prepareTablesStatements() throws Exception {
}
public void Disconnect() throws Exception {
// UI.Print(DebugPrintLevel.Database, "закрытие соединения с базой данных " + file.getAbsolutePath());
disconnect();
}
public void BeginTransaction() throws Exception {
// UI.Print(DebugPrintLevel.Database, "BEGIN TRANSACTION:");
beginTransaction();
}
public void Commit() throws Exception {
// UI.Print(DebugPrintLevel.Database, "COMMIT");
commit();
}
public void CreateAllTables() throws Exception {
BeginTransaction();
initAllTables(); // все добавления новых таблиц - туть.
for (DBTable table : tables.values()) {
CreateTable(table);
table.setDb(this);
}
Commit();
}
//схема как с проходами. в методе initAllTables добавляем все таблицы через уникальные конструкторы
public void addTable(DBTable table) {
tables.put(table.d, table);
}
public void Synchronize() throws Exception {
BeginTransaction();
for (DBTable table : tables.values())
LoadAll(table);
Init(); //перегружаемая часть синхронизации.
Commit();
}
public void LoadAllTablesWithoutInit() throws Exception {
BeginTransaction();
for (DBTable table : tables.values())
LoadAll(table);
Commit();
}
public <K, D extends DBObject> void LoadAll(DBTable<K, D> table) throws Exception {
table.Data.clear();
loadAll(table);
}
public DBObject Insert(DBObject o) throws Exception {
DBTable table = tables.get(o.getClass());
insert(table, o);
table.Data.put(o.getPK(), o);
return o;
}
public DBObject InsertWithCheck(DBObject o) throws Exception {
DBTable table = tables.get(o.getClass());
if (!table.Data.containsKey(o.getPK())) {
insert(table, o);
table.Data.put(o.getPK(), o);
} else
throw new RepositoryRefuseException("Таблица " + Utils.Brackets(table.Name) + " уже содержит объект с ключом " + Utils.Brackets(o.getPK().toString()));
return o;
}
public DBObject InsertWithCheck_(DBObject o) throws Exception {
DBTable table = tables.get(o.getClass());
if (!table.Data.containsKey(o.getPK())) {
insert(table, o);
table.Data.put(o.getPK(), o);
return o;
}
return null;
}
// не работает с автоинкрементом.
public DBObject UpdateWithCheck(DBObject to_update) throws Exception {
DBTable table = tables.get(to_update.getClass());
if (table.Data.containsKey(to_update.getPK())) {
DBObject o = (DBObject) table.Data.get(to_update.getPK());
o.SynchronizeFields(to_update);
update(table, o);
return o;
} else {
insert(table, to_update);
table.Data.put(to_update.getPK(), to_update);
return to_update;
}
}
public DBObject DeleteWithCheck(DBObject to_delete) throws Exception {
DBTable table = tables.get(to_delete.getClass());
if (table.Data.containsKey(to_delete.getPK())) {
DBObject o = (DBObject) table.Data.get(to_delete.getPK());
delete(table, o);
table.Data.remove(o.getPK());
return o;
} else
throw new RepositoryRefuseException("Таблица " + Utils.Brackets(table.Name) + " не содержит объект с ключом " + Utils.Brackets(to_delete.getPK().toString()));
}
// не работает с автоинкрементом.
public DBObject getObjectCopyByPK(Class table_class, Object pk) throws Exception {
DBTable table = tables.get(table_class);
Object res_ = table_class.newInstance();
DBObject res = (DBObject) res_;
if (table.Data.containsKey(pk)) {
DBObject original = (DBObject) table.Data.get(pk);
res.SynchronizeFields(original);
} else {
table_class.getField(table.getPKName()).set(res, pk); //инче просто синхроним пк. и вставляем
insert(table, res);
}
return res;
}
public boolean checkObjectExistense(Class table_class, Object pk) throws Exception {
DBTable table = tables.get(table_class);
return table.containsKey(pk);
}
public Vector<Object> getObjectsCopies(Class table_class, Vector<Object> keys) {
Vector<Object> res = new Vector<>();
DBTable table = tables.get(table_class);
for (Object key : keys)
if (table.containsKey(key))
res.add(table.Data.get(key));
return res;
}
public void Delete(DBObject o) throws Exception {
DBTable table = tables.get(o.getClass());
delete(table, o);
table.Data.remove(o.getPK());
}
public void DeleteAll(Class<? extends DBObject> c) throws Exception {
DBTable table = tables.get(c);
deleteAll(table);
table.Data.clear();
}
//не вполне обычный случай. подразумевается что поле объекта изменено
//этот же метод закрепляет изменение в бд
//в дальнейшем возможно сделать новое значение поля 2 параметром метода?
public void Update(DBObject o) throws Exception {
DBTable table = tables.get(o.getClass());
update(table, o);
}
public void ResetAI(Class<? extends DBObject> c) throws Exception {
resetAI(tables.get(c));
}
//</editor-fold>
//<editor-fold desc="работа с внешними ключами">
public <O extends DBObject, F extends DBObject> Vector<DBObject> getVectorByFK(O owner, Class<F> fk_class) {
Vector<DBObject> res = new Vector<>();
try {
for (Object o : tables.get(fk_class).Data.values()) {
if (fk_class.getField(owner.getFKName()).get(o).equals(owner.getPK())) res.add((DBObject) o);
}
} catch (Exception e) {
Global.Log.PrintException(e);
}
return res;
}
public <F extends DBObject> void DeleteByFK(DBObject master, Class<F> fk_class) throws Exception {
Vector<DBObject> to_delete = getVectorByFK(master, fk_class);
BeginTransaction();
for (DBObject object : to_delete)
Delete(object);
Commit();
}
//-----------
public <F extends DBObject> void DropByFK(DBObject master, Class<F> fk_class) throws Exception {
Vector<DBObject> to_drop = getVectorByFK(master, fk_class);
BeginTransaction();
for (DBObject object : to_drop) {
fk_class.getField(master.getFKName()).set(object, master.getEmptyFK());
Update(object);
}
Commit();
}
public <K, O extends DBObject, F extends DBObject> LinkedHashMap<K, F> getMapByFK(O owner, Class<F> fk_class, Class<K> key_class) {
LinkedHashMap<K, F> res = new LinkedHashMap<>();
try {
for (Object o : tables.get(fk_class).Data.values()) {
F f = (F) o;
if (fk_class.getField(owner.getFKName()).get(f).equals(owner.getPK())) res.put((K) f.getPK(), f);
}
} catch (Exception e) {
Global.Log.PrintException(e);
}
return res;
}
public <O extends DBObject, F extends iDBObject> LinkedHashMap<Integer, F> getMapByFKi(O owner, Class<F> fk_class) {
return getMapByFK(owner, fk_class, java.lang.Integer.class);
}
//-
public <O extends DBObject, F extends DBObject> Vector<String> getVectorStringByFK(O owner, Class<F> fk_class) {
Vector<String> res = new Vector<>();
try {
for (Object o : tables.get(fk_class).Data.values()) {
if (fk_class.getField(owner.getFKName()).get(o).equals(owner.getPK())) res.add(o.toString());
}
} catch (Exception e) {
Global.Log.PrintException(e);
}
return res;
}
//безопасное получение объекта по первичному ключу.
public <O extends DBObject> O getByPK(Class<O> class_in, Object pk, Object undefined_pk) {
return ((!pk.equals(undefined_pk)) && tables.get(class_in).Data.containsKey(pk)) ?
(O) (tables.get(class_in).Data.get(pk)) : null;
}
public <O extends iDBObject> O getById(Class<O> class_in, int pk) {
return getByPK(class_in, pk, Utils.Nan);
}
public <G, O extends DBObject, F extends DBObject> LinkedHashMap<G, F> getByFKAndGroupBy(O owner, Class<F> fk_class, String group_field, Class<G> group_class) {
LinkedHashMap<G, F> res = new LinkedHashMap<>();
try {
for (Object o : tables.get(fk_class).Data.values()) {
F f = (F) o;
if (fk_class.getField(owner.getFKName()).get(f).equals(owner.getPK()))
res.put((G) (fk_class.getField(group_field).get(f)), f);
}
} catch (Exception e) {
Global.Log.PrintException(e);
}
return res;
}
//</editor-fold>
//<editor-fold desc="Перегружаемая часть">
//-
protected abstract void connect() throws Exception;
protected abstract void disconnect() throws Exception;
//-
protected abstract void beginTransaction() throws Exception;
protected abstract void commit() throws Exception;
//-
protected abstract boolean TableExists(DBTable table) throws Exception;
protected abstract void CreateTable(DBTable table) throws Exception;
protected abstract <K, D extends DBObject> void loadAll(DBTable<K, D> table) throws Exception;
protected abstract void initAllTables() throws Exception;
//перегружаемая часть синхронизации
public void Init() throws Exception {
}
protected abstract void insert(DBTable table, DBObject o) throws Exception;
protected abstract void delete(DBTable table, DBObject o) throws Exception;
protected abstract void deleteAll(DBTable table) throws Exception;
protected abstract void update(DBTable table, DBObject o) throws Exception;
protected abstract void resetAI(DBTable table) throws Exception;
//-
public void SaveLastSelections() {
for (DataSet dataSet : tables.values())
dataSet.SaveLastSelections();
}
public void RestoreLastSelections() {
for (DataSet dataSet : tables.values())
dataSet.RestoreLastSelections();
}
}

View File

@@ -0,0 +1,9 @@
package Common.Database;
public class FKBehaviour {
public FKDataBehaviour data; //поведение данных внешнего ключа при удалении/модификации
public FKCurrentObjectBehaviuor ui; //поведение интерфейсов таблиц внешнего ключа при показе текущего объекта.
public FKBehaviour(FKDataBehaviour data_in, FKCurrentObjectBehaviuor ui_in) {
data = data_in;
ui = ui_in;
}
}

View File

@@ -0,0 +1,5 @@
package Common.Database;
public enum FKCurrentObjectBehaviuor {
PASSIVE,
ACTIVE
}

View File

@@ -0,0 +1,7 @@
package Common.Database;
//поведение таблиц имеющих внешние ключи
public enum FKDataBehaviour {
NONE,
DROP,
DELETE
}

View File

@@ -0,0 +1,261 @@
package Common.Database.SQLITE;
import Common.Database.DBObject;
import Common.Database.DBTable;
import Common.Database.DBTableColumn;
import Common.Database.Database;
import Common.UI.UI;
import Common.Utils.Utils;
import Visual_DVM_2021.Passes.PassException;
import javafx.util.Pair;
import java.io.File;
import java.sql.*;
import java.util.LinkedHashMap;
import java.util.Vector;
import static Common.Utils.Utils.requireNonNullElse;
public abstract class SQLiteDatabase extends Database {
protected Connection conn = null;
protected Statement statement = null;
protected ResultSet resSet = null;
public LinkedHashMap<Class<? extends DBObject>, PreparedStatement> insertStatements = new LinkedHashMap<>();
public LinkedHashMap<Class<? extends DBObject>, PreparedStatement> updateStatements = new LinkedHashMap<>();
public LinkedHashMap<Class<? extends DBObject>, PreparedStatement> deleteStatements = new LinkedHashMap<>();
//->>
public SQLiteDatabase(File file_in) {
super(file_in);
}
@Override
protected void connect() throws Exception {
Class.forName("org.sqlite.JDBC");
for (int i = 0; i < 5; ++i) {
try {
conn = DriverManager.getConnection("jdbc:sqlite:" + file.getAbsolutePath());
break;
} catch (Exception ex) {
ex.printStackTrace();
conn = null;
System.gc();
Utils.sleep(2000);
}
}
if (conn == null)
throw new PassException("Внутренняя ошибка sqlite. Не удалось установить соединение за 5 попыток.");
statement = conn.createStatement();
}
@Override
protected void disconnect() throws Exception {
if (conn != null) {
conn.close();
conn = null;
}
if (statement != null) {
statement.close();
statement = null;
}
if (resSet != null) {
resSet.close();
resSet = null;
}
for (PreparedStatement preparedStatement : insertStatements.values()) {
if (preparedStatement != null)
preparedStatement.close();
}
for (PreparedStatement preparedStatement : updateStatements.values()) {
if (preparedStatement != null)
preparedStatement.close();
}
for (PreparedStatement preparedStatement : deleteStatements.values()) {
if (preparedStatement != null)
preparedStatement.close();
}
insertStatements.clear();
updateStatements.clear();
deleteStatements.clear();
//-->>
System.gc();
//->>
}
@Override
protected void beginTransaction() throws Exception {
conn.setAutoCommit(false);
}
@Override
protected void commit() throws Exception {
conn.commit();
conn.setAutoCommit(true);
}
@Override
protected boolean TableExists(DBTable table) throws Exception {
int count = 0;
resSet = statement.executeQuery("SELECT count(*) FROM 'sqlite_master' WHERE type=\"table\" AND name=" + table.QName());
if (resSet.next())
count = resSet.getInt(1);
return count > 0;
}
@Override
public void CreateTable(DBTable table) throws Exception {
if (table.columns.size() > 0) {
if (TableExists(table)) {
Vector<String> existing_columns = new Vector<>();
Vector<String> columns_to_create = new Vector<>();
//предполагаем что первичный ключ и атрибуты не изменятся.
//и что не будет столбов с одинаковыми именами но разными типами.
resSet = statement.executeQuery("pragma table_info(" + table.QName() + ")");
while (resSet.next())
existing_columns.add(resSet.getString(2));
//-
for (String target_column : table.columns.keySet()) {
if (!existing_columns.contains(target_column))
columns_to_create.add(target_column);
}
for (String cn : columns_to_create)
statement.execute("ALTER TABLE " + table.QName() + " ADD COLUMN " + table.columns.get(cn));
} else {
String cmd = "CREATE TABLE if not exists " + table.QName() + " ";
Vector<String> columns_names = new Vector<>();
for (DBTableColumn column : table.columns.values())
columns_names.add(column.toString());
cmd += Utils.RBrackets(String.join(",", columns_names));
statement.execute(cmd);
}
}
}
@Override
public void prepareTablesStatements() throws Exception {
for (DBTable table : tables.values()) {
//---
Vector<String> column_names = new Vector<>();
Vector<String> column_values = new Vector<>();
for (DBTableColumn column : table.columns.values()) {
if (!column.AutoIncrement) {
column_names.add(column.QName());
column_values.add("?");
}
}
insertStatements.put(table.d, conn.prepareStatement(
"INSERT OR REPLACE INTO " + table.QName() + " " +
Utils.RBrackets(String.join(",", column_names)) + " " + "VALUES " +
Utils.RBrackets(String.join(",", column_values))));
//------------------------------------------------------------------------------->>
Vector<String> new_values = new Vector();
for (DBTableColumn column : table.columns.values()) {
if (!column.AutoIncrement) {
new_values.add(column.QName() + "=?");
}
}
updateStatements.put(table.d, conn.prepareStatement(
"UPDATE " + table.QName() + " " +
"SET " + String.join(",", new_values) + " " +
"WHERE (" + table.PK.QName() + "=?)"
));
//---------------------------------------------------------------------------------->>>
deleteStatements.put(table.d, conn.prepareStatement("DELETE FROM " + table.QName() + " WHERE " + table.PK.QName() + " = ?"));
}
}
@Override
protected void delete(DBTable table, DBObject o) throws Exception {
PreparedStatement ps = deleteStatements.get(table.d);
ps.setObject(1, o.getPK());
ps.executeUpdate();
}
protected <K, D extends DBObject> Pair<K, D> readRecord(DBTable<K, D> table) throws Exception {
D o = table.d.newInstance();
for (DBTableColumn column : table.columns.values()) {
Object field_value = null;
switch (column.type) {
case DOUBLE:
field_value = requireNonNullElse(resSet.getDouble(column.Name), 0);
break;
case UNDEFINED:
break;
case INT:
field_value = requireNonNullElse(resSet.getInt(column.Name), 0);
break;
case LONG:
field_value = requireNonNullElse(resSet.getLong(column.Name), 0);
break;
case STRING:
if (table.d.getField(column.Name).getType().isEnum()) {
Class enum_class = Class.forName(table.d.getField(column.Name).getType().getName());
String string = resSet.getString(column.Name);
Object[] enum_constants = enum_class.getEnumConstants();
if (string != null) {
try {
field_value = Enum.valueOf(enum_class, string);
} catch (Exception ignore) {
System.out.println(Utils.Brackets(string) + "not found");
field_value = enum_constants[0];
System.out.println(field_value);
}
} else field_value = enum_constants[0];
} else
field_value = requireNonNullElse(resSet.getString(column.Name), "");
break;
}
if (field_value != null) {
table.d.getField(column.Name).set(o, field_value);
} else
throw new PassException("Ошибка при загрузке поля " + Utils.Brackets(column.Name) + " класса " + Utils.Brackets(table.d.getSimpleName()));
}
return new Pair<>((K) o.getPK(), o);
}
@Override
protected <K, D extends DBObject> void loadAll(DBTable<K, D> table) throws Exception {
resSet = statement.executeQuery("SELECT * FROM " + table.QName());
while (resSet.next()) {
Pair<K, D> record = readRecord(table);
table.Data.put(record.getKey(), record.getValue());
}
}
@Override
protected void insert(DBTable table, DBObject o) throws Exception {
PreparedStatement ps = insertStatements.get(table.d);
if (ps == null)
UI.Info("INSERT NULL");
int i = 1;
for (DBTableColumn column : table.columns.values()) {
if (!column.AutoIncrement) {
ps.setObject(i, o.getClass().getField(column.Name).get(o));
++i;
}
}
ps.execute();
//-->
for (DBTableColumn column : table.columns.values()) {
if (column.AutoIncrement) {
resSet = statement.executeQuery("SELECT MAX(" + column.QName() + ") AS LAST FROM " + table.QName());
String maxId = resSet.getString("LAST");
int intMaxId = Integer.parseInt(maxId);
o.getClass().getField(column.Name).set(o, intMaxId);
break;
}
}
}
@Override
protected void update(DBTable table, DBObject o) throws Exception {
PreparedStatement ps = updateStatements.get(table.d);
if (ps == null)
UI.Info("UPDATE NULL");
int i = 1;
for (DBTableColumn column : table.columns.values()) {
if (!column.AutoIncrement) {
ps.setObject(i, o.getClass().getField(column.Name).get(o));
++i;
}
}
ps.setObject(i, o.getPK());
ps.executeUpdate();
}
@Override
protected void deleteAll(DBTable table) throws Exception {
statement.executeUpdate("DELETE FROM " + table.QName());
}
@Override
protected void resetAI(DBTable table) throws Exception {
statement.executeUpdate("UPDATE SQLITE_SEQUENCE SET SEQ = 0 WHERE NAME =" + table.QName());
}
//--
//https://stackoverflow.com/questions/8558099/sqlite-query-with-byte-where-clause
}

View File

@@ -0,0 +1,43 @@
package Common.Database;
import Common.UI.Menus_2023.StableMenuItem;
import Common.Utils.Utils;
import javax.swing.*;
public class TableFilter<D extends DBObject> {
DataSet table;
public JMenuItem menuItem; //пункт меню фильтра. ( возможно потом сделать и кнопку)
String description;
boolean active = false; //включен ли фильтр
public int count = 0;
protected boolean validate(D object) {
return true;
}
public boolean Validate(D object) {
boolean valid;
if (valid=validate(object))
count++;
return !active || valid;
}
static String getNotActiveIconPath() {
return "/icons/NotPick.png";
}
static String getActiveIconPath() {
return "/icons/Pick.png";
}
public TableFilter(DataSet table_in, String description_in) {
table = table_in;
menuItem = new StableMenuItem((description = description_in)+" (0)");
menuItem.addActionListener(e -> {
active = !active;
Mark();
table.ShowUI();
});
Mark();
}
public void Mark() {
menuItem.setIcon(Utils.getIcon(active ? getActiveIconPath() : getNotActiveIconPath()));
}
public void ShowDescriptionAndCount() {
menuItem.setText(description + " " + Utils.RBrackets(count));
}
}

View File

@@ -0,0 +1,30 @@
package Common.Database;
import Common.Utils.Utils;
import com.sun.org.glassfish.gmbal.Description;
//автоинкрементальный ключ
public class iDBObject extends DBObject {
@Description("PRIMARY KEY,AUTOINCREMENT")
public int id;
@Override
public Object getPK() {
return id;
}
@Override
public String getFKName() {
return getClass().getSimpleName().toLowerCase() + "_id";
}
@Override
public Object getEmptyFK() {
return Utils.Nan;
}
//---
@Override
public void SynchronizeFields(DBObject src) {
super.SynchronizeFields(src);
id = ((iDBObject)src).id;
}
public iDBObject(){}
public iDBObject(iDBObject src){
this.SynchronizeFields(src);
}
}

View File

@@ -0,0 +1,6 @@
package Common.Database;
public abstract class iDBTable<D extends iDBObject> extends DBTable<Integer, D> {
public iDBTable(Class<D> d_in) {
super(Integer.class, d_in);
}
}

View File

@@ -0,0 +1,35 @@
package Common.Database;
import Common.Utils.Utils;
import com.sun.org.glassfish.gmbal.Description;
public abstract class nDBObject extends DBObject {
String getClassNameL() {
return getClass().getSimpleName().toLowerCase();
}
@Description("PRIMARY KEY, UNIQUE")
public String id = "";
@Override
public Object getPK() {
return id;
}
@Override
public String getFKName() {
return getClassNameL() + "_id";
}
@Override
public Object getEmptyFK() {
return "";
}
public void genName() {
id = Utils.getDateName(getClassNameL());
}
//-
@Override
public void SynchronizeFields(DBObject src) {
super.SynchronizeFields(src);
id = ((nDBObject)src).id;
}
public nDBObject(nDBObject src){
this.SynchronizeFields(src);
}
public nDBObject(){}
}

View File

@@ -0,0 +1,32 @@
package Common.Database;
import java.util.Date;
//объект репозитория. ключ имя, и есть данные отправителя.
public class rDBObject extends nDBObject {
public String sender_name = "";
public String sender_address = "";
public String description = "";
//-
public long date = 0;
public long change_date;
public Date getDate() {
return new Date(date);
}
public Date getChangeDate() {
return new Date(change_date);
}
@Override
public void SynchronizeFields(DBObject src) {
super.SynchronizeFields(src);
rDBObject r = (rDBObject) src;
sender_name = r.sender_name;
sender_address = r.sender_address;
description = r.description;
date = r.date;
change_date = r.change_date;
}
public rDBObject(rDBObject src) {
this.SynchronizeFields(src);
}
public rDBObject() {
}
}