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.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          InputStream is = getClass().getResourceAsStream("/examples/animal/data/CreateAnimalData.sql");
54          assert is != null;
55          try (Connection connection = DriverManager.getConnection(JDBC_URL, "sa", "")) {
56              ScriptRunner sr = new ScriptRunner(connection);
57              sr.setLogWriter(null);
58              sr.runScript(new InputStreamReader(is));
59          }
60  
61          UnpooledDataSource ds = new UnpooledDataSource(JDBC_DRIVER, JDBC_URL, "sa", "");
62          Environment environment = new Environment("test", new JdbcTransactionFactory(), ds);
63          Configuration config = new Configuration(environment);
64          config.addMapper(AnimalDataMapper.class);
65          sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
66      }
67  
68      @Test
69      void testOffsetAndFetchFirstAfterFrom() {
70          try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
71              SelectStatementProvider selectStatement = select(animalData.allColumns())
72                      .from(animalData)
73                      .offset(22)
74                      .fetchFirst(3).rowsOnly()
75                      .build()
76                      .render(RenderingStrategies.MYBATIS3);
77  
78              AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
79              List<AnimalData> records = mapper.selectMany(selectStatement);
80  
81              assertAll(
82                      () -> assertThat(records).hasSize(3),
83                      () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23),
84                      () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"),
85                      () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 3L),
86                      () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 22L)
87              );
88          }
89      }
90  
91      @Test
92      void testFetchFirstOnlyAfterFrom() {
93          try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
94              SelectStatementProvider selectStatement = select(animalData.allColumns())
95                      .from(animalData)
96                      .fetchFirst(3).rowsOnly()
97                      .build()
98                      .render(RenderingStrategies.MYBATIS3);
99  
100             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
101             List<AnimalData> records = mapper.selectMany(selectStatement);
102 
103             assertAll(
104                     () -> assertThat(records).hasSize(3),
105                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1),
106                     () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData fetch first #{parameters.p1} rows only"),
107                     () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L)
108             );
109         }
110     }
111 
112     @Test
113     void testOffsetAndFetchFirstAfterWhere() {
114         try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
115             SelectStatementProvider selectStatement = select(animalData.allColumns())
116                     .from(animalData)
117                     .where(id, isLessThan(50))
118                     .and(id, isGreaterThan(22))
119                     .offset(22)
120                     .fetchFirst(3).rowsOnly()
121                     .build()
122                     .render(RenderingStrategies.MYBATIS3);
123 
124             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
125             List<AnimalData> records = mapper.selectMany(selectStatement);
126 
127             assertAll(
128                     () -> assertThat(records).hasSize(3),
129                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(45),
130                     () -> 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"),
131                     () -> assertThat(selectStatement.getParameters()).contains(entry("p4", 3L), entry("p3", 22L))
132             );
133         }
134     }
135 
136     @Test
137     void testFetchFirstOnlyAfterWhere() {
138         try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
139             SelectStatementProvider selectStatement = select(animalData.allColumns())
140                     .from(animalData)
141                     .where(id, isLessThan(50))
142                     .fetchFirst(3).rowsOnly()
143                     .build()
144                     .render(RenderingStrategies.MYBATIS3);
145 
146             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
147             List<AnimalData> records = mapper.selectMany(selectStatement);
148 
149             assertAll(
150                     () -> assertThat(records).hasSize(3),
151                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1),
152                     () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} fetch first #{parameters.p2} rows only"),
153                     () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 3L)
154             );
155         }
156     }
157 
158     @Test
159     void testOffsetAndFetchFirstAfterOrderBy() {
160         try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
161             SelectStatementProvider selectStatement = select(animalData.allColumns())
162                     .from(animalData)
163                     .orderBy(id)
164                     .offset(22)
165                     .fetchFirst(3).rowsOnly()
166                     .build()
167                     .render(RenderingStrategies.MYBATIS3);
168 
169             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
170             List<AnimalData> records = mapper.selectMany(selectStatement);
171 
172             assertAll(
173                     () -> assertThat(records).hasSize(3),
174                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23),
175                     () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"),
176                     () -> assertThat(selectStatement)
177                             .extracting(SelectStatementProvider::getParameters)
178                             .extracting("p2", "p1")
179                             .containsExactly(3L, 22L)
180             );
181         }
182     }
183 
184     @Test
185     void testLimitOnlyAfterOrderBy() {
186         try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
187             SelectStatementProvider selectStatement = select(animalData.allColumns())
188                     .from(animalData)
189                     .orderBy(id)
190                     .fetchFirst(3).rowsOnly()
191                     .build()
192                     .render(RenderingStrategies.MYBATIS3);
193 
194             AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class);
195             List<AnimalData> records = mapper.selectMany(selectStatement);
196 
197             assertAll(
198                     () -> assertThat(records).hasSize(3),
199                     () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1),
200                     () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id fetch first #{parameters.p1} rows only"),
201                     () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L)
202             );
203         }
204     }
205 }