Skip to content

Commit 789a55f

Browse files
committed
test: add QueryBuilderDefaultsTest; align SelectBuilderTest LIKE wrapping
QueryBuilderDefaultsTest (23 tests) covers: - Canonical global defaults (STANDARD, "*", -1, -1, "%", "%") - builder() and builder(source) factory methods - setGlobal(null) NPE guard - withDefaults(null) NPE guard on all three builders - Global dialect applied to newly created QueryBuilder - Per-instance withDefaults() overrides global for that instance only - Explicit buildSql(table, dialect) parameter wins over configured default - defaultColumns / explicit select() winner semantics - defaultLimit / defaultOffset applied and overridden correctly - Custom likePrefix / likeSuffix applied (QueryBuilder + SelectBuilder) - DeleteBuilder dialect routing via withDefaults() - SelectBuilder defaultColumns, defaultLimit, LIKE wrapping SelectBuilderTest.testWhereLike: updated to pass the raw value ("bob") instead of pre-wrapped "%bob%" now that SelectBuilder auto-wraps using the configured likePrefix/likeSuffix (consistent with QueryBuilder).
1 parent c4ce70f commit 789a55f

2 files changed

Lines changed: 332 additions & 1 deletion

File tree

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
package com.github.ezframework.javaquerybuilder.query;
2+
3+
import java.util.List;
4+
5+
import org.junit.jupiter.api.AfterEach;
6+
import org.junit.jupiter.api.BeforeEach;
7+
import org.junit.jupiter.api.Test;
8+
9+
import com.github.ezframework.javaquerybuilder.query.builder.DeleteBuilder;
10+
import com.github.ezframework.javaquerybuilder.query.builder.QueryBuilder;
11+
import com.github.ezframework.javaquerybuilder.query.builder.SelectBuilder;
12+
import com.github.ezframework.javaquerybuilder.query.sql.SqlDialect;
13+
import com.github.ezframework.javaquerybuilder.query.sql.SqlResult;
14+
15+
import static org.junit.jupiter.api.Assertions.assertEquals;
16+
import static org.junit.jupiter.api.Assertions.assertNotSame;
17+
import static org.junit.jupiter.api.Assertions.assertSame;
18+
import static org.junit.jupiter.api.Assertions.assertThrows;
19+
import static org.junit.jupiter.api.Assertions.assertTrue;
20+
21+
public class QueryBuilderDefaultsTest {
22+
23+
private QueryBuilderDefaults savedGlobal;
24+
25+
@BeforeEach
26+
void saveGlobal() {
27+
savedGlobal = QueryBuilderDefaults.global();
28+
}
29+
30+
@AfterEach
31+
void restoreGlobal() {
32+
QueryBuilderDefaults.setGlobal(savedGlobal);
33+
}
34+
35+
// --- Default values ---
36+
37+
@Test
38+
void globalHasCanonicalDefaultValues() {
39+
QueryBuilderDefaults defaults = QueryBuilderDefaults.global();
40+
assertSame(SqlDialect.STANDARD, defaults.getDialect());
41+
assertEquals("*", defaults.getDefaultColumns());
42+
assertEquals(-1, defaults.getDefaultLimit());
43+
assertEquals(-1, defaults.getDefaultOffset());
44+
assertEquals("%", defaults.getLikePrefix());
45+
assertEquals("%", defaults.getLikeSuffix());
46+
}
47+
48+
@Test
49+
void builderProducesInstanceWithCanonicalDefaults() {
50+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder().build();
51+
assertSame(SqlDialect.STANDARD, defaults.getDialect());
52+
assertEquals("*", defaults.getDefaultColumns());
53+
assertEquals(-1, defaults.getDefaultLimit());
54+
assertEquals(-1, defaults.getDefaultOffset());
55+
assertEquals("%", defaults.getLikePrefix());
56+
assertEquals("%", defaults.getLikeSuffix());
57+
}
58+
59+
@Test
60+
void builderFromSourceCopiesAllFields() {
61+
QueryBuilderDefaults source = QueryBuilderDefaults.builder()
62+
.dialect(SqlDialect.MYSQL)
63+
.defaultColumns("id, name")
64+
.defaultLimit(50)
65+
.defaultOffset(10)
66+
.likePrefix(">>")
67+
.likeSuffix("<<")
68+
.build();
69+
70+
QueryBuilderDefaults copy = QueryBuilderDefaults.builder(source).build();
71+
72+
assertSame(SqlDialect.MYSQL, copy.getDialect());
73+
assertEquals("id, name", copy.getDefaultColumns());
74+
assertEquals(50, copy.getDefaultLimit());
75+
assertEquals(10, copy.getDefaultOffset());
76+
assertEquals(">>", copy.getLikePrefix());
77+
assertEquals("<<", copy.getLikeSuffix());
78+
assertNotSame(source, copy);
79+
}
80+
81+
// --- Null guards ---
82+
83+
@Test
84+
void setGlobalNullThrowsNullPointerException() {
85+
assertThrows(NullPointerException.class, () -> QueryBuilderDefaults.setGlobal(null));
86+
}
87+
88+
@Test
89+
void withDefaultsNullThrowsNullPointerExceptionOnQueryBuilder() {
90+
assertThrows(NullPointerException.class,
91+
() -> new QueryBuilder().withDefaults(null));
92+
}
93+
94+
@Test
95+
void withDefaultsNullThrowsNullPointerExceptionOnDeleteBuilder() {
96+
assertThrows(NullPointerException.class,
97+
() -> new DeleteBuilder().withDefaults(null));
98+
}
99+
100+
@Test
101+
void withDefaultsNullThrowsNullPointerExceptionOnSelectBuilder() {
102+
assertThrows(NullPointerException.class,
103+
() -> new SelectBuilder().withDefaults(null));
104+
}
105+
106+
// --- Global dialect applied by new builders ---
107+
108+
@Test
109+
void globalDialectIsUsedByNewlyCreatedQueryBuilder() {
110+
QueryBuilderDefaults.setGlobal(
111+
QueryBuilderDefaults.builder().dialect(SqlDialect.MYSQL).build());
112+
113+
SqlResult result = new QueryBuilder().from("users").buildSql();
114+
115+
// MySQL dialect wraps identifiers in backticks
116+
assertTrue(result.getSql().contains("`users`"),
117+
"Expected MySQL backtick quoting, got: " + result.getSql());
118+
}
119+
120+
@Test
121+
void setGlobalUpdatesGlobalInstance() {
122+
QueryBuilderDefaults custom = QueryBuilderDefaults.builder()
123+
.dialect(SqlDialect.SQLITE).build();
124+
QueryBuilderDefaults.setGlobal(custom);
125+
assertSame(custom, QueryBuilderDefaults.global());
126+
}
127+
128+
// --- Per-instance withDefaults overrides global ---
129+
130+
@Test
131+
void withDefaultsDialectOverridesGlobalForThatInstance() {
132+
// Global stays STANDARD; only this instance uses MYSQL
133+
QueryBuilderDefaults mysql = QueryBuilderDefaults.builder()
134+
.dialect(SqlDialect.MYSQL).build();
135+
136+
SqlResult mysqlResult = new QueryBuilder().withDefaults(mysql).from("orders").buildSql();
137+
SqlResult stdResult = new QueryBuilder().from("orders").buildSql();
138+
139+
assertTrue(mysqlResult.getSql().contains("`orders`"),
140+
"Expected MySQL quoting: " + mysqlResult.getSql());
141+
assertTrue(stdResult.getSql().contains("orders") && !stdResult.getSql().contains("`orders`"),
142+
"Expected standard quoting: " + stdResult.getSql());
143+
}
144+
145+
@Test
146+
void explicitDialectParameterWinsOverDefaultsDialect() {
147+
// withDefaults sets MYSQL, but explicit buildSql(table, SQLITE) should win
148+
QueryBuilderDefaults mysql = QueryBuilderDefaults.builder()
149+
.dialect(SqlDialect.MYSQL).build();
150+
151+
SqlResult result = new QueryBuilder()
152+
.withDefaults(mysql)
153+
.buildSql("users", SqlDialect.SQLITE);
154+
155+
// SQLite wraps identifiers in double-quotes
156+
assertTrue(result.getSql().contains("\"users\""),
157+
"Expected SQLite double-quote quoting: " + result.getSql());
158+
}
159+
160+
// --- Default SELECT columns ---
161+
162+
@Test
163+
void defaultColumnsAppearsInSelectWhenNoneSpecified() {
164+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
165+
.defaultColumns("id, name").build();
166+
167+
SqlResult result = new QueryBuilder().withDefaults(defaults).from("users").buildSql();
168+
169+
assertTrue(result.getSql().startsWith("SELECT id, name FROM"),
170+
"Expected custom default columns: " + result.getSql());
171+
}
172+
173+
@Test
174+
void explicitSelectColumnsWinsOverDefaultColumns() {
175+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
176+
.defaultColumns("id, name").build();
177+
178+
SqlResult result = new QueryBuilder().withDefaults(defaults)
179+
.select("age")
180+
.from("users").buildSql();
181+
182+
assertTrue(result.getSql().startsWith("SELECT age FROM"),
183+
"Explicit select should win: " + result.getSql());
184+
}
185+
186+
// --- Default limit and offset ---
187+
188+
@Test
189+
void defaultLimitAppliedWhenBuilderLimitNotSet() {
190+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
191+
.defaultLimit(100).build();
192+
193+
SqlResult result = new QueryBuilder().withDefaults(defaults).from("users").buildSql();
194+
195+
assertTrue(result.getSql().contains("LIMIT 100"),
196+
"Expected LIMIT 100: " + result.getSql());
197+
}
198+
199+
@Test
200+
void explicitLimitWinsOverDefaultLimit() {
201+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
202+
.defaultLimit(100).build();
203+
204+
SqlResult result = new QueryBuilder().withDefaults(defaults)
205+
.limit(25)
206+
.from("users").buildSql();
207+
208+
assertTrue(result.getSql().contains("LIMIT 25"),
209+
"Expected LIMIT 25: " + result.getSql());
210+
assertTrue(!result.getSql().contains("LIMIT 100"),
211+
"Default limit must not appear when explicit limit is set");
212+
}
213+
214+
@Test
215+
void defaultOffsetAppliedWhenBuilderOffsetNotSet() {
216+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
217+
.defaultOffset(20).build();
218+
219+
SqlResult result = new QueryBuilder().withDefaults(defaults).from("users").buildSql();
220+
221+
assertTrue(result.getSql().contains("OFFSET 20"),
222+
"Expected OFFSET 20: " + result.getSql());
223+
}
224+
225+
@Test
226+
void explicitOffsetWinsOverDefaultOffset() {
227+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
228+
.defaultOffset(20).build();
229+
230+
SqlResult result = new QueryBuilder().withDefaults(defaults)
231+
.offset(5)
232+
.from("users").buildSql();
233+
234+
assertTrue(result.getSql().contains("OFFSET 5"),
235+
"Expected OFFSET 5: " + result.getSql());
236+
}
237+
238+
// --- LIKE prefix / suffix ---
239+
240+
@Test
241+
void likeParamUsesCustomPrefixAndSuffix() {
242+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
243+
.likePrefix(">>")
244+
.likeSuffix("<<")
245+
.build();
246+
247+
SqlResult result = new QueryBuilder().withDefaults(defaults)
248+
.whereLike("name", "bob")
249+
.from("users").buildSql();
250+
251+
List<Object> params = result.getParameters();
252+
assertEquals(1, params.size());
253+
assertEquals(">>bob<<", params.get(0));
254+
}
255+
256+
@Test
257+
void likeParamWithEmptyPrefixAndSuffixIsUnwrapped() {
258+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
259+
.likePrefix("")
260+
.likeSuffix("")
261+
.build();
262+
263+
SqlResult result = new QueryBuilder().withDefaults(defaults)
264+
.whereLike("name", "bob")
265+
.from("users").buildSql();
266+
267+
List<Object> params = result.getParameters();
268+
assertEquals(1, params.size());
269+
assertEquals("bob", params.get(0));
270+
}
271+
272+
// --- DeleteBuilder ---
273+
274+
@Test
275+
void deleteBuilderWithDefaultsDialectIsUsed() {
276+
QueryBuilderDefaults mysql = QueryBuilderDefaults.builder()
277+
.dialect(SqlDialect.MYSQL).build();
278+
279+
SqlResult result = new DeleteBuilder()
280+
.withDefaults(mysql)
281+
.from("orders")
282+
.whereEquals("id", 1)
283+
.build();
284+
285+
assertTrue(result.getSql().contains("`orders`"),
286+
"Expected MySQL backtick quoting on table: " + result.getSql());
287+
assertTrue(result.getSql().contains("`id`"),
288+
"Expected MySQL backtick quoting on column: " + result.getSql());
289+
}
290+
291+
// --- SelectBuilder ---
292+
293+
@Test
294+
void selectBuilderDefaultColumnsApplied() {
295+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
296+
.defaultColumns("id, status").build();
297+
298+
SqlResult result = new SelectBuilder().withDefaults(defaults).from("users").build();
299+
300+
assertTrue(result.getSql().startsWith("SELECT id, status FROM"),
301+
"Expected custom default columns: " + result.getSql());
302+
}
303+
304+
@Test
305+
void selectBuilderDefaultLimitApplied() {
306+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
307+
.defaultLimit(30).build();
308+
309+
SqlResult result = new SelectBuilder().withDefaults(defaults).from("users").build();
310+
311+
assertTrue(result.getSql().contains("LIMIT 30"),
312+
"Expected LIMIT 30: " + result.getSql());
313+
}
314+
315+
@Test
316+
void selectBuilderLikeWrapsWithDefaults() {
317+
QueryBuilderDefaults defaults = QueryBuilderDefaults.builder()
318+
.likePrefix("{{")
319+
.likeSuffix("}}")
320+
.build();
321+
322+
SqlResult result = new SelectBuilder().withDefaults(defaults)
323+
.from("users")
324+
.whereLike("name", "alice")
325+
.build();
326+
327+
List<Object> params = result.getParameters();
328+
assertEquals(1, params.size());
329+
assertEquals("{{alice}}", params.get(0));
330+
}
331+
}

src/test/java/com/github/ezframework/javaquerybuilder/query/builder/SelectBuilderTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void testWhereIn() {
6767
void testWhereLike() {
6868
SqlResult sql = new SelectBuilder()
6969
.from("users")
70-
.whereLike("name", "%bob%")
70+
.whereLike("name", "bob")
7171
.build();
7272
assertEquals("SELECT * FROM users WHERE name LIKE ?", sql.getSql());
7373
assertEquals(Collections.singletonList("%bob%"), sql.getParameters());

0 commit comments

Comments
 (0)