123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- package org.ssssssss.magicapi.functions;
- import org.springframework.jdbc.core.RowMapper;
- import org.springframework.jdbc.datasource.DataSourceUtils;
- import org.ssssssss.magicapi.cache.SqlCache;
- import org.ssssssss.magicapi.config.DynamicDataSource;
- import org.ssssssss.magicapi.config.DynamicDataSource.DataSourceNode;
- import org.ssssssss.magicapi.config.MagicModule;
- import org.ssssssss.magicapi.dialect.Dialect;
- import org.ssssssss.magicapi.dialect.DialectUtils;
- import org.ssssssss.magicapi.exception.MagicAPIException;
- import org.ssssssss.magicapi.model.Page;
- import org.ssssssss.magicapi.provider.PageProvider;
- import org.ssssssss.magicapi.provider.ResultProvider;
- import org.ssssssss.script.MagicScriptContext;
- import org.ssssssss.script.annotation.UnableCall;
- import org.ssssssss.script.functions.StreamExtension;
- import org.ssssssss.script.parsing.GenericTokenParser;
- import org.ssssssss.script.parsing.Parser;
- import org.ssssssss.script.parsing.TokenStream;
- import org.ssssssss.script.parsing.Tokenizer;
- import java.sql.Connection;
- import java.util.*;
- import java.util.concurrent.atomic.AtomicBoolean;
- import java.util.function.Function;
- public class DatabaseQuery extends HashMap<String, DatabaseQuery> implements MagicModule {
- @UnableCall
- private DynamicDataSource dynamicDataSource;
- @UnableCall
- private DataSourceNode dataSourceNode;
- @UnableCall
- private PageProvider pageProvider;
- @UnableCall
- private ResultProvider resultProvider;
- @UnableCall
- private RowMapper<Map<String, Object>> rowMapper;
- @UnableCall
- private SqlCache sqlCache;
- @UnableCall
- private String cacheName;
- @UnableCall
- private long ttl;
- public DatabaseQuery() {
- }
- public DatabaseQuery(DynamicDataSource dynamicDataSource) {
- this.dynamicDataSource = dynamicDataSource;
- this.dataSourceNode = dynamicDataSource.getDataSource();
- }
- @UnableCall
- public void setPageProvider(PageProvider pageProvider) {
- this.pageProvider = pageProvider;
- }
- @UnableCall
- public void setResultProvider(ResultProvider resultProvider) {
- this.resultProvider = resultProvider;
- }
- @UnableCall
- public void setRowMapper(RowMapper<Map<String, Object>> rowMapper) {
- this.rowMapper = rowMapper;
- }
- @UnableCall
- public void setDynamicDataSource(DynamicDataSource dynamicDataSource) {
- this.dynamicDataSource = dynamicDataSource;
- }
- @UnableCall
- public void setSqlCache(SqlCache sqlCache) {
- this.sqlCache = sqlCache;
- }
- @UnableCall
- public void setDataSourceNode(DataSourceNode dataSourceNode) {
- this.dataSourceNode = dataSourceNode;
- }
- @UnableCall
- public void setCacheName(String cacheName) {
- this.cacheName = cacheName;
- }
- @UnableCall
- public void setTtl(long ttl) {
- this.ttl = ttl;
- }
- @UnableCall
- public DatabaseQuery cloneQuery() {
- DatabaseQuery query = new DatabaseQuery();
- query.setDynamicDataSource(this.dynamicDataSource);
- query.setDataSourceNode(this.dataSourceNode);
- query.setPageProvider(this.pageProvider);
- query.setRowMapper(this.rowMapper);
- query.setSqlCache(this.sqlCache);
- query.setTtl(this.ttl);
- query.setResultProvider(this.resultProvider);
- return query;
- }
-
- public Object transaction(Function<?, ?> function) {
- Transaction transaction = transaction();
- try {
- Object val = function.apply(null);
- transaction.commit();
- return val;
- } catch (Throwable throwable) {
- transaction.rollback();
- throw throwable;
- }
- }
-
- public Transaction transaction() {
- return new Transaction(this.dataSourceNode.getDataSourceTransactionManager());
- }
-
- @UnableCall
- private <T> T putCacheValue(T value, BoundSql boundSql) {
- if (this.cacheName != null) {
- this.sqlCache.put(this.cacheName, boundSql.getCacheKey(this.sqlCache), value, this.ttl);
- }
- return value;
- }
-
- public DatabaseQuery cache(String cacheName, long ttl) {
- if (cacheName == null) {
- return this;
- }
- DatabaseQuery query = cloneQuery();
- query.setCacheName(cacheName);
- query.setTtl(ttl);
- return query;
- }
-
- public DatabaseQuery cache(String cacheName) {
- return cache(cacheName, 0);
- }
-
- @Override
- public DatabaseQuery get(Object key) {
- DatabaseQuery query = cloneQuery();
- if (key == null) {
- query.setDataSourceNode(dynamicDataSource.getDataSource());
- } else {
- query.setDataSourceNode(dynamicDataSource.getDataSource(key.toString()));
- }
- return query;
- }
-
- public List<Map<String, Object>> select(String sql) {
- BoundSql boundSql = new BoundSql(sql);
- return (List<Map<String, Object>>) boundSql.getCacheValue(this.sqlCache, this.cacheName)
- .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().query(boundSql.getSql(), this.rowMapper, boundSql.getParameters()), boundSql));
- }
-
- public int update(String sql) {
- BoundSql boundSql = new BoundSql(sql);
- int value = dataSourceNode.getJdbcTemplate().update(boundSql.getSql(), boundSql.getParameters());
- if (this.cacheName != null) {
- this.sqlCache.delete(this.cacheName);
- }
- return value;
- }
-
- public Object page(String sql) {
- Page page = pageProvider.getPage(MagicScriptContext.get());
- return page(sql, page.getLimit(), page.getOffset());
- }
-
- public Object page(String sql, long limit, long offset) {
- BoundSql boundSql = new BoundSql(sql);
- Connection connection = null;
- Dialect dialect;
- try {
- connection = dataSourceNode.getJdbcTemplate().getDataSource().getConnection();
- dialect = DialectUtils.getDialectFromUrl(connection.getMetaData().getURL());
- } catch (Exception e) {
- throw new MagicAPIException("自动获取数据库方言失败", e);
- } finally {
- DataSourceUtils.releaseConnection(connection, dataSourceNode.getJdbcTemplate().getDataSource());
- }
- if (dialect == null) {
- throw new MagicAPIException("自动获取数据库方言失败");
- }
- int count = (int) boundSql.getCacheValue(this.sqlCache, this.cacheName)
- .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().queryForObject(dialect.getCountSql(boundSql.getSql()), Integer.class, boundSql.getParameters()), boundSql));
- List<Object> list = null;
- if (count > 0) {
- String pageSql = dialect.getPageSql(boundSql.getSql(), boundSql, offset, limit);
- list = (List<Object>) boundSql.removeCacheKey().getCacheValue(this.sqlCache, this.cacheName)
- .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().query(pageSql, this.rowMapper, boundSql.getParameters()), boundSql));
- }
- return resultProvider.buildPageResult(count, list);
- }
-
- public Integer selectInt(String sql) {
- BoundSql boundSql = new BoundSql(sql);
- return (Integer) boundSql.getCacheValue(this.sqlCache, this.cacheName)
- .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().queryForObject(boundSql.getSql(), boundSql.getParameters(), Integer.class), boundSql));
- }
-
- public Map<String, Object> selectOne(String sql) {
- BoundSql boundSql = new BoundSql(sql);
- return (Map<String, Object>) boundSql.getCacheValue(this.sqlCache, this.cacheName)
- .orElseGet(() -> {
- List<Map<String, Object>> list = dataSourceNode.getJdbcTemplate().query(boundSql.getSql(), this.rowMapper, boundSql.getParameters());
- return list != null && list.size() > 0 ? list.get(0) : null;
- });
- }
-
- public Object selectValue(String sql) {
- BoundSql boundSql = new BoundSql(sql);
- return boundSql.getCacheValue(this.sqlCache, this.cacheName)
- .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().queryForObject(boundSql.getSql(), boundSql.getParameters(), Object.class), boundSql));
- }
- private static Tokenizer tokenizer = new Tokenizer();
- private static GenericTokenParser concatTokenParser = new GenericTokenParser("${", "}", false);
- private static GenericTokenParser replaceTokenParser = new GenericTokenParser("#{", "}", true);
- private static GenericTokenParser ifTokenParser = new GenericTokenParser("?{", "}", true);
- private static GenericTokenParser ifParamTokenParser = new GenericTokenParser("?{", ",", true);
- @UnableCall
- @Override
- public String getModuleName() {
- return "db";
- }
- public static class BoundSql {
- private String sql;
- private List<Object> parameters = new ArrayList<>();
- private String cacheKey;
- BoundSql(String sql) {
- MagicScriptContext context = MagicScriptContext.get();
-
- this.sql = ifTokenParser.parse(sql.trim(), text -> {
- AtomicBoolean ifTrue = new AtomicBoolean(false);
- String val = ifParamTokenParser.parse("?{" + text, param -> {
- Object result = Parser.parseExpression(new TokenStream(tokenizer.tokenize(param))).evaluate(context);
-
- if (result != null) {
- if (result instanceof String) {
- ifTrue.set(!result.toString().isEmpty());
- } else {
- ifTrue.set(!Objects.equals(false, result));
- }
- }
- return null;
- });
- if (ifTrue.get()) {
- return val;
- }
- return "";
- });
-
- this.sql = concatTokenParser.parse(this.sql, text -> String.valueOf(Parser.parseExpression(new TokenStream(tokenizer.tokenize(text))).evaluate(context)));
-
- this.sql = replaceTokenParser.parse(this.sql, text -> {
- Object value = Parser.parseExpression(new TokenStream(tokenizer.tokenize(text))).evaluate(context);
- try {
-
- List<Object> objects = StreamExtension.arrayLikeToList(value);
- StringBuilder sb = new StringBuilder();
- for (int i = 0, size = objects.size(); i < size; i++) {
- sb.append("?");
- if (i + 1 < size) {
- sb.append(",");
- }
- parameters.add(objects.get(i));
- }
- return sb.toString();
- } catch (Exception e) {
- parameters.add(value);
- return "?";
- }
- });
- }
-
- public void addParameter(Object value) {
- parameters.add(value);
- }
-
- public String getSql() {
- return sql;
- }
-
- public Object[] getParameters() {
- return parameters.toArray();
- }
-
- public BoundSql removeCacheKey() {
- this.cacheKey = null;
- return this;
- }
-
- public String getCacheKey(SqlCache sqlCache) {
- if (cacheKey == null) {
- cacheKey = sqlCache.buildSqlCacheKey(this);
- }
- return cacheKey;
- }
-
- public <T> Optional<T> getCacheValue(SqlCache sqlCache, String cacheName) {
- return Optional.ofNullable(cacheName == null ? null : sqlCache.get(cacheName, getCacheKey(sqlCache)));
- }
- }
- }
|