Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 66 additions & 1 deletion task-1/schema.sql
Original file line number Diff line number Diff line change
@@ -1 +1,66 @@
-- Write here your DDL statements to create the tables for the database.
-- Write here your DDL statements to create the tables for the database.
CREATE TABLE members (
member_id SERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
phone TEXT,
address TEXT
);

CREATE TABLE library_cards (
card_id SERIAL PRIMARY KEY,
card_number TEXT UNIQUE NOT NULL,
issued_on DATE NOT NULL,
expires_on DATE NOT NULL CHECK (expires_on > issued_on),
member_id INT UNIQUE NOT NULL REFERENCES members(member_id)
);

CREATE TABLE publishers (
publisher_id SERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL
);

CREATE TABLE books (
book_id SERIAL PRIMARY KEY,
isbn TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
publisher_id INT REFERENCES publishers(publisher_id)
);
CREATE TABLE authors (
author_id SERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL
);
CREATE TABLE book_authors (
book_id INT NOT NULL REFERENCES books(book_id),
author_id INT NOT NULL REFERENCES authors(author_id),
PRIMARY KEY (book_id, author_id)
);
CREATE TABLE tags (
tag_id SERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL
);
CREATE TABLE book_tags (
book_id INT NOT NULL REFERENCES books(book_id),
tag_id INT NOT NULL REFERENCES tags(tag_id),
PRIMARY KEY (book_id, tag_id)
);
CREATE TABLE copies (
copy_id SERIAL PRIMARY KEY,
barcode TEXT UNIQUE NOT NULL,
shelf_code TEXT,
book_id INT NOT NULL REFERENCES books(book_id)
);

CREATE TABLE borrowings (
borrowing_id SERIAL PRIMARY KEY,
copy_id INT NOT NULL REFERENCES copies(copy_id),
member_id INT NOT NULL REFERENCES members(member_id),
borrowed_at TIMESTAMP NOT NULL,
due_date TIMESTAMP NOT NULL,
returned_at TIMESTAMP,
fine_eur NUMERIC DEFAULT 0 CHECK (fine_eur >= 0),
CHECK (returned_at IS NULL OR returned_at >= borrowed_at)

);


199 changes: 198 additions & 1 deletion task-2/src/main/java/org/hyf/Main.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,204 @@
package org.hyf;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.PreparedStatement;


