diff --git a/pom.xml b/pom.xml
index 683e84ec..9e45dc54 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,6 +18,14 @@
+
+
+ com.mysql
+ mysql-connector-j
+ 8.4.0
+
+
+
diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java
index 0058fbf9..88f3de9a 100644
--- a/src/main/java/mate/academy/Main.java
+++ b/src/main/java/mate/academy/Main.java
@@ -1,7 +1,47 @@
package mate.academy;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import mate.academy.dao.BookDao;
+import mate.academy.lib.Injector;
+import mate.academy.models.Book;
+import mate.academy.service.BookService;
+import mate.academy.service.BookServiceImpl;
+
public class Main {
+ private static final Injector injector = Injector
+ .getInstance("mate.academy");
+ private static final BigDecimal NEW_PRICE = new BigDecimal("120.50");
+
public static void main(String[] args) {
+ BookDao bookDao = (BookDao) injector.getInstance(BookDao.class);
+ BookService bookService = new BookServiceImpl(bookDao);
+
+ List savedBooks = new ArrayList<>();
+ Map.of("Java", new BigDecimal(300),
+ "Python", new BigDecimal(200),
+ "C++", new BigDecimal(100))
+ .forEach((title, price) -> {
+ Book currentBook = new Book();
+ currentBook.setTitle(title);
+ currentBook.setPrice(price);
+ savedBooks.add(bookService.save(currentBook));
+ });
+ System.out.println("savedBooks = " + savedBooks);
+
+ Book book = bookService.get(2L);
+ System.out.printf("Method get return: " + book);
+
+ book.setPrice(book.getPrice().multiply(NEW_PRICE));
+ book = bookService.update(book);
+ System.out.printf("Method update return: " + book);
+
+ boolean isDeleteBook = bookService.delete(savedBooks.get(0));
+ System.out.printf("Method delete return: " + isDeleteBook);
+ List bookList2 = bookService.getAll();
+ System.out.printf("Method getAll return: " + bookList2.toString());
}
}
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..2b9c3353
--- /dev/null
+++ b/src/main/java/mate/academy/dao/BookDao.java
@@ -0,0 +1,18 @@
+package mate.academy.dao;
+
+import java.util.List;
+import java.util.Optional;
+import mate.academy.models.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..d4c04093
--- /dev/null
+++ b/src/main/java/mate/academy/dao/BookDaoImpl.java
@@ -0,0 +1,121 @@
+package mate.academy.dao;
+
+import java.math.BigDecimal;
+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.exceptions.DataProcessingException;
+import mate.academy.lib.Dao;
+import mate.academy.models.Book;
+
+@Dao
+public class BookDaoImpl implements BookDao {
+ @Override
+ public Book create(Book book) {
+ String sql = "INSERT INTO books (title, price) VALUE (?, ?)";
+ try (PreparedStatement prepareStatement = ConnectionUtilImpl.getConnection()
+ .prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
+
+ prepareStatement.setString(1, book.getTitle());
+ prepareStatement.setBigDecimal(2, book.getPrice());
+
+ if (prepareStatement.executeUpdate() > 1) {
+ book.setId(getIdFromResultSet(prepareStatement.getGeneratedKeys()));
+ return book;
+ }
+ throw new DataProcessingException("Can't save the new book: " + book);
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't save a book: " + book, e);
+ }
+ }
+
+ @Override
+ public Optional findById(Long id) {
+ String sql = "SELECT * FROM books WHERE id = ?";
+ try (PreparedStatement prepareStatement = ConnectionUtilImpl.getConnection()
+ .prepareStatement(sql)) {
+
+ prepareStatement.setLong(1, id);
+
+ return getBookFromResultSet(prepareStatement.executeQuery());
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't get a book by id: " + id, e);
+ }
+ }
+
+ @Override
+ public List findAll() {
+ String sql = "SELECT * FROM books";
+ try (Statement statement = ConnectionUtilImpl.getConnection().createStatement()) {
+
+ return getAllFromResultSet(statement.executeQuery(sql));
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't get any books from the database", e);
+ }
+ }
+
+ @Override
+ public Book update(Book book) {
+ String sql = "UPDATE books SET title = ?, price = ? WHERE id = ?";
+ try (PreparedStatement prepareStatement = ConnectionUtilImpl.getConnection()
+ .prepareStatement(sql)) {
+
+ prepareStatement.setString(1, book.getTitle());
+ prepareStatement.setBigDecimal(2, book.getPrice());
+ prepareStatement.setLong(3, book.getId());
+
+ if (prepareStatement.executeUpdate() > 1) {
+ return book;
+ }
+ throw new DataProcessingException("Can't update the book: " + book);
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't update the book: " + book, e);
+ }
+ }
+
+ @Override
+ public boolean deleteById(Long id) {
+ String sql = "DELETE FROM books WHERE id = ?";
+ try (PreparedStatement prepareStatement = ConnectionUtilImpl.getConnection()
+ .prepareStatement(sql)) {
+
+ prepareStatement.setLong(1, id);
+
+ return prepareStatement.executeUpdate() > 1;
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't delete the book by id: " + id, e);
+ }
+ }
+
+ private Long getIdFromResultSet(ResultSet generatedKeys) throws SQLException {
+ if (generatedKeys.next()) {
+ return generatedKeys.getObject(1, Long.class);
+ }
+ throw new DataProcessingException("Can't writing the book to the database, missing ID");
+ }
+
+ private Optional getBookFromResultSet(ResultSet resultSet) throws SQLException {
+ if (resultSet.next()) {
+ Book book = new Book();
+
+ book.setId(resultSet.getObject("id", Long.class));
+ book.setTitle(resultSet.getString("title"));
+ book.setPrice(resultSet.getObject("price", BigDecimal.class));
+
+ return Optional.of(book);
+ }
+ return Optional.empty();
+ }
+
+ private List getAllFromResultSet(ResultSet resultSet) throws SQLException {
+ List bookList = new ArrayList<>();
+ do {
+ getBookFromResultSet(resultSet).ifPresent(bookList::add);
+ } while (resultSet.next());
+ return bookList;
+ }
+}
diff --git a/src/main/java/mate/academy/dao/ConnectionUtil.java b/src/main/java/mate/academy/dao/ConnectionUtil.java
new file mode 100644
index 00000000..70ecc1b5
--- /dev/null
+++ b/src/main/java/mate/academy/dao/ConnectionUtil.java
@@ -0,0 +1,4 @@
+package mate.academy.dao;
+
+public interface ConnectionUtil {
+}
diff --git a/src/main/java/mate/academy/dao/ConnectionUtilImpl.java b/src/main/java/mate/academy/dao/ConnectionUtilImpl.java
new file mode 100644
index 00000000..69e31ba5
--- /dev/null
+++ b/src/main/java/mate/academy/dao/ConnectionUtilImpl.java
@@ -0,0 +1,30 @@
+package mate.academy.dao;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Properties;
+
+public class ConnectionUtilImpl implements ConnectionUtil {
+ private static final String USER = "root";
+ private static final String PASSWORD = "illya";
+ private static final String DB_URL = "jdbs.mysql://localhost:3306/my_db";
+ private static final Properties DB_PROPERTIES;
+
+ static {
+ DB_PROPERTIES = new Properties();
+ DB_PROPERTIES.put("user", USER);
+ DB_PROPERTIES.put("password", PASSWORD);
+
+ try {
+ Class.forName("com.mysql.cj.jdbs.Driver");
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Can not load JDBS driver", e);
+ }
+ }
+
+ static Connection getConnection() throws SQLException {
+ return DriverManager.getConnection(DB_URL, DB_PROPERTIES);
+ }
+
+}
diff --git a/src/main/java/mate/academy/exceptions/DataProcessingException.java b/src/main/java/mate/academy/exceptions/DataProcessingException.java
new file mode 100644
index 00000000..e5a244c1
--- /dev/null
+++ b/src/main/java/mate/academy/exceptions/DataProcessingException.java
@@ -0,0 +1,12 @@
+package mate.academy.exceptions;
+
+public class DataProcessingException extends RuntimeException {
+ public DataProcessingException(String message) {
+ super(message);
+ }
+
+ public DataProcessingException(String message, Throwable cause) {
+ super(message, cause);
+
+ }
+}
diff --git a/src/main/java/mate/academy/lib/Dao.java b/src/main/java/mate/academy/lib/Dao.java
index f558d09a..22f45911 100644
--- a/src/main/java/mate/academy/lib/Dao.java
+++ b/src/main/java/mate/academy/lib/Dao.java
@@ -1,8 +1,4 @@
package mate.academy.lib;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-@Retention(RetentionPolicy.RUNTIME)
public @interface Dao {
}
diff --git a/src/main/java/mate/academy/models/Book.java b/src/main/java/mate/academy/models/Book.java
new file mode 100644
index 00000000..de901713
--- /dev/null
+++ b/src/main/java/mate/academy/models/Book.java
@@ -0,0 +1,45 @@
+package mate.academy.models;
+
+import java.math.BigDecimal;
+
+public class Book {
+ private Long id;
+ private String title;
+ private BigDecimal price;
+
+ public Book() {
+ }
+
+ 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/service/BookService.java b/src/main/java/mate/academy/service/BookService.java
new file mode 100644
index 00000000..c25e2937
--- /dev/null
+++ b/src/main/java/mate/academy/service/BookService.java
@@ -0,0 +1,16 @@
+package mate.academy.service;
+
+import java.util.List;
+import mate.academy.models.Book;
+
+public interface BookService {
+ Book save(Book book);
+
+ Book get(Long id);
+
+ List getAll();
+
+ Book update(Book book);
+
+ boolean delete(Book book);
+}
diff --git a/src/main/java/mate/academy/service/BookServiceImpl.java b/src/main/java/mate/academy/service/BookServiceImpl.java
new file mode 100644
index 00000000..3a4717d8
--- /dev/null
+++ b/src/main/java/mate/academy/service/BookServiceImpl.java
@@ -0,0 +1,60 @@
+package mate.academy.service;
+
+import java.util.List;
+import mate.academy.dao.BookDao;
+import mate.academy.exceptions.DataProcessingException;
+import mate.academy.models.Book;
+
+public class BookServiceImpl implements BookService {
+ private final BookDao bookDao;
+
+ public BookServiceImpl(BookDao bookDao) {
+ if (bookDao == null) {
+ throw new DataProcessingException("The argument (bookDao) is null");
+ }
+ this.bookDao = bookDao;
+ }
+
+ @Override
+ public Book save(Book book) {
+ if (book == null) {
+ throw new DataProcessingException("The argument (book) is null");
+ }
+ return bookDao.create(book);
+ }
+
+ @Override
+ public Book get(Long id) {
+ if (id == null) {
+ throw new DataProcessingException("The argument (id) is null");
+ }
+ return bookDao.findById(id)
+ .orElseThrow(() -> new DataProcessingException("Can't find a book with id: "
+ + id));
+ }
+
+ @Override
+ public List getAll() {
+ List bookList = bookDao.findAll();
+ if (bookList.isEmpty()) {
+ throw new DataProcessingException("Can't get any books from the database");
+ }
+ return bookList;
+ }
+
+ @Override
+ public Book update(Book book) {
+ if (book == null) {
+ throw new DataProcessingException("The argument (book) is null");
+ }
+ return bookDao.update(book);
+ }
+
+ @Override
+ public boolean delete(Book book) {
+ if (book == null || book.getId() == null) {
+ throw new DataProcessingException("The argument (book) or id is null");
+ }
+ return bookDao.deleteById(book.getId());
+ }
+}
diff --git a/src/main/resources/init_db.sql b/src/main/resources/init_db.sql
new file mode 100644
index 00000000..b4dfc36e
--- /dev/null
+++ b/src/main/resources/init_db.sql
@@ -0,0 +1,7 @@
+CREATE DATABASE `my_db`;
+USE my_db;
+CREATE TABLE books (
+ id BIGINT PRIMARY KEY,
+ title VARCHAR(50),
+ price DECIMAL(10,2)
+ );
\ No newline at end of file