Skip to content

Commit e4b6304

Browse files
committed
Server:调整 SIDE, CROSS JOIN 的实现;完善 OUTER, ANTI, FOREIGN JOIN 的无条件边界情况;重命名错误单词 outter 为 outer
1 parent 25e9400 commit e4b6304

File tree

3 files changed

+109
-89
lines changed

3 files changed

+109
-89
lines changed

APIJSON-Java-Server/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ else if (join != null){
10561056
j.setTargetKey(targetKey);
10571057
j.setKeyAndType(key);
10581058
j.setRequest(getJoinObject(table, tableObj, key));
1059-
j.setOutter((JSONObject) e.getValue());
1059+
j.setOuter((JSONObject) e.getValue());
10601060

10611061
joinList.add(j);
10621062

APIJSON-Java-Server/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java

Lines changed: 103 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ public String getGroupString(boolean hasPrefix) {
422422
continue;
423423
}
424424

425-
cfg = j.isLeftOrRightJoin() ? j.getOutterConfig() : j.getJoinConfig();
425+
cfg = j.isLeftOrRightJoin() ? j.getOuterConfig() : j.getJoinConfig();
426426
if (StringUtil.isEmpty(cfg.getAlias(), true)) {
427427
cfg.setAlias(cfg.getTable());
428428
}
@@ -484,7 +484,7 @@ public String getHavingString(boolean hasPrefix) {
484484
continue;
485485
}
486486

487-
cfg = j.isLeftOrRightJoin() ? j.getOutterConfig() : j.getJoinConfig();
487+
cfg = j.isLeftOrRightJoin() ? j.getOuterConfig() : j.getJoinConfig();
488488
if (StringUtil.isEmpty(cfg.getAlias(), true)) {
489489
cfg.setAlias(cfg.getTable());
490490
}
@@ -594,7 +594,7 @@ public String getOrderString(boolean hasPrefix) {
594594
continue;
595595
}
596596

597-
cfg = j.isLeftOrRightJoin() ? j.getOutterConfig() : j.getJoinConfig();
597+
cfg = j.isLeftOrRightJoin() ? j.getOuterConfig() : j.getJoinConfig();
598598
if (StringUtil.isEmpty(cfg.getAlias(), true)) {
599599
cfg.setAlias(cfg.getTable());
600600
}
@@ -766,7 +766,7 @@ public String getColumnString(boolean inSQLJoin) throws Exception {
766766
continue;
767767
}
768768

769-
ecfg = j.getOutterConfig();
769+
ecfg = j.getOuterConfig();
770770
if (ecfg != null && ecfg.getColumn() != null) { //优先级更高
771771
cfg = ecfg;
772772
}
@@ -1361,94 +1361,108 @@ else if ("!".equals(ce.getKey())) {
13611361
boolean changed = false;
13621362
//各种 JOIN 没办法统一用 & | !连接,只能按优先级,和 @combine 一样?
13631363
for (Join j : joinList) {
1364-
switch (j.getJoinType()) {
1364+
String jt = j.getJoinType();
1365+
1366+
switch (jt) {
1367+
case "*": // CROSS JOIN
13651368
case "@": // APP JOIN
13661369
case "<": // LEFT JOIN
13671370
case ">": // RIGHT JOIN
13681371
break;
13691372

1370-
case "": // FULL JOIN
1371-
case "|": // FULL JOIN 不支持 <>, [] ,避免太多符号
1372-
case "&": // INNER JOIN
1373-
case "!": // OUTTER JOIN
1374-
case "(": // ANTI JOIN
1375-
case ")": // FOREIGN JOIN
1376-
case "^": // SIDE JOIN
1377-
case "*": // CROSS JOIN
1373+
case "&": // INNER JOIN: A & B
1374+
case "": // FULL JOIN: A | B
1375+
case "|": // FULL JOIN: A | B
1376+
case "!": // OUTER JOIN: ! (A | B)
1377+
case "^": // SIDE JOIN: ! (A & B)
1378+
case "(": // ANTI JOIN: A & ! B
1379+
case ")": // FOREIGN JOIN: B & ! A
13781380
jc = j.getJoinConfig();
13791381
boolean isMain = jc.isMain();
13801382
jc.setMain(false).setPrepared(isPrepared()).setPreparedValueList(new ArrayList<Object>());
13811383
js = jc.getWhereString(false);
13821384
jc.setMain(isMain);
13831385

1386+
boolean isOuterJoin = "!".equals(jt);
1387+
boolean isSideJoin = "^".equals(jt);
1388+
boolean isAntiJoin = "(".equals(jt);
1389+
boolean isForeignJoin = ")".equals(jt);
13841390
boolean isWsEmpty = StringUtil.isEmpty(ws, true);
1385-
1391+
1392+
if (isWsEmpty) {
1393+
if (isOuterJoin) { // ! OUTER JOIN: ! (A | B)
1394+
throw new NotExistException("no result for ! OUTER JOIN( ! (A | B) ) when A or B is empty!");
1395+
}
1396+
if (isForeignJoin) { // ) FOREIGN JOIN: B & ! A
1397+
throw new NotExistException("no result for ) FOREIGN JOIN( B & ! A ) when A is empty!");
1398+
}
1399+
}
1400+
13861401
if (StringUtil.isEmpty(js, true)) {
1387-
if (")".equals(j.getJoinType())) { // FOREIGN JOIN: B & ! A
1388-
if (isWsEmpty) {
1389-
throw new NotExistException("no result for ) FOREIGN JOIN(A & ! B) while both A and B are empty!");
1402+
if (isOuterJoin) { // ! OUTER JOIN: ! (A | B)
1403+
throw new NotExistException("no result for ! OUTER JOIN( ! (A | B) ) when A or B is empty!");
1404+
}
1405+
if (isAntiJoin) { // ( ANTI JOIN: A & ! B
1406+
throw new NotExistException("no result for ( ANTI JOIN( A & ! B ) when B is empty!");
1407+
}
1408+
1409+
if (isWsEmpty) {
1410+
if (isSideJoin) {
1411+
throw new NotExistException("no result for ^ SIDE JOIN( ! (A & B) ) when both A and B are empty!");
1412+
}
1413+
}
1414+
else {
1415+
if (isSideJoin || isForeignJoin) {
1416+
newWs += " ( " + getCondition(true, ws) + " ) ";
1417+
1418+
newPvl.addAll(pvl);
1419+
newPvl.addAll(jc.getPreparedValueList());
1420+
changed = true;
13901421
}
1391-
1392-
newWs += " ( " + getCondition(true, ws) + " ) ";
1393-
newPvl.addAll(pvl);
1394-
changed = true;
13951422
}
1423+
13961424
continue;
13971425
}
13981426

13991427
if (StringUtil.isEmpty(newWs, true) == false) {
14001428
newWs += AND;
14011429
}
14021430

1403-
//MySQL 因为 NULL 值处理问题,(A & ! B) | (B & ! A) 与 ! (A & B) 返回结果不一样,后者往往更多
1404-
if ("^".equals(j.getJoinType())) { //SIDE JOIN: (A & ! B) | (B & ! A)
1405-
if (isWsEmpty) {
1406-
newWs += js;
1407-
1408-
newPvl.addAll(pvl);
1409-
newPvl.addAll(jc.getPreparedValueList());
1410-
}
1411-
else {
1412-
newWs += " ( ( " + ws + AND + NOT + " ( " + js + " ) ) "
1413-
+ OR
1414-
+ " ( " + js + AND + NOT + " ( " + ws + " ) ) ) ";
1415-
1416-
newPvl.addAll(pvl);
1417-
newPvl.addAll(jc.getPreparedValueList());
1418-
newPvl.addAll(jc.getPreparedValueList());
1419-
newPvl.addAll(pvl);
1420-
}
1431+
if (isAntiJoin) { // ( ANTI JOIN: A & ! B
1432+
newWs += " ( " + ( isWsEmpty ? "" : ws + AND ) + NOT + " ( " + js + " ) " + " ) ";
14211433
}
1422-
else {
1423-
if ("(".equals(j.getJoinType())) { // ANTI JOIN: A & ! B
1424-
newWs += " ( " + ( isWsEmpty ? "" : ws + AND ) + NOT + " ( " + js + " ) " + " ) ";
1425-
}
1426-
else if (")".equals(j.getJoinType())) { // FOREIGN JOIN: B & ! A
1427-
newWs += " ( " + " ( " + js + " ) " + ( isWsEmpty ? "" : AND + NOT + ws ) + " ) ";
1428-
}
1429-
else { // & INNER JOIN: A & B; | FULL JOIN: A | B; OUTER JOIN: ! (A & B)
1430-
logic = Logic.getType(j.getJoinType());
1431-
newWs += " ( "
1432-
+ getCondition(
1433-
Logic.isNot(logic),
1434-
ws
1435-
+ ( isWsEmpty ? "" : (Logic.isAnd(logic) ? AND : OR) )
1436-
+ " ( " + js + " ) "
1437-
)
1438-
+ " ) ";
1439-
}
1440-
1441-
newPvl.addAll(pvl);
1442-
newPvl.addAll(jc.getPreparedValueList());
1434+
else if (isForeignJoin) { // ) FOREIGN JOIN: B & ! A
1435+
newWs += " ( " + " ( " + js + " ) " + ( isWsEmpty ? "" : AND + NOT + ws ) + " ) ";
1436+
}
1437+
else if (isSideJoin) { // ^ SIDE JOIN: ! (A & B)
1438+
//MySQL 因为 NULL 值处理问题,(A & ! B) | (B & ! A) 与 ! (A & B) 返回结果不一样,后者往往更多
1439+
newWs += " ( " + getCondition(
1440+
true,
1441+
( isWsEmpty ? "" : ws + AND ) + " ( " + js + " ) "
1442+
) + " ) ";
1443+
}
1444+
else { // & INNER JOIN: A & B; | FULL JOIN: A | B; OUTER JOIN: ! (A | B)
1445+
logic = Logic.getType(jt);
1446+
newWs += " ( "
1447+
+ getCondition(
1448+
Logic.isNot(logic),
1449+
ws
1450+
+ ( isWsEmpty ? "" : (Logic.isAnd(logic) ? AND : OR) )
1451+
+ " ( " + js + " ) "
1452+
)
1453+
+ " ) ";
14431454
}
14441455

1456+
newPvl.addAll(pvl);
1457+
newPvl.addAll(jc.getPreparedValueList());
1458+
14451459
changed = true;
14461460
break;
14471461
default:
14481462
throw new UnsupportedOperationException(
1449-
"join:value 中 value 里的 " + j.getJoinType() + "/" + j.getPath()
1450-
+ "错误!不支持 " + j.getJoinType() + " 等 [ @ APP, < LEFT, > RIGHT, | FULL, & INNER, ! OUTTER"
1451-
+ ", ( ANTI, ) FOREIGN, ^ SIDE, * CROSS ] 之外的JOIN类型 !"
1463+
"join:value 中 value 里的 " + jt + "/" + j.getPath()
1464+
+ "错误!不支持 " + jt + " 等 [ @ APP, < LEFT, > RIGHT, * CROSS"
1465+
+ ", & INNER, | FULL, ! OUTER, ^ SIDE, ( ANTI, ) FOREIGN ] 之外的 JOIN 类型 !"
14521466
);
14531467
}
14541468
}
@@ -2307,6 +2321,7 @@ public String getJoinString() throws Exception {
23072321
if (j.isAppJoin()) { // APP JOIN,只是作为一个标记,执行完主表的查询后自动执行副表的查询 User.id IN($commentIdList)
23082322
continue;
23092323
}
2324+
String type = j.getJoinType();
23102325

23112326
//LEFT JOIN sys.apijson_user AS User ON User.id = Moment.userId, 都是用 = ,通过relateType处理缓存
23122327
// <"INNER JOIN User ON User.id = Moment.userId", UserConfig> TODO AS 放 getSQLTable 内
@@ -2322,41 +2337,42 @@ public String getJoinString() throws Exception {
23222337
// tn = tn.toLowerCase();
23232338
// }
23242339

2325-
switch (j.getJoinType()) { //TODO $ SELF JOIN
2326-
// case "@": // APP JOIN
2340+
switch (type) {
2341+
//前面已跳过 case "@": // APP JOIN
23272342
// continue;
23282343

2344+
case "*": // CROSS JOIN
2345+
onGetCrossJoinString(j);
23292346
case "<": // LEFT JOIN
23302347
case ">": // RIGHT JOIN
23312348
jc.setMain(true).setKeyPrefix(false);
2332-
sql = ( ">".equals(j.getJoinType()) ? " RIGHT" : " LEFT") + " JOIN ( " + jc.getSQL(isPrepared()) + " ) AS "
2349+
sql = ( "<".equals(type) ? " LEFT" : (">".equals(type) ? " RIGHT" : " CROSS") )
2350+
+ " JOIN ( " + jc.getSQL(isPrepared()) + " ) AS "
23332351
+ quote + jt + quote + " ON " + quote + jt + quote + "." + quote + j.getKey() + quote + " = "
23342352
+ quote + tn + quote + "." + quote + j.getTargetKey() + quote;
23352353
jc.setMain(false).setKeyPrefix(true);
23362354

2337-
// preparedValueList.addAll(jc.getPreparedValueList());
2338-
23392355
pvl.addAll(jc.getPreparedValueList());
23402356
changed = true;
23412357
break;
23422358

2343-
case "": // FULL JOIN
2344-
case "|": // FULL JOIN 不支持 <>, [] ,避免太多符号
2345-
case "&": // INNER JOIN
2346-
case "!": // OUTTER JOIN
2347-
case "^": // SIDE JOIN
2348-
case "(": // ANTI JOIN
2349-
case ")": // FOREIGN JOIN
2350-
//场景少且性能差,默认禁用 case "*": // CROSS JOIN
2351-
sql = ("*".equals(j.getJoinType()) ? " CROSS JOIN " : " INNER JOIN ") + jc.getTablePath()
2359+
case "&": // INNER JOIN: A & B
2360+
case "": // FULL JOIN: A | B
2361+
case "|": // FULL JOIN: A | B
2362+
case "!": // OUTER JOIN: ! (A | B)
2363+
case "^": // SIDE JOIN: ! (A & B)
2364+
case "(": // ANTI JOIN: A & ! B
2365+
case ")": // FOREIGN JOIN: B & ! A
2366+
sql = " INNER JOIN " + jc.getTablePath()
23522367
+ " ON " + quote + jt + quote + "." + quote + j.getKey() + quote + " = " + quote + tn + quote + "." + quote + j.getTargetKey() + quote;
23532368
break;
23542369
default:
23552370
throw new UnsupportedOperationException(
2356-
"join:value 中 value 里的 " + j.getJoinType() + "/" + j.getPath()
2357-
+ "错误!不支持 " + j.getJoinType() + " 等 [ @ APP, < LEFT, > RIGHT, | FULL, & INNER, ! OUTTER"
2358-
+ ", ( ANTI, ) FOREIGN, ^ SIDE, * CROSS ] 之外的JOIN类型 !"
2359-
); }
2371+
"join:value 中 value 里的 " + jt + "/" + j.getPath()
2372+
+ "错误!不支持 " + jt + " 等 [ @ APP, < LEFT, > RIGHT, * CROSS"
2373+
+ ", & INNER, | FULL, ! OUTER, ^ SIDE, ( ANTI, ) FOREIGN ] 之外的 JOIN 类型 !"
2374+
);
2375+
}
23602376

23612377
joinOns += " \n " + sql;
23622378
}
@@ -2372,6 +2388,10 @@ public String getJoinString() throws Exception {
23722388
return joinOns;
23732389
}
23742390

2391+
protected void onGetCrossJoinString(Join j) throws UnsupportedOperationException {
2392+
throw new UnsupportedOperationException("已禁用 * CROSS JOIN !性能很差、需求极少,如要取消禁用可在后端重写相关方法!");
2393+
}
2394+
23752395
/**新建SQL配置
23762396
* @param table
23772397
* @param request
@@ -2752,9 +2772,9 @@ else if (joinConfig.getDatabase().equals(config.getDatabase()) == false) {
27522772
joinConfig.setMain(false).setKeyPrefix(true);
27532773

27542774
if (j.isLeftOrRightJoin()) {
2755-
SQLConfig outterConfig = newSQLConfig(method, table, alias, j.getOutter(), null, false, callback);
2775+
SQLConfig outterConfig = newSQLConfig(method, table, alias, j.getOuter(), null, false, callback);
27562776
outterConfig.setMain(false).setKeyPrefix(true).setDatabase(joinConfig.getDatabase()).setSchema(joinConfig.getSchema()); //解决主表 JOIN 副表,引号不一致
2757-
j.setOutterConfig(outterConfig);
2777+
j.setOuterConfig(outterConfig);
27582778
}
27592779
}
27602780

APIJSON-Java-Server/APIJSONORM/src/main/java/apijson/orm/Join.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class Join {
2828
private String originKey;
2929
private String originValue;
3030

31-
private String joinType; // "@" - APP, "<" - LEFT, ">" - RIGHT, "&" - INNER, "|" - FULL, "!" - OUTTER, "(" - ANTI, ")" - FOREIGN, "^" - SIDE, "*" - CROSS
31+
private String joinType; // "@" - APP, "<" - LEFT, ">" - RIGHT, "&" - INNER, "|" - FULL, "!" - OUTER, "(" - ANTI, ")" - FOREIGN, "^" - SIDE, "*" - CROSS
3232
private String relateType; // "" - 一对一, "{}" - 一对多, "<>" - 多对一
3333
private JSONObject request; // { "id@":"/Moment/userId" }
3434
private String table; //User
@@ -113,10 +113,10 @@ public void setTargetKey(String targetKey) {
113113
this.targetKey = targetKey;
114114
}
115115

116-
public JSONObject getOutter() {
116+
public JSONObject getOuter() {
117117
return outter;
118118
}
119-
public void setOutter(JSONObject outter) {
119+
public void setOuter(JSONObject outter) {
120120
this.outter = outter;
121121
}
122122

@@ -133,10 +133,10 @@ public void setCacheConfig(SQLConfig cacheConfig) {
133133
this.cacheConfig = cacheConfig;
134134
}
135135

136-
public SQLConfig getOutterConfig() {
136+
public SQLConfig getOuterConfig() {
137137
return outterConfig;
138138
}
139-
public void setOutterConfig(SQLConfig outterConfig) {
139+
public void setOuterConfig(SQLConfig outterConfig) {
140140
this.outterConfig = outterConfig;
141141
}
142142

0 commit comments

Comments
 (0)