Skip to content

Commit ce98d55

Browse files
committed
Code cleaning
1 parent b418e86 commit ce98d55

File tree

3 files changed

+77
-97
lines changed

3 files changed

+77
-97
lines changed

utils/SqlExecutor.java

Lines changed: 73 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
*/
88
package utils;
99

10-
import org.jetbrains.annotations.NotNull;
11-
import org.junit.jupiter.api.Assertions;
1210
import java.io.Closeable;
13-
import java.io.IOException;
1411
import java.sql.*;
1512
import java.time.LocalDate;
1613
import java.util.*;
@@ -27,12 +24,13 @@ public final class SqlExecutor {
2724
private final LocalDate someDate = LocalDate.parse("2018-09-12");
2825

2926
public static void main(final String[] args) throws Exception {
27+
System.out.println("Arguments: " + List.of(args));
3028
try (Connection dbConnection = db.connection()) {
31-
new SqlExecutor().mainStart(dbConnection, args);
29+
new SqlExecutor().mainStart(dbConnection);
3230
}
3331
}
3432

35-
void mainStart(Connection dbConnection, String... args) throws Exception {
33+
void mainStart(Connection dbConnection) throws Exception {
3634
try (SqlParamBuilder builder = new SqlParamBuilder(dbConnection)) {
3735
// CREATE TABLE:
3836
builder.sql("""
@@ -41,16 +39,15 @@ void mainStart(Connection dbConnection, String... args) throws Exception {
4139
, name VARCHAR(256) DEFAULT 'test'
4240
, code VARCHAR(1)
4341
, created DATE NOT NULL
44-
)""".stripLeading())
42+
)""")
4543
.execute();
4644

4745
// SINGLE INSERT:
48-
System.out.println("SINGLE INSERT");
4946
builder.sql("""
5047
INSERT INTO employee
5148
( id, code, created ) VALUES
5249
( :id, :code, :created )
53-
""".stripLeading())
50+
""")
5451
.bind("id", 1)
5552
.bind("code", "T")
5653
.bind("created", someDate)
@@ -62,7 +59,7 @@ void mainStart(Connection dbConnection, String... args) throws Exception {
6259
(id,code,created) VALUES
6360
(:id1,:code,:created),
6461
(:id2,:code,:created)
65-
""".stripLeading())
62+
""")
6663
.bind("id1", 2)
6764
.bind("id2", 3)
6865
.bind("code", "T")
@@ -80,28 +77,29 @@ void mainStart(Connection dbConnection, String... args) throws Exception {
8077
WHERE t.id < :id
8178
AND t.code IN (:code)
8279
ORDER BY t.id
83-
""".stripLeading())
80+
""")
8481
.bind("id", 10)
8582
.bind("code", "T", "V")
8683
.streamMap(rs -> new Employee(
8784
rs.getInt(1),
8885
rs.getString(2),
8986
rs.getObject(3, LocalDate.class)))
9087
.toList();
91-
Assertions.assertEquals(3, employees.size());
92-
Assertions.assertEquals(1, employees.get(0).id);
93-
Assertions.assertEquals("test", employees.get(0).name);
94-
Assertions.assertEquals(someDate, employees.get(0).created);
9588

96-
// REUSE SELECT:
89+
assertEquals(3, employees.size());
90+
assertEquals(1, employees.get(0).id);
91+
assertEquals("test", employees.get(0).name);
92+
assertEquals(someDate, employees.get(0).created);
93+
94+
// REUSE THE SELECT:
9795
List<Employee> employees2 = builder
9896
.bind("id", 100)
9997
.streamMap(rs -> new Employee(
10098
rs.getInt(1),
10199
rs.getString(2),
102100
rs.getObject(3, LocalDate.class)))
103101
.toList();
104-
Assertions.assertEquals(5, employees2.size());
102+
assertEquals(5, employees2.size());
105103
}
106104
}
107105

@@ -125,53 +123,85 @@ public static ConnectionProvider forH2(String user, String passwd) {
125123
}
126124
}
127125

