Skip to content

Commit

Permalink
Refactor: Update QueryFragment API to use method chaining for better …
Browse files Browse the repository at this point in the history
…readability and consistency
  • Loading branch information
vnobo committed Dec 22, 2024
1 parent c6b2467 commit 6b89b84
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
* <pre>
* {@code
* QueryFragment queryFragment = QueryFragment.withNew()
* .addColumn("id", "name", "email")
* .addQuery("users")
* .addWhere("age > :age", 18)
* .addOrder("name ASC")
* .addOrder("email DESC");
* .columns("id", "name", "email")
* .query("users")
* .where("age > :age", 18)
* .orderBy("name ASC")
* .orderBy("email DESC");
*
* // Bind parameters
* queryFragment.put("age", 18);
Expand All @@ -48,7 +48,7 @@ public class QueryFragment extends HashMap<String, Object> {
* Example usage:
* <pre>
* {@code
* queryFragment.addColumn("id", "name", "email");
* queryFragment.columns("id", "name", "email");
* }
* </pre>
*/
Expand All @@ -59,18 +59,18 @@ public class QueryFragment extends HashMap<String, Object> {
* Example usage:
* <pre>
* {@code
* queryFragment.addQuery("users");
* queryFragment.query("users");
* }
* </pre>
*/
private final StringJoiner select = new StringJoiner(" ");
private final StringJoiner from = new StringJoiner(" ");

/**
* A StringJoiner to accumulate WHERE conditions.
* Example usage:
* <pre>
* {@code
* queryFragment.addWhere("age > :age");
* queryFragment.where("age > :age");
* }
* </pre>
*/
Expand All @@ -81,7 +81,7 @@ public class QueryFragment extends HashMap<String, Object> {
* Example usage:
* <pre>
* {@code
* queryFragment.addOrder("name ASC");
* queryFragment.orderBy("name ASC");
* }
* </pre>
*/
Expand All @@ -92,64 +92,68 @@ public class QueryFragment extends HashMap<String, Object> {
/**
* The maximum number of rows to return (LIMIT clause).
*/
private final int size;
private int size = 25;

/**
* The number of rows to skip before starting to return rows (OFFSET clause).
*/
private final long offset;
private long offset = 0;

public QueryFragment(int size, long offset, QueryFragment params) {
super(16);
this.size = size;
this.offset = offset;
this.mergeWhere(params.getWhere());
this.putAll(params);
public QueryFragment(QueryFragment fragment) {
super(fragment);
this.size = fragment.size;
this.offset = fragment.offset;
this.columns.merge(fragment.getColumns());
this.from.merge(fragment.getFrom());
this.orderBy.merge(fragment.getOrderBy());
this.where.merge(fragment.getWhere());
}

public QueryFragment(int size, long offset, Map<String, Object> params) {
super(16);
this.size = size;
this.offset = offset;
this.putAll(params);
/**
* Creates a new QueryFragment instance with the specified parameters.
*
* @param params the parameters to initialize the QueryFragment with
*/
public QueryFragment(Map<String, Object> params) {
super(params);
}

public static QueryFragment withNew() {
return withMap(Map.of());
}

public static QueryFragment withMap(Map<String, Object> params) {
return new QueryFragment(Integer.MAX_VALUE, 0, params);
return new QueryFragment(params);
}

public static QueryFragment withMap(int size, long offset, Map<String, Object> params) {
return new QueryFragment(size, offset, params);
return withMap(params).limit(size, offset);
}

public static QueryFragment of(QueryFragment params) {
return of(Integer.MAX_VALUE, 0, params);
}

public static QueryFragment of(int size, long offset, QueryFragment params) {
return new QueryFragment(size, offset, params);
return of(params).limit(size, offset);
}

public QueryFragment addColumn(CharSequence... columns) {
public QueryFragment columns(CharSequence... columns) {
for (CharSequence column : columns) {
this.columns.add(column);
}
return this;
}

public QueryFragment addQuery(CharSequence... queries) {
this.select.setEmptyValue("");
public QueryFragment query(CharSequence... queries) {
this.from.setEmptyValue("");
for (CharSequence query : queries) {
this.select.add(query);
this.from.add(query);
}
return this;
}

public QueryFragment addWhere(CharSequence where) {
public QueryFragment where(CharSequence where) {
this.where.add(where);
return this;
}
Expand All @@ -160,40 +164,17 @@ public QueryFragment addWhere(CharSequence where) {
* @param order the order
* @return this
*/
public QueryFragment addOrder(CharSequence order) {
public QueryFragment orderBy(CharSequence order) {
this.orderBy.add(order);
return this;
}

/**
* Merges the given where clause with the existing one.
*
* @param where the where
* @return this
*/
public QueryFragment mergeWhere(StringJoiner where) {
this.where.merge(where);
return this;
}

/**
* Merges the given order clause with the existing one.
*
* @param order the order
* @return this
*/
public QueryFragment mergeOrder(StringJoiner order) {
this.orderBy.merge(order);
public QueryFragment limit(int size, long offset) {
this.size = size;
this.offset = offset;
return this;
}

/**
* Generates the WHERE clause part of a SQL query based on the stored conditions.
* If conditions have been accumulated, it prefixes the conditions with the 'WHERE' keyword;
* otherwise, it returns an empty string to indicate no conditions.
*
* @return A String forming the WHERE clause of the SQL query, or an empty string if no conditions are present.
*/
public String whereSql() {
if (this.where.length() > 0) {
return " WHERE " + this.where;
Expand All @@ -220,9 +201,9 @@ public String orderSql() {
* @throws QueryException if the querySql is null, indicating that the query structure is incomplete.
*/
public String querySql() {
if (this.select.length() > 0) {
if (this.from.length() > 0) {
return String.format("SELECT %s FROM %s %s %s LIMIT %d OFFSET %d",
this.columns, this.select, whereSql(), orderSql(), this.size, this.offset);
this.columns, this.from, whereSql(), orderSql(), this.size, this.offset);
}
throw QueryException.withError("This querySql is null, please use whereSql() method!",
new IllegalArgumentException("This querySql is null, please use whereSql() method"));
Expand All @@ -240,8 +221,8 @@ public String querySql() {
* @throws QueryException if the countSql is null, indicating that the query structure is incomplete.
*/
public String countSql() {
if (this.select.length() > 0) {
return "SELECT COUNT(*) FROM (" + String.format("SELECT %s FROM %s", this.columns, this.select)
if (this.from.length() > 0) {
return "SELECT COUNT(*) FROM (" + String.format("SELECT %s FROM %s", this.columns, this.from)
+ whereSql() + ") t";
}
throw QueryException.withError("This countSql is null, please use whereSql() method!",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ private static void processQueryKey(QueryFragment queryFragment, Map<String, Obj
if (objectMap.containsKey("query")) {
var jsonMap = (Map<String, Object>) objectMap.get("query");
var jsonQueryFragment = QueryJsonHelper.queryJson(jsonMap, prefix);
queryFragment.mergeWhere(jsonQueryFragment.getWhere());
queryFragment.getWhere().merge(jsonQueryFragment.getWhere());
queryFragment.putAll(jsonQueryFragment);
}
}
Expand All @@ -257,7 +257,7 @@ private static void processQueryKey(QueryFragment queryFragment, Map<String, Obj
private static void processSecurityCodeKey(QueryFragment queryFragment, Map<String, Object> objectMap, Collection<String> skipKeys, String prefix) {
if (!skipKeys.contains("securityCode") && objectMap.containsKey("securityCode")) {
var column = StringUtils.hasLength(prefix) ? prefix + ".tenant_code" : "tenant_code";
queryFragment.addWhere(column + " LIKE :securityCode");
queryFragment.where(column + " LIKE :securityCode");
queryFragment.put("securityCode", objectMap.get("securityCode"));
}
}
Expand All @@ -273,9 +273,9 @@ private static void processSearchKey(QueryFragment queryFragment, Map<String, Ob
if (objectMap.containsKey("search") && !ObjectUtils.isEmpty(objectMap.get("search"))) {
var textSearch = (String) objectMap.get("search");
var column = StringUtils.hasLength(prefix) ? prefix + ".text_search" : "text_search";
queryFragment.addColumn("TS_RANK_CD(" + column + ", queryTextSearch) AS rank");
queryFragment.addQuery(",TO_TSQUERY('chinese',:textSearch) queryTextSearch");
queryFragment.addWhere(column + "@@TO_TSQUERY('chinese',:textSearch)");
queryFragment.columns("TS_RANK_CD(" + column + ", queryTextSearch) AS rank");
queryFragment.query(",TO_TSQUERY('chinese',:textSearch) queryTextSearch");
queryFragment.where(column + "@@TO_TSQUERY('chinese',:textSearch)");
queryFragment.put("textSearch", textSearch);
}
}
Expand Down Expand Up @@ -317,7 +317,7 @@ public static void applySort(QueryFragment queryFragment, Sort sort, String pref
if (StringUtils.hasLength(prefix)) {
sortedProperty = prefix + "." + sortedProperty;
}
queryFragment.addOrder(sortedProperty + (order.isAscending() ? " ASC" : " DESC"));
queryFragment.orderBy(sortedProperty + (order.isAscending() ? " ASC" : " DESC"));
}
}

Expand All @@ -330,7 +330,7 @@ public static void applySort(QueryFragment queryFragment, Sort sort, String pref
public static void applyWhere(QueryFragment queryFragment, String prefix) {
for (Map.Entry<String, Object> entry : queryFragment.entrySet()) {
String conditionSql = buildConditionSql(entry, prefix);
queryFragment.addWhere(conditionSql);
queryFragment.where(conditionSql);
}
}

Expand All @@ -352,8 +352,8 @@ public static void applyQuerySql(QueryFragment queryFragment, Object object) {
}

String tableName = StringUtils.hasLength(table.value()) ? table.value() : objectClass.getName();
queryFragment.addColumn("*");
queryFragment.addQuery(tableName);
queryFragment.columns("*");
queryFragment.query(tableName);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public static QueryFragment queryJson(Map<String, Object> params, String prefix)
QueryFragment queryFragment = QueryFragment.withNew();
for (Map.Entry<String, Object> entry : params.entrySet()) {
var condition = buildJsonCondition(entry, prefix);
queryFragment.mergeWhere(condition.getWhere());
queryFragment.getWhere().merge(condition.getWhere());
queryFragment.putAll(condition);
}
return queryFragment;
Expand Down Expand Up @@ -232,7 +232,7 @@ private static QueryFragment buildJsonCondition(Map.Entry<String, Object> entry,
//处理最后键
QueryFragment lastCondition = buildLastCondition(keys, entry.getValue());
conditionBuilder.append(lastCondition.getWhere());
return QueryFragment.withMap(lastCondition).addWhere(conditionBuilder.toString());
return QueryFragment.withMap(lastCondition).where(conditionBuilder.toString());
}

/**
Expand Down Expand Up @@ -260,7 +260,7 @@ private static QueryFragment buildLastCondition(String[] keys, Object value) {
Map.Entry<String, String> exps = queryKeywordMapper(lastKey);
if (exps == null) {
conditionSql.append(lastKey).append("' = :").append(paramName);
return QueryFragment.withMap(Map.of(paramName, value)).addWhere(conditionSql.toString());
return QueryFragment.withMap(Map.of(paramName, value)).where(conditionSql.toString());
}

String key = lastKey.substring(0, lastKey.length() - exps.getKey().length());
Expand All @@ -280,7 +280,7 @@ private static QueryFragment buildLastCondition(String[] keys, Object value) {
conditionSql.append(exps.getValue()).append(" :").append(paramName);
params = Map.of(paramName, value);
}
return QueryFragment.withMap(params).addWhere(conditionSql.toString());
return QueryFragment.withMap(params).where(conditionSql.toString());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,24 +64,24 @@ public class SecurityManager extends AbstractDatabase
implements ReactiveUserDetailsService, ReactiveUserDetailsPasswordService {

private final static QueryFragment QUERY_GROUP_MEMBERS_FRAGMENT = QueryFragment.withNew()
.addColumn("a.*", "b.name", "b.extend")
.addQuery("se_group_members a", "join se_groups b on a.group_code=b.code")
.addWhere("a.user_code like :userCode");
.columns("a.*", "b.name", "b.extend")
.query("se_group_members a", "join se_groups b on a.group_code=b.code")
.where("a.user_code like :userCode");
private final static QueryFragment QUERY_TENANT_MEMBERS_FRAGMENT = QueryFragment.withNew()
.addColumn("a.*", "b.name", "b.extend")
.addQuery("se_tenant_members a", "join se_tenants b on a.tenant_code=b.code")
.addWhere("a.user_code like :userCode");
.columns("a.*", "b.name", "b.extend")
.query("se_tenant_members a", "join se_tenants b on a.tenant_code=b.code")
.where("a.user_code like :userCode");
private final static QueryFragment QUERY_USER_AUTHORITY_FRAGMENT = QueryFragment.withNew()
.addColumn("*")
.addQuery("se_authorities")
.addWhere("user_code = :userCode");
.columns("*")
.query("se_authorities")
.where("user_code = :userCode");
private final static QueryFragment QUERY_GROUP_AUTHORITY_FRAGMENT = QueryFragment.withNew()
.addColumn("ga.*")
.addQuery("se_group_authorities ga",
.columns("ga.*")
.query("se_group_authorities ga",
"join se_group_members gm on ga.group_code = gm.group_code",
"join se_users su on gm.user_code = su.code",
"join se_groups sg on gm.group_code = sg.code and sg.tenant_code = su.tenant_code")
.addWhere("gm.user_code = :userCode");
.where("gm.user_code = :userCode");

/**
* Represents the service layer for handling user-related operations.
Expand Down Expand Up @@ -133,8 +133,8 @@ public Mono<User> registerOrModifyUser(UserRequest request) {
* @return A Mono emitting the User if found, or an empty Mono if no user matches the given OAuth2 binding data.
*/
public Mono<User> loadByOauth2(String bindType, String openid) {
QueryFragment queryFragment = QueryFragment.withNew().addColumn("*").addQuery("se_users")
.addWhere("extend->'oauth2'->:bindType->>'openid'::varchar = :openid");
QueryFragment queryFragment = QueryFragment.withNew().columns("*").query("se_users")
.where("extend->'oauth2'->:bindType->>'openid'::varchar = :openid");
queryFragment.put("bindType", bindType);
queryFragment.put("openid", openid);
var userMono = this.databaseClient.sql(queryFragment::querySql).bindValues(queryFragment)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ public Criteria toCriteria() {
public QueryFragment toParamSql() {
QueryFragment queryFragment = QueryHelper.query(this, List.of("users", "username"), "a");
if (!ObjectUtils.isEmpty(this.getUsers())) {
queryFragment.addWhere("a.user_code in :users");
queryFragment.where("a.user_code in :users");
queryFragment.put("users", this.getUsers());
}

if (StringUtils.hasLength(this.getUsername())) {
queryFragment.addWhere("c.username = :username");
queryFragment.where("c.username = :username");
queryFragment.put("username", this.getUsername());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ public QueryFragment toParamSql() {
QueryFragment fragment = QueryHelper.query(this, List.of("users", "securityCode", "username"), "a");

if (!ObjectUtils.isEmpty(this.getUsers())) {
fragment.addWhere("a.user_code in (:users)");
fragment.where("a.user_code in (:users)");
fragment.put("users", StringUtils.collectionToCommaDelimitedString(this.getUsers()));
}

if (StringUtils.hasLength(this.getSecurityCode())) {
fragment.addWhere("a.tenant_code like :securityCode");
fragment.where("a.tenant_code like :securityCode");
fragment.put("securityCode", this.getSecurityCode());
}

if (StringUtils.hasLength(this.getUsername())) {
fragment.addWhere("c.username = :username");
fragment.where("c.username = :username");
fragment.put("username", this.getUsername());
}

Expand Down
Loading

0 comments on commit 6b89b84

Please sign in to comment.