diff --git a/pom.xml b/pom.xml index 969b5f3e..1466d4de 100644 --- a/pom.xml +++ b/pom.xml @@ -13,5 +13,12 @@ 17 UTF-8 + + + mysql + mysql-connector-java + 8.0.24 + + \ No newline at end of file diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 0058fbf9..41df75ba 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -1,7 +1,29 @@ package mate.academy; +import mate.academy.dao.BookDao; +import mate.academy.lib.Injector; +import mate.academy.model.Book; + +import java.math.BigDecimal; + public class Main { + private static Injector injector = Injector.getInstance("mate.academy"); public static void main(String[] args) { - + BookDao bookDao = (BookDao) injector.getInstance(BookDao.class); + Book firstBook = new Book(); + firstBook.setTitle("Harry Potter"); + firstBook.setPrice(BigDecimal.valueOf(100)); + firstBook = bookDao.create(firstBook); + Book secondBook = new Book(); + secondBook.setTitle("Witcher"); + secondBook.setPrice(BigDecimal.valueOf(120)); + secondBook = bookDao.create(secondBook); + System.out.println(bookDao.findById(firstBook.getId())); + System.out.println(bookDao.findById(secondBook.getId())); + System.out.println(bookDao.findAll()); + System.out.println(bookDao.deleteById(firstBook.getId())); + secondBook.setPrice(BigDecimal.valueOf(140)); + bookDao.update(secondBook); + System.out.println(bookDao.findAll()); } } 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..5c3db0dd --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDao.java @@ -0,0 +1,17 @@ +package mate.academy.dao; + +import mate.academy.model.Book; +import java.util.List; +import java.util.Optional; + +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/impl/BookDaoImpl.java b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java new file mode 100644 index 00000000..aa4351db --- /dev/null +++ b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java @@ -0,0 +1,119 @@ +package mate.academy.dao.impl; + +import mate.academy.dao.BookDao; +import mate.academy.exception.DataProcessingException; +import mate.academy.lib.Dao; +import mate.academy.model.Book; +import mate.academy.util.ConnectionUtil; +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; + +@Dao +public class BookDaoImpl implements BookDao { + @Override + public Book create(Book book) { + String createBookQuery = "INSERT INTO books (title, price) VALUES (?, ?);"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement createBookStatement = + connection.prepareStatement(createBookQuery, + Statement.RETURN_GENERATED_KEYS)) { + createBookStatement.setString(1, book.getTitle()); + createBookStatement.setBigDecimal(2, book.getPrice()); + int insertedRows = createBookStatement.executeUpdate(); + if (insertedRows < 1) { + throw new DataProcessingException("Expected to insert at least 1 row," + + " but nothing was inserted by adding book: " + book); + } + ResultSet generatedKeys = createBookStatement.getGeneratedKeys(); + if (generatedKeys.next()) { + Long id = generatedKeys.getObject(1, Long.class); + book.setId(id); + } + return book; + } catch (SQLException e) { + throw new DataProcessingException("Can t insert the book in db: " + book, e); + } + } + + @Override + public Optional findById(Long id) { + String getByIdQuery = "SELECT * FROM books WHERE id = ? AND is_deleted = FALSE;"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement getByIdStatement = + connection.prepareStatement(getByIdQuery)) { + getByIdStatement.setLong(1, id); + ResultSet resultSet = getByIdStatement.executeQuery(); + Book book = null; + if (resultSet.next()) { + book = parseBookFromResultSet(resultSet); + } + return Optional.ofNullable(book); + } catch (SQLException e) { + throw new DataProcessingException("Can't find book by id: " + id, e); + } + } + + @Override + public List findAll() { + String getAllQuery = "SELECT * FROM books WHERE is_deleted = FALSE;"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement getAllStatement = + connection.prepareStatement(getAllQuery)) { + ResultSet resultSet = getAllStatement.executeQuery(); + List booksList = new ArrayList<>(); + while (resultSet.next()) { + booksList.add(parseBookFromResultSet(resultSet)); + } + return booksList; + } catch (SQLException e) { + throw new DataProcessingException("Can't get all books from db", e); + } + } + + @Override + public Book update(Book book) { + String updateBookQuery = "UPDATE books SET title = ?, price = ? WHERE is_deleted = FALSE;"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement updateBookStatement = + connection.prepareStatement(updateBookQuery)) { + updateBookStatement.setString(1, book.getTitle()); + updateBookStatement.setBigDecimal(2, book.getPrice()); + int updatedRows = updateBookStatement.executeUpdate(); + if (updatedRows < 1) { + throw new DataProcessingException("Rows were not updated for book" + book); + } + return book; + } catch (SQLException e) { + throw new DataProcessingException("Can't update book: " + book, e); + } + } + + @Override + public boolean deleteById(Long id) { + String deleteByIdQuery = "UPDATE books SET is_deleted = TRUE WHERE id = ?;"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement deleteByIdStatement = + connection.prepareStatement(deleteByIdQuery)) { + deleteByIdStatement.setLong(1, id); + int deletedRows = deleteByIdStatement.executeUpdate(); + return deletedRows > 0; + } catch (SQLException e) { + throw new DataProcessingException("Can't delete book by id: " + id, e); + } + } + + private Book parseBookFromResultSet(ResultSet resultSet) throws SQLException { + Book book = new Book(); + book.setId(resultSet.getObject("id", Long.class)); + book.setTitle(resultSet.getString("title")); + book.setPrice(resultSet.getObject("price", 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..c6f86d61 --- /dev/null +++ b/src/main/java/mate/academy/exception/DataProcessingException.java @@ -0,0 +1,11 @@ +package mate.academy.exception; + +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/model/Book.java b/src/main/java/mate/academy/model/Book.java new file mode 100644 index 00000000..b43614b9 --- /dev/null +++ b/src/main/java/mate/academy/model/Book.java @@ -0,0 +1,72 @@ +package mate.academy.model; + +import java.math.BigDecimal; +import java.util.Objects; + +public class Book { + private Long id; + private String title; + private BigDecimal price; + + public Book() { + + } + + public Book(Long id, String title, BigDecimal price) { + this.id = id; + this.price = price; + this.title = title; + } + + 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 int hashCode() { + return Objects.hash(id, title, price); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + Book book = (Book) obj; + return Objects.equals(id, book.id) + && Objects.equals(title, book.title) + && Objects.equals(price, book.price); + } + + @Override + public String toString() { + return "Car{" + + "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..9d3c7785 --- /dev/null +++ b/src/main/java/mate/academy/util/ConnectionUtil.java @@ -0,0 +1,32 @@ +package mate.academy.util; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +public class ConnectionUtil { + private static final String URL = "jdbc:mysql://localhost:3306/library_db"; + private static final String USERNAME = "root"; + private static final String PASSWORD = "Ghfnfnbg123"; + private static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; + + static { + try { + Class.forName(JDBC_DRIVER); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Can't find SQL Driver", e); + } + } + + public static Connection getConnection() { + Properties dbProperties = new Properties(); + dbProperties.setProperty("user", USERNAME); + dbProperties.setProperty("password", PASSWORD); + try { + return DriverManager.getConnection(URL, dbProperties); + } catch (SQLException e) { + throw new RuntimeException("Can't create connection to DB ", e); + } + } +} diff --git a/src/main/java/resources/init_db.sql b/src/main/java/resources/init_db.sql new file mode 100644 index 00000000..f3be32d7 --- /dev/null +++ b/src/main/java/resources/init_db.sql @@ -0,0 +1,8 @@ +CREATE DATABASE `library_db` /*!40100 DEFAULT CHARACTER SET utf8mb3 */ /*!80016 DEFAULT ENCRYPTION='N' */; +CREATE TABLE `book` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `title` varchar(255) DEFAULT NULL, + `price` decimal(10,0) DEFAULT NULL, + `is_deleted` tinyint NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;