Skip to content

Commit 29ed0f9

Browse files
extend the logic of the RecordBase + manual test (iluwatar#79)
1 parent fe908cc commit 29ed0f9

File tree

4 files changed

+132
-30
lines changed

4 files changed

+132
-30
lines changed

active-record/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ understand and maintain codebases.
2525

2626
## Tutorials
2727

28-
* [Panache – Active Record Pattern](https://thorben-janssen.com/panache-active-record-pattern/)
29-
* [Active Record pattern in Java](https://objsql.hashnode.dev/active-record-pattern-in-java)
28+
* [Active Record](https://www.martinfowler.com/eaaCatalog/activeRecord.html/)
29+
* [Overview of the Active Record Pattern](https://blog.savetchuk.com/overview-of-the-active-record-pattern)
3030

3131
## Consequences
3232

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.iluwatar.activerecord;
2+
3+
import java.sql.SQLException;
4+
import javax.sql.DataSource;
5+
import lombok.extern.slf4j.Slf4j;
6+
import org.h2.jdbcx.JdbcDataSource;
7+
8+
@Slf4j
9+
public class App {
10+
11+
private static final String DB_URL = "jdbc:h2:mem:dao;DB_CLOSE_DELAY=-1";
12+
13+
private static final String CREATE_SCHEMA_SQL = "CREATE TABLE customer\n"
14+
+ "(\n"
15+
+ " id BIGINT NOT NULL,\n"
16+
+ " customer_number VARCHAR(15) NOT NULL,\n"
17+
+ " first_name VARCHAR(45) NOT NULL,\n"
18+
+ " last_name VARCHAR(45) NOT NULL,\n"
19+
+ " CONSTRAINT customer_pkey PRIMARY KEY (id)\n"
20+
+ ");\n"
21+
+ "\n"
22+
+ "CREATE TABLE \"order\"\n"
23+
+ "(\n"
24+
+ " id BIGINT NOT NULL,\n"
25+
+ " order_number VARCHAR(15) NOT NULL,\n"
26+
+ " customer_id BIGINT NOT NULL,\n"
27+
+ " CONSTRAINT order_pkey PRIMARY KEY (id),\n"
28+
+ " CONSTRAINT customer_id_fk FOREIGN KEY (customer_id) REFERENCES customer (id)\n"
29+
+ ")";
30+
31+
32+
public static void main(final String[] args) throws Exception {
33+
final var dataSource = createDataSource();
34+
createSchema(dataSource);
35+
RecordBase.setDataSource(dataSource);
36+
executeOperation();
37+
}
38+
39+
private static void executeOperation() {
40+
LOGGER.info("saving the customer data...");
41+
Customer customer = new Customer();
42+
customer.setId(1L);
43+
customer.setCustomerNumber("C123");
44+
customer.setFirstName("John");
45+
customer.setLastName("Smith");
46+
47+
Order order = new Order();
48+
order.setId(1L);
49+
order.setOrderNumber("O123");
50+
51+
// customer.addOrder(order);
52+
customer.save();
53+
54+
LOGGER.info("The customer data by ID={}", customer.findById(1L));
55+
56+
LOGGER.info("find all the customers={}", customer.findAll());
57+
}
58+
59+
private static void createSchema(DataSource dataSource) throws SQLException {
60+
try (var connection = dataSource.getConnection();
61+
var statement = connection.createStatement()) {
62+
statement.execute(CREATE_SCHEMA_SQL);
63+
}
64+
}
65+
66+
private static DataSource createDataSource() {
67+
var dataSource = new JdbcDataSource();
68+
dataSource.setURL(DB_URL);
69+
return dataSource;
70+
}
71+
72+
}
Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
package com.iluwatar.activerecord;
22

3+
import java.sql.PreparedStatement;
34
import java.sql.ResultSet;
5+
import java.sql.SQLException;
46
import java.util.List;
5-
import javax.sql.DataSource;
67
import lombok.Getter;
78
import lombok.Setter;
9+
import lombok.ToString;
810

911
@Getter
1012
@Setter
11-
public class Customer extends RecordBase {
13+
@ToString
14+
public class Customer extends RecordBase<Customer> {
1215

1316
private Long id;
1417
private String customerNumber;
1518
private String firstName;
1619
private String lastName;
1720
private List<Order> orders;
1821

19-
public Customer(DataSource dataSource) {
20-
super(dataSource);
21-
}
22-
2322
public Customer findByNumber(String customerNumber) {
2423
// TODO
2524
return null;
26-
// return new Customer();
25+
}
26+
27+
public void addOrder(Order order) {
28+
orders.add(order);
2729
}
2830

2931
@Override
@@ -32,7 +34,15 @@ protected String getTableName() {
3234
}
3335

3436
@Override
35-
protected void setFieldsFromResultSet(ResultSet rs) {
37+
protected void setFieldsFromResultSet(ResultSet rs) throws SQLException {
38+
this.id = rs.getLong("id");
39+
this.customerNumber = rs.getString("customer_number");
40+
this.firstName = rs.getString("first_name");
41+
this.lastName = rs.getString("last_name");
42+
}
43+
44+
@Override
45+
protected void setPreparedStatementParams(PreparedStatement pstmt) throws SQLException {
3646

3747
}
3848
}

active-record/src/main/java/com/iluwatar/activerecord/RecordBase.java

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@
99
import java.util.List;
1010
import javax.sql.DataSource;
1111
import lombok.RequiredArgsConstructor;
12+
import lombok.Setter;
1213

1314
@RequiredArgsConstructor
14-
public abstract class RecordBase {
15+
public abstract class RecordBase<T extends RecordBase<?>> {
1516

16-
private final DataSource dataSource;
17+
@Setter
18+
private static DataSource dataSource;
19+
20+
@SuppressWarnings({"unchecked"})
21+
private final Class<T> clazz = (Class<T>) getClass();
1722

1823
protected Connection getConnection() throws SQLException {
1924
return dataSource.getConnection();
@@ -26,22 +31,22 @@ protected Connection getConnection() throws SQLException {
2631
*/
2732
protected abstract String getTableName();
2833

29-
protected abstract void setFieldsFromResultSet(ResultSet rs);
34+
protected abstract void setFieldsFromResultSet(ResultSet rs) throws SQLException;
35+
36+
protected abstract void setPreparedStatementParams(PreparedStatement pstmt) throws SQLException;
3037

3138
/**
3239
* Find all the records for a corresponding domain model.
3340
*
34-
* @param clazz domain model class.
35-
* @param <T> domain model type.
3641
* @return all the domain model related records.
3742
*/
38-
public <T extends RecordBase> List<T> findAll(Class<T> clazz) {
43+
public List<T> findAll() {
3944
List<T> recordList = new ArrayList<>();
4045
try (Connection conn = getConnection();
41-
PreparedStatement pstmt = conn.prepareStatement(constructGetByIdQuery(clazz))) {
46+
PreparedStatement pstmt = conn.prepareStatement(constructFindAllQuery())) {
4247
try (ResultSet rs = pstmt.executeQuery()) {
4348
while (rs.next()) {
44-
T record = getDeclaredClassInstance(clazz);
49+
T record = getDeclaredClassInstance();
4550
record.setFieldsFromResultSet(rs);
4651
recordList.add(record);
4752
}
@@ -57,26 +62,24 @@ public <T extends RecordBase> List<T> findAll(Class<T> clazz) {
5762
/**
5863
* Find a domain model by its ID.
5964
*
60-
* @param id domain model identifier.
61-
* @param clazz domain model class.
62-
* @param <T> domain model type.
65+
* @param id domain model identifier.
6366
* @return the domain model.
6467
*/
65-
public <T extends RecordBase> T findById(Long id, Class<T> clazz) {
68+
public T findById(Long id) {
6669
try (Connection conn = getConnection();
67-
PreparedStatement pstmt = conn.prepareStatement(constructGetByIdQuery(clazz))) {
70+
PreparedStatement pstmt = conn.prepareStatement(constructFindByIdQuery())) {
6871
pstmt.setLong(1, id);
6972
try (ResultSet rs = pstmt.executeQuery()) {
7073
if (rs.next()) {
71-
T record = getDeclaredClassInstance(clazz);
74+
T record = getDeclaredClassInstance();
7275
record.setFieldsFromResultSet(rs);
7376
return record;
7477
}
75-
return getDeclaredClassInstance(clazz);
78+
return getDeclaredClassInstance();
7679
}
7780
} catch (SQLException e) {
7881
throw new RuntimeException(
79-
"Unable to fine a record for the following domain model : " + clazz.getName() + " by id="
82+
"Unable to find a record for the following domain model : " + clazz.getName() + " by id="
8083
+ id
8184
+ " due to the data persistence error", e);
8285
}
@@ -86,15 +89,32 @@ public <T extends RecordBase> T findById(Long id, Class<T> clazz) {
8689
* Save the record.
8790
*/
8891
public void save() {
89-
// TODO
92+
try (Connection connection = getConnection();
93+
// TODO
94+
PreparedStatement pstmt = connection.prepareStatement(null,
95+
PreparedStatement.RETURN_GENERATED_KEYS)) {
96+
97+
setPreparedStatementParams(pstmt);
98+
pstmt.executeUpdate();
99+
100+
} catch (SQLException e) {
101+
throw new RuntimeException(
102+
"Unable to save the record for the following domain model : " + clazz.getName()
103+
+ " due to the data persistence error", e);
104+
}
105+
}
106+
107+
108+
private String constructFindAllQuery() {
109+
return "SELECT * FROM " + getDeclaredClassInstance().getTableName();
90110
}
91111

92-
private <T extends RecordBase> String constructGetByIdQuery(Class<T> clazz) {
93-
return "SELECT * FROM " + getDeclaredClassInstance(clazz).getTableName()
112+
private String constructFindByIdQuery() {
113+
return "SELECT * FROM " + getDeclaredClassInstance().getTableName()
94114
+ " WHERE id = ?";
95115
}
96116

97-
private <T extends RecordBase> T getDeclaredClassInstance(Class<T> clazz) {
117+
private T getDeclaredClassInstance() {
98118
try {
99119
return clazz.getDeclaredConstructor().newInstance();
100120
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException |

0 commit comments

Comments
 (0)