public class Main {

private static Connection getConnection() throws SQLException {
String url = "jdbc:postgresql://localhost:5432/library_db";
String user = "postgres";
String pass = "postgres";
return DriverManager.getConnection(url, user, pass);
}

// Inset Data
public static void insertData() {
try (Connection conn = getConnection()) {

// Publisher 2 rows
PreparedStatement pub = conn.prepareStatement(
"INSERT INTO publishers (name) VALUES (?) ON CONFLICT (name) DO NOTHING"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice that you try to avoid duplicate insert errors using ON CONFLICT DO NOTHING. That makes the seed data easier to rerun during development. One thing to watch out for is that the code still uses hardcoded IDs afterwards. For example, if the publisher already exists with a different publisher_id, then using 1 as the hardcoded publisher_id can cause problems later on.

One way to avoid this is to return the actual ID from the database:

INSERT INTO publishers (name)
VALUES (?)
ON CONFLICT (name)
DO UPDATE SET name = EXCLUDED.name
RETURNING publisher_id;

Then you can use the publisher_id returned by the query to set the foreign keys later on.

);
pub.setString(1, "O'Reilly");
pub.executeUpdate();
pub.setString(1, "Addison-Wesley");
pub.executeUpdate();

// Authors 2 rows
PreparedStatement auth = conn.prepareStatement(
"INSERT INTO authors (name) VALUES (?) ON CONFLICT (name) DO NOTHING"
);

//row 1
auth.setString(1, "Douglas Crockford");
auth.executeUpdate();

//row 2
auth.setString(1, "Eric Freeman");
auth.executeUpdate();

// Books
PreparedStatement book = conn.prepareStatement(
"INSERT INTO books (isbn, title, publisher_id) VALUES (?, ?, ?) ON CONFLICT (isbn) DO NOTHING"
);

// row 1
book.setString(1, "9780596517748");
book.setString(2, "JavaScript: The Good Parts");
book.setInt(3, 1);
book.executeUpdate();

// row 2
book.setString(1, "9780596007126");
book.setString(2, "Head First Design Patterns");
book.setInt(3, 1);
book.executeUpdate();


// Members
PreparedStatement mem = conn.prepareStatement(
"INSERT INTO members (email, name, phone, address) VALUES (?, ?, ?, ?) ON CONFLICT (email) DO NOTHING"
);

//row 1
mem.setString(1, "omar@example.com");
mem.setString(2, "Omar");
mem.setString(3, "+31689012345");
mem.setString(4, "Rijnkade 19, Utrecht");
mem.executeUpdate();

//row 2
mem.setString(1, "tom@example.com");
mem.setString(2, "Tom");
mem.setString(3, "+31645678901");
mem.setString(4, "Biltstraat 88, Utrecht");
mem.executeUpdate();

// Library Cards
PreparedStatement card = conn.prepareStatement(
"INSERT INTO library_cards (card_number, issued_on, expires_on, member_id) VALUES (?, ?, ?, ?) ON CONFLICT (card_number) DO NOTHING"
);

// row 1
card.setString(1, "C-1008");
card.setDate(2, java.sql.Date.valueOf("2024-01-30"));
card.setDate(3, java.sql.Date.valueOf("2027-01-30"));
card.setInt(4, 1);
card.executeUpdate();

//row 2
card.setString(1, "C-1004");
card.setDate(2, java.sql.Date.valueOf("2023-11-20"));
card.setDate(3, java.sql.Date.valueOf("2026-11-20"));
card.setInt(4, 2);
card.executeUpdate();

// Copies
PreparedStatement copy = conn.prepareStatement(
"INSERT INTO copies (barcode, shelf_code, book_id) VALUES (?, ?, ?) ON CONFLICT (barcode) DO NOTHING"
);

// row 1
copy.setString(1, "BC-0011");
copy.setString(2, "B-03");
copy.setInt(3, 1);
copy.executeUpdate();

//row 2
copy.setString(1, "BC-0013");
copy.setString(2, "B-03");
copy.setInt(3, 1);
copy.executeUpdate();

// Borrowings
PreparedStatement bor = conn.prepareStatement(
"INSERT INTO borrowings (copy_id, member_id, borrowed_at, due_date, returned_at, fine_eur) " +
"VALUES (?, ?, ?, ?, ?, ?)"
);

// row 1 Omar
bor.setInt(1, 1);
bor.setInt(2, 1);
bor.setTimestamp(3, java.sql.Timestamp.valueOf("2025-12-02 08:08:00"));
bor.setTimestamp(4, java.sql.Timestamp.valueOf("2025-12-23 08:08:00"));
bor.setTimestamp(5, java.sql.Timestamp.valueOf("2025-12-13 08:08:00"));
bor.setBigDecimal(6, new java.math.BigDecimal("0.00"));
bor.executeUpdate();

//row 2 Tom
bor.setInt(1, 2);
bor.setInt(2, 2);
bor.setTimestamp(3, java.sql.Timestamp.valueOf("2026-01-10 08:51:00"));
bor.setTimestamp(4, java.sql.Timestamp.valueOf("2026-01-31 08:51:00"));
bor.setTimestamp(5, java.sql.Timestamp.valueOf("2026-01-25 08:51:00"));
bor.setBigDecimal(6, new java.math.BigDecimal("0.00"));
bor.executeUpdate();

System.out.println("Inserted 2 rows per table.");

} catch (SQLException e) {
e.printStackTrace();

}

}

// Fetch Data
public static void fetchData() {
String sql = """
SELECT
b.title AS book_title,
p.name AS publisher_name,
c.barcode AS copy_barcode,
m.name AS member_name,
br.borrowed_at,
br.returned_at
FROM borrowings br
JOIN copies c ON br.copy_id = c.copy_id
JOIN books b ON c.book_id = b.book_id
JOIN publishers p ON b.publisher_id = p.publisher_id
JOIN members m ON br.member_id = m.member_id
ORDER BY br.borrowed_at
LIMIT 10
""";

try (Connection conn = getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {

System.out.println("\n BORROWING RECORDS ");
System.out.println("---------------------------");

while (rs.next()) {
String title = rs.getString("book_title");
String publisher = rs.getString("publisher_name");
String barcode = rs.getString("copy_barcode");
String member = rs.getString("member_name");
String borrowedAt = rs.getString("borrowed_at");
String returnedAt = rs.getString("returned_at");

System.out.println(
"Book: " + title +
" | Publisher: " + publisher +
" | Copy: " + barcode +
" | Member: " + member +
" | Borrowed: " + borrowedAt +
" | Returned: " + returnedAt
);
}

} catch (SQLException e) {
e.printStackTrace();
}

}

public static void main(String[] args) {
System.out.println("You code goes here :) You can overwrite this entire method.");
insertData();
fetchData();
}
}