View Javadoc
1   /*
2    *    Copyright 2016-2026 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.animal.data;
17  
18  import static examples.animal.data.AnimalDataDynamicSqlSupport.*;
19  import static org.assertj.core.api.Assertions.assertThat;
20  import static org.assertj.core.api.Assertions.entry;
21  import static org.junit.jupiter.api.Assertions.assertAll;
22  import static org.mybatis.dynamic.sql.SqlBuilder.*;
23  
24  import java.io.InputStream;
25  import java.io.InputStreamReader;
26  import java.sql.Connection;
27  import java.sql.DriverManager;
28  import java.util.List;
29  
30  import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
31  import org.apache.ibatis.jdbc.ScriptRunner;
32  import org.apache.ibatis.mapping.Environment;
33  import org.apache.ibatis.session.Configuration;
34  import org.apache.ibatis.session.SqlSession;
35  import org.apache.ibatis.session.SqlSessionFactory;
36  import org.apache.ibatis.session.SqlSessionFactoryBuilder;
37  import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
38  import org.junit.jupiter.api.BeforeEach;
39  import org.junit.jupiter.api.Test;
40  import org.mybatis.dynamic.sql.render.RenderingStrategies;
41  import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
42  
43  class FetchFirstTest {
44  
45      private static final String JDBC_URL = "jdbc:hsqldb:mem:aname";
46      private static final String JDBC_DRIVER = "org.hsqldb.jdbcDriver";
47  
48      private SqlSessionFactory sqlSessionFactory;
49  
50      @BeforeEach
51      void setup() throws Exception {
52          Class.forName(JDBC_DRIVER);
53          try (InputStream is = getClass().getResourceAsStream("/examples/animal/data/CreateAnimalData.sql")) {
54              assert is != null;
55              try (Connection connection = DriverManager.getConnection(JDBC_URL, "sa", "");
56                  InputStreamReader isr = new InputStreamReader(is)) {
57                  ScriptRunner sr = new ScriptRunner(connection);
58                  sr.setLogWriter(null);
59                  sr.runScript(isr);
60              }
61          }
62  
63          UnpooledDataSource ds = new UnpooledDataSource(JDBC_DRIVER, JDBC_URL, "sa", "");
64          Environment environment = new Environment("test", new JdbcTransactionFactory(), ds);
65          Configuration config = new Configuration(environment);
66          config.addMapper(AnimalDataMapper.class);
67          sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
68      }
69  
70      @Test
71      void testOffsetAndFetchFirstAfterFrom() {
72          try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
73              SelectStatementProvider selectStatement = select(animalData.allColumns())
74                      .from(animalData)
75                      .offset(22)
76                      .fetchFirst(3).rowsOnly()
77                      .build()
78                      .render(RenderingStrategies.MYBATIS3);
79  
80              AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
81              List<AnimalData> records = mapper.selectMany(selectStatement);
82  
83              assertAll(
84                      () -> assertThat(records).hasSize(3),
85                      () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23),
86                      () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"),
87                      () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 3L),
88                      () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 22L)
89              );
90          }
91      }
92  
93      @Test
94      void testFetchFirstOnlyAfterFrom() {
95          try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
96              SelectStatementProvider selectStatement = select(animalData.allColumns())
97                      .from(animalData)
98                      .fetchFirst(3).rowsOnly()
99                      .build()
100                     .render(RenderingStrategies.MYBATIS3);
101 
102             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
103             List<AnimalData> records = mapper.selectMany(selectStatement);
104 
105             assertAll(
106                     () -> assertThat(records).hasSize(3),
107                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1),
108                     () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData fetch first #{parameters.p1} rows only"),
109                     () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L)
110             );
111         }
112     }
113 
114     @Test
115     void testOffsetAndFetchFirstAfterWhere() {
116         try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
117             SelectStatementProvider selectStatement = select(animalData.allColumns())
118                     .from(animalData)
119                     .where(id, isLessThan(50))
120                     .and(id, isGreaterThan(22))
121                     .offset(22)
122                     .fetchFirst(3).rowsOnly()
123                     .build()
124                     .render(RenderingStrategies.MYBATIS3);
125 
126             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
127             List<AnimalData> records = mapper.selectMany(selectStatement);
128 
129             assertAll(
130                     () -> assertThat(records).hasSize(3),
131                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(45),
132                     () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} and id > #{parameters.p2,jdbcType=INTEGER} offset #{parameters.p3} rows fetch first #{parameters.p4} rows only"),
133                     () -> assertThat(selectStatement.getParameters()).contains(entry("p4", 3L), entry("p3", 22L))
134             );
135         }
136     }
137 
138     @Test
139     void testFetchFirstOnlyAfterWhere() {
140         try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
141             SelectStatementProvider selectStatement = select(animalData.allColumns())
142                     .from(animalData)
143                     .where(id, isLessThan(50))
144                     .fetchFirst(3).rowsOnly()
145                     .build()
146                     .render(RenderingStrategies.MYBATIS3);
147 
148             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
149             List<AnimalData> records = mapper.selectMany(selectStatement);
150 
151             assertAll(
152                     () -> assertThat(records).hasSize(3),
153                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1),
154                     () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} fetch first #{parameters.p2} rows only"),
155                     () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 3L)
156             );
157         }
158     }
159 
160     @Test
161     void testOffsetAndFetchFirstAfterOrderBy() {
162         try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
163             SelectStatementProvider selectStatement = select(animalData.allColumns())
164                     .from(animalData)
165                     .orderBy(id)
166                     .offset(22)
167                     .fetchFirst(3).rowsOnly()
168                     .build()
169                     .render(RenderingStrategies.MYBATIS3);
170 
171             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
172             List<AnimalData> records = mapper.selectMany(selectStatement);
173 
174             assertAll(
175                     () -> assertThat(records).hasSize(3),
176                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23),
177                     () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"),
178                     () -> assertThat(selectStatement)
179                             .extracting(SelectStatementProvider::getParameters)
180                             .extracting("p2", "p1")
181                             .containsExactly(3L, 22L)
182             );
183         }
184     }
185 
186     @Test
187     void testLimitOnlyAfterOrderBy() {
188         try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
189             SelectStatementProvider selectStatement = select(animalData.allColumns())
190                     .from(animalData)
191                     .orderBy(id)
192                     .fetchFirst(3).rowsOnly()
193                     .build()
194                     .render(RenderingStrategies.MYBATIS3);
195 
196             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
197             List<AnimalData> records = mapper.selectMany(selectStatement);
198 
199             assertAll(
200                     () -> assertThat(records).hasSize(3),
201                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1),
202                     () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id fetch first #{parameters.p1} rows only"),
203                     () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L)
204             );
205         }
206     }
207 }