View Javadoc
1   /*
2    *    Copyright 2016-2025 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package examples.simple;
17  
18  import static examples.simple.AddressDynamicSqlSupport.address;
19  import static examples.simple.PersonDynamicSqlSupport.addressId;
20  import static examples.simple.PersonDynamicSqlSupport.birthDate;
21  import static examples.simple.PersonDynamicSqlSupport.employed;
22  import static examples.simple.PersonDynamicSqlSupport.firstName;
23  import static examples.simple.PersonDynamicSqlSupport.id;
24  import static examples.simple.PersonDynamicSqlSupport.lastName;
25  import static examples.simple.PersonDynamicSqlSupport.occupation;
26  import static examples.simple.PersonDynamicSqlSupport.person;
27  import static org.assertj.core.api.Assertions.assertThat;
28  import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
29  import static org.assertj.core.api.Assertions.entry;
30  import static org.mybatis.dynamic.sql.SqlBuilder.*;
31  
32  import java.io.InputStream;
33  import java.io.InputStreamReader;
34  import java.sql.Connection;
35  import java.sql.DriverManager;
36  import java.util.Collection;
37  import java.util.Date;
38  import java.util.List;
39  import java.util.Optional;
40  
41  import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
42  import org.apache.ibatis.jdbc.ScriptRunner;
43  import org.apache.ibatis.mapping.Environment;
44  import org.apache.ibatis.session.Configuration;
45  import org.apache.ibatis.session.SqlSession;
46  import org.apache.ibatis.session.SqlSessionFactory;
47  import org.apache.ibatis.session.SqlSessionFactoryBuilder;
48  import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
49  import org.junit.jupiter.api.BeforeEach;
50  import org.junit.jupiter.api.Test;
51  import org.mybatis.dynamic.sql.SortSpecification;
52  import org.mybatis.dynamic.sql.delete.DeleteDSLCompleter;
53  import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider;
54  import org.mybatis.dynamic.sql.exception.NonRenderingWhereClauseException;
55  import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider;
56  import org.mybatis.dynamic.sql.render.RenderingStrategies;
57  import org.mybatis.dynamic.sql.select.CountDSLCompleter;
58  import org.mybatis.dynamic.sql.select.SelectDSLCompleter;
59  import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
60  import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider;
61  
62  class PersonMapperTest {
63  
64      private static final String JDBC_URL = "jdbc:hsqldb:mem:aname";
65      private static final String JDBC_DRIVER = "org.hsqldb.jdbcDriver";
66  
67      private SqlSessionFactory sqlSessionFactory;
68  
69      @BeforeEach
70      void setup() throws Exception {
71          Class.forName(JDBC_DRIVER);
72          InputStream is = getClass().getResourceAsStream("/examples/simple/CreateSimpleDB.sql");
73          assert is != null;
74          try (Connection connection = DriverManager.getConnection(JDBC_URL, "sa", "")) {
75              ScriptRunner sr = new ScriptRunner(connection);
76              sr.setLogWriter(null);
77              sr.runScript(new InputStreamReader(is));
78          }
79  
80          UnpooledDataSource ds = new UnpooledDataSource(JDBC_DRIVER, JDBC_URL, "sa", "");
81          Environment environment = new Environment("test", new JdbcTransactionFactory(), ds);
82          Configuration config = new Configuration(environment);
83          config.addMapper(PersonMapper.class);
84          config.addMapper(PersonWithAddressMapper.class);
85          config.addMapper(AddressMapper.class);
86          sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
87      }
88  
89      @Test
90      void testSelect() {
91          try (SqlSession session = sqlSessionFactory.openSession()) {
92              PersonMapper mapper = session.getMapper(PersonMapper.class);
93  
94              List<PersonRecord> rows = mapper.select(c ->
95                      c.where(id, isEqualTo(1))
96                      .or(occupation, isNull()));
97  
98              assertThat(rows).hasSize(3);
99          }
100     }
101 
102     @Test
103     void testSelectEmployed() {
104         try (SqlSession session = sqlSessionFactory.openSession()) {
105             PersonMapper mapper = session.getMapper(PersonMapper.class);
106 
107             List<PersonRecord> rows = mapper.select(c ->
108                     c.where(employed, isTrue())
109                     .orderBy(id));
110 
111             assertThat(rows).hasSize(4);
112             assertThat(rows.get(0).id()).isEqualTo(1);
113         }
114     }
115 
116     @Test
117     void testSelectUnemployed() {
118         try (SqlSession session = sqlSessionFactory.openSession()) {
119             PersonMapper mapper = session.getMapper(PersonMapper.class);
120 
121             List<PersonRecord> rows = mapper.select(c ->
122                     c.where(employed, isFalse())
123                             .orderBy(id));
124 
125             assertThat(rows).hasSize(2);
126             assertThat(rows.get(0).id()).isEqualTo(3);
127         }
128     }
129 
130     @Test
131     void testSelectWithTypeConversion() {
132         try (SqlSession session = sqlSessionFactory.openSession()) {
133             PersonMapper mapper = session.getMapper(PersonMapper.class);
134 
135             List<PersonRecord> rows = mapper.select(c ->
136                     c.where(id, isEqualTo("1").map(Integer::parseInt))
137                             .or(occupation, isNull()));
138 
139             assertThat(rows).hasSize(3);
140         }
141     }
142 
143     @Test
144     void testSelectWithTypeConversionAndFilterAndNull() {
145         try (SqlSession session = sqlSessionFactory.openSession()) {
146             PersonMapper mapper = session.getMapper(PersonMapper.class);
147 
148             List<PersonRecord> rows = mapper.select(c ->
149                     c.where(id, isEqualToWhenPresent((String) null).map(Integer::parseInt))
150                             .or(occupation, isNull()));
151 
152             assertThat(rows).hasSize(2);
153         }
154     }
155 
156     // this example is in the quick start documentation...
157     @Test
158     void testGeneralSelect() {
159         try (SqlSession session = sqlSessionFactory.openSession()) {
160             PersonMapper mapper = session.getMapper(PersonMapper.class);
161 
162             SelectStatementProvider selectStatement = select(id.as("A_ID"), firstName, lastName, birthDate, employed,
163                         occupation, addressId)
164                     .from(person)
165                     .where(id, isEqualTo(1))
166                     .or(occupation, isNull())
167                     .build()
168                     .render(RenderingStrategies.MYBATIS3);
169 
170             List<PersonRecord> rows = mapper.selectMany(selectStatement);
171             assertThat(rows).hasSize(3);
172         }
173     }
174 
175     @Test
176     void testSelectAll() {
177         try (SqlSession session = sqlSessionFactory.openSession()) {
178             PersonMapper mapper = session.getMapper(PersonMapper.class);
179 
180             List<PersonRecord> rows = mapper.select(SelectDSLCompleter.allRows());
181 
182             assertThat(rows).hasSize(6);
183             assertThat(rows.get(0).id()).isEqualTo(1);
184             assertThat(rows.get(5).id()).isEqualTo(6);
185         }
186     }
187 
188     @Test
189     void testSelectAllOrdered() {
190         try (SqlSession session = sqlSessionFactory.openSession()) {
191             PersonMapper mapper = session.getMapper(PersonMapper.class);
192 
193             List<PersonRecord> rows = mapper
194                     .select(SelectDSLCompleter.allRowsOrderedBy(lastName.descending(), firstName.descending()));
195 
196             assertThat(rows).hasSize(6);
197             assertThat(rows.get(0).id()).isEqualTo(5);
198             assertThat(rows.get(5).id()).isEqualTo(1);
199         }
200     }
201 
202     @Test
203     void testSelectDistinct() {
204         try (SqlSession session = sqlSessionFactory.openSession()) {
205             PersonMapper mapper = session.getMapper(PersonMapper.class);
206 
207             List<PersonRecord> rows = mapper.selectDistinct(c ->
208                     c.where(id, isGreaterThan(1))
209                     .or(occupation, isNull()));
210 
211             assertThat(rows).hasSize(5);
212         }
213     }
214 
215     @Test
216     void testSelectWithTypeHandler() {
217         try (SqlSession session = sqlSessionFactory.openSession()) {
218             PersonMapper mapper = session.getMapper(PersonMapper.class);
219 
220             List<PersonRecord> rows = mapper.select(c ->
221                     c.where(employed, isEqualTo(false))
222                     .orderBy(id));
223 
224             assertThat(rows).hasSize(2);
225             assertThat(rows.get(0).id()).isEqualTo(3);
226             assertThat(rows.get(1).id()).isEqualTo(6);
227         }
228     }
229 
230     @Test
231     void testSelectByPrimaryKeyWithMissingRecord() {
232         try (SqlSession session = sqlSessionFactory.openSession()) {
233             PersonMapper mapper = session.getMapper(PersonMapper.class);
234 
235             Optional<PersonRecord> row = mapper.selectByPrimaryKey(300);
236             assertThat(row).isNotPresent();
237         }
238     }
239 
240     @Test
241     void testFirstNameIn() {
242         try (SqlSession session = sqlSessionFactory.openSession()) {
243             PersonMapper mapper = session.getMapper(PersonMapper.class);
244 
245             List<PersonRecord> rows = mapper.select(c ->
246                     c.where(firstName, isIn("Fred", "Barney")));
247 
248             assertThat(rows).hasSize(2);
249             assertThat(rows.get(0))
250                     .isNotNull()
251                     .extracting("lastName").isNotNull()
252                     .extracting("name").isEqualTo("Flintstone");
253             assertThat(rows.get(1))
254                     .isNotNull()
255                     .extracting("lastName").isNotNull()
256                     .extracting("name").isEqualTo("Rubble");
257         }
258     }
259 
260     @Test
261     void testOrderByCollection() {
262         Collection<SortSpecification> orderByColumns = List.of(firstName);
263 
264         try (SqlSession session = sqlSessionFactory.openSession()) {
265             PersonMapper mapper = session.getMapper(PersonMapper.class);
266 
267             List<PersonRecord> rows = mapper.select(c -> c
268                     .where(firstName, isIn("Fred", "Barney"))
269                     .orderBy(orderByColumns)
270             );
271 
272             assertThat(rows).hasSize(2);
273             assertThat(rows.get(0))
274                     .isNotNull()
275                     .extracting("lastName").isNotNull()
276                     .extracting("name").isEqualTo("Rubble");
277             assertThat(rows.get(1))
278                     .isNotNull()
279                     .extracting("lastName").isNotNull()
280                     .extracting("name").isEqualTo("Flintstone");
281         }
282     }
283 
284     @Test
285     void testDelete() {
286         try (SqlSession session = sqlSessionFactory.openSession()) {
287             PersonMapper mapper = session.getMapper(PersonMapper.class);
288             int rows = mapper.delete(c ->
289                     c.where(occupation, isNull()));
290             assertThat(rows).isEqualTo(2);
291         }
292     }
293 
294     // this test is in the quick start documentation
295     @Test
296     void testGeneralDelete() {
297         try (SqlSession session = sqlSessionFactory.openSession()) {
298             PersonMapper mapper = session.getMapper(PersonMapper.class);
299 
300             DeleteStatementProvider deleteStatement = deleteFrom(person)
301                     .where(occupation, isNull())
302                     .build()
303                     .render(RenderingStrategies.MYBATIS3);
304 
305             int rows = mapper.delete(deleteStatement);
306             assertThat(rows).isEqualTo(2);
307         }
308     }
309 
310     @Test
311     void testDeleteAll() {
312         try (SqlSession session = sqlSessionFactory.openSession()) {
313             PersonMapper mapper = session.getMapper(PersonMapper.class);
314             int rows = mapper.delete(DeleteDSLCompleter.allRows());
315 
316             assertThat(rows).isEqualTo(6);
317         }
318     }
319 
320     @Test
321     void testDeleteByPrimaryKey() {
322         try (SqlSession session = sqlSessionFactory.openSession()) {
323             PersonMapper mapper = session.getMapper(PersonMapper.class);
324             int rows = mapper.deleteByPrimaryKey(2);
325 
326             assertThat(rows).isEqualTo(1);
327         }
328     }
329 
330     @Test
331     void testInsert() {
332         try (SqlSession session = sqlSessionFactory.openSession()) {
333             PersonMapper mapper = session.getMapper(PersonMapper.class);
334             PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1);
335 
336             int rows = mapper.insert(row);
337             assertThat(rows).isEqualTo(1);
338         }
339     }
340 
341     @Test
342     void testGeneralInsert() {
343         try (SqlSession session = sqlSessionFactory.openSession()) {
344             PersonMapper mapper = session.getMapper(PersonMapper.class);
345             int rows = mapper.generalInsert(c ->
346                 c.set(id).toValue(100)
347                 .set(firstName).toValue("Joe")
348                 .set(lastName).toValue(new LastName("Jones"))
349                 .set(birthDate).toValue(new Date())
350                 .set(employed).toValue(true)
351                 .set(occupation).toValue("Developer")
352                 .set(addressId).toValue(1)
353             );
354 
355             assertThat(rows).isEqualTo(1);
356         }
357     }
358 
359     @Test
360     void testInsertMultiple() {
361         try (SqlSession session = sqlSessionFactory.openSession()) {
362             PersonMapper mapper = session.getMapper(PersonMapper.class);
363 
364             List<PersonRecord> records = List.of(
365                     new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1),
366                     new PersonRecord(101, "Sarah", new LastName("Smith"), new Date(), true, "Architect", 2)
367             );
368 
369             int rows = mapper.insertMultiple(records);
370             assertThat(rows).isEqualTo(2);
371         }
372     }
373 
374     @Test
375     void testInsertSelective() {
376         try (SqlSession session = sqlSessionFactory.openSession()) {
377             PersonMapper mapper = session.getMapper(PersonMapper.class);
378             PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), false, null, 1);
379 
380             int rows = mapper.insertSelective(row);
381             assertThat(rows).isEqualTo(1);
382         }
383     }
384 
385     @Test
386     void testUpdateByPrimaryKeyNullKeyShouldThrowException() {
387         try (SqlSession session = sqlSessionFactory.openSession()) {
388             PersonMapper mapper = session.getMapper(PersonMapper.class);
389             PersonRecord row = new PersonRecord(null, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1);
390 
391             assertThatExceptionOfType(NonRenderingWhereClauseException.class).isThrownBy(() -> mapper.updateByPrimaryKey(row));
392         }
393     }
394 
395     @Test
396     void testUpdateByPrimaryKey() {
397         try (SqlSession session = sqlSessionFactory.openSession()) {
398             PersonMapper mapper = session.getMapper(PersonMapper.class);
399             PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1);
400 
401             int rows = mapper.insert(row);
402             assertThat(rows).isEqualTo(1);
403 
404             row = row.withOccupation("Programmer");
405             rows = mapper.updateByPrimaryKey(row);
406             assertThat(rows).isEqualTo(1);
407 
408             Optional<PersonRecord> newRecord = mapper.selectByPrimaryKey(100);
409             assertThat(newRecord).hasValueSatisfying(r ->
410                     assertThat(r.occupation()).isEqualTo("Programmer"));
411         }
412     }
413 
414     @Test
415     void testUpdateByPrimaryKeySelective() {
416         try (SqlSession session = sqlSessionFactory.openSession()) {
417             PersonMapper mapper = session.getMapper(PersonMapper.class);
418             PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1);
419 
420             int rows = mapper.insert(row);
421             assertThat(rows).isEqualTo(1);
422 
423             PersonRecord updateRecord = new PersonRecord(100, null, null, null, null, "Programmer", null);
424             rows = mapper.updateByPrimaryKeySelective(updateRecord);
425             assertThat(rows).isEqualTo(1);
426 
427             Optional<PersonRecord> newRecord = mapper.selectByPrimaryKey(100);
428             assertThat(newRecord).hasValueSatisfying(r -> {
429                 assertThat(r.occupation()).isEqualTo("Programmer");
430                 assertThat(r.firstName()).isEqualTo("Joe");
431             });
432         }
433     }
434 
435     @Test
436     void testUpdate() {
437         try (SqlSession session = sqlSessionFactory.openSession()) {
438             PersonMapper mapper = session.getMapper(PersonMapper.class);
439             PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1);
440 
441             int rows = mapper.insert(row);
442             assertThat(rows).isEqualTo(1);
443 
444             PersonRecord updateRow = row.withOccupation("Programmer");
445 
446             rows = mapper.update(c ->
447                 PersonMapper.updateAllColumns(updateRow, c)
448                 .where(id, isEqualTo(100))
449                 .and(firstName, isEqualTo("Joe")));
450 
451             assertThat(rows).isEqualTo(1);
452 
453             Optional<PersonRecord> newRecord = mapper.selectByPrimaryKey(100);
454             assertThat(newRecord).hasValueSatisfying(r ->
455                     assertThat(r.occupation()).isEqualTo("Programmer"));
456         }
457     }
458 
459     @Test
460     void testUpdateOneField() {
461         try (SqlSession session = sqlSessionFactory.openSession()) {
462             PersonMapper mapper = session.getMapper(PersonMapper.class);
463             PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1);
464 
465             int rows = mapper.insert(row);
466             assertThat(rows).isEqualTo(1);
467 
468             rows = mapper.update(c ->
469                 c.set(occupation).equalTo("Programmer")
470                 .where(id, isEqualTo(100)));
471 
472             assertThat(rows).isEqualTo(1);
473 
474             Optional<PersonRecord> newRecord = mapper.selectByPrimaryKey(100);
475             assertThat(newRecord).hasValueSatisfying(r ->
476                     assertThat(r.occupation()).isEqualTo("Programmer"));
477         }
478     }
479 
480     @Test
481     void testUpdateAll() {
482         try (SqlSession session = sqlSessionFactory.openSession()) {
483             PersonMapper mapper = session.getMapper(PersonMapper.class);
484             PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1);
485 
486             int rows = mapper.insert(row);
487             assertThat(rows).isEqualTo(1);
488 
489             PersonRecord updateRecord = new PersonRecord(null, null, null, null, null, "Programmer", null);
490             rows = mapper.update(c ->
491                 PersonMapper.updateSelectiveColumns(updateRecord, c));
492 
493             assertThat(rows).isEqualTo(7);
494 
495             Optional<PersonRecord> newRecord = mapper.selectByPrimaryKey(100);
496             assertThat(newRecord).hasValueSatisfying(r ->
497                     assertThat(r.occupation()).isEqualTo("Programmer"));
498         }
499     }
500 
501     @Test
502     void testUpdateSelective() {
503         try (SqlSession session = sqlSessionFactory.openSession()) {
504             PersonMapper mapper = session.getMapper(PersonMapper.class);
505             PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1);
506 
507             int rows = mapper.insert(row);
508             assertThat(rows).isEqualTo(1);
509 
510             PersonRecord updateRecord = new PersonRecord(null, null, null, null, null, "Programmer", null);
511             rows = mapper.update(c ->
512                 PersonMapper.updateSelectiveColumns(updateRecord, c)
513                 .where(id, isEqualTo(100)));
514 
515             assertThat(rows).isEqualTo(1);
516 
517             Optional<PersonRecord> newRecord = mapper.selectByPrimaryKey(100);
518             assertThat(newRecord).hasValueSatisfying(r ->
519                     assertThat(r.occupation()).isEqualTo("Programmer"));
520         }
521     }
522 
523     @Test
524     void testCount() {
525         try (SqlSession session = sqlSessionFactory.openSession()) {
526             PersonMapper mapper = session.getMapper(PersonMapper.class);
527             long rows = mapper.count(c ->
528                     c.where(occupation, isNull()));
529 
530             assertThat(rows).isEqualTo(2L);
531         }
532     }
533 
534     @Test
535     void testCountAll() {
536         try (SqlSession session = sqlSessionFactory.openSession()) {
537             PersonMapper mapper = session.getMapper(PersonMapper.class);
538             long rows = mapper.count(CountDSLCompleter.allRows());
539 
540             assertThat(rows).isEqualTo(6L);
541         }
542     }
543 
544     @Test
545     void testCountLastName() {
546         try (SqlSession session = sqlSessionFactory.openSession()) {
547             PersonMapper mapper = session.getMapper(PersonMapper.class);
548             long rows = mapper.count(lastName, CountDSLCompleter.allRows());
549 
550             assertThat(rows).isEqualTo(6L);
551         }
552     }
553 
554     @Test
555     void testCountDistinctLastName() {
556         try (SqlSession session = sqlSessionFactory.openSession()) {
557             PersonMapper mapper = session.getMapper(PersonMapper.class);
558             long rows = mapper.countDistinct(lastName, CountDSLCompleter.allRows());
559 
560             assertThat(rows).isEqualTo(2L);
561         }
562     }
563 
564     @Test
565     void testTypeHandledLike() {
566         try (SqlSession session = sqlSessionFactory.openSession()) {
567             PersonMapper mapper = session.getMapper(PersonMapper.class);
568 
569             List<PersonRecord> rows = mapper.select(c ->
570                     c.where(lastName, isLike(new LastName("Fl%")))
571                     .orderBy(id));
572 
573             assertThat(rows).hasSize(3);
574             assertThat(rows.get(0).firstName()).isEqualTo("Fred");
575         }
576     }
577 
578     @Test
579     void testTypeHandledNotLike() {
580         try (SqlSession session = sqlSessionFactory.openSession()) {
581             PersonMapper mapper = session.getMapper(PersonMapper.class);
582 
583             List<PersonRecord> rows = mapper.select(c ->
584                     c.where(lastName, isNotLike(new LastName("Fl%")))
585                     .orderBy(id));
586 
587             assertThat(rows).hasSize(3);
588             assertThat(rows.get(0).firstName()).isEqualTo("Barney");
589         }
590     }
591 
592     @Test
593     void testJoinAllRows() {
594         try (SqlSession session = sqlSessionFactory.openSession()) {
595             PersonWithAddressMapper mapper = session.getMapper(PersonWithAddressMapper.class);
596             List<PersonWithAddress> records = mapper.select(
597                     SelectDSLCompleter.allRowsOrderedBy(id)
598             );
599 
600             assertThat(records).hasSize(6);
601             assertThat(records.get(0).getId()).isEqualTo(1);
602             assertThat(records.get(0).getEmployed()).isTrue();
603             assertThat(records.get(0).getFirstName()).isEqualTo("Fred");
604             assertThat(records.get(0).getLastName()).isEqualTo(new LastName("Flintstone"));
605             assertThat(records.get(0).getOccupation()).isEqualTo("Brontosaurus Operator");
606             assertThat(records.get(0).getBirthDate()).isNotNull();
607             assertThat(records.get(0).getAddress().getId()).isEqualTo(1);
608             assertThat(records.get(0).getAddress().getStreetAddress()).isEqualTo("123 Main Street");
609             assertThat(records.get(0).getAddress().getCity()).isEqualTo("Bedrock");
610             assertThat(records.get(0).getAddress().getState()).isEqualTo("IN");
611             assertThat(records.get(0).getAddress().getAddressType()).isEqualTo(AddressRecord.AddressType.HOME);
612 
613             assertThat(records.get(4).getAddress().getAddressType()).isEqualTo(AddressRecord.AddressType.BUSINESS);
614         }
615     }
616 
617     @Test
618     void testJoinOneRow() {
619         try (SqlSession session = sqlSessionFactory.openSession()) {
620             PersonWithAddressMapper mapper = session.getMapper(PersonWithAddressMapper.class);
621             List<PersonWithAddress> records = mapper.select(c -> c.where(id, isEqualTo(1)));
622 
623             assertThat(records).hasSize(1);
624             assertThat(records.get(0).getId()).isEqualTo(1);
625             assertThat(records.get(0).getEmployed()).isTrue();
626             assertThat(records.get(0).getFirstName()).isEqualTo("Fred");
627             assertThat(records.get(0).getLastName()).isEqualTo(new LastName("Flintstone"));
628             assertThat(records.get(0).getOccupation()).isEqualTo("Brontosaurus Operator");
629             assertThat(records.get(0).getBirthDate()).isNotNull();
630             assertThat(records.get(0).getAddress().getId()).isEqualTo(1);
631             assertThat(records.get(0).getAddress().getStreetAddress()).isEqualTo("123 Main Street");
632             assertThat(records.get(0).getAddress().getCity()).isEqualTo("Bedrock");
633             assertThat(records.get(0).getAddress().getState()).isEqualTo("IN");
634         }
635     }
636 
637     @Test
638     void testJoinPrimaryKey() {
639         try (SqlSession session = sqlSessionFactory.openSession()) {
640             PersonWithAddressMapper mapper = session.getMapper(PersonWithAddressMapper.class);
641             Optional<PersonWithAddress> row = mapper.selectByPrimaryKey(1);
642 
643             assertThat(row).hasValueSatisfying(r -> {
644                 assertThat(r.getId()).isEqualTo(1);
645                 assertThat(r.getEmployed()).isTrue();
646                 assertThat(r.getFirstName()).isEqualTo("Fred");
647                 assertThat(r.getLastName()).isEqualTo(new LastName("Flintstone"));
648                 assertThat(r.getOccupation()).isEqualTo("Brontosaurus Operator");
649                 assertThat(r.getBirthDate()).isNotNull();
650                 assertThat(r.getAddress().getId()).isEqualTo(1);
651                 assertThat(r.getAddress().getStreetAddress()).isEqualTo("123 Main Street");
652                 assertThat(r.getAddress().getCity()).isEqualTo("Bedrock");
653                 assertThat(r.getAddress().getState()).isEqualTo("IN");
654             });
655         }
656     }
657 
658     @Test
659     void testJoinPrimaryKeyInvalidRecord() {
660         try (SqlSession session = sqlSessionFactory.openSession()) {
661             PersonWithAddressMapper mapper = session.getMapper(PersonWithAddressMapper.class);
662             Optional<PersonWithAddress> row = mapper.selectByPrimaryKey(55);
663 
664             assertThat(row).isEmpty();
665         }
666     }
667 
668     @Test
669     void testJoinCount() {
670         try (SqlSession session = sqlSessionFactory.openSession()) {
671             PersonWithAddressMapper mapper = session.getMapper(PersonWithAddressMapper.class);
672             long count = mapper.count(c -> c.where(person.id, isEqualTo(55)));
673 
674             assertThat(count).isZero();
675         }
676     }
677 
678     @Test
679     void testJoinCountWithSubcriteria() {
680         try (SqlSession session = sqlSessionFactory.openSession()) {
681             PersonWithAddressMapper mapper = session.getMapper(PersonWithAddressMapper.class);
682             long count = mapper.count(c -> c.where(person.id, isEqualTo(55), or(person.id, isEqualTo(1))));
683 
684             assertThat(count).isEqualTo(1);
685         }
686     }
687 
688     @Test
689     void testWithEnumOrdinalTypeHandler() {
690         try (SqlSession session = sqlSessionFactory.openSession()) {
691             AddressMapper mapper = session.getMapper(AddressMapper.class);
692 
693             GeneralInsertStatementProvider insertStatement = insertInto(address)
694                     .set(address.id).toValue(4)
695                     .set(address.streetAddress).toValue("987 Elm Street")
696                     .set(address.city).toValue("Mayberry")
697                     .set(address.state).toValue("NC")
698                     .set(address.addressType).toValue(AddressRecord.AddressType.HOME)
699                     .build()
700                     .render(RenderingStrategies.MYBATIS3);
701 
702             int rows = mapper.generalInsert(insertStatement);
703             assertThat(rows).isEqualTo(1);
704 
705             SelectStatementProvider selectStatement = select(address.addressType)
706                     .from(address)
707                     .where(address.id, isEqualTo(4))
708                     .build()
709                     .render(RenderingStrategies.MYBATIS3);
710 
711             Optional<Integer> type = mapper.selectOptionalInteger(selectStatement);
712             assertThat(type).hasValueSatisfying(i -> assertThat(i).isZero());
713         }
714     }
715 
716     @Test
717     void testMultiSelectWithUnion() {
718         try (SqlSession session = sqlSessionFactory.openSession()) {
719             PersonMapper mapper = session.getMapper(PersonMapper.class);
720 
721             SelectStatementProvider selectStatement = multiSelect(
722                     select(id.as("A_ID"), firstName, lastName, birthDate, employed, occupation, addressId)
723                             .from(person)
724                             .where(id, isLessThanOrEqualTo(2))
725                             .orderBy(id)
726                             .limit(1)
727             ).union(
728                     select(id.as("A_ID"), firstName, lastName, birthDate, employed, occupation, addressId)
729                             .from(person)
730                             .where(id, isGreaterThanOrEqualTo(4))
731                             .orderBy(id.descending())
732                             .limit(1)
733             )
734             .orderBy(sortColumn("A_ID"))
735             .limit(3)
736             .build()
737             .render(RenderingStrategies.MYBATIS3);
738 
739             String expected =
740                     "(select id as A_ID, first_name, last_name, birth_date, employed, occupation, address_id " +
741                     "from Person " +
742                     "where id <= #{parameters.p1,jdbcType=INTEGER} " +
743                     "order by id limit #{parameters.p2}) " +
744                     "union " +
745                     "(select id as A_ID, first_name, last_name, birth_date, employed, occupation, address_id " +
746                     "from Person " +
747                     "where id >= #{parameters.p3,jdbcType=INTEGER} " +
748                     "order by id DESC limit #{parameters.p4}) " +
749                     "order by A_ID " +
750                     "limit #{parameters.p5}";
751 
752             assertThat(selectStatement.getSelectStatement()).isEqualTo(expected);
753 
754             List<PersonRecord> records = mapper.selectMany(selectStatement);
755 
756             assertThat(records).hasSize(2);
757             assertThat(records.get(0).id()).isEqualTo(1);
758             assertThat(records.get(1).id()).isEqualTo(6);
759         }
760     }
761 
762     @Test
763     void testMultiSelectWithUnionAll() {
764         try (SqlSession session = sqlSessionFactory.openSession()) {
765             PersonMapper mapper = session.getMapper(PersonMapper.class);
766 
767             SelectStatementProvider selectStatement = multiSelect(
768                     select(id.as("A_ID"), firstName, lastName, birthDate, employed, occupation, addressId)
769                             .from(person)
770                             .where(id, isLessThanOrEqualTo(2))
771                             .orderBy(id)
772                             .limit(1)
773             ).unionAll(
774                     select(id.as("A_ID"), firstName, lastName, birthDate, employed, occupation, addressId)
775                             .from(person)
776                             .where(id, isGreaterThanOrEqualTo(4))
777                             .orderBy(id.descending())
778                             .limit(1)
779                     ).orderBy(sortColumn("A_ID"))
780                     .fetchFirst(2).rowsOnly()
781                     .build()
782                     .render(RenderingStrategies.MYBATIS3);
783 
784             String expected =
785                     "(select id as A_ID, first_name, last_name, birth_date, employed, occupation, address_id " +
786                             "from Person " +
787                             "where id <= #{parameters.p1,jdbcType=INTEGER} " +
788                             "order by id limit #{parameters.p2}) " +
789                             "union all " +
790                             "(select id as A_ID, first_name, last_name, birth_date, employed, occupation, address_id " +
791                             "from Person " +
792                             "where id >= #{parameters.p3,jdbcType=INTEGER} " +
793                             "order by id DESC limit #{parameters.p4}) " +
794                             "order by A_ID " +
795                             "fetch first #{parameters.p5} rows only";
796 
797             assertThat(selectStatement.getSelectStatement()).isEqualTo(expected);
798 
799             List<PersonRecord> records = mapper.selectMany(selectStatement);
800 
801             assertThat(records).hasSize(2);
802             assertThat(records.get(0).id()).isEqualTo(1);
803             assertThat(records.get(1).id()).isEqualTo(6);
804         }
805     }
806 
807     @Test
808     void testMultiSelectPagingVariation1() {
809         SelectStatementProvider selectStatement = multiSelect(
810                 select(id, firstName, lastName, birthDate, employed, occupation, addressId)
811                         .from(person)
812                         .where(id, isLessThanOrEqualTo(2))
813         ).unionAll(
814                 select(id, firstName, lastName, birthDate, employed, occupation, addressId)
815                         .from(person)
816                         .where(id, isGreaterThanOrEqualTo(4))
817                 )
818                 .orderBy(id)
819                 .limit(3).offset(2)
820                 .build()
821                 .render(RenderingStrategies.MYBATIS3);
822 
823         String expected =
824                 "(select id, first_name, last_name, birth_date, employed, occupation, address_id " +
825                         "from Person " +
826                         "where id <= #{parameters.p1,jdbcType=INTEGER}) " +
827                         "union all " +
828                         "(select id, first_name, last_name, birth_date, employed, occupation, address_id " +
829                         "from Person " +
830                         "where id >= #{parameters.p2,jdbcType=INTEGER}) " +
831                         "order by id " +
832                         "limit #{parameters.p3} offset #{parameters.p4}";
833 
834         assertThat(selectStatement.getSelectStatement()).isEqualTo(expected);
835     }
836 
837     @Test
838     void testMultiSelectPagingVariation2() {
839         SelectStatementProvider selectStatement = multiSelect(
840                 select(id, firstName, lastName, birthDate, employed, occupation, addressId)
841                         .from(person)
842                         .where(id, isLessThanOrEqualTo(2))
843         ).unionAll(
844                 select(id, firstName, lastName, birthDate, employed, occupation, addressId)
845                         .from(person)
846                         .where(id, isGreaterThanOrEqualTo(4))
847                 )
848                 .orderBy(id)
849                 .offset(2)
850                 .build()
851                 .render(RenderingStrategies.MYBATIS3);
852 
853         String expected =
854                 "(select id, first_name, last_name, birth_date, employed, occupation, address_id " +
855                         "from Person " +
856                         "where id <= #{parameters.p1,jdbcType=INTEGER}) " +
857                         "union all " +
858                         "(select id, first_name, last_name, birth_date, employed, occupation, address_id " +
859                         "from Person " +
860                         "where id >= #{parameters.p2,jdbcType=INTEGER}) " +
861                         "order by id " +
862                         "offset #{parameters.p3} rows";
863 
864         assertThat(selectStatement.getSelectStatement()).isEqualTo(expected);
865     }
866 
867     @Test
868     void testMultiSelectPagingVariation3() {
869         SelectStatementProvider selectStatement = multiSelect(
870                 select(id, firstName, lastName, birthDate, employed, occupation, addressId)
871                         .from(person)
872                         .where(id, isLessThanOrEqualTo(2))
873         ).unionAll(
874                 select(id, firstName, lastName, birthDate, employed, occupation, addressId)
875                         .from(person)
876                         .where(id, isGreaterThanOrEqualTo(4))
877                 )
878                 .orderBy(id)
879                 .offset(2).fetchFirst(3).rowsOnly()
880                 .build()
881                 .render(RenderingStrategies.MYBATIS3);
882 
883         String expected =
884                 "(select id, first_name, last_name, birth_date, employed, occupation, address_id " +
885                         "from Person " +
886                         "where id <= #{parameters.p1,jdbcType=INTEGER}) " +
887                         "union all " +
888                         "(select id, first_name, last_name, birth_date, employed, occupation, address_id " +
889                         "from Person " +
890                         "where id >= #{parameters.p2,jdbcType=INTEGER}) " +
891                         "order by id " +
892                         "offset #{parameters.p3} rows fetch first #{parameters.p4} rows only";
893 
894         assertThat(selectStatement.getSelectStatement()).isEqualTo(expected);
895     }
896 
897     @Test
898     void testMultiSelectPagingVariation() {
899         SelectStatementProvider selectStatement = multiSelect(
900                 select(id, firstName, lastName, birthDate, employed, occupation, addressId)
901                         .from(person)
902                         .where(id, isLessThanOrEqualTo(2))
903         ).unionAll(
904                 select(id, firstName, lastName, birthDate, employed, occupation, addressId)
905                         .from(person)
906                         .where(id, isGreaterThanOrEqualTo(4))
907                 )
908                 .orderBy(id)
909                 .build()
910                 .render(RenderingStrategies.MYBATIS3);
911 
912         String expected =
913                 "(select id, first_name, last_name, birth_date, employed, occupation, address_id " +
914                         "from Person " +
915                         "where id <= #{parameters.p1,jdbcType=INTEGER}) " +
916                         "union all " +
917                         "(select id, first_name, last_name, birth_date, employed, occupation, address_id " +
918                         "from Person " +
919                         "where id >= #{parameters.p2,jdbcType=INTEGER}) " +
920                         "order by id";
921 
922         assertThat(selectStatement.getSelectStatement()).isEqualTo(expected);
923     }
924 
925     @Test
926     void gh737() {
927         UpdateStatementProvider updateStatement = update(person)
928                 .set(addressId).equalTo(add(addressId, value(4)))
929                 .where(id, isEqualTo(5))
930                 .build()
931                 .render(RenderingStrategies.MYBATIS3);
932 
933         String expected = "update Person " +
934                 "set address_id = (address_id + #{parameters.p1}) " +
935                 "where id = #{parameters.p2,jdbcType=INTEGER}";
936 
937         assertThat(updateStatement.getUpdateStatement()).isEqualTo(expected);
938         assertThat(updateStatement.getParameters()).containsExactly(entry("p1", 4), entry("p2", 5));
939     }
940 }