128-
/** A utility class from the Ujorm framework */
129-
static class SqlParamBuilder implements Closeable {
126+
private <T> void assertEquals(T expected, T result) {
127+
if (!Objects.equals(expected, result)) {
128+
throw new IllegalStateException("Objects are not equals: '%s' <> '%s'".formatted(expected, result));
129+
}
130+
}
130131

132+
/**
133+
* 170 lines long class to simplify working with JDBC.
134+
* Original source: <a href="https://github.com/pponec/DirectoryBookmarks/blob/development/utils/SqlExecutor.java">GitHub</a>
135+
* @version 1.0.5
136+
*/
137+
static class SqlParamBuilder implements Closeable {
131138
/** SQL parameter mark type of {@code :param} */
132-
private static final Pattern SQL_MARK = Pattern.compile(":(\\w+)(?=[\\s,;\\])]|$)");
139+
private static final Pattern SQL_MARK = Pattern.compile(":(\\w+)");
133140
private final Connection dbConnection;
134141
private final Map<String, Object> params = new HashMap<>();
135142
private String sqlTemplate = null;
136143
private PreparedStatement preparedStatement = null;
137-
private ResultSetWrapper rsWrapper = null;
144+
private ResultSet resultSet = null;
138145

139146
public SqlParamBuilder(Connection dbConnection) {
140147
this.dbConnection = dbConnection;
141148
}
142149

143150
/** Close statement (if any) and set a new SQL template */
144-
public SqlParamBuilder sql(@NotNull String... sqlTemplates ) {
151+
public SqlParamBuilder sql(String... sqlTemplates ) {
145152
close();
153+
this.params.clear();
146154
this.sqlTemplate = sqlTemplates.length == 1
147155
? sqlTemplates[0] : String.join("\n", sqlTemplates);
148156
return this;
149157
}
150158

151159
/** Assign a SQL value(s) */
152-
public SqlParamBuilder bind(@NotNull String key, @NotNull Object... value) {
160+
public SqlParamBuilder bind(String key, Object... value) {
153161
this.params.put(key, value.length == 1 ? value[0] : List.of(value));
154162
return this;
155163
}
156164

157-
public Iterable<ResultSet> executeSelect() throws IllegalStateException, SQLException {
158-
try (Closeable rs = rsWrapper) {
159-
} catch (IOException e) {
165+
private ResultSet executeSelect() throws IllegalStateException {
166+
try (AutoCloseable rs = resultSet) {
167+
} catch (Exception e) {
160168
throw new IllegalStateException("Closing fails", e);
161169
}
162-
rsWrapper = new ResultSetWrapper(prepareStatement().executeQuery());
163-
return rsWrapper;
170+
try {
171+
resultSet = prepareStatement().executeQuery();
172+
return resultSet;
173+
} catch (Exception ex) {
174+
throw (ex instanceof RuntimeException re) ? re : new IllegalStateException(ex);
175+
}
176+
}
177+
178+
/** Use a {@link #streamMap(SqlFunction)} rather */
179+
private Stream<ResultSet> stream() {
180+
final var resultSet = executeSelect();
181+
final var iterator = new Iterator<ResultSet>() {
182+
@Override
183+
public boolean hasNext() {
184+
try {
185+
return resultSet.next();
186+
} catch (SQLException e) {
187+
throw new IllegalStateException(e);
188+
}
189+
}
190+
@Override
191+
public ResultSet next() {
192+
return resultSet;
193+
}
194+
};
195+
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false);
164196
}
165197

166198
/** Iterate executed select */
167199
public void forEach(SqlConsumer<ResultSet> consumer) throws IllegalStateException, SQLException {
168-
for (ResultSet rs : executeSelect()) {
169-
consumer.accept(rs);
170-
}
200+
stream().forEach(consumer);
171201
}
172202

173-
public <R> Stream<R> streamMap(SqlFunction<ResultSet, ? extends R> mapper ) throws SQLException {
174-
return StreamSupport.stream(executeSelect().spliterator(), false).map(mapper);
203+
public <R> Stream<R> streamMap(SqlFunction<ResultSet, ? extends R> mapper ) {
204+
return stream().map(mapper);
175205
}
176206

177207
public int execute() throws IllegalStateException, SQLException {
@@ -185,11 +215,11 @@ public Connection getConnection() {
185215
/** The method closes a PreparedStatement object with related objects, not the database connection. */
186216
@Override
187217
public void close() {
188-
try (Closeable c1 = rsWrapper; PreparedStatement c2 = preparedStatement) {
218+
try (AutoCloseable c1 = resultSet; PreparedStatement c2 = preparedStatement) {
189219
} catch (Exception e) {
190220
throw new IllegalStateException("Closing fails", e);
191221
} finally {
192-
rsWrapper = null;
222+
resultSet = null;
193223
preparedStatement = null;
194224
}
195225
}
@@ -245,80 +275,29 @@ public String toString() {
245275
return buildSql(new ArrayList<>(), true);
246276
}
247277

248-
/** Based on the {@code RowIterator} class of Ujorm framework. */
249-
static final class ResultSetWrapper implements Iterable<ResultSet>, Iterator<ResultSet>, Closeable {
250-
private ResultSet resultSet;
251-
/** It the cursor ready for reading? After a row reading the value will be set to false */
252-
private boolean cursorReady = false;
253-
/** Has a resultset a next row? */
254-
private boolean hasNext = false;
255-
256-
public ResultSetWrapper( final ResultSet resultSet) {
257-
this.resultSet = resultSet;
258-
}
259-
260-
@Override
261-
public Iterator<ResultSet> iterator() {
262-
return this;
263-
}
264-
265-
/** The last checking closes all resources. */
266-
@Override
267-
public boolean hasNext() throws IllegalStateException {
268-
if (!cursorReady) try {
269-
hasNext = resultSet.next();
270-
if (!hasNext) {
271-
close();
272-
}
273-
cursorReady = true;
274-
} catch (SQLException e) {
275-
throw new IllegalStateException(e);
276-
}
277-
return hasNext;
278-
}
279-
280-
@Override
281-
public ResultSet next() {
282-
if (hasNext()) {
283-
cursorReady = false;
284-
return resultSet;
285-
}
286-
throw new NoSuchElementException();
287-
}
288-
289-
@Override
290-
public void close() {
291-
try (ResultSet rs = resultSet) {
292-
cursorReady = true;
293-
hasNext = false;
294-
} catch (SQLException e) {
295-
throw new IllegalStateException(e);
296-
}
297-
}
298-
}
299-
300-
301278
@FunctionalInterface
302279
public interface SqlFunction<T, R> extends Function<T, R> {
303280
default R apply(T resultSet) {
304-
try { return applyRs(resultSet); } catch (SQLException ex) {
305-
throw new IllegalStateException(ex);
281+
try {
282+
return applyRs(resultSet);
283+
} catch (Exception ex) {
284+
throw (ex instanceof RuntimeException re) ? re : new IllegalStateException(ex);
306285
}
307286
}
308-
309287
R applyRs(T resultSet) throws SQLException;
310288
}
311289

312290
@FunctionalInterface
313291
public interface SqlConsumer<T> extends Consumer<T> {
314292
@Override
315293
default void accept(final T t) {
316-
try { acceptResultSet(t); } catch (SQLException e) {
317-
throw new IllegalStateException(e);
294+
try {
295+
acceptResultSet(t);
296+
} catch (Exception ex) {
297+
throw (ex instanceof RuntimeException re) ? re : new IllegalStateException(ex);
318298
}
319299
}
320-
321-
void acceptResultSet(T t) throws SQLException;
300+
void acceptResultSet(T t) throws Exception;
322301
}
323302
}
324303
}

utils/SqlExecutor.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#!/bin/bash
22
# Sample SQL scripting for the Bash and Java v17.
33

4-
java -cp ../lib/h2-2.2.224.jar SqlExecutor.java
4+
java -cp ../lib/h2-2.2.224.jar SqlExecutor.java "$@"
5+
6+

utils/SqlParamBuilderTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ public void loggingSql() {
123123
Assertions.assertEquals(builder.sqlTemplate(), builder.toString());
124124

125125
IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> {
126-
for (ResultSet rs : builder.executeSelect()) {
127-
}
126+
var count = builder.streamMap(t -> t).count();
128127
});
129128
assertEquals("Missing value of the keys: [code, id]", ex.getMessage());
130129

0 commit comments

Comments
 (0)