Skip to content

Commit e471537

Browse files
authored
Merge pull request #8 from Rurutia1027/b_support-impl
remove integration tests, and re-impl the sharding query service
2 parents 36d03d6 + 426e836 commit e471537

File tree

8 files changed

+132
-686
lines changed

8 files changed

+132
-686
lines changed

persistence-sharding/src/main/java/org/tus/common/sharding/service/ShardingAwareQueryService.java

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,92 @@
11
package org.tus.common.sharding.service;
22

33
import org.tus.common.domain.persistence.QueryService;
4-
import org.tus.common.sharding.util.ShardingUtil;
54

65
import java.util.List;
76
import java.util.Map;
87

98
/**
109
* Extension of QueryService that provides sharding-aware operations.
11-
*
10+
*
1211
* This service adds methods to work with sharded entities while maintaining
1312
* compatibility with the base QueryService interface. It provides utilities
1413
* for determining shard locations and handling cross-shard queries.
15-
*
14+
*
1615
* Note: Most sharding logic is handled transparently by ShardingSphere,
17-
* but this service provides additional utilities for cases where you need
16+
* but this service provides additional utilities for case where you need
1817
* explicit shard awareness.
1918
*/
20-
public interface ShardingAwareQueryService extends QueryService {
21-
19+
public interface ShardingAwareQueryService extends QueryService {
2220
/**
2321
* Finds an object by ID with explicit sharding key.
24-
* Useful when the sharding key is different from the ID.
25-
*
22+
* The sharding key is included in the HQL so ShardingSphere can route to the correct
23+
* shard.
24+
* Uses default sharding property name "userId" for backward compatibility.
25+
*
2626
* @param clazz Entity class
2727
* @param id Entity ID
28-
* @param shardingKey The sharding key (e.g., user_id for user_coupon table)
28+
* @param shardingKey The sharding key value (e.g., user_id for user_coupon table)
2929
* @param <T> Entity type
3030
* @return Found entity or null
3131
*/
3232
<T> T findObjectByIdWithShardingKey(Class<T> clazz, String id, Long shardingKey);
3333

3434
/**
35-
* Executes a query that may span multiple shards.
36-
* ShardingSphere will automatically route to correct shards.
37-
*
38-
* @param hql HQL query
39-
* @param namedParameters Query parameters
40-
* @param shardingKeys List of sharding keys (for IN queries across shards)
35+
* Finds an object by ID with explicit sharding key and property name.
36+
* The sharding key is included in the HQL so ShardingSphere can route to the correct
37+
* shard.
38+
* Use this when the sharding column is not "userId" (e.g., shop_number -> "shopNumber").
39+
*
40+
* @param clazz Entity class
41+
* @param id Entity ID
42+
* @param shardingKeyPropertyName HQL property name of the sharding column (e.g.,
43+
* "userId", "shopNumber")
44+
* @param shardingKeyValue The sharding key value
45+
* @param <T> Entity type
46+
* @return Found entity or null
47+
*/
48+
<T> T findObjectByIdWithShardingKey(Class<T> clazz, String id,
49+
String shardingKeyPropertyName,
50+
Object shardingKeyValue);
51+
52+
/**
53+
* Executes a query with sharding keys. The HQL must contain a condition on the sharding
54+
* column (e.g., {@code user IN (:shardingKeys)} and the same param name must be used.
55+
* ShardingSphere will route based on the values in the query.
56+
*
57+
* @param hql HQL query (must include sharding column in WHERE, e.g. userId IN
58+
* (:shardingKeys))
59+
* @param namedParameters Query parameters (shardingKeys will be merged if provided)
60+
* @param shardingKeys List of sharding keys (for IN queries across shards)
61+
* @return Query results
62+
*/
63+
List queryWithShardingKeys(String hql, Map<String, Object> namedParameters,
64+
List<Long> shardingKeys);
65+
66+
67+
/**
68+
* Executes a query ensuring the sharding key participates in the query.
69+
* Appends {@code AND shardingKeyPropertyName IN (:__shardingKeys)} (or WHERE if no
70+
* WHERE present) so ShardingSphere can route correctly. Use this when you do not want
71+
* to hand-write the sharding condition in HQL.
72+
*
73+
* @param hql Base HQL query (may or may not have WHERE)
74+
* @param namedParameters Query parameters (must not use key "__shardingKeys")
75+
* @param shardingKeyPropertyName HQL property name of the sharding column (e.g.,
76+
* "userId", "shopNumber")
77+
* @param shardingKeys List of sharding key values
4178
* @return Query results
4279
*/
43-
List queryWithShardingKeys(String hql, Map<String, Object> namedParameters, List<Long> shardingKeys);
80+
List queryWithShardingKeys(String hql, Map<String, Object> namedParameters,
81+
String shardingKeyPropertyName, List<?> shardingKeys);
4482

4583
/**
4684
* Gets the shard information for a given sharding key.
47-
*
48-
* @param shardingKey The sharding key value
85+
*
86+
* @param shardingKey The sharding key value
4987
* @param shardingCount Total sharding count
5088
* @param databaseCount Number of databases
51-
* @param tableCount Number of tables per database
89+
* @param tableCount Number of tables per database
5290
* @return Shard information
5391
*/
5492
ShardInfo getShardInfo(Long shardingKey, int shardingCount, int databaseCount, int tableCount);

persistence-sharding/src/main/java/org/tus/common/sharding/service/ShardingAwareQueryServiceImpl.java

Lines changed: 75 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,99 @@
11
package org.tus.common.sharding.service;
22

3+
import lombok.RequiredArgsConstructor;
4+
import org.hibernate.Session;
5+
import org.tus.common.domain.persistence.NamedArtifact;
6+
import org.tus.common.domain.persistence.PersistedObject;
7+
import org.tus.common.domain.persistence.QueryPostProcessor;
38
import org.tus.common.domain.persistence.QueryService;
9+
import org.tus.common.domain.persistence.SimplePersistedObject;
10+
import org.tus.common.domain.persistence.UniqueNamedArtifact;
411
import org.tus.common.sharding.util.ShardingUtil;
512

13+
import java.util.HashMap;
614
import java.util.List;
715
import java.util.Map;
816

917
/**
1018
* Implementation of ShardingAwareQueryService.
11-
*
19+
*
1220
* This implementation extends the base QueryService functionality with
13-
* sharding-aware operations. Most operations delegate to the base QueryService,
14-
* as ShardingSphere handles the routing transparently.
21+
* sharding-aware operations. All sharded queries include the sharding value
22+
* in the HQL so ShardingSphere can route to the correct shard(s).
1523
*/
24+
@RequiredArgsConstructor
1625
public class ShardingAwareQueryServiceImpl implements ShardingAwareQueryService {
1726

27+
/**
28+
* Parameter name used when appending sharding key IN clause in queryWithShardingKeys.
29+
*/
30+
public static final String SHARDING_KEYS_PARAM = "__shardingKeys";
31+
1832
private final QueryService delegate;
1933

20-
public ShardingAwareQueryServiceImpl(QueryService delegate) {
21-
this.delegate = delegate;
22-
}
2334

2435
@Override
2536
public <T> T findObjectByIdWithShardingKey(Class<T> clazz, String id, Long shardingKey) {
26-
// ShardingSphere will automatically route based on sharding key in WHERE clause
27-
// We need to include the sharding key in the query
28-
String hql = "from " + clazz.getName() + " where id = :id";
29-
Map<String, Object> params = Map.of("id", id);
30-
31-
// If the entity has a sharding key field, include it in the query
32-
// This ensures ShardingSphere routes correctly
33-
// Note: The actual routing is handled by ShardingSphere based on table configuration
37+
return findObjectByIdWithShardingKey(clazz, id, "userId", shardingKey);
38+
}
39+
40+
@Override
41+
public <T> T findObjectByIdWithShardingKey(Class<T> clazz, String id, String shardingKeyPropertyName, Object shardingKeyValue) {
42+
if (shardingKeyPropertyName == null || shardingKeyPropertyName.isBlank()) {
43+
throw new IllegalArgumentException("shardingKeyPropertyName must not be null or blank");
44+
}
45+
if (shardingKeyValue == null) {
46+
throw new IllegalArgumentException("shardingKeyValue must not be null for shard routing");
47+
}
48+
String hql = "from " + clazz.getName() + " where id = :id and " + shardingKeyPropertyName + " = :shardingKeyValue";
49+
Map<String, Object> params = new HashMap<>();
50+
params.put("id", id);
51+
params.put("shardingKeyValue", shardingKeyValue);
3452
Object result = delegate.querySingle(hql, params, null);
3553
return result != null ? clazz.cast(result) : null;
3654
}
3755

3856
@Override
3957
public List queryWithShardingKeys(String hql, Map<String, Object> namedParameters, List<Long> shardingKeys) {
40-
// ShardingSphere automatically handles IN queries across shards
41-
// Just execute the query normally - ShardingSphere will route correctly
4258
if (shardingKeys != null && !shardingKeys.isEmpty()) {
43-
// Add sharding keys to parameters if needed
44-
Map<String, Object> params = new java.util.HashMap<>(namedParameters);
59+
Map<String, Object> params = namedParameters == null ? new HashMap<>() : new HashMap<>(namedParameters);
4560
params.put("shardingKeys", shardingKeys);
4661
return delegate.query(hql, params);
4762
}
48-
return delegate.query(hql, namedParameters);
63+
return delegate.query(hql, namedParameters != null ? namedParameters : Map.of());
64+
}
65+
66+
@Override
67+
public List queryWithShardingKeys(String hql, Map<String, Object> namedParameters, String shardingKeyPropertyName, List<?> shardingKeys) {
68+
if (shardingKeyPropertyName == null || shardingKeyPropertyName.isBlank()) {
69+
throw new IllegalArgumentException("shardingKeyPropertyName must not be null or blank");
70+
}
71+
Map<String, Object> params = namedParameters == null ? new HashMap<>() : new HashMap<>(namedParameters);
72+
if (shardingKeys != null && !shardingKeys.isEmpty()) {
73+
String condition = shardingKeyPropertyName + " IN (:" + SHARDING_KEYS_PARAM + ")";
74+
String normalizedHql = hql.trim();
75+
boolean hasWhere = normalizedHql.toUpperCase().contains(" WHERE ");
76+
String fullHql = hasWhere ? (normalizedHql + " AND " + condition) : (normalizedHql + " WHERE " + condition);
77+
params.put(SHARDING_KEYS_PARAM, shardingKeys);
78+
return delegate.query(fullHql, params);
79+
}
80+
return delegate.query(hql, params);
4981
}
5082

5183
@Override
5284
public ShardInfo getShardInfo(Long shardingKey, int shardingCount, int databaseCount, int tableCount) {
5385
int dbIndex = ShardingUtil.calculateDatabaseShard(shardingKey, shardingCount, databaseCount);
5486
int tableIndex = ShardingUtil.calculateTableShard(shardingKey, tableCount);
55-
87+
5688
String dbName = "ds_" + dbIndex;
5789
String tableName = "t_" + tableIndex; // Base name should be provided
58-
90+
5991
return new ShardInfo(dbIndex, tableIndex, dbName, tableName);
6092
}
6193

6294
// Delegate all QueryService methods to the underlying service
6395
@Override
64-
public org.hibernate.Session openSession() {
96+
public Session openSession() {
6597
return delegate.openSession();
6698
}
6799

@@ -76,7 +108,7 @@ public List query(String hql, Object... params) {
76108
}
77109

78110
@Override
79-
public List query(String hql, org.tus.common.domain.persistence.QueryPostProcessor post, Object... params) {
111+
public List query(String hql, QueryPostProcessor post, Object... params) {
80112
return delegate.query(hql, post, params);
81113
}
82114

@@ -86,7 +118,7 @@ public List query(String hql, Map<String, Object> namedParams) {
86118
}
87119

88120
@Override
89-
public List query(String hql, Map<String, Object> namedParams, org.tus.common.domain.persistence.QueryPostProcessor post) {
121+
public List query(String hql, Map<String, Object> namedParams, QueryPostProcessor post) {
90122
return delegate.query(hql, namedParams, post);
91123
}
92124

@@ -96,13 +128,13 @@ public List pagedQuery(String hql, Map<String, Object> namedParameters, Integer
96128
}
97129

98130
@Override
99-
public List pagedQuery(String hql, Map<String, Object> namedParameters, Integer pageStart, Integer pageSize,
100-
org.tus.common.domain.persistence.QueryPostProcessor post) {
131+
public List pagedQuery(String hql, Map<String, Object> namedParameters, Integer pageStart, Integer pageSize,
132+
QueryPostProcessor post) {
101133
return delegate.pagedQuery(hql, namedParameters, pageStart, pageSize, post);
102134
}
103135

104136
@Override
105-
public <T extends org.tus.common.domain.persistence.SimplePersistedObject> T save(T item) {
137+
public <T extends SimplePersistedObject> T save(T item) {
106138
return delegate.save(item);
107139
}
108140

@@ -127,7 +159,7 @@ public <T> void deleteAll(List<T> objects) {
127159
}
128160

129161
@Override
130-
public <T extends org.tus.common.domain.persistence.SimplePersistedObject> List<T> saveAll(List<T> itemList) {
162+
public <T extends SimplePersistedObject> List<T> saveAll(List<T> itemList) {
131163
return delegate.saveAll(itemList);
132164
}
133165

@@ -137,12 +169,12 @@ public <T> T save(T item) {
137169
}
138170

139171
@Override
140-
public <T extends org.tus.common.domain.persistence.SimplePersistedObject> T delete(T item) {
172+
public <T extends SimplePersistedObject> T delete(T item) {
141173
return delegate.delete(item);
142174
}
143175

144176
@Override
145-
public <T extends org.tus.common.domain.persistence.SimplePersistedObject> List<T> mergeAll(List<T> itemList) {
177+
public <T extends SimplePersistedObject> List<T> mergeAll(List<T> itemList) {
146178
return delegate.mergeAll(itemList);
147179
}
148180

@@ -167,51 +199,49 @@ public int sqlUpdate(String sql, Object... params) {
167199
}
168200

169201
@Override
170-
public <T extends org.tus.common.domain.persistence.UniqueNamedArtifact> T findObjectByName(Class<T> clazz, String name) {
202+
public <T extends UniqueNamedArtifact> T findObjectByName(Class<T> clazz, String name) {
171203
return delegate.findObjectByName(clazz, name);
172204
}
173205

174206
@Override
175-
public <T extends org.tus.common.domain.persistence.SimplePersistedObject> T findSimpleObjectById(Class<T> clazz, String objId, String typeName) {
207+
public <T extends SimplePersistedObject> T findSimpleObjectById(Class<T> clazz, String objId, String typeName) {
176208
return delegate.findSimpleObjectById(clazz, objId, typeName);
177209
}
178210

179211
@Override
180-
public <T extends org.tus.common.domain.persistence.SimplePersistedObject> T findSimpleObjectById(Class<T> clazz, String objId) {
212+
public <T extends SimplePersistedObject> T findSimpleObjectById(Class<T> clazz, String objId) {
181213
return delegate.findSimpleObjectById(clazz, objId);
182214
}
183215

184216
@Override
185-
public <T extends org.tus.common.domain.persistence.UniqueNamedArtifact> T findObjectByName(Class<T> clazz, String name,
186-
org.tus.common.domain.persistence.QueryPostProcessor post) {
217+
public <T extends UniqueNamedArtifact> T findObjectByName(Class<T> clazz, String name,
218+
QueryPostProcessor post) {
187219
return delegate.findObjectByName(clazz, name, post);
188220
}
189221

190222
@Override
191-
public <T extends org.tus.common.domain.persistence.PersistedObject> T findObjectById(Class<T> clazz, String id) {
223+
public <T extends PersistedObject> T findObjectById(Class<T> clazz, String id) {
192224
return delegate.findObjectById(clazz, id);
193225
}
194226

195227
@Override
196-
public <T extends org.tus.common.domain.persistence.PersistedObject> T findObjectById(Class<T> clazz, String id,
197-
org.tus.common.domain.persistence.QueryPostProcessor post) {
228+
public <T extends PersistedObject> T findObjectById(Class<T> clazz, String id, QueryPostProcessor post) {
198229
return delegate.findObjectById(clazz, id, post);
199230
}
200231

201232
@Override
202-
public <T extends org.tus.common.domain.persistence.PersistedObject> T findObjectByIdOrName(Class<T> clazz, String idOrName) {
233+
public <T extends PersistedObject> T findObjectByIdOrName(Class<T> clazz, String idOrName) {
203234
return delegate.findObjectByIdOrName(clazz, idOrName);
204235
}
205236

206237
@Override
207-
public <T extends org.tus.common.domain.persistence.PersistedObject> T findObjectByIdOrName(Class<T> clazz, String idName,
208-
org.tus.common.domain.persistence.QueryPostProcessor post) {
238+
public <T extends PersistedObject> T findObjectByIdOrName(Class<T> clazz, String idName, QueryPostProcessor post) {
209239
return delegate.findObjectByIdOrName(clazz, idName, post);
210240
}
211241

212242
@Override
213-
public <T extends org.tus.common.domain.persistence.PersistedObject> List<T> findObjectsByAndingParams(Class<T> tClass,
214-
Map<String, String> params) {
243+
public <T extends PersistedObject> List<T> findObjectsByAndingParams(Class<T> tClass,
244+
Map<String, String> params) {
215245
return delegate.findObjectsByAndingParams(tClass, params);
216246
}
217247

@@ -236,13 +266,12 @@ public int executeQuery(String hql, Map<String, Object> namedParameters) {
236266
}
237267

238268
@Override
239-
public Object querySingle(String hql, Map<String, Object> namedParameters,
240-
org.tus.common.domain.persistence.QueryPostProcessor post) {
269+
public Object querySingle(String hql, Map<String, Object> namedParameters, QueryPostProcessor post) {
241270
return delegate.querySingle(hql, namedParameters, post);
242271
}
243272

244273
@Override
245-
public <T extends org.tus.common.domain.persistence.NamedArtifact> T findOrSave(String hql, Map<String, Object> namedParameters, T item) {
274+
public <T extends NamedArtifact> T findOrSave(String hql, Map<String, Object> namedParameters, T item) {
246275
return delegate.findOrSave(hql, namedParameters, item);
247276
}
248277
}

0 commit comments

Comments
 (0)