feat: sql parser 추가

dev
Jonguk. Lim 2 years ago
parent 31aae6f084
commit 85215cedf5

@ -169,8 +169,12 @@ dependencies {
runtimeOnly 'com.h2database:h2:1.4.199' // 2.0.202 runtimeOnly 'com.h2database:h2:1.4.199' // 2.0.202
implementation 'org.postgresql:postgresql:42.3.1' implementation 'org.postgresql:postgresql:42.3.1'
// https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils
implementation group: 'commons-beanutils', name: 'commons-beanutils', version: '1.9.4' //-----------------------------------------------------------------------------------//
// sql parser lib
//-----------------------------------------------------------------------------------//
implementation 'dom4j:dom4j:1.6.1'
implementation 'jaxen:jaxen:1.2.0'
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//

@ -12,6 +12,7 @@ import com.xit.core.constant.ErrorCode;
import com.xit.core.exception.CustomBaseException; import com.xit.core.exception.CustomBaseException;
import com.xit.core.oauth2.utils.HeaderUtil; import com.xit.core.oauth2.utils.HeaderUtil;
import com.xit.core.support.jpa.JpaUtil; import com.xit.core.support.jpa.JpaUtil;
import com.xit.core.support.sql.parser.QueryGenerator;
import com.xit.core.util.Checks; import com.xit.core.util.Checks;
import com.xit.core.util.CommUtil; import com.xit.core.util.CommUtil;
import com.xit.core.util.DBUtils; import com.xit.core.util.DBUtils;
@ -24,6 +25,7 @@ import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
import org.dom4j.DocumentException;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.data.domain.Example; import org.springframework.data.domain.Example;
@ -50,9 +52,17 @@ public class BoardService implements IBoardService {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<BoardDto> findAll(final BoardDto dto, Pageable pageable) { public List<BoardDto> findAll(final BoardDto dto, Pageable pageable) {
String sql = DBUtils.getXmlSql("sql/board2-mapper", "selectBoardList"); //String sql = DBUtils.getXmlSql("sql/board2-mapper", "selectBoardList");
//String sql = DBUtils.getMybatisSql(sqlSessionTemplate, "board.selectBoardList", dto); //String sql = DBUtils.getMybatisSql(sqlSessionTemplate, "board.selectBoardList", dto);
String sql = QueryGenerator.createNamedQuery("board", "selectBoardList")
.setParameter("ciTitle", dto.getCiTitle())
.setParameter("ciName", dto.getCiName())
.setParameter("ciContents", dto.getCiContents())
.getQueryString();
System.out.println(sql);
MpowerUtils sendXml = new MpowerUtils(); MpowerUtils sendXml = new MpowerUtils();
sendXml.setFeilds("ciCode, ciName, ciContentno, ciTitle, ciContents, ciNalja, ciStep, ciRevel, ciRef, ciHit, ciPass, ciId"); sendXml.setFeilds("ciCode, ciName, ciContentno, ciTitle, ciContents, ciNalja, ciStep, ciRevel, ciRef, ciHit, ciPass, ciId");
sendXml.setQuery(sql); sendXml.setQuery(sql);

@ -1,6 +1,7 @@
package com.xit.core.oauth2.api.dao; package com.xit.core.oauth2.api.dao;
import com.xit.core.oauth2.api.entity.RefreshToken; import com.xit.core.oauth2.api.entity.RefreshToken;
import com.xit.core.support.sql.parser.QueryGenerator;
import com.xit.core.util.DBUtils; import com.xit.core.util.DBUtils;
import com.xit.core.util.mpower.MpowerUtils; import com.xit.core.util.mpower.MpowerUtils;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@ -13,8 +14,11 @@ public class RefreshTokenDao {
private static final String sqlXmlFile = "sql/refreshToken-mapper"; private static final String sqlXmlFile = "sql/refreshToken-mapper";
public Optional<RefreshToken> findByKey(String key){ public Optional<RefreshToken> findByKey(String key){
String sql = DBUtils.getXmlSql(sqlXmlFile, "selectRefreshToken"); String sql = QueryGenerator.createNamedQuery("refreshToken", "selectRefreshToken")
sql = sql.replaceFirst(":userId", key); .setParameter("key", key)
.getQueryString();
//String sql = DBUtils.getXmlSql(sqlXmlFile, "selectRefreshToken");
//sql = sql.replaceFirst(":userId", key);
MpowerUtils sendXml = new MpowerUtils(); MpowerUtils sendXml = new MpowerUtils();
sendXml.setFeilds("key, value"); sendXml.setFeilds("key, value");
@ -23,9 +27,15 @@ public class RefreshTokenDao {
} }
public void save(RefreshToken refreshToken){ public void save(RefreshToken refreshToken){
String sql = DBUtils.getXmlSql(sqlXmlFile, "saveRefreshToken"); // String sql = DBUtils.getXmlSql(sqlXmlFile, "saveRefreshToken");
sql = sql.replaceFirst(":userId", refreshToken.getKey()); // sql = sql.replaceFirst(":userId", refreshToken.getKey());
sql = sql.replaceFirst(":tokenValue", refreshToken.getValue()); // sql = sql.replaceFirst(":tokenValue", refreshToken.getValue());
String sql = QueryGenerator.createNamedQuery("refreshToken", "insertRefreshToken")
.setParameter("key", refreshToken.getKey())
.setParameter("value", refreshToken.getValue())
.getQueryString();
MpowerUtils sendXml = new MpowerUtils(); MpowerUtils sendXml = new MpowerUtils();
//sendXml.setFeilds("key, value"); //sendXml.setFeilds("key, value");
@ -34,9 +44,15 @@ public class RefreshTokenDao {
} }
public void update(RefreshToken refreshToken){ public void update(RefreshToken refreshToken){
String sql = DBUtils.getXmlSql(sqlXmlFile, "updateRefreshToken"); // String sql = DBUtils.getXmlSql(sqlXmlFile, "updateRefreshToken");
sql = sql.replaceFirst(":userId", refreshToken.getKey()); // sql = sql.replaceFirst(":userId", refreshToken.getKey());
sql = sql.replaceFirst(":tokenValue", refreshToken.getValue()); // sql = sql.replaceFirst(":tokenValue", refreshToken.getValue());
String sql = QueryGenerator.createNamedQuery("refreshToken", "updateRefreshToken")
.setParameter("value", refreshToken.getValue())
.setParameter("key", refreshToken.getKey())
.getQueryString();
MpowerUtils sendXml = new MpowerUtils(); MpowerUtils sendXml = new MpowerUtils();
//sendXml.setFeilds("key, value"); //sendXml.setFeilds("key, value");

@ -0,0 +1,112 @@
package com.xit.core.support.sql.parser;
import com.xit.core.support.sql.parser.sqlQuery.BasicSqlQuery;
import com.xit.core.support.sql.parser.sqlQuery.EmptySqlQuery;
import com.xit.core.support.sql.parser.sqlQuery.SqlQuery;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* lib use
* implementation 'dom4j:dom4j:1.6.1'
* implementation 'jaxen:jaxen:1.2.0'
*/
public class QueryGenerator {
private static volatile Map<String, Element> classNameRootElementMap;
private static final String ROOT_PATH = System.getProperty("user.dir");
private QueryGenerator() {
}
public static SqlQuery createNamedQuery(String className, String queryName) {
Element rootElement = getElementFromMapping(className);
if (rootElement == null || rootElement.isTextOnly()) {
return new EmptySqlQuery();
}
Element element = findElementWithQueryName(queryName, rootElement);
return element == null ? new EmptySqlQuery() : new BasicSqlQuery(element);
}
private static void initializeConfig() {
synchronized (QueryGenerator.class) {
if (classNameRootElementMap == null) {
classNameRootElementMap = new HashMap<>();
File confFile = new File(ROOT_PATH + "/src/main/resources/sqlMapping.xml");
SAXReader saxReader = new SAXReader();
Document document = null;
try {
document = saxReader.read(confFile);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
Element rootElement = document.getRootElement();
Iterator iterator = rootElement.elementIterator();
while (iterator.hasNext()) {
Element element = (Element) iterator.next();
String tagName = element.getName();
String path = ROOT_PATH + element.attributeValue("path");
if (tagName.equals("file-location") || tagName.equals("directory-location")) {
loadMappingFile(new File(path));
} else {
throw new RuntimeException("Invalid tag name, could only be 'file-location' or 'directory-location'");
}
}
}
}
}
private static void loadMappingFile(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File mappingFile : files) {
loadMappingFile(mappingFile);
}
}
return;
}
SAXReader saxReader = new SAXReader();
Document document = null;
try {
document = saxReader.read(file);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
Element rootElement = document.getRootElement();
String nameSpace = rootElement.attributeValue("namespace");
if (nameSpace == null || nameSpace.isEmpty()) {
throw new RuntimeException("namespace for config file " + file.getName() + " cannot be empty");
}
classNameRootElementMap.put(nameSpace, rootElement);
}
private static Element getElementFromMapping(String className) {
if (classNameRootElementMap == null) {
initializeConfig();
}
return classNameRootElementMap.get(className);
}
private static Element findElementWithQueryName(String queryName, Element rootElement) {
Iterator iterator = rootElement.elementIterator();
while (iterator.hasNext()) {
Element element = (Element) iterator.next();
if (element.getName().equals("named-native-query")) {
String name = element.attributeValue("name");
if (name != null && name.trim().equals(queryName.trim())) {
return element;
}
}
}
return null;
}
}

@ -0,0 +1,94 @@
package com.xit.core.support.sql.parser.parameter;
import com.xit.core.support.sql.parser.parameter.exceptions.IllegalParameterIndexException;
import com.xit.core.support.sql.parser.parameter.exceptions.NoParameterFoundForMarkException;
class ParameterList {
private int curIndex;
ParamNode dummyHead;
ParamNode dummayTail;
private int numOfNodes;
ParameterList(){
this.curIndex = 1;
this.dummyHead = new ParamNode(0, null);
this.dummayTail = new ParamNode(Integer.MAX_VALUE, null);
this.dummyHead.next = this.dummayTail;
this.dummayTail.prev = this.dummyHead;
}
public void put(int position, String value){
if (position <= 0 || position == Integer.MAX_VALUE) {
throw new IllegalParameterIndexException();
}
ParamNode cur = dummyHead;
while (cur.index < position) {
cur = cur.next;
}
if (cur.index == position) {
cur.value = value;
} else {
ParamNode newNode = new ParamNode(position, value);
newNode.prev = cur.prev;
newNode.next = cur;
cur.prev.next = newNode;
cur.prev = newNode;
}
numOfNodes++;
}
public String peek() {
if (isEmpty()) {
return null;
}
return dummyHead.next.index == curIndex ? dummyHead.next.value : null;
}
public String poll() {
if (isEmpty()) {
throw new NoParameterFoundForMarkException(curIndex);
}
if (dummyHead.next.index == curIndex) {
String value = dummyHead.next.value;
remove(dummyHead.next);
curIndex++;
return value;
} else {
throw new NoParameterFoundForMarkException(curIndex);
}
}
private void remove(ParamNode paramNode) {
ParamNode prev = paramNode.prev;
ParamNode next = paramNode.next;
prev.next = next;
next.prev = prev;
this.numOfNodes--;
}
public boolean isEmpty() {
return numOfNodes == 0;
}
static class ParamNode{
int index;
String value;
ParamNode next;
ParamNode prev;
ParamNode(int index, String value){
this.index = index;
this.value = value;
}
}
}

@ -0,0 +1,39 @@
package com.xit.core.support.sql.parser.parameter;
import java.util.HashMap;
import java.util.Map;
public class ParameterMap {
private Map<String, String> map;
private ParameterList parameterList;
public ParameterMap(){
this.map = new HashMap<>();
this.parameterList = new ParameterList();
}
public void put(int index, String value){
this.parameterList.put(index, value);
}
public void put(String key, String value) {
this.map.put(key, value);
}
public String get(String key) {
return map.get(key);
}
public boolean containsKey(String key) {
return map.containsKey(key);
}
public String poll() {
return parameterList.poll();
}
public String peek() {
return parameterList.peek();
}
}

@ -0,0 +1,9 @@
package com.xit.core.support.sql.parser.parameter.exceptions;
public class IllegalParameterIndexException extends RuntimeException {
@Override
public String getMessage() {
return "The Index for the parameter should range from 1 to " + Integer.MAX_VALUE;
}
}

@ -0,0 +1,15 @@
package com.xit.core.support.sql.parser.parameter.exceptions;
public class NoMarkValueFoundException extends RuntimeException {
String key;
public NoMarkValueFoundException(String key) {
this.key = key;
}
@Override
public String getMessage(){
return "No value found for key " + key;
}
}

@ -0,0 +1,15 @@
package com.xit.core.support.sql.parser.parameter.exceptions;
public class NoParameterFoundForMarkException extends RuntimeException {
private int index;
public NoParameterFoundForMarkException(int index) {
this.index = index;
}
@Override
public String getMessage() {
return "No parameter set for the '?' mark on index " + index;
}
}

@ -0,0 +1,121 @@
package com.xit.core.support.sql.parser.sqlNodes;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import com.xit.core.support.sql.parser.parameter.exceptions.NoMarkValueFoundException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.XPath;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class AbstractSqlNode implements SqlNode {
/**
* Regular expression to find the marks which are used to set the parameters
* There are three types of marks: #{value}, (:List), ?
*/
public static final String REGEXPS = "#\\{[^}]*}|\\(:[^)]*\\)|\\?";
protected Element element;
protected ParameterMap parameterMap;
public AbstractSqlNode(Element element, ParameterMap parameterMap) {
this.element = element;
this.parameterMap = parameterMap;
}
@Override
public String parseText(String text) {
text = preProcessText(text);
Pattern pattern = Pattern.compile(REGEXPS);
Matcher matcher = pattern.matcher(text);
StringBuffer stringBuffer = new StringBuffer();
while (matcher.find()) {
String key = getKeyFromMatchedPattern(matcher.group());
if (key == null) {
matcher.appendReplacement(stringBuffer, "");
} else {
if (key.equals("?")) {
matcher.appendReplacement(stringBuffer, parameterMap.poll());
} else {
if (!parameterMap.containsKey(key)) {
throw new NoMarkValueFoundException(key);
}
matcher.appendReplacement(stringBuffer, parameterMap.get(key));
}
}
}
matcher.appendTail(stringBuffer);
return stringBuffer.toString();
}
private List<Node> filterEmptyNodeList(List<Node>nodes) {
List<Node>nodeList = new LinkedList<>();
if (nodes == null) {
return nodeList;
}
for (Node node : nodes) {
if (node.getName() != null) {
nodeList.add(node);
} else {
String text = node.getText();
if (text == null) {
continue;
}
text = text.replaceAll(System.lineSeparator(), "");
if (!text.trim().isEmpty()) {
nodeList.add(node);
}
}
}
return nodeList;
}
@Override
public String getFullText() {
if (element.isTextOnly()) {
return parseText(element.getText());
}
StringBuilder stringBuilder = new StringBuilder();
XPath xPath = DocumentHelper.createXPath("./node()");
List<Node> nodeList = filterEmptyNodeList(xPath.selectNodes(element));
for (Node node : nodeList) {
if (node.getName() != null) {
SqlNode sqlNode = SimpleSqlNodeFactory.getSqlNode((Element)node, parameterMap);
if (sqlNode.display()) {
stringBuilder.append(System.lineSeparator()).append(sqlNode.getFullText());
}
} else {
stringBuilder.append(parseText(node.getText()));
}
}
return stringBuilder.toString();
}
private String preProcessText(String text) {
text.replaceAll(System.lineSeparator(), " ");
text = text.trim();
return text + " ";
}
private String getKeyFromMatchedPattern(String matchedPattern) {
if (matchedPattern == null || matchedPattern.isEmpty()) {
return null;
}
switch (matchedPattern.charAt(0)) {
case '#':
case '(': {
return matchedPattern.substring(2, matchedPattern.length() - 1);
}
case '?': {
return "?";
}
}
return null;
}
}

@ -0,0 +1,16 @@
package com.xit.core.support.sql.parser.sqlNodes;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import org.dom4j.Element;
public class BasicSqlNode extends AbstractSqlNode {
public BasicSqlNode(Element element, ParameterMap parameterMap) {
super(element, parameterMap);
}
@Override
public boolean display() {
return true;
}
}

@ -0,0 +1,18 @@
package com.xit.core.support.sql.parser.sqlNodes;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import com.xit.core.support.sql.parser.sqlNodes.expression.ExpressionUtils;
import org.dom4j.Element;
public class CaseSqlNode extends AbstractSqlNode {
public CaseSqlNode(Element element, ParameterMap parameterMap) {
super(element, parameterMap);
}
@Override
public boolean display() {
return ExpressionUtils.isTrueExpression(this.element.attributeValue("text"), parameterMap);
}
}

@ -0,0 +1,21 @@
package com.xit.core.support.sql.parser.sqlNodes;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import com.xit.core.support.sql.parser.sqlNodes.expression.ExpressionUtils;
import org.dom4j.Element;
public class IfSqlNode extends AbstractSqlNode {
public IfSqlNode(Element element, ParameterMap parameterMap) {
super(element, parameterMap);
}
@Override
public boolean display() {
String expression = element.attributeValue("text");
if (expression == null || expression.trim().isEmpty()) {
return false;
}
return ExpressionUtils.isTrueExpression(this.element.attributeValue("text"), parameterMap);
}
}

@ -0,0 +1,8 @@
package com.xit.core.support.sql.parser.sqlNodes;
public class InvalidTagNameException extends RuntimeException {
public InvalidTagNameException(String message) {
super(message);
}
}

@ -0,0 +1,16 @@
package com.xit.core.support.sql.parser.sqlNodes;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import org.dom4j.Element;
public class OtherwiseSqlNode extends AbstractSqlNode {
public OtherwiseSqlNode(Element element, ParameterMap parameterMap) {
super(element, parameterMap);
}
@Override
public boolean display() {
return true;
}
}

@ -0,0 +1,37 @@
package com.xit.core.support.sql.parser.sqlNodes;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import org.dom4j.Element;
public class SimpleSqlNodeFactory {
public static SqlNode getSqlNode(Element element, ParameterMap parameterMap) {
if (element == null) {
return null;
}
SqlNode result;
switch (element.getName().toLowerCase()) {
case "if":
result = new IfSqlNode(element, parameterMap);
break;
case "switch":
result = new SwitchSqlNode(element, parameterMap);
break;
case "case":
result = new CaseSqlNode(element, parameterMap);
break;
case "where":
result = new WhereSqlNode(element, parameterMap);
break;
case "otherwise":
result = new OtherwiseSqlNode(element, parameterMap);
break;
case "named-native-query":
result = new BasicSqlNode(element, parameterMap);
break;
default:
throw new InvalidTagNameException("Invalid tag name: " + element.getName());
}
return result;
}
}

@ -0,0 +1,14 @@
package com.xit.core.support.sql.parser.sqlNodes;
/**
* Basic interface for each tag in xml
*/
public interface SqlNode {
String parseText(String text);
String getFullText();
boolean display();
}

@ -0,0 +1,38 @@
package com.xit.core.support.sql.parser.sqlNodes;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import org.dom4j.Element;
import java.util.Iterator;
public class SwitchSqlNode extends AbstractSqlNode {
public SwitchSqlNode(Element element, ParameterMap parameterMap) {
super(element, parameterMap);
}
@Override
public String getFullText() {
StringBuilder stringBuilder = new StringBuilder();
if (element.isTextOnly()) {
return stringBuilder.toString();
}
Iterator iterator = element.elementIterator();
while (iterator.hasNext()) {
SqlNode sqlNode = SimpleSqlNodeFactory.getSqlNode((Element) iterator.next(), parameterMap);
if (!(sqlNode instanceof CaseSqlNode) && !(sqlNode instanceof OtherwiseSqlNode)) {
throw new RuntimeException("Invalid xml tag inside switch tag, must be 'case' or 'otherwise'");
}
if (sqlNode.display()) {
stringBuilder.append(sqlNode.getFullText()).append(System.lineSeparator());
break;
}
}
return stringBuilder.toString();
}
@Override
public boolean display() {
return true;
}
}

@ -0,0 +1,55 @@
package com.xit.core.support.sql.parser.sqlNodes;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import org.dom4j.Element;
import java.util.Iterator;
public class WhereSqlNode extends AbstractSqlNode {
public WhereSqlNode(Element element, ParameterMap parameterMap) {
super(element, parameterMap);
}
@Override
public String getFullText() {
StringBuilder stringBuilder = new StringBuilder();
if (element.isTextOnly()) {
return stringBuilder.toString();
}
Iterator iterator = element.elementIterator();
boolean firstMatch = true;
while(iterator.hasNext()) {
SqlNode sqlNode = SimpleSqlNodeFactory.getSqlNode((Element)iterator.next(), parameterMap);
if (!(sqlNode instanceof IfSqlNode)) {
throw new RuntimeException("Invalid xml tag inside where tag, must be 'if'");
}
if (sqlNode.display()) {
String childText = sqlNode.getFullText();
if (childText == null || childText.isEmpty()) {
continue;
}
childText = childText.trim();
if (firstMatch) {
stringBuilder.append("WHERE ");
if (childText.toLowerCase().startsWith("and")) {
childText = childText.substring(3);
}
firstMatch = false;
} else {
if (!childText.toLowerCase().startsWith("and")) {
childText = "AND" + childText;
}
}
stringBuilder.append(childText).append(System.lineSeparator());
}
}
return stringBuilder.toString();
}
@Override
public boolean display() {
return true;
}
}

@ -0,0 +1,135 @@
package com.xit.core.support.sql.parser.sqlNodes.expression;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import com.xit.core.support.sql.parser.parameter.exceptions.NoMarkValueFoundException;
import java.util.regex.Pattern;
public class ExpressionUtils {
private static final String AND_KEYWORDS = " +AND +| +and +";
private static final String OR_KEYWORDS = " +OR +| +or +";
private ExpressionUtils() {}
public static boolean isTrueExpression(String expression, ParameterMap parameterMap) {
checkIfExpressionIsValid(expression);
if (isAndExpression(expression)) {
return isTrueAndExpression(expression, parameterMap);
}
if (isOrExpression(expression)) {
return isTrueOrExpression(expression, parameterMap);
}
return isTrueSingleExpression(expression, parameterMap);
}
private static boolean isTrueAndExpression(String expression, ParameterMap parameterMap) {
String[]statements = expression.split(AND_KEYWORDS);
for (String singleStatement : statements) {
if (!isTrueSingleExpression(singleStatement, parameterMap)) {
return false;
}
}
return true;
}
private static boolean isTrueOrExpression(String expression, ParameterMap parameterMap) {
String[]statements = expression.split(AND_KEYWORDS);
for (String singleStatement : statements) {
if (isTrueSingleExpression(singleStatement, parameterMap)) {
return true;
}
}
return false;
}
/**
* Support statement author != null, author == null, author == 'yize', author != 'yize'
*
* @param expression
* @param parameterMap
* @return
*/
private static boolean isTrueSingleExpression(String expression, ParameterMap parameterMap) {
expression = expression.trim();
for (Operator operator : Operator.values()) {
if (expression.contains(operator.toString())) {
String[]words = expression.split(operator.toString());
if (words.length != 2) {
throw new InvalidExpressionException("Invalid expression " + expression);
}
String leftVal = words[0].trim();
String rightVal = words[1].trim();
String value = parameterMap.get(leftVal);
switch (operator) {
case EQUAL: {
if (rightVal.toLowerCase().equals("null")) {
return value == null;
} else {
if (!parameterMap.containsKey(leftVal)) {
throw new NoMarkValueFoundException(leftVal);
}
return rightVal.equals(value);
}
}
case NOT_EQUAL: {
if (rightVal.toLowerCase().equals("null")) {
return value != null;
} else {
if (!parameterMap.containsKey(leftVal)) {
throw new NoMarkValueFoundException(leftVal);
}
return !rightVal.equals(value);
}
}
case LARGE: {
if (!parameterMap.containsKey(leftVal)) {
throw new NoMarkValueFoundException(leftVal);
}
return Integer.parseInt(value) > Integer.parseInt(rightVal);
}
case LARGE_EQUAL: {
if (!parameterMap.containsKey(leftVal)) {
throw new NoMarkValueFoundException(leftVal);
}
return Integer.parseInt(value) >= Integer.parseInt(rightVal);
}
case LESS: {
if (!parameterMap.containsKey(leftVal)) {
throw new NoMarkValueFoundException(leftVal);
}
return Integer.parseInt(value) < Integer.parseInt(rightVal);
}
case LESS_EQUAL: {
if (!parameterMap.containsKey(leftVal)) {
throw new NoMarkValueFoundException(leftVal);
}
return Integer.parseInt(value) <= Integer.parseInt(rightVal);
}
default:
return false;
}
}
}
return false;
}
private static void checkIfExpressionIsValid(String expression) {
if (expression == null || expression.isEmpty()) {
throw new InvalidExpressionException("Expression is empty");
}
if (isAndExpression(expression) && isOrExpression(expression)) {
throw new InvalidExpressionException("Expression doesn't support the combination of both 'AND' and 'OR' condition");
}
}
private static boolean isAndExpression(String expression) {
return Pattern.compile(AND_KEYWORDS).matcher(expression).find();
}
private static boolean isOrExpression(String expression) {
return Pattern.compile(OR_KEYWORDS).matcher(expression).find();
}
}

@ -0,0 +1,8 @@
package com.xit.core.support.sql.parser.sqlNodes.expression;
public class InvalidExpressionException extends RuntimeException {
public InvalidExpressionException(String errorMsg) {
super(errorMsg);
}
}

@ -0,0 +1,17 @@
package com.xit.core.support.sql.parser.sqlNodes.expression;
public enum Operator {
EQUAL("=="), NOT_EQUAL("!="), LARGE_EQUAL(">="), LESS_EQUAL("<="), LESS("<"), LARGE(">");
private String operator;
Operator(String operator) {
this.operator = operator;
}
@Override
public String toString() {
return this.operator;
}
}

@ -0,0 +1,114 @@
package com.xit.core.support.sql.parser.sqlQuery;
import com.xit.core.support.sql.parser.parameter.ParameterMap;
import com.xit.core.support.sql.parser.sqlNodes.SimpleSqlNodeFactory;
import com.xit.core.support.sql.parser.sqlNodes.SqlNode;
import org.dom4j.Element;
import java.util.List;
import java.util.StringJoiner;
public class BasicSqlQuery implements SqlQuery {
private Element element;
private ParameterMap parameterMap;
public BasicSqlQuery(Element element) {
this.element = element;
this.parameterMap = new ParameterMap();
}
@Override
public SqlQuery setParameter(int pos, String value){
this.parameterMap.put(pos, prevProcessValue(value));
return this;
}
@Override
public SqlQuery setParameter(int pos, int value) {
this.parameterMap.put(pos, String.valueOf(value));
return this;
}
@Override
public SqlQuery setParameter(int pos, boolean value) {
if (value) {
return setParameter(pos, 1);
}
return setParameter(pos, 0);
}
@Override
public SqlQuery setParameter(int pos, List<String> list) {
if (list == null) {
String nullStr = null;
return this.setParameter(pos, nullStr);
}
StringJoiner stringJoiner = new StringJoiner(",", "(", ")");
for (String value : list) {
stringJoiner.add(prevProcessValue(value));
}
parameterMap.put(pos, stringJoiner.toString());
return this;
}
@Override
public SqlQuery setParameter(String key, String value) {
this.parameterMap.put(key, prevProcessValue(value));
return this;
}
@Override
public SqlQuery setParameter(String key, boolean value) {
if (value) {
return setParameter(key, 1);
}
return setParameter(key, 0);
}
@Override
public SqlQuery setParameter(String key, int value) {
this.parameterMap.put(key, String.valueOf(value));
return this;
}
@Override
public SqlQuery setParameter(String key, List<String> list) {
if (list == null) {
String nullstr = null;
return this.setParameter(key, nullstr);
}
StringJoiner stringJoiner = new StringJoiner(",", "(", ")");
for (String value : list) {
stringJoiner.add(prevProcessValue(value));
}
parameterMap.put(key, stringJoiner.toString());
return this;
}
@Override
public String getQueryString() {
SqlNode rootSqlNode = SimpleSqlNodeFactory.getSqlNode(element, parameterMap);
return rootSqlNode.getFullText().trim()
.replaceAll(System.lineSeparator(), " ")
.replaceAll(" +", " ");
}
private String prevProcessValue(String value) {
if (value == null) {
return null;
}
if (value.isEmpty()) {
return "";
}
if (value.startsWith("'") && value.endsWith("'")) {
return value;
}
return "'" + value + "'";
}
@Override
public String toString() {
return getQueryString();
}
}

@ -0,0 +1,56 @@
package com.xit.core.support.sql.parser.sqlQuery;
import java.util.List;
public class EmptySqlQuery implements SqlQuery {
@Override
public SqlQuery setParameter(int pos, String value) {
return this;
}
@Override
public SqlQuery setParameter(int pos, int value) {
return null;
}
@Override
public SqlQuery setParameter(int pos, boolean value) {
return null;
}
@Override
public SqlQuery setParameter(int pos, List<String> list) {
return null;
}
@Override
public SqlQuery setParameter(String key, String value) {
return this;
}
@Override
public SqlQuery setParameter(String key, boolean value) {
return null;
}
@Override
public SqlQuery setParameter(String key, int value) {
return null;
}
@Override
public SqlQuery setParameter(String key, List<String> list) {
return null;
}
@Override
public String getQueryString() {
return null;
}
@Override
public String toString(){
return "Empty Sql Query";
}
}

@ -0,0 +1,24 @@
package com.xit.core.support.sql.parser.sqlQuery;
import java.util.List;
public interface SqlQuery {
SqlQuery setParameter(int pos, String value);
SqlQuery setParameter(int pos, int value);
SqlQuery setParameter(int pos, boolean value);
SqlQuery setParameter(int pos, List<String> list);
SqlQuery setParameter(String key, String value);
SqlQuery setParameter(String key, boolean value);
SqlQuery setParameter(String key, int value);
SqlQuery setParameter(String key, List<String> list);
String getQueryString();
}

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings namespace="board">
<named-native-query name="selectBoardList">
/* board-mapper|selectBoardList|julim */
SELECT MCB.ci_code,
MU.name,
MCB.ci_contentno,
MCB.ci_title,
MCB.ci_contents,
MCB.ci_nalja,
MCB.ci_step,
MCB.ci_revel,
MCB.ci_ref,
MCB.ci_hit,
MCB.ci_pass,
MCB.ci_id
FROM min_civ_board680 MCB
LEFT OUTER JOIN min_userinfo MU
ON MCB.ci_id = MU.userid
WHERE 1=1
<if text="ciTitle != null and ciTitle != ''">AND INSTR(MCB.ci_title, #{ciTitle}) > 0</if>
<if text="ciName != null and ciName != ''">AND MCB.ci_name like #{ciName}||'%'</if>
<if text="ciContents != null and ciContents != ''">AND INSTR(MCB.ci_contents, #{ciContents}) > 0</if>
ORDER BY MCB.ci_ref DESC,
MCB.ci_step ASC,
MCB.ci_code DESC
</named-native-query>
</entity-mappings>

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<sqlMapper>
<selectBoardList>
/* board-mapper|selectBoardList|julim */
SELECT MCB.ci_code,
MU.name,
MCB.ci_contentno,
MCB.ci_title,
MCB.ci_contents,
MCB.ci_nalja,
MCB.ci_step,
MCB.ci_revel,
MCB.ci_ref,
MCB.ci_hit,
MCB.ci_pass,
MCB.ci_id
FROM min_civ_board680 MCB
LEFT OUTER JOIN min_userinfo MU
ON MCB.ci_id = MU.userid
WHERE 1=1
AND INSTR(MCB.ci_title, #{ciTitle}) > 0
AND MCB.ci_name like #{ciName}||'%'
ORDER BY MCB.ci_ref DESC,
MCB.ci_step ASC,
MCB.ci_code DESC
</selectBoardList>
<select id="selectBoardList2" parameterType="com.xit.biz.ctgy.dto.BoardDto" resultType="camelCaseLinkedMap">
/* board-mapper|selectBoardList2|julim */
SELECT MCB.ci_code,
MU.name,
MCB.ci_contentno,
MCB.ci_title,
MCB.ci_contents,
MCB.ci_nalja,
MCB.ci_step,
MCB.ci_revel,
MCB.ci_ref,
MCB.ci_hit,
MCB.ci_pass,
MCB.ci_id
FROM min_civ_board680 MCB
LEFT OUTER JOIN min_userinfo MU
ON MCB.ci_id = MU.userid
WHERE 1=1
AND INSTR(MCB.ci_title, #{ciTitle}) > 0
AND MCB.ci_name like #{ciName}||'%'
ORDER BY MCB.ci_ref DESC,
MCB.ci_step ASC,
MCB.ci_code DESC
</select>
</sqlMapper>

@ -1,30 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<sqlMapper> <entity-mappings namespace="refreshToken">
<selectRefreshToken> <named-native-query name="selectRefreshToken">
/* refreshToken-mapper|selectRefreshToken|julim */ /* refreshToken-mapper|selectRefreshToken|julim */
SELECT key, SELECT key,
value value
FROM refresh_token FROM refresh_token
WHERE key = :userId WHERE key = #{key}
</selectRefreshToken> </named-native-query>
<updateRefreshToken> <named-native-query name="insertRefreshToken">
/* refreshToken-mapper|insertRefreshToken|julim */ /* refreshToken-mapper|insertRefreshToken|julim */
INSERT INSERT
INTO refresh_token ( INTO refresh_token (
key, key,
value value
) VALUE ( ) VALUE (
:userId, #{key},
:tokenValue #{value}
) )
</updateRefreshToken> </named-native-query>
<updateRefreshToken> <named-native-query name="updateRefreshToken">
/* refreshToken-mapper|updateRefreshToken|julim */ /* refreshToken-mapper|updateRefreshToken|julim */
UPDATE refresh_token UPDATE refresh_token
SET value = :tokenValue SET value = #{value}
WHERE key = :userId WHERE key = #{key}
</updateRefreshToken> </named-native-query>
</entity-mappings>
</sqlMapper>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<mapping-locations>
<!-- specify the file location for one xml file which includes sql queries-->
<!-- <file-location path="/src/main/resources/sql/orm.xml"/>-->
<!-- specify the directory location, which will include all xml files for sql queries under the directory-->
<directory-location path="/src/main/resources/sql/"/>
</mapping-locations>
Loading…
Cancel
Save