diff --git a/projects/liza22/pom.xml b/projects/liza22/pom.xml
new file mode 100644
index 0000000..2c6271b
--- /dev/null
+++ b/projects/liza22/pom.xml
@@ -0,0 +1,46 @@
+
+
+ 4.0.0
+
+ ru.mipt.diht.students
+ parent
+ 1.0-SNAPSHOT
+
+ ru.mipt.diht.students
+ liza22
+ 1.0-SNAPSHOT
+ liza22
+ http://maven.apache.org
+
+ UTF-8
+ 1.7
+ 1.7
+
+
+
+
+ com.h2database
+ h2
+ 1.4.190
+
+
+ org.powermock
+ powermock-module-junit4
+ 1.6.1
+ test
+ true
+
+
+ junit
+ junit
+
+
+
+
+
+ com.beust
+ jcommander
+ 1.48
+
+
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/App.java b/projects/liza22/src/main/java/ru/mipt/diht/students/App.java
new file mode 100644
index 0000000..31d6fa9
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/App.java
@@ -0,0 +1,11 @@
+package ru.mipt.diht.students;
+
+/**
+ * Hello world!
+ *
+ */
+public class App {
+ public static void main(String[] args) {
+ System.out.println("Hello World!");
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/pom.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/pom.xml
new file mode 100644
index 0000000..877c46d
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/pom.xml
@@ -0,0 +1,72 @@
+
+
+ 4.0.0
+
+ mini.orm
+ orm
+ 1.0
+
+
+ 1.7
+ 1.7
+
+
+
+
+ com.h2database
+ h2
+ 1.4.190
+
+
+ junit
+ junit
+ 4.4
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+ 1.8
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ 2.16
+
+ src/checkstyle.xml
+ src/checkstyle-suppressions.xml
+ Cp1251
+ true
+ true
+
+
+
+ validate
+ validate
+
+ check
+
+
+
+
+
+ com.puppycrawl.tools
+ checkstyle
+ 6.10.1
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml
new file mode 100644
index 0000000..ecd3542
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml
new file mode 100644
index 0000000..3401cf5
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java
new file mode 100644
index 0000000..f82e03d
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java
@@ -0,0 +1,16 @@
+package mini.orm.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/*
+ * Annotation for Table Columns.
+ * Default value is used now "", but it will be used as "field_name" later in code.
+ */
+@Target(value = ElementType.FIELD)
+@Retention(value = RetentionPolicy.RUNTIME)
+public @interface Column {
+ String name() default "";
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java
new file mode 100644
index 0000000..413ae39
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java
@@ -0,0 +1,25 @@
+package mini.orm.api;
+
+import java.util.List;
+
+/**
+ * Main ORM interface.
+ * @param type of entity
+ * @param type of primary key for entity
+ */
+public interface DatabaseService {
+
+ T queryById(K entityKey);
+
+ List queryForAll();
+
+ void insert(T newEntity);
+
+ void update(T updatedEntity);
+
+ void delete(T deleteEntity);
+
+ void createTable();
+
+ void dropTable();
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java
new file mode 100644
index 0000000..4a462fd
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java
@@ -0,0 +1,14 @@
+package mini.orm.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for Column which is Primary Key of table.
+ */
+@Target(value = ElementType.FIELD)
+@Retention(value = RetentionPolicy.RUNTIME)
+public @interface PrimaryKey {
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java
new file mode 100644
index 0000000..c4ad8c1
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java
@@ -0,0 +1,16 @@
+package mini.orm.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for Table.
+ * Default value is used now "", but it will be used as "class_name" later in code.
+ */
+@Target(value = ElementType.TYPE)
+@Retention(value = RetentionPolicy.RUNTIME)
+public @interface Table {
+ String name() default "";
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java
new file mode 100644
index 0000000..75832a9
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java
@@ -0,0 +1,182 @@
+package mini.orm.core;
+
+import mini.orm.api.DatabaseService;
+import mini.orm.core.db.ConnectionProvider;
+import mini.orm.core.db.impl.JdbcConnectionProvider;
+import mini.orm.core.model.ColumnDescriptor;
+import mini.orm.core.model.TableDescriptor;
+import mini.orm.core.utils.Constants;
+import mini.orm.core.utils.QueryStorage;
+
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * implementation ORM-service by JDBC base.
+ * @param - content type
+ * @param - primary key type
+ */
+public final class JdbcDatabaseService implements DatabaseService {
+ private static final boolean LOGGING = true;
+
+ private Class entityType;
+ private TableDescriptor tableDescriptor;
+
+ private ConnectionProvider connectionProvider;
+
+ public JdbcDatabaseService(Class entityClass) {
+ this.entityType = entityClass;
+ this.tableDescriptor = TableDescriptor.fromEntityClass(entityClass);
+ this.connectionProvider = new JdbcConnectionProvider();
+ }
+
+ public T queryById(K entityKey) {
+ // get query with TABLE name and primary key name
+ String query = QueryStorage.getSelectByPkQuery(tableDescriptor.getTableName(),
+ tableDescriptor.getPrimaryKey().getColumnName());
+ if (LOGGING) {
+ System.out.println("Method 'queryById' query is: " + query);
+ }
+ // make DB connection, then PreparedStatement, run query and processing the ResultSet
+ try (Connection conn = connectionProvider.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(query)) {
+ stmt.setObject(1, entityKey);
+ try (ResultSet result = stmt.executeQuery()) {
+ if (result.next()) {
+ return buildEntityFromResult(result);
+ } else {
+ return null;
+ }
+ }
+ } catch (SQLException e) {
+ System.err.println("Error while perform queryById: " + e.getMessage());
+ return null;
+ }
+ }
+
+ public List queryForAll() {
+ String query = QueryStorage.getSelectAllQuery(tableDescriptor.getTableName());
+ if (LOGGING) {
+ System.out.println("Method 'queryForAll' query is: " + query);
+ }
+ try (Connection conn = connectionProvider.getConnection();
+ Statement stmt = conn.createStatement();
+ ResultSet result = stmt.executeQuery(query)) {
+ List entities = new ArrayList<>();
+ while (result.next()) {
+ entities.add(buildEntityFromResult(result));
+ }
+ return entities;
+ } catch (SQLException e) {
+ System.err.println("Error while perform queryForAll: " + e.getMessage());
+ return null;
+ }
+ }
+
+ public void insert(T newEntity) {
+ String query = QueryStorage.getInsertQuery(tableDescriptor.getTableName(), tableDescriptor.getColumns().size());
+ if (LOGGING) {
+ System.out.println("Method 'insert' query is: " + query);
+ }
+ try (Connection conn = connectionProvider.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(query)) {
+ for (ColumnDescriptor columnDescriptor : tableDescriptor.getColumns()) {
+ int bindNum = tableDescriptor.getColumns().indexOf(columnDescriptor) + 1;
+ Object columnValue = columnDescriptor.getColumnField().get(newEntity);
+ stmt.setObject(bindNum, columnValue);
+ }
+ stmt.executeUpdate();
+ } catch (SQLException | IllegalAccessException e) {
+ System.err.println("Error while perform insert: " + e.getMessage());
+ }
+ }
+
+ public void update(T updatedEntity) {
+ List updateColumns = tableDescriptor.getColumnsExceptPK();
+ String[] updateColumnNames = new String[updateColumns.size()];
+ for (ColumnDescriptor cd : updateColumns) {
+ updateColumnNames[updateColumns.indexOf(cd)] = cd.getColumnName();
+ }
+ String query = QueryStorage.getUpdateByPkQuery(tableDescriptor.getTableName(),
+ updateColumnNames, tableDescriptor.getPrimaryKey().getColumnName());
+ if (LOGGING) {
+ System.out.println("Method 'update' query is: " + query);
+ }
+ try (Connection conn = connectionProvider.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(query)) {
+ int bindNum = 0;
+ for (ColumnDescriptor columnDescriptor : updateColumns) {
+ bindNum = updateColumns.indexOf(columnDescriptor) + 1;
+ Object columnValue = columnDescriptor.getColumnField().get(updatedEntity);
+ stmt.setObject(bindNum, columnValue);
+ }
+ stmt.setObject(bindNum + 1, tableDescriptor.getPrimaryKey().getColumnField().get(updatedEntity));
+ stmt.executeUpdate();
+ } catch (SQLException | IllegalAccessException e) {
+ System.err.println("Error while perform update: " + e.getMessage());
+ }
+ }
+
+ public void delete(T deleteEntity) {
+ ColumnDescriptor pkColumn = tableDescriptor.getPrimaryKey();
+ String query = QueryStorage.getDeleteByPkQuery(tableDescriptor.getTableName(), pkColumn.getColumnName());
+ if (LOGGING) {
+ System.out.println("Method 'delete' query is: " + query);
+ }
+ try (Connection conn = connectionProvider.getConnection();
+ PreparedStatement stmt = conn.prepareStatement(query)) {
+ stmt.setObject(1, pkColumn.getColumnField().get(deleteEntity));
+ stmt.executeUpdate();
+ } catch (SQLException | IllegalAccessException e) {
+ System.err.println("Error while perform delete: " + e.getMessage());
+ }
+ }
+
+ public void createTable() {
+ List columns = tableDescriptor.getColumns();
+ String[] columnNames = new String[columns.size()];
+ String[] columnTypes = new String[columns.size()];
+ for (int i = 0; i < columns.size(); i++) {
+ ColumnDescriptor columnDescriptor = columns.get(i);
+ columnNames[i] = columnDescriptor.getColumnName();
+ columnTypes[i] = Constants.JAVA_TO_SQL_TYPES.get(columnDescriptor.getColumnType());
+ }
+ String query = QueryStorage.getCreateTableQuery(tableDescriptor.getTableName(),
+ columnNames, columnTypes, tableDescriptor.getPrimaryKey().getColumnName());
+ if (LOGGING) {
+ System.out.println("Method 'createTable' query is: " + query);
+ }
+ try (Connection conn = connectionProvider.getConnection(); Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate(query);
+ } catch (SQLException e) {
+ System.err.println("Error while perform createTable: " + e.getMessage());
+ }
+ }
+
+ public void dropTable() {
+ String query = QueryStorage.getDropTableQuery(tableDescriptor.getTableName());
+ if (LOGGING) {
+ System.out.println("Method 'dropTable' query is: " + query);
+ }
+ try (Connection conn = connectionProvider.getConnection(); Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate(query);
+ } catch (SQLException e) {
+ System.err.println("Error while perform dropTable: " + e.getMessage());
+ }
+ }
+
+ private T buildEntityFromResult(ResultSet resultSet) {
+ try {
+ T entity = entityType.newInstance();
+ for (ColumnDescriptor column : tableDescriptor.getColumns()) {
+ Object columnValue = resultSet.getObject(column.getColumnName());
+ column.getColumnField().set(entity, columnValue);
+ }
+ return entity;
+ } catch (Exception e) {
+ System.err.println("Entity class = " + entityType + " is incorrect: " + e.getMessage());
+ return null;
+ }
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java
new file mode 100644
index 0000000..b07e365
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java
@@ -0,0 +1,12 @@
+package mini.orm.core.db;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/*
+ * provide Connection to DB.
+ */
+public interface ConnectionProvider {
+
+ Connection getConnection() throws SQLException;
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java
new file mode 100644
index 0000000..2817a4b
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java
@@ -0,0 +1,107 @@
+package mini.orm.core.db;
+
+import mini.orm.core.utils.Constants;
+
+import java.io.*;
+
+/*
+ * config file with parameters DB connection's.
+ * will be use by DriverManager to getting DB Connection.
+ */
+public class DbConfig {
+ /*
+ * keys names from property file.
+ */
+ private static final String JDBC_DRIVER_PROP_NAME = "db.jdbc.driver";
+ private static final String DB_URL_PROP_NAME = "db.url";
+ private static final String DB_USER_PROP_NAME = "db.user";
+ private static final String DB_PASSWORD_PROP_NAME = "db.password";
+
+ private String jdbcDriver;
+ private String url;
+ private String username;
+ private String password;
+
+ public DbConfig() {
+ init();
+ // load Jdbc Driver class
+ try {
+ Class.forName(jdbcDriver);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Driver Class = '" + jdbcDriver + "' not found", e);
+ }
+ }
+
+ private void init() {
+ File cfgFile = new File(Constants.DB_CONFIG_FILE);
+ try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(cfgFile)))) {
+ while (in.ready()) {
+ String line = in.readLine();
+ int indexOfDelimiter = line.indexOf('=');
+ if (indexOfDelimiter == -1) {
+ System.err.println("Incorrect line in DB configuration = '" + line + "'");
+ continue;
+ }
+ String propName = line.substring(0, indexOfDelimiter);
+ String propValue = line.substring(indexOfDelimiter + 1, line.length());
+ switch (propName) {
+ case JDBC_DRIVER_PROP_NAME:
+ jdbcDriver = propValue;
+ break;
+ case DB_URL_PROP_NAME:
+ url = propValue;
+ break;
+ case DB_USER_PROP_NAME:
+ username = propValue;
+ break;
+ case DB_PASSWORD_PROP_NAME:
+ password = propValue;
+ break;
+ default:
+ System.err.println("Property '" + propName + "' not recognized");
+ }
+ }
+ } catch (FileNotFoundException e) {
+ System.err.println("DB config file by path = \"" + cfgFile.getAbsolutePath() + "\" not found");
+ } catch (IOException e) {
+ System.err.println("Problem with reading DB config file: " + e.getMessage());
+ }
+
+ validate();
+ }
+
+ private void validate() {
+ if (jdbcDriver == null
+ || url == null
+ || username == null
+ || password == null) {
+ throw new IllegalStateException("DB configuration file is incorrect");
+ }
+ }
+
+ public final String getJdbcDriver() {
+ return jdbcDriver;
+ }
+
+ public final String getUrl() {
+ return url;
+ }
+
+ public final String getUsername() {
+ return username;
+ }
+
+ public final String getPassword() {
+ return password;
+ }
+
+ @Override
+ public final String toString() {
+ return "DbConfig{"
+ + "jdbcDriver='" + jdbcDriver + '\''
+ + ", url='" + url + '\''
+ + ", username='" + username + '\''
+ + ", password='" + password + '\''
+ + '}';
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java
new file mode 100644
index 0000000..0b1fb6b
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java
@@ -0,0 +1,24 @@
+package mini.orm.core.db.impl;
+
+import mini.orm.core.db.ConnectionProvider;
+import mini.orm.core.db.DbConfig;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * ConnectionProvider on the JDBC base.
+ * Using DB config with parameters to make Connection.
+ */
+public class JdbcConnectionProvider implements ConnectionProvider {
+ private DbConfig dbConfig;
+
+ public JdbcConnectionProvider() {
+ this.dbConfig = new DbConfig();
+ }
+
+ public final Connection getConnection() throws SQLException {
+ return DriverManager.getConnection(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword());
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java
new file mode 100644
index 0000000..5fc8d36
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java
@@ -0,0 +1,48 @@
+package mini.orm.core.model;
+
+import mini.orm.api.Column;
+import mini.orm.core.utils.NameUtils;
+
+import java.lang.reflect.Field;
+
+/**
+ * this class describes one column of table.
+ */
+public class ColumnDescriptor {
+ private String name;
+ private Class> type;
+ private Field columnField;
+
+ ColumnDescriptor(String columnName, Class> columnType, Field columnField1) {
+ this.name = columnName;
+ this.type = columnType;
+ this.columnField = columnField1;
+ columnField.setAccessible(true);
+ }
+
+ public final String getColumnName() {
+ return name;
+ }
+
+ public final Class> getColumnType() {
+ return type;
+ }
+
+ public final Field getColumnField() {
+ return columnField;
+ }
+
+ public static ColumnDescriptor fromEntityField(Field entityField) {
+ if (!entityField.isAnnotationPresent(Column.class)) {
+ throw new IllegalArgumentException("Field = " + entityField + " not annotated by @Column");
+ }
+
+ String columnName = entityField.getAnnotation(Column.class).name();
+ if (columnName.isEmpty()) {
+ // use default value - field name
+ columnName = NameUtils.convertFromCamelCaseToUnderscore(entityField.getName());
+ }
+ Class> columnType = entityField.getType();
+ return new ColumnDescriptor(columnName, columnType, entityField);
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java
new file mode 100644
index 0000000..701034c
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java
@@ -0,0 +1,79 @@
+package mini.orm.core.model;
+
+import mini.orm.api.PrimaryKey;
+import mini.orm.api.Table;
+import mini.orm.core.utils.NameUtils;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/*
+ * create descriptor to Table
+ */
+public final class TableDescriptor {
+ private String name;
+ private ColumnDescriptor primaryKey;
+ private List columns;
+
+ TableDescriptor(String tableName) {
+ this.name = tableName;
+ this.columns = new ArrayList<>();
+ }
+
+ void addColumn(ColumnDescriptor columnDescriptor) {
+ columns.add(columnDescriptor);
+ }
+
+ void setPrimaryKey(ColumnDescriptor primaryKeyColumn) {
+ this.primaryKey = primaryKeyColumn;
+ }
+
+ public String getTableName() {
+ return name;
+ }
+
+ public List getColumns() {
+ return Collections.unmodifiableList(columns);
+ }
+
+ public List getColumnsExceptPK() {
+ List columnsExceptPK = new ArrayList<>(columns);
+ columnsExceptPK.remove(primaryKey);
+ return columnsExceptPK;
+ }
+
+ public ColumnDescriptor getPrimaryKey() {
+ return primaryKey;
+ }
+
+ public static TableDescriptor fromEntityClass(Class> entityClass) {
+ if (!entityClass.isAnnotationPresent(Table.class)) {
+ throw new IllegalArgumentException("Class = " + entityClass.getSimpleName()
+ + " is not annotated by @Table");
+ }
+ String tableName = entityClass.getAnnotation(Table.class).name();
+ if (tableName.isEmpty()) {
+ // use default - class name
+ tableName = NameUtils.convertFromCamelCaseToUnderscore(entityClass.getSimpleName());
+ }
+
+ TableDescriptor tableDescriptor = new TableDescriptor(tableName);
+ boolean primaryKeyExists = false;
+ for (Field entityField : entityClass.getDeclaredFields()) {
+ ColumnDescriptor columnDescriptor = ColumnDescriptor.fromEntityField(entityField);
+ tableDescriptor.addColumn(columnDescriptor);
+ if (entityField.isAnnotationPresent(PrimaryKey.class)) {
+ tableDescriptor.setPrimaryKey(columnDescriptor);
+ primaryKeyExists = true;
+ }
+ }
+ if (!primaryKeyExists) {
+ throw new IllegalArgumentException("Entity class = " + entityClass.getSimpleName()
+ + " does not have @PrimaryKey field");
+ }
+
+ return tableDescriptor;
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java
new file mode 100644
index 0000000..07f9aca
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java
@@ -0,0 +1,28 @@
+package mini.orm.core.utils;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Project constants.
+ */
+public class Constants {
+ public static final String DB_CONFIG_FILE = "db.config";
+
+ /**
+ * correlate Java-types with SQL-types.
+ */
+ public static final Map, String> JAVA_TO_SQL_TYPES;
+ static {
+ JAVA_TO_SQL_TYPES = new HashMap<>();
+ JAVA_TO_SQL_TYPES.put(Boolean.class, "BOOLEAN");
+ JAVA_TO_SQL_TYPES.put(boolean.class, "BOOLEAN");
+ JAVA_TO_SQL_TYPES.put(Integer.class, "INTEGER");
+ JAVA_TO_SQL_TYPES.put(int.class, "INTEGER");
+ JAVA_TO_SQL_TYPES.put(Long.class, "BIGINT");
+ JAVA_TO_SQL_TYPES.put(long.class, "BIGINT");
+ JAVA_TO_SQL_TYPES.put(String.class, "VARCHAR(256)");
+ JAVA_TO_SQL_TYPES.put(Date.class, "TIMESTAMP");
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java
new file mode 100644
index 0000000..6975465
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java
@@ -0,0 +1,13 @@
+package mini.orm.core.utils;
+
+public final class NameUtils {
+
+ /*
+ * convert CamelCase format string to underscore format using regexp
+ */
+ public static String convertFromCamelCaseToUnderscore(String ccStr) {
+ String regex = "([a-z])([A-Z])";
+ String replacement = "$1_$2";
+ return ccStr.replaceAll(regex, replacement).toLowerCase();
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java
new file mode 100644
index 0000000..ced0024
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java
@@ -0,0 +1,71 @@
+package mini.orm.core.utils;
+
+import java.text.MessageFormat;
+
+/*
+ * this class contains SQL queries teplates.
+ */
+public class QueryStorage {
+
+ private static final String SELECT_BY_PK_QUERY =
+ "SELECT * FROM {0} WHERE {1} = ?";
+ public static String getSelectByPkQuery(String tableName, String pkColumnName) {
+ return MessageFormat.format(SELECT_BY_PK_QUERY, tableName, pkColumnName);
+ }
+
+ private static final String SELECT_ALL_QUERY =
+ "SELECT * FROM {0}";
+ public static String getSelectAllQuery(String tableName) {
+ return MessageFormat.format(SELECT_ALL_QUERY, tableName);
+ }
+
+ private static final String INSERT_QUERY =
+ "INSERT INTO {0} VALUES({1})";
+ public static String getInsertQuery(String tableName, int countOfColumns) {
+ StringBuilder valueBinds = new StringBuilder();
+ for (int i = 0; i < countOfColumns; i++) {
+ valueBinds.append("?");
+ if (i != countOfColumns - 1) {
+ valueBinds.append(", ");
+ }
+ }
+ return MessageFormat.format(INSERT_QUERY, tableName, valueBinds);
+ }
+
+ private static final String UPDATE_BY_PK_QUERY =
+ "UPDATE {0} SET {1} WHERE {2} = ?";
+ public static String getUpdateByPkQuery(String tableName, String[] columns, String pkColumnName) {
+ StringBuilder valueBinds = new StringBuilder();
+ for (int i = 0; i < columns.length; i++) {
+ valueBinds.append(columns[i]).append("=?");
+ if (i != columns.length - 1) {
+ valueBinds.append(", ");
+ }
+ }
+ return MessageFormat.format(UPDATE_BY_PK_QUERY, tableName, valueBinds, pkColumnName);
+ }
+
+ private static final String DELETE_BY_PK_QUERY =
+ "DELETE FROM {0} WHERE {1} = ?";
+ public static String getDeleteByPkQuery(String tableName, String pkColumnName) {
+ return MessageFormat.format(DELETE_BY_PK_QUERY, tableName, pkColumnName);
+ }
+
+ private static final String CREATE_TABLE_QUERY = "CREATE TABLE {0} ({1} PRIMARY KEY ( {2} ))";
+ public static String getCreateTableQuery(String tableName, String[] columnNames,
+ String[] columnTypes, String pkColumnName) {
+ StringBuilder columnsInfo = new StringBuilder();
+ for (int i = 0; i < columnNames.length; i++) {
+ String columnName = columnNames[i];
+ String columnType = columnTypes[i];
+ columnsInfo.append(columnName).append(" ").append(columnType).append(", ");
+ }
+ return MessageFormat.format(CREATE_TABLE_QUERY, tableName, columnsInfo, pkColumnName);
+ }
+
+ private static final String DROP_TABLE_QUERY =
+ "DROP TABLE {0}";
+ public static String getDropTableQuery(String tableName) {
+ return MessageFormat.format(DROP_TABLE_QUERY, tableName);
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java
new file mode 100644
index 0000000..d9c6d68
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java
@@ -0,0 +1,136 @@
+package mini.orm;
+
+import mini.orm.api.DatabaseService;
+import mini.orm.model.CarEntity;
+import mini.orm.model.IncorrectEntityWithoutColumnAnn;
+import mini.orm.model.IncorrectEntityWithoutPrimaryKeyAnn;
+import mini.orm.model.IncorrectEntityWithoutTableAnn;
+import mini.orm.core.JdbcDatabaseService;
+import org.h2.tools.Server;
+import org.junit.Test;
+import org.junit.Before;
+import org.junit.After;
+
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+public final class DatabaseServiceModuleTest {
+ private static final int N3 = 3;
+ private static final int N5 = 5;
+ private static final int N10 = 10;
+
+ private DatabaseService carDbService = new JdbcDatabaseService<>(CarEntity.class);
+
+ @Before
+ public void setUp() throws SQLException {
+ // start DB server
+ Server.createTcpServer("-tcpPort", "9001", "-tcpAllowOthers").start();
+ // firstly create table
+ carDbService.createTable();
+ }
+
+ @After
+ public void setDown() throws SQLException {
+ // drop table if it exists
+ carDbService.dropTable();
+ // stop DB server
+ Server.shutdownTcpServer("tcp://localhost:9001", "", true, true);
+ }
+
+ @Test
+ public void restAllDmlOperations() throws ParseException {
+ // add data to table
+ final CarEntity car1 = new CarEntity();
+ car1.setId(1);
+ car1.setName("Car#1");
+ car1.setColor("green");
+ car1.setTruck(false);
+ car1.setCountOfDoors(N5);
+ car1.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2010-12-01"));
+
+ final CarEntity car2 = new CarEntity();
+ car2.setId(2);
+ car2.setName("Car#2");
+ car2.setColor("blue");
+ car2.setTruck(false);
+ car2.setCountOfDoors(N3);
+ car2.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2013-01-20"));
+
+ final CarEntity truck = new CarEntity();
+ truck.setId(N3);
+ truck.setName("MegaTruck");
+ truck.setColor("grey");
+ truck.setTruck(true);
+ truck.setCountOfDoors(2);
+ truck.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2000-07-15"));
+
+ carDbService.insert(car1);
+ carDbService.insert(car2);
+ carDbService.insert(truck);
+
+ // select entity by primary key (car_2 expected)
+ CarEntity carByPK = carDbService.queryById(2);
+ assertNotNull(carByPK);
+ assertEquals(car2, carByPK);
+
+ CarEntity notExistedCar = carDbService.queryById(N10);
+ assertNull(notExistedCar);
+
+ // select all cars
+ List cars = carDbService.queryForAll();
+ assertEquals(N3, cars.size());
+ assertTrue(cars.contains(car1));
+ assertTrue(cars.contains(car2));
+ assertTrue(cars.contains(truck));
+
+ // update any car
+ CarEntity newTruck = new CarEntity();
+ newTruck.setId(N3);
+ newTruck.setName("New TheMegaTruck");
+ newTruck.setColor("dark-grey");
+ newTruck.setTruck(true);
+ newTruck.setCountOfDoors(2);
+ newTruck.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2015-07-15"));
+ carDbService.update(newTruck);
+ // select new truck and validate that it updated
+ CarEntity newTruckSelected = carDbService.queryById(N3);
+ assertEquals(newTruck, newTruckSelected);
+
+ // delete cars
+ carDbService.delete(car1);
+ carDbService.delete(car2);
+ // select all cars and check that deletion completed
+ List carsAfterDeletion = carDbService.queryForAll();
+ assertEquals(1, carsAfterDeletion.size());
+ assertTrue(carsAfterDeletion.contains(newTruck));
+
+ carDbService.delete(newTruck);
+ List noCarsAnymore = carDbService.queryForAll();
+ assertTrue(noCarsAnymore.isEmpty());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testIncorrectEntityWithoutTableAnnotation() {
+ DatabaseService dbService =
+ new JdbcDatabaseService<>(IncorrectEntityWithoutTableAnn.class);
+ dbService.queryForAll();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testIncorrectEntityWithoutColumnAnnotation() {
+ DatabaseService dbService =
+ new JdbcDatabaseService<>(IncorrectEntityWithoutColumnAnn.class);
+ dbService.queryForAll();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testIncorrectEntityWithoutPrimaryKeyAnnotation() {
+ DatabaseService dbService =
+ new JdbcDatabaseService<>(IncorrectEntityWithoutPrimaryKeyAnn.class);
+ dbService.queryForAll();
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java
new file mode 100644
index 0000000..1db881c
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java
@@ -0,0 +1,149 @@
+package mini.orm.model;
+
+import mini.orm.api.Column;
+import mini.orm.api.PrimaryKey;
+import mini.orm.api.Table;
+
+import java.util.Date;
+
+@Table(name = "cars")
+public final class CarEntity {
+
+ private static final int CONST31 = 31;
+
+ @PrimaryKey
+ @Column(name = "car_id")
+ private int id;
+
+ @Column
+ private String name;
+
+ @Column
+ private String color;
+
+ @Column
+ private int countOfDoors;
+
+ @Column(name = "is_truck")
+ private boolean truck;
+
+ @Column
+ private Date releaseDate;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int carid) {
+ this.id = carid;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String carname) {
+ this.name = carname;
+ }
+
+ public String getColor() {
+ return color;
+ }
+
+ public void setColor(String carcolor) {
+ this.color = carcolor;
+ }
+
+ public int getCountOfDoors() {
+ return countOfDoors;
+ }
+
+ public void setCountOfDoors(int carcountOfDoors) {
+ this.countOfDoors = carcountOfDoors;
+ }
+
+ public boolean isTruck() {
+ return truck;
+ }
+
+ public void setTruck(boolean cartruck) {
+ this.truck = cartruck;
+ }
+
+ public Date getReleaseDate() {
+ return releaseDate;
+ }
+
+ public void setReleaseDate(Date carreleaseDate) {
+ this.releaseDate = carreleaseDate;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ CarEntity carEntity = (CarEntity) o;
+
+ if (id != carEntity.id) {
+ return false;
+ }
+ if (countOfDoors != carEntity.countOfDoors) {
+ return false;
+ }
+ if (truck != carEntity.truck) {
+ return false;
+ }
+ if (name != null && !name.equals(carEntity.name) || name == null && carEntity.name != null) {
+ return false;
+ }
+ if (color != null && !color.equals(carEntity.color)
+ || color == null && carEntity.color != null) {
+ return false;
+ }
+ return !(releaseDate != null && !releaseDate.equals(carEntity.releaseDate)
+ || releaseDate == null && carEntity.releaseDate != null);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = id;
+ result = CONST31 * result;
+ if (name != null) {
+ result = result + name.hashCode();
+ }
+ result = CONST31 * result;
+ if (color != null) {
+ result = result + color.hashCode();
+ }
+ result = CONST31 * result + countOfDoors;
+ result = CONST31 * result;
+ if (truck) {
+ result = result + 1;
+ }
+ result = CONST31 * result;
+ if (releaseDate != null) {
+ result = result + releaseDate.hashCode();
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "CarEntity{"
+ + "id=" + id
+ + ", name='" + name
+ + '\''
+ + ", color='" + color
+ + '\''
+ + ", countOfDoors=" + countOfDoors
+ + ", truck=" + truck
+ + ", releaseDate=" + releaseDate
+ + '}';
+ }
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java
new file mode 100644
index 0000000..ad670d0
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java
@@ -0,0 +1,15 @@
+package mini.orm.model;
+
+import mini.orm.api.Column;
+import mini.orm.api.PrimaryKey;
+import mini.orm.api.Table;
+
+@Table
+public class IncorrectEntityWithoutColumnAnn {
+
+ @PrimaryKey
+ @Column
+ private Integer id;
+
+ private String name;
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java
new file mode 100644
index 0000000..b836ce9
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java
@@ -0,0 +1,14 @@
+package mini.orm.model;
+
+import mini.orm.api.Column;
+import mini.orm.api.Table;
+
+@Table
+public class IncorrectEntityWithoutPrimaryKeyAnn {
+
+ @Column
+ private Integer id;
+
+ @Column
+ private String name;
+}
diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java
new file mode 100644
index 0000000..3af530e
--- /dev/null
+++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java
@@ -0,0 +1,14 @@
+package mini.orm.model;
+
+import mini.orm.api.Column;
+import mini.orm.api.PrimaryKey;
+
+public class IncorrectEntityWithoutTableAnn {
+
+ @PrimaryKey
+ @Column
+ private Integer id;
+
+ @Column
+ private String name;
+}
diff --git a/projects/liza22/src/test/java/ru/mipt/diht/students/AppTest.java b/projects/liza22/src/test/java/ru/mipt/diht/students/AppTest.java
new file mode 100644
index 0000000..4bb8dd4
--- /dev/null
+++ b/projects/liza22/src/test/java/ru/mipt/diht/students/AppTest.java
@@ -0,0 +1,38 @@
+package ru.mipt.diht.students;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest
+ extends TestCase
+{
+ /**
+ * Create the test case
+ *
+ * @param testName name of the test case
+ */
+ public AppTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * @return the suite of tests being tested
+ */
+ public static Test suite()
+ {
+ return new TestSuite( AppTest.class );
+ }
+
+ /**
+ * Rigourous Test :-)
+ */
+ public void testApp()
+ {
+ assertTrue( true );
+ }
+}
diff --git a/projects/pom.xml b/projects/pom.xml
index 5d14966..5fc3c22 100644
--- a/projects/pom.xml
+++ b/projects/pom.xml
@@ -1,5 +1,5 @@
-
+
+
4.0.0
ru.mipt.diht.students
@@ -30,7 +30,8 @@
dkhurtin
ale3otik
Pitovsky
-
+ liza22
+
@@ -133,4 +134,4 @@
-
+
\ No newline at end of file