Skip to content

Commit abf6266

Browse files
committed
Tests for new sharding support
1 parent 157a035 commit abf6266

File tree

7 files changed

+450
-0
lines changed

7 files changed

+450
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2016-2022 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.sharding;
17+
18+
import org.mybatis.dynamic.sql.util.mybatis3.CommonCountMapper;
19+
import org.mybatis.dynamic.sql.util.mybatis3.CommonGeneralInsertMapper;
20+
import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
21+
22+
public interface ShardedMapper extends CommonCountMapper, CommonGeneralInsertMapper, CommonSelectMapper {
23+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright 2016-2022 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.sharding;
17+
18+
import static examples.sharding.TableCodesDynamicSqlSupport.tableCodes;
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.mybatis.dynamic.sql.SqlBuilder.countFrom;
21+
import static org.mybatis.dynamic.sql.SqlBuilder.insertInto;
22+
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
23+
import static org.mybatis.dynamic.sql.SqlBuilder.select;
24+
25+
import java.io.InputStream;
26+
import java.io.InputStreamReader;
27+
import java.sql.Connection;
28+
import java.sql.DriverManager;
29+
30+
import examples.sharding.TableCodesDynamicSqlSupport.TableCodes;
31+
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
32+
import org.apache.ibatis.jdbc.ScriptRunner;
33+
import org.apache.ibatis.mapping.Environment;
34+
import org.apache.ibatis.session.Configuration;
35+
import org.apache.ibatis.session.SqlSession;
36+
import org.apache.ibatis.session.SqlSessionFactory;
37+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
38+
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
39+
import org.junit.jupiter.api.BeforeEach;
40+
import org.junit.jupiter.api.Test;
41+
import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider;
42+
import org.mybatis.dynamic.sql.render.RenderingStrategies;
43+
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
44+
45+
class ShardingTest {
46+
private static final String JDBC_URL = "jdbc:hsqldb:mem:aname";
47+
private static final String JDBC_DRIVER = "org.hsqldb.jdbcDriver";
48+
49+
private SqlSessionFactory sqlSessionFactory;
50+
51+
@BeforeEach
52+
void setup() throws Exception {
53+
Class.forName(JDBC_DRIVER);
54+
InputStream is = getClass().getResourceAsStream("/examples/sharding/ShardingDB.sql");
55+
assert is != null;
56+
try (Connection connection = DriverManager.getConnection(JDBC_URL, "sa", "")) {
57+
ScriptRunner sr = new ScriptRunner(connection);
58+
sr.setLogWriter(null);
59+
sr.runScript(new InputStreamReader(is));
60+
}
61+
62+
UnpooledDataSource ds = new UnpooledDataSource(JDBC_DRIVER, JDBC_URL, "sa", "");
63+
Environment environment = new Environment("test", new JdbcTransactionFactory(), ds);
64+
Configuration config = new Configuration(environment);
65+
config.addMapper(ShardedMapper.class);
66+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
67+
}
68+
69+
@Test
70+
void testShardedSelect() {
71+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
72+
ShardedMapper mapper = sqlSession.getMapper(ShardedMapper.class);
73+
TableCodes table = calculateTable(1);
74+
75+
SelectStatementProvider selectStatement = select(table.description)
76+
.from(table)
77+
.where(table.id, isEqualTo(1))
78+
.build()
79+
.render(RenderingStrategies.MYBATIS3);
80+
81+
assertThat(selectStatement.getSelectStatement())
82+
.isEqualTo("select description from tableCodes_odd where id = #{parameters.p1,jdbcType=INTEGER}");
83+
84+
String description = mapper.selectOneString(selectStatement);
85+
assertThat(description).isNull();
86+
}
87+
}
88+
89+
@Test
90+
void testShardedInserts() {
91+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
92+
ShardedMapper mapper = sqlSession.getMapper(ShardedMapper.class);
93+
94+
mapper.generalInsert(buildInsert(1, "Description 1"));
95+
mapper.generalInsert(buildInsert(2, "Description 2"));
96+
mapper.generalInsert(buildInsert(3, "Description 3"));
97+
mapper.generalInsert(buildInsert(4, "Description 4"));
98+
mapper.generalInsert(buildInsert(5, "Description 5"));
99+
mapper.generalInsert(buildInsert(6, "Description 6"));
100+
mapper.generalInsert(buildInsert(7, "Description 7"));
101+
102+
TableCodes oddTable = calculateTable(1);
103+
SelectStatementProvider oddCountStatement = countFrom(oddTable)
104+
.build()
105+
.render(RenderingStrategies.MYBATIS3);
106+
assertThat(oddCountStatement.getSelectStatement()).isEqualTo("select count(*) from tableCodes_odd");
107+
long oddRows = mapper.count(oddCountStatement);
108+
assertThat(oddRows).isEqualTo(4L);
109+
110+
TableCodes evenTable = calculateTable(2);
111+
SelectStatementProvider evenCountStatement = countFrom(evenTable)
112+
.build()
113+
.render(RenderingStrategies.MYBATIS3);
114+
assertThat(evenCountStatement.getSelectStatement()).isEqualTo("select count(*) from tableCodes_even");
115+
long evenRows = mapper.count(evenCountStatement);
116+
assertThat(evenRows).isEqualTo(3L);
117+
}
118+
}
119+
120+
@Test
121+
void testShardedSelects() {
122+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
123+
ShardedMapper mapper = sqlSession.getMapper(ShardedMapper.class);
124+
125+
mapper.generalInsert(buildInsert(1, "Description 1"));
126+
mapper.generalInsert(buildInsert(2, "Description 2"));
127+
128+
assertThat(mapper.selectOneString(buildSelect(1))).isEqualTo("Description 1");
129+
assertThat(mapper.selectOneString(buildSelect(2))).isEqualTo("Description 2");
130+
assertThat(mapper.selectOneString(buildSelect(3))).isNull();
131+
assertThat(mapper.selectOneString(buildSelect(4))).isNull();
132+
}
133+
}
134+
135+
private GeneralInsertStatementProvider buildInsert(int id, String description) {
136+
TableCodesDynamicSqlSupport.TableCodes table = calculateTable(id);
137+
return insertInto(table)
138+
.set(table.id).toValue(id)
139+
.set(table.description).toValue(description)
140+
.build()
141+
.render(RenderingStrategies.MYBATIS3);
142+
}
143+
144+
private SelectStatementProvider buildSelect(int id) {
145+
TableCodesDynamicSqlSupport.TableCodes table = calculateTable(id);
146+
return select(table.description)
147+
.from(table)
148+
.where(table.id, isEqualTo(id))
149+
.build()
150+
.render(RenderingStrategies.MYBATIS3);
151+
}
152+
153+
private TableCodes calculateTable(int id) {
154+
// it might be better to lookup instances in a Map rather than creating a new instance
155+
// every time
156+
return tableCodes.withName(calculateTableName(id));
157+
}
158+
159+
private String calculateTableName(int id) {
160+
if (id % 2 == 0) {
161+
return "tableCodes_even";
162+
} else {
163+
return "tableCodes_odd";
164+
}
165+
}
166+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2016-2022 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.sharding;
17+
18+
import org.mybatis.dynamic.sql.AliasableSqlTable;
19+
import org.mybatis.dynamic.sql.SqlColumn;
20+
21+
import java.sql.JDBCType;
22+
23+
public final class TableCodesDynamicSqlSupport {
24+
public static final TableCodes tableCodes = new TableCodes();
25+
public static final SqlColumn<Integer> id = tableCodes.id;
26+
public static final SqlColumn<String> description = tableCodes.description;
27+
28+
public static final class TableCodes extends AliasableSqlTable<TableCodes> {
29+
public final SqlColumn<Integer> id = column("id", JDBCType.INTEGER);
30+
public final SqlColumn<String> description = column("description", JDBCType.VARCHAR);
31+
public TableCodes() {
32+
super("tableCodes_even", TableCodes::new);
33+
}
34+
}
35+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2016-2022 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.kotlin.mybatis3.sharding
17+
18+
import org.mybatis.dynamic.sql.util.mybatis3.CommonCountMapper
19+
import org.mybatis.dynamic.sql.util.mybatis3.CommonGeneralInsertMapper
20+
import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper
21+
22+
interface KShardedMapper: CommonCountMapper, CommonGeneralInsertMapper, CommonSelectMapper
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright 2016-2022 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.kotlin.mybatis3.sharding
17+
18+
import examples.kotlin.mybatis3.TestUtils
19+
import examples.kotlin.mybatis3.sharding.KTableCodesTableDynamicSQLSupport.tableCodes
20+
import org.apache.ibatis.session.SqlSessionFactory
21+
import org.assertj.core.api.Assertions.assertThat
22+
import org.junit.jupiter.api.BeforeAll
23+
import org.junit.jupiter.api.Test
24+
import org.junit.jupiter.api.TestInstance
25+
import org.mybatis.dynamic.sql.util.kotlin.mybatis3.countFrom
26+
import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertInto
27+
import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select
28+
29+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
30+
class KShardingTest {
31+
private lateinit var sqlSessionFactory: SqlSessionFactory
32+
33+
@BeforeAll
34+
fun setup() {
35+
sqlSessionFactory = TestUtils.buildSqlSessionFactory {
36+
withInitializationScript("/examples/sharding/ShardingDB.sql")
37+
withMapper(KShardedMapper::class)
38+
}
39+
}
40+
41+
@Test
42+
fun testShardedSelect() {
43+
sqlSessionFactory.openSession().use { session ->
44+
val mapper = session.getMapper(KShardedMapper::class.java)
45+
val table = calculateTable(1)
46+
47+
val selectStatement = select(table.description) {
48+
from(table)
49+
where {
50+
table.id isEqualTo 1
51+
}
52+
}
53+
54+
assertThat(selectStatement.selectStatement).isEqualTo(
55+
"select description from tableCodes_odd where id = #{parameters.p1,jdbcType=INTEGER}"
56+
)
57+
58+
val description = mapper.selectOneString(selectStatement)
59+
60+
assertThat(description).isNull()
61+
}
62+
}
63+
64+
@Test
65+
fun testShardedInserts() {
66+
sqlSessionFactory.openSession().use { session ->
67+
val mapper = session.getMapper(KShardedMapper::class.java)
68+
69+
mapper.insert(1, "Description 1")
70+
mapper.insert(2, "Description 2")
71+
mapper.insert(3, "Description 3")
72+
mapper.insert(4, "Description 4")
73+
mapper.insert(5, "Description 5")
74+
mapper.insert(6, "Description 6")
75+
mapper.insert(7, "Description 7")
76+
77+
val oddTable = calculateTable(1)
78+
val oddCountStatement = countFrom(oddTable) {
79+
allRows()
80+
}
81+
82+
assertThat(oddCountStatement.selectStatement).isEqualTo("select count(*) from tableCodes_odd")
83+
val oddRows = mapper.count(oddCountStatement)
84+
assertThat(oddRows).isEqualTo(4L)
85+
86+
val evenTable = calculateTable(2)
87+
val evenCountStatement = countFrom(evenTable) {
88+
allRows()
89+
}
90+
91+
assertThat(evenCountStatement.selectStatement).isEqualTo("select count(*) from tableCodes_even")
92+
val evenRows = mapper.count(evenCountStatement)
93+
assertThat(evenRows).isEqualTo(3L)
94+
}
95+
}
96+
97+
@Test
98+
fun testShardedSelects() {
99+
sqlSessionFactory.openSession().use { session ->
100+
val mapper = session.getMapper(KShardedMapper::class.java)
101+
102+
mapper.insert(1, "Description 1")
103+
mapper.insert(2, "Description 2")
104+
105+
assertThat(mapper.select(1)).isEqualTo("Description 1")
106+
assertThat(mapper.select(2)).isEqualTo("Description 2")
107+
assertThat(mapper.select(3)).isNull()
108+
assertThat(mapper.select(4)).isNull()
109+
}
110+
}
111+
112+
fun KShardedMapper.insert(id: Int, description: String): Int {
113+
val table = calculateTable(id)
114+
val insertStatement = insertInto(table) {
115+
set(table.id) toValue id
116+
set(table.description) toValue description
117+
}
118+
119+
return generalInsert(insertStatement)
120+
}
121+
122+
fun KShardedMapper.select(id: Int): String? {
123+
val table = calculateTable(id)
124+
val selectStatement = select(table.description) {
125+
from(table)
126+
where {
127+
table.id isEqualTo id
128+
}
129+
}
130+
131+
return selectOneString(selectStatement)
132+
}
133+
134+
private fun calculateTable(id: Int) = tableCodes.withName(calculateTableName(id))
135+
136+
private fun calculateTableName(id: Int): String {
137+
return if (id.mod(2) == 0) {
138+
"tableCodes_even"
139+
} else {
140+
"tableCodes_odd"
141+
}
142+
}
143+
}

0 commit comments

Comments
 (0)