• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jhannes / fluent-jdbc / #198

06 Oct 2025 10:27PM UTC coverage: 91.711% (-0.5%) from 92.242%
#198

push

jhannes-test
improved ergonomics of select builders

88 of 100 new or added lines in 13 files covered. (88.0%)

2 existing lines in 1 file now uncovered.

1195 of 1303 relevant lines covered (91.71%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.19
/src/main/java/org/fluentjdbc/DatabaseTableQueryBuilder.java
1
package org.fluentjdbc;
2

3
import javax.annotation.Nonnull;
4
import javax.annotation.ParametersAreNonnullByDefault;
5
import java.sql.Connection;
6
import java.util.ArrayList;
7
import java.util.List;
8
import java.util.stream.Stream;
9

10
/**
11
 * Generate <code>SELECT</code> statements by collecting <code>WHERE</code> expressions and parameters.Example:
12
 *
13
 * <pre>
14
 *  List&lt;Person&gt; result = table
15
 *     .where("firstName", firstName)
16
 *     .whereExpression("lastName like ?", "joh%")
17
 *     .whereIn("status", statuses)
18
 *     .orderBy("lastName")
19
 *     .list(connection, row -&gt; new Person(row));
20
 * </pre>
21
 */
22
@ParametersAreNonnullByDefault
23
public class DatabaseTableQueryBuilder implements
24
        DatabaseSimpleQueryBuilder<DatabaseTableQueryBuilder>,
25
        DatabaseListableQueryBuilder<DatabaseTableQueryBuilder>
26
{
27

28
    protected final DatabaseTable table;
29
    protected final DatabaseWhereBuilder whereBuilder = new DatabaseWhereBuilder();
1✔
30
    protected final List<String> orderByClauses = new ArrayList<>();
1✔
31

32
    DatabaseTableQueryBuilder(DatabaseTable table) {
1✔
33
        this.table = table;
1✔
34
    }
1✔
35

36
    /**
37
     * Add the arguments to the column list for the <code>SELECT column, column...</code> statement
38
     */
39
    public DatabaseSelectBuilder select(String... columns) {
NEW
40
        return createSelectBuilder().select(columns);
×
41
    }
42

43
    /**
44
     * Adds the parameter to the WHERE-clause and all the parameter list.
45
     * E.g. <code>where(new DatabaseQueryParameter("created_at between ? and ?", List.of(earliestDate, latestDate)))</code>
46
     */
47
    @Override
48
    public DatabaseTableQueryBuilder where(DatabaseQueryParameter parameter) {
49
        whereBuilder.where(parameter);
1✔
50
        return this;
1✔
51
    }
52

53
    /**
54
     * Creates a {@link DatabaseUpdateBuilder} object to fluently generate a <code>UPDATE ...</code> statement
55
     */
56
    @Override
57
    public DatabaseUpdateBuilder update() {
58
        return table.update().where(whereBuilder);
1✔
59
    }
60

61
    /**
62
     * Creates a {@link DatabaseInsertOrUpdateBuilder} object to fluently generate a statement that will result
63
     * in either an <code>UPDATE ...</code> or <code>INSERT ...</code> depending on whether the row exists already
64
     */
65
    @Override
66
    public DatabaseInsertOrUpdateBuilder insertOrUpdate() {
67
        return table.insertOrUpdate().where(whereBuilder);
1✔
68
    }
69

70
    /**
71
     * Executes <code>DELETE FROM tableName WHERE ....</code>
72
     */
73
    @Override
74
    public int delete(Connection connection) {
75
        return table.delete().where(whereBuilder).execute(connection);
1✔
76
    }
77

78
    /**
79
     * Adds <code>ORDER BY ...</code> clause to the <code>SELECT</code> statement
80
     */
81
    @Override
82
    public DatabaseTableQueryBuilder orderBy(String orderByClause) {
83
        orderByClauses.add(orderByClause);
1✔
84
        return this;
1✔
85
    }
86

87
    /**
88
     * Sets the <code>ORDER BY ...</code> clause of the <code>SELECT</code> statement
89
     */
90
    @Override
91
    public DatabaseTableQueryBuilder orderBy(List<String> orderByClauses) {
NEW
92
        this.orderByClauses.clear();
×
NEW
93
        this.orderByClauses.addAll(orderByClauses);
×
NEW
94
        return this;
×
95
    }
96

97
    /**
98
     * If you haven't called {@link #orderBy}, the results of {@link #list(Connection, DatabaseResult.RowMapper)}
99
     * will be unpredictable. Call <code>unordered()</code> if you are okay with this.
100
     */
101
    @Override
102
    public DatabaseTableQueryBuilder unordered() {
103
        return this;
1✔
104
    }
105

106
    /**
107
     * Adds <code>OFFSET ... ROWS FETCH ... ROWS ONLY</code> clause to the <code>SELECT</code>
108
     * statement. FETCH FIRST was introduced in
109
     * <a href="https://en.wikipedia.org/wiki/Select_%28SQL%29#Limiting_result_rows">SQL:2008</a>
110
     * and is supported by Postgresql 8.4, Oracle 12c, IBM DB2, HSQLDB, H2, and SQL Server 2012.
111
     */
112
    public DatabaseSelectBuilder skipAndLimit(Integer offset, Integer rowCount) {
113
        return createSelectBuilder().skipAndLimit(offset, rowCount);
1✔
114
    }
115

116
    /**
117
     * If the query returns no rows, returns {@link SingleRow#absent}, if exactly one row is returned, maps it and return it,
118
     * if more than one is returned, throws `IllegalStateException`
119
     *
120
     * @param connection Database connection
121
     * @param mapper Function object to map a single returned row to an object
122
     * @return the mapped row if one row is returned, {@link SingleRow#absent} otherwise
123
     * @throws MultipleRowsReturnedException if more than one row was matched the query
124
     */
125
    @Nonnull
126
    @Override
127
    public <T> SingleRow<T> singleObject(Connection connection, DatabaseResult.RowMapper<T> mapper) {
128
        return createSelectBuilder().singleObject(connection, mapper);
1✔
129
    }
130

131
    /**
132
     * Execute the query and map each return value over the {@link DatabaseResult.RowMapper} function to return a stream. Example:
133
     * <pre>
134
     *     table.where("status", status).stream(connection, row -&gt; row.getInstant("created_at"))
135
     * </pre>
136
     */
137
    @Override
138
    public <T> Stream<T> stream(Connection connection, DatabaseResult.RowMapper<T> mapper) {
139
        return createSelectBuilder().stream(connection, mapper);
1✔
140
    }
141

142
    /**
143
     * Executes the <code>SELECT * FROM ...</code> statement and calls back to
144
     * {@link DatabaseResult.RowConsumer} for each returned row
145
     */
146
    @Override
147
    public void forEach(Connection connection, DatabaseResult.RowConsumer consumer) {
148
        createSelectBuilder().forEach(connection, consumer);
1✔
149
    }
1✔
150

151
    /**
152
     * Executes <code>SELECT count(*) FROM ...</code> on the query and returns the result
153
     */
154
    @Override
155
    public int getCount(Connection connection) {
156
        return createSelectBuilder().getCount(connection);
1✔
157
    }
158

159
    /**
160
     * Implemented as <code>return this</code> for compatibility purposes
161
     */
162
    @Override
163
    public DatabaseTableQueryBuilder query() {
164
        return this;
1✔
165
    }
166

167
    public DatabaseSelectBuilder createSelectBuilder() {
168
        return new DatabaseSelectBuilder(table.getFactory(), whereBuilder)
1✔
169
                .orderBy(orderByClauses)
1✔
170
                .from(table.getTableName());
1✔
171
    }
172
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc