diff --git a/pom.xml b/pom.xml
index 526fbcf3..f985b04f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,4 +14,12 @@
UTF-8
+
+
+ mysql
+ mysql-connector-java
+ 8.0.33
+
+
+
diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java
index 0058fbf9..a416fb4d 100644
--- a/src/main/java/mate/academy/Main.java
+++ b/src/main/java/mate/academy/Main.java
@@ -1,7 +1,39 @@
package mate.academy;
+import java.math.BigDecimal;
+import mate.academy.dao.BookDao;
+import mate.academy.dao.BookDaoImpl;
+import mate.academy.lib.Injector;
+import mate.academy.model.Book;
+
public class Main {
public static void main(String[] args) {
+ Injector injector = Injector.getInstance("mate.academy");
+ BookDao bookDao = (BookDaoImpl) injector.getInstance(BookDao.class);
+
+ Book cleanCodeBook = new Book();
+ cleanCodeBook.setTitle("Clean Code");
+ cleanCodeBook.setPrice(BigDecimal.valueOf(29.99));
+ bookDao.create(cleanCodeBook);
+
+ Book colorOfMagicBook = new Book();
+ colorOfMagicBook.setTitle("The color of magic");
+ colorOfMagicBook.setPrice(BigDecimal.valueOf(69.99));
+ bookDao.create(colorOfMagicBook);
+
+ System.out.println(bookDao.findById(1L));
+
+ colorOfMagicBook.setPrice(BigDecimal.valueOf(6.99));
+ bookDao.update(colorOfMagicBook);
+
+ System.out.println(bookDao.findAll());
+
+ bookDao.deleteById(colorOfMagicBook.getId());
+ bookDao.findAll().stream()
+ .peek(b -> {
+ b.setPrice(b.getPrice().multiply(BigDecimal.valueOf(0.9)));
+ bookDao.update(b);
+ }).forEach(System.out::println);
}
}
diff --git a/src/main/java/mate/academy/dao/BookDao.java b/src/main/java/mate/academy/dao/BookDao.java
new file mode 100644
index 00000000..d60c063d
--- /dev/null
+++ b/src/main/java/mate/academy/dao/BookDao.java
@@ -0,0 +1,17 @@
+package mate.academy.dao;
+
+import java.util.List;
+import java.util.Optional;
+import mate.academy.model.Book;
+
+public interface BookDao {
+ Book create(Book book);
+
+ Optional findById(Long id);
+
+ List findAll();
+
+ Book update(Book book);
+
+ boolean deleteById(Long id);
+}
diff --git a/src/main/java/mate/academy/dao/BookDaoImpl.java b/src/main/java/mate/academy/dao/BookDaoImpl.java
new file mode 100644
index 00000000..45761f3b
--- /dev/null
+++ b/src/main/java/mate/academy/dao/BookDaoImpl.java
@@ -0,0 +1,129 @@
+package mate.academy.dao;
+
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import mate.academy.exception.DataProcessingException;
+import mate.academy.lib.Dao;
+import mate.academy.model.Book;
+import mate.academy.util.ConnectionUtil;
+
+@Dao
+public class BookDaoImpl implements BookDao {
+ private static final int ZERO_UPDATES = 0;
+ private static final int ID_INDEX = 1;
+ private static final int TITLE_INDEX = 2;
+ private static final int PRICE_INDEX = 3;
+ private static final int TITLE_INDEX_FOR_UPDATE_OPERATION = 1;
+ private static final int PRICE_INDEX_FOR_UPDATE_OPERATION = 2;
+ private static final int ID_INDEX_FOR_UPDATE_OPERATION = 3;
+ private static final String ID_COLUMN = "books.id";
+ private static final String TITLE_COLUMN = "books.title";
+ private static final String PRICE_COLUMN = "books.price";
+ private static final String NO_UPDATES_EXCEPTION_TEXT = "Expected to update at least 1 value, but updated 0 values.";
+ private static final String CREATING_BOOK_EXCEPTION_TEXT = "Can't save a book ";
+ private static final String FINDING_BOOK_BY_ID_EXCEPTION_TEXT = "Can't get a book by id = ";
+ private static final String GETTING_LIST_OF_ALL_BOOKS_EXCEPTION_TEXT = "Can't get a book list from db";
+ private static final String UPDATING_BOOK_EXCEPTION_TEXT = "Can't update book ";
+ private static final String DELETING_BOOK_BY_ID_EXCEPTION_TEXT = "Can't delete a book by id = ";
+
+ @Override
+ public Book create(Book book) {
+ try (Connection connection = ConnectionUtil.getConnection();
+ PreparedStatement statement = connection.prepareStatement("INSERT INTO books (id, title, price) VALUES (?, ?, ?)", Statement.RETURN_GENERATED_KEYS)) {
+
+ statement.setLong(ID_INDEX, book.getId());
+ statement.setString(TITLE_INDEX, book.getTitle());
+ statement.setBigDecimal(PRICE_INDEX, book.getPrice());
+
+ if (statement.executeUpdate() == ZERO_UPDATES) {
+ throw new RuntimeException(NO_UPDATES_EXCEPTION_TEXT);
+ }
+ ResultSet generatedKeys = statement.getGeneratedKeys();
+ if (generatedKeys.next()) {
+ Integer id = generatedKeys.getObject(ID_INDEX, Integer.class);
+ book.setId(id);
+ }
+ } catch (SQLException e) {
+ throw new DataProcessingException(CREATING_BOOK_EXCEPTION_TEXT + book, e);
+ }
+ return book;
+ }
+
+ @Override
+ public Optional findById(Long id) {
+ try (Connection connection = ConnectionUtil.getConnection();
+ PreparedStatement statement = connection.prepareStatement("SELECT * FROM books WHERE id = ?")) {
+
+ statement.setLong(ID_INDEX, id);
+ ResultSet resultSet = statement.executeQuery();
+ if (resultSet.next()) {
+ return Optional.of(parseBookFromQuery(resultSet));
+ }
+ return Optional.empty();
+ } catch (SQLException e) {
+ throw new DataProcessingException(FINDING_BOOK_BY_ID_EXCEPTION_TEXT + id, e);
+ }
+ }
+
+ @Override
+ public List findAll() {
+ try (Connection connection = ConnectionUtil.getConnection();
+ PreparedStatement statement = connection.prepareStatement("SELECT * FROM books")) {
+
+ ResultSet resultSet = statement.executeQuery();
+ List books = new ArrayList<>();
+ while (resultSet.next()) {
+ books.add(parseBookFromQuery(resultSet));
+ }
+ return books;
+ } catch (SQLException e) {
+ throw new DataProcessingException(GETTING_LIST_OF_ALL_BOOKS_EXCEPTION_TEXT, e);
+ }
+ }
+
+ @Override
+ public Book update(Book book) {
+ try (Connection connection = ConnectionUtil.getConnection();
+ PreparedStatement statement = connection.prepareStatement("UPDATE books SET title = ?, price = ? WHERE id = ?")) {
+
+ statement.setString(TITLE_INDEX_FOR_UPDATE_OPERATION, book.getTitle());
+ statement.setBigDecimal(PRICE_INDEX_FOR_UPDATE_OPERATION, book.getPrice());
+ statement.setLong(ID_INDEX_FOR_UPDATE_OPERATION, book.getId());
+
+ if (statement.executeUpdate() == ZERO_UPDATES) {
+ throw new RuntimeException(NO_UPDATES_EXCEPTION_TEXT);
+ }
+ } catch (SQLException e) {
+ throw new DataProcessingException(UPDATING_BOOK_EXCEPTION_TEXT + book, e);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean deleteById(Long id) {
+ try (Connection connection = ConnectionUtil.getConnection();
+ PreparedStatement statement = connection.prepareStatement("DELETE FROM books WHERE id = ?")) {
+
+ statement.setLong(ID_INDEX, id);
+
+ return statement.executeUpdate() > ZERO_UPDATES;
+ } catch (SQLException e) {
+ throw new DataProcessingException(DELETING_BOOK_BY_ID_EXCEPTION_TEXT + id, e);
+ }
+ }
+
+ private Book parseBookFromQuery(ResultSet resultSet) throws SQLException{
+ Book book = new Book();
+ book.setId(resultSet.getObject(ID_COLUMN, Long.class));
+ book.setTitle(resultSet.getObject(TITLE_COLUMN, String.class));
+ book.setPrice(resultSet.getObject(PRICE_COLUMN, BigDecimal.class));
+ return book;
+ }
+}
diff --git a/src/main/java/mate/academy/exception/DataProcessingException.java b/src/main/java/mate/academy/exception/DataProcessingException.java
new file mode 100644
index 00000000..27877dca
--- /dev/null
+++ b/src/main/java/mate/academy/exception/DataProcessingException.java
@@ -0,0 +1,7 @@
+package mate.academy.exception;
+
+public class DataProcessingException extends RuntimeException{
+ public DataProcessingException(String message, Throwable ex) {
+ super(message, ex);
+ }
+}
diff --git a/src/main/java/mate/academy/model/Book.java b/src/main/java/mate/academy/model/Book.java
new file mode 100644
index 00000000..619de082
--- /dev/null
+++ b/src/main/java/mate/academy/model/Book.java
@@ -0,0 +1,42 @@
+package mate.academy.model;
+
+import java.math.BigDecimal;
+
+public class Book {
+ private long id;
+ private String title;
+ private BigDecimal price;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public BigDecimal getPrice() {
+ return price;
+ }
+
+ public void setPrice(BigDecimal price) {
+ this.price = price;
+ }
+
+ @Override
+ public String toString() {
+ return "Book{" +
+ "id=" + id +
+ ", title='" + title + '\'' +
+ ", price=" + price +
+ '}';
+ }
+}
diff --git a/src/main/java/mate/academy/util/ConnectionUtil.java b/src/main/java/mate/academy/util/ConnectionUtil.java
new file mode 100644
index 00000000..6205bab9
--- /dev/null
+++ b/src/main/java/mate/academy/util/ConnectionUtil.java
@@ -0,0 +1,26 @@
+package mate.academy.util;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Properties;
+
+public class ConnectionUtil {
+ public static final String DB_URL = "jdbc:mysql://localhost:3306/book_schema";
+ public static final Properties DB_PROPERTIES;
+ static {
+ DB_PROPERTIES = new Properties();
+ DB_PROPERTIES.put("user", "root");
+ DB_PROPERTIES.put("password", "qwerty123");
+
+ try {
+ Class.forName("com.mysql.cj.jdbc.Driver");
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Failed to load JDBC driver", e);
+ }
+ }
+
+ public static Connection getConnection() throws SQLException {
+ return DriverManager.getConnection(DB_URL, DB_PROPERTIES);
+ }
+}
diff --git a/src/main/resources/init_db.sql b/src/main/resources/init_db.sql
new file mode 100644
index 00000000..c7a89b5f
--- /dev/null
+++ b/src/main/resources/init_db.sql
@@ -0,0 +1,7 @@
+CREATE DATABASE book_schema;
+USE book_schema;
+CREATE TABLE books (
+ `id` BIGINT NOT NULL AUTO_INCREMENT,
+ `title` VARCHAR(255),
+ `price` DECIMAL,
+ PRIMARY KEY (`id`));