Skip to content

Commit 890a349

Browse files
author
Nikolai Malygin
committed
Define abstractions in README.md
1 parent 34485bf commit 890a349

File tree

3 files changed

+278
-13
lines changed

3 files changed

+278
-13
lines changed

README.md

Lines changed: 130 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
**Superb JDBC** is an object-oriented wrapper of JDBC API that simplifies work with relational databases.
44

5-
**Key Features:**
6-
- Convenient use through clear DBMS abstractions (Queries, Transactions, etc.).
7-
- Close attention to the reliable (encapsulation of closing Connections, ResultSets, etc.).
8-
- Close attention to the performance (encapsulation of PreparedStatements, etc.).
9-
- SQL and nothing more.
10-
- Zero dependencies.
11-
- MIT License.
5+
**Principles:**
6+
- Convenient use through clear DBMS abstractions (Queries, Transactions, etc.)
7+
- Close attention to the reliable
8+
- Close attention to the performance
9+
- SQL and nothing more
10+
- Zero dependencies
11+
- MIT License
1212

1313
## Quick Start
1414

@@ -31,12 +31,131 @@ Rdbms rdbms = new RealRdbms(dataSource);
3131
rdbms.change("INSERT INTO books(title) VALUES ('Clean Code')").apply();
3232
```
3333

34-
## Use cases
34+
## Abstractions
3535

36-
### Simple - select
36+
### Rdbms
3737

38+
Interface `Rdbms` combines interfaces: `Queries`, `Changes`, `Batches`, `Transactions` (factories of objects `Query`,
39+
`Change`, `Batch` and `Transaction`).
40+
41+
This separation of interfaces allows us to not violate the _Liskov's Substitution Principle_ in places where we
42+
want to provide partial functionality.
43+
44+
Note that extracting interfaces also allows us to use doubles (Fake, Stub, etc.) to write tests.
45+
46+
For real interaction with the RDBMS, the `RealRdbms` class is used, an example of creating an object of the corresponding class:
3847
```java
39-
List<String> titles = rdbms
48+
Rdbms rdbms = new RealRdbms(dataSource);
49+
```
50+
51+
### Query
52+
53+
Interface `Query` is a request to which RDBMS returns a result set, which must then be processed in some way.
54+
55+
#### Simple example
56+
57+
```java
58+
List<String> titles = queries
4059
.query("SELECT title FROM books")
41-
.executeWith(new StringListHandler("title"));
60+
.executeWith(new ColumnToListRsh<>(new StringColumn("title")));
4261
```
62+
63+
#### Using parameters
64+
65+
```java
66+
List<String> titles = queries
67+
.query("SELECT title FROM books WHERE title LIKE ?",
68+
new StringArgument("Clean%"))
69+
.executeWith(new ColumnToListRsh<>(new StringColumn("title")));
70+
```
71+
72+
Implementations of the `Argument` interface are used to define arguments. `Superb-jdbc` has several commonly used
73+
implementations of the corresponding interface, but you can always implement your own implementation.
74+
This approach makes `superb-jdbc` open to extension (_Open–closed principle_).
75+
76+
It is also worth paying attention to the fact that the arguments are specified directly in the place where the
77+
parameterized query is defined, which reduces the likelihood of making a mistake (unlike `jdbc`, where we first
78+
define the query and then set the parameter values).
79+
80+
#### Building a query
81+
82+
```java
83+
Query titlesQuery = queries.query("SELECT title FROM books");
84+
titlesQuery.append(" WHERE title LIKE ?", new StringArgument("Clean%"));
85+
titlesQuery.append(" LIMIT ?", new IntArgument(10));
86+
List<String> titles = titlesQuery
87+
.executeWith(new ColumnToListRsh<>(new StringColumn("title")));
88+
```
89+
90+
This approach can be useful, for example, when we have a web form and, depending on the fields filled in it, we want to
91+
be able to change the structure of our query (include or exclude some parts of the query).
92+
93+
### Change
94+
95+
The `Change` interface is a request to change the database (_DDL or DML_).
96+
97+
#### Simple example
98+
99+
```java
100+
changes
101+
.change("INSERT INTO books(title) VALUES ('Clean Code')")
102+
.apply();
103+
```
104+
105+
#### Using parameters
106+
107+
```java
108+
changes
109+
.change("INSERT INTO books(title) VALUES (?)", new StringArgument("Clean Code"))
110+
.apply();
111+
```
112+
113+
### Batch
114+
115+
The `Batch` interface is designed to efficiently insert a batch of data.
116+
117+
#### Simple example
118+
119+
```java
120+
try (Batch batch = batches.batch("INSERT INTO books(title) VALUES (?)")) {
121+
batch.put(new StringArgument("Clean Code"));
122+
batch.put(new StringArgument("Code Complete"));
123+
batch.put(new StringArgument("Effective Java"));
124+
batch.apply();
125+
}
126+
```
127+
128+
### Transaction
129+
130+
The `Transaction` interface is a transaction within which you can combine several queries to the RDBMS.
131+
132+
#### Simple example
133+
134+
```java
135+
try (Transaction transaction = transactions.transaction()) {
136+
transaction.change("INSERT INTO books(title) VALUES ('Clean Code')").apply();
137+
transaction.change("INSERT INTO books(title) VALUES ('Code Complete')").apply();
138+
transaction.change("INSERT INTO books(title) VALUES ('Effective Java')").apply();
139+
transaction.commit();
140+
}
141+
```
142+
143+
#### Setting the transaction isolation level
144+
145+
```java
146+
try (Transaction transaction = transactions.transaction(1)) {
147+
// some code
148+
}
149+
```
150+
151+
#### Using savepoints
152+
```java
153+
try (Transaction transaction = transactions.transaction()) {
154+
transaction.change("INSERT INTO books(title) VALUES ('Clean Code')").apply();
155+
transaction.setSavepoint("MySavepoint");
156+
transaction.change("INSERT INTO books(title) VALUES ('Code Complete')").apply();
157+
transaction.rollbackTo("MySavepoint");
158+
transaction.change("INSERT INTO books(title) VALUES ('Effective Java')").apply();
159+
transaction.commit();
160+
}
161+
```

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ SOFTWARE.
2929

3030
<groupId>com.nmalygin</groupId>
3131
<artifactId>superb-jdbc</artifactId>
32-
<version>0.0.4-SNAPSHOT</version>
32+
<version>0.0.5-SNAPSHOT</version>
3333
<packaging>jar</packaging>
3434

3535
<name>Superb JDBC</name>

src/test/java/com/nmalygin/superb/jdbc/real/ReadmeTest.java

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@
2424

2525
package com.nmalygin.superb.jdbc.real;
2626

27-
import com.nmalygin.superb.jdbc.api.Rdbms;
27+
import com.nmalygin.superb.jdbc.api.*;
28+
import com.nmalygin.superb.jdbc.api.arguments.IntArgument;
29+
import com.nmalygin.superb.jdbc.api.arguments.ObjectArgument;
30+
import com.nmalygin.superb.jdbc.api.arguments.StringArgument;
31+
import com.nmalygin.superb.jdbc.api.handlers.ColumnToListRsh;
32+
import com.nmalygin.superb.jdbc.api.handlers.columns.StringColumn;
2833
import com.nmalygin.superb.jdbc.real.testdb.BooksTable;
2934
import com.nmalygin.superb.jdbc.real.testdb.DataSourceBooksTable;
3035
import com.nmalygin.superb.jdbc.real.testdb.H2DataSource;
@@ -33,6 +38,8 @@
3338

3439
import javax.sql.DataSource;
3540
import java.sql.SQLException;
41+
import java.util.List;
42+
import java.util.UUID;
3643

3744
import static org.junit.jupiter.api.Assertions.assertEquals;
3845

@@ -49,4 +56,143 @@ void quickStart() throws SQLException {
4956

5057
assertEquals(1, booksTable.books().size());
5158
}
59+
60+
@Test
61+
void simpleSelect() throws SQLException {
62+
final DataSource dataSource = new H2DataSource();
63+
new LibraryDB(dataSource).init();
64+
final BooksTable booksTable = new DataSourceBooksTable(dataSource);
65+
booksTable.insert(UUID.randomUUID(), "Clean Code");
66+
67+
Queries queries = new RealRdbms(dataSource);
68+
List<String> titles = queries
69+
.query("SELECT title FROM books")
70+
.executeWith(new ColumnToListRsh<>(new StringColumn("title")));
71+
72+
assertEquals(1, titles.size());
73+
assertEquals("Clean Code", titles.get(0));
74+
}
75+
76+
@Test
77+
void selectWithParams() throws SQLException {
78+
final DataSource dataSource = new H2DataSource();
79+
new LibraryDB(dataSource).init();
80+
final BooksTable booksTable = new DataSourceBooksTable(dataSource);
81+
booksTable.insert(UUID.randomUUID(), "Clean Code");
82+
83+
Queries queries = new RealRdbms(dataSource);
84+
List<String> titles = queries
85+
.query(
86+
"SELECT title FROM books WHERE title LIKE ?",
87+
new StringArgument("Clean%")
88+
)
89+
.executeWith(new ColumnToListRsh<>(new StringColumn("title")));
90+
91+
assertEquals(1, titles.size());
92+
assertEquals("Clean Code", titles.get(0));
93+
}
94+
95+
@Test
96+
void buildingSelect() throws SQLException {
97+
final DataSource dataSource = new H2DataSource();
98+
new LibraryDB(dataSource).init();
99+
final BooksTable booksTable = new DataSourceBooksTable(dataSource);
100+
booksTable.insert(UUID.randomUUID(), "Clean Code");
101+
102+
Queries queries = new RealRdbms(dataSource);
103+
104+
Query titlesQuery = queries.query("SELECT title FROM books");
105+
titlesQuery.append(" WHERE title LIKE ?", new StringArgument("Clean%"));
106+
titlesQuery.append(" LIMIT ?", new IntArgument(10));
107+
List<String> titles = titlesQuery.executeWith(new ColumnToListRsh<>(new StringColumn("title")));
108+
109+
assertEquals(1, titles.size());
110+
assertEquals("Clean Code", titles.get(0));
111+
}
112+
113+
@Test
114+
void changeSimpleExample() throws SQLException {
115+
final DataSource dataSource = new H2DataSource();
116+
new LibraryDB(dataSource).init();
117+
final BooksTable booksTable = new DataSourceBooksTable(dataSource);
118+
119+
Changes changes = new RealRdbms(dataSource);
120+
121+
changes
122+
.change("INSERT INTO books(title) VALUES ('Clean Code')")
123+
.apply();
124+
125+
assertEquals(1, booksTable.books().size());
126+
}
127+
128+
@Test
129+
void changeWithParams() throws SQLException {
130+
final DataSource dataSource = new H2DataSource();
131+
new LibraryDB(dataSource).init();
132+
final BooksTable booksTable = new DataSourceBooksTable(dataSource);
133+
134+
Changes changes = new RealRdbms(dataSource);
135+
136+
changes
137+
.change("INSERT INTO books(title) VALUES (?)", new StringArgument("Clean Code"))
138+
.apply();
139+
140+
assertEquals(1, booksTable.books().size());
141+
}
142+
143+
@Test
144+
void batchSimpleExample() throws SQLException {
145+
final DataSource dataSource = new H2DataSource();
146+
new LibraryDB(dataSource).init();
147+
final BooksTable booksTable = new DataSourceBooksTable(dataSource);
148+
149+
Batches batches = new RealRdbms(dataSource);
150+
151+
try (Batch batch = batches.batch("INSERT INTO books(title) VALUES (?)")) {
152+
batch.put(new StringArgument("Clean Code"));
153+
batch.put(new StringArgument("Code Complete"));
154+
batch.put(new StringArgument("Effective Java"));
155+
batch.apply();
156+
}
157+
158+
assertEquals(3, booksTable.books().size());
159+
}
160+
161+
@Test
162+
void transactionSimpleExample() throws SQLException {
163+
final DataSource dataSource = new H2DataSource();
164+
new LibraryDB(dataSource).init();
165+
final BooksTable booksTable = new DataSourceBooksTable(dataSource);
166+
167+
Transactions transactions = new RealRdbms(dataSource);
168+
169+
try (Transaction transaction = transactions.transaction()) {
170+
transaction.change("INSERT INTO books(title) VALUES ('Clean Code')").apply();
171+
transaction.change("INSERT INTO books(title) VALUES ('Code Complete')").apply();
172+
transaction.change("INSERT INTO books(title) VALUES ('Effective Java')").apply();
173+
transaction.commit();
174+
}
175+
176+
assertEquals(3, booksTable.books().size());
177+
}
178+
179+
@Test
180+
void transactionUsingSavepoints() throws SQLException {
181+
final DataSource dataSource = new H2DataSource();
182+
new LibraryDB(dataSource).init();
183+
final BooksTable booksTable = new DataSourceBooksTable(dataSource);
184+
185+
Transactions transactions = new RealRdbms(dataSource);
186+
187+
try (Transaction transaction = transactions.transaction()) {
188+
transaction.change("INSERT INTO books(title) VALUES ('Clean Code')").apply();
189+
transaction.setSavepoint("MySavepoint");
190+
transaction.change("INSERT INTO books(title) VALUES ('Code Complete')").apply();
191+
transaction.rollbackTo("MySavepoint");
192+
transaction.change("INSERT INTO books(title) VALUES ('Effective Java')").apply();
193+
transaction.commit();
194+
}
195+
196+
assertEquals(3, booksTable.books().size());
197+
}
52198
}

0 commit comments

Comments
 (0)