001/*
002 *  Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.mybatisflex.core.dialect;
017
018import com.mybatisflex.core.constant.SqlConsts;
019import com.mybatisflex.core.util.StringUtil;
020
021import java.util.Arrays;
022import java.util.Collections;
023import java.util.Set;
024import java.util.stream.Collectors;
025
026/**
027 * 用于对数据库的关键字包装
028 */
029public class KeywordWrap {
030
031    /**
032     * 无反义处理, 适用于 db2, informix, clickhouse 等
033     */
034    public static final KeywordWrap NONE = new KeywordWrap("", "") {
035        @Override
036        public String wrap(String keyword) {
037            return keyword;
038        }
039    };
040
041    /**
042     * 无反义区分大小写处理, 适用于 db2, informix, clickhouse 等
043     */
044    public static final KeywordWrap NONE_CASE_SENSITIVE = new KeywordWrap(true, "", "") {
045        @Override
046        public String wrap(String keyword) {
047            return keyword;
048        }
049    };
050
051    /**
052     * 反引号反义处理, 适用于 mysql, h2 等
053     */
054    public static final KeywordWrap BACK_QUOTE = new KeywordWrap("`", "`");
055
056    /**
057     * 双引号反义处理, 适用于 postgresql, sqlite, derby, oracle 等
058     */
059    public static final KeywordWrap DOUBLE_QUOTATION = new KeywordWrap("\"", "\"");
060
061    /**
062     * 方括号反义处理, 适用于 sqlserver
063     */
064    public static final KeywordWrap SQUARE_BRACKETS = new KeywordWrap("[", "]");
065    /**
066     * 大小写敏感
067     */
068    private boolean caseSensitive = false;
069
070    /**
071     * 自动把关键字转换为大写
072     */
073    private boolean keywordsToUpperCase = false;
074    /**
075     * 数据库关键字
076     */
077    private final Set<String> keywords;
078    /**
079     * 前缀
080     */
081    private final String prefix;
082    /**
083     * 后缀
084     */
085    private final String suffix;
086
087
088    public KeywordWrap(String prefix, String suffix) {
089        this(false, Collections.emptySet(), prefix, suffix);
090    }
091
092
093    public KeywordWrap(boolean caseSensitive, String prefix, String suffix) {
094        this(caseSensitive, Collections.emptySet(), prefix, suffix);
095    }
096
097    public KeywordWrap(Set<String> keywords, String prefix, String suffix) {
098        this(false, keywords, prefix, suffix);
099    }
100
101    public KeywordWrap(boolean caseSensitive, Set<String> keywords, String prefix, String suffix) {
102        this.caseSensitive = caseSensitive;
103        this.keywords = keywords.stream().map(String::toUpperCase).collect(Collectors.toSet());
104        this.prefix = prefix;
105        this.suffix = suffix;
106    }
107
108    public KeywordWrap(boolean caseSensitive, boolean keywordsToUpperCase, Set<String> keywords, String prefix,
109        String suffix) {
110        this.caseSensitive = caseSensitive;
111        this.keywordsToUpperCase = keywordsToUpperCase;
112        this.keywords = keywords.stream().map(String::toUpperCase).collect(Collectors.toSet());
113        this.prefix = prefix;
114        this.suffix = suffix;
115    }
116
117    public String wrap(String keyword) {
118        if (StringUtil.isBlank(keyword) || SqlConsts.ASTERISK.equals(keyword.trim())) {
119            return keyword;
120        }
121
122        if (caseSensitive || keywords.isEmpty()) {
123            return prefix + keyword + suffix;
124        }
125
126        if (keywordsToUpperCase) {
127            keyword = keyword.toUpperCase();
128            return keywords.contains(keyword) ? (prefix + keyword + suffix) : keyword;
129        } else {
130            return keywords.contains(keyword.toUpperCase()) ? (prefix + keyword + suffix) : keyword;
131        }
132    }
133
134    //数据scheme table 包装 根据 . 分割后分别包装
135    public String wrapKeyword(String keyword) {
136        StringBuilder resultBuilder = new StringBuilder();
137        String[] split = keyword.split("\\.");
138        if (split != null && split.length > 0) {
139            Arrays.asList(split)
140                .forEach(f -> resultBuilder.append(prefix).append(f).append(suffix).append("."));
141            return resultBuilder.toString().substring(0, resultBuilder.length() - 1);
142        } else {
143            return prefix + keyword + suffix;
144        }
145    }
146
147    //sqlserver 转义 scheme table colums 包装 根据 . 分割后分别包装
148    public String wrap4Sqlserver(String keyword) {
149        if (StringUtil.isBlank(keyword) || SqlConsts.ASTERISK.equals(keyword.trim())) {
150            return keyword;
151        }
152
153        if (caseSensitive || keywords.isEmpty()) {
154            return wrapKeyword(keyword);
155        }
156
157        if (keywordsToUpperCase) {
158            keyword = keyword.toUpperCase();
159            return keywords.contains(keyword) ? wrapKeyword(keyword) : keyword;
160        } else {
161            return keywords.contains(keyword.toUpperCase()) ? wrapKeyword(keyword) : keyword;
162        }
163    }
164
165    public boolean isCaseSensitive() {
166        return caseSensitive;
167    }
168
169    public void setCaseSensitive(boolean caseSensitive) {
170        this.caseSensitive = caseSensitive;
171    }
172
173    public boolean isKeywordsToUpperCase() {
174        return keywordsToUpperCase;
175    }
176
177    public void setKeywordsToUpperCase(boolean keywordsToUpperCase) {
178        this.keywordsToUpperCase = keywordsToUpperCase;
179    }
180
181    public Set<String> getKeywords() {
182        return keywords;
183    }
184
185    public String getPrefix() {
186        return prefix;
187    }
188
189    public String getSuffix() {
190        return suffix;
191    }
192}