mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 10:38:19 +08:00
feat(sql): Try to implement sql source
This commit is contained in:
+10
-10
@@ -6,16 +6,16 @@ SQL database implementation, support for MySQL or MariaDB.
|
||||
```mysql
|
||||
CREATE TABLE IF NOT EXISTS conf
|
||||
(
|
||||
`namespace` VARCHAR(32) NOT NULL, # 命名空间 (代表其属于谁,类似于单个配置文件地址的概念)
|
||||
`path` VARCHAR(96) NOT NULL, # 配置路径 (ConfigPath)
|
||||
`type` TINYINT UNSIGNED NOT NULL DEFAULT 0, # 数据类型 (Integer/Byte/List/Map/...)
|
||||
`value` MEDIUMTEXT, # 配置项的值 (可能为JSON格式)
|
||||
`inline_comment` TEXT, # 配置项的用法,本质是行内注释
|
||||
`header_comment` MEDIUMTEXT, # 配置项的描述,本质是顶部注释
|
||||
`footer_comment` MEDIUMTEXT, # 配置项的描述,本质是顶部注释
|
||||
`version` INT UNSIGNED NOT NULL DEFAULT 0, # 配置项的版本
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, # 创建时间
|
||||
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`namespace` VARCHAR(32) NOT NULL, # 命名空间 (代表其属于谁,类似于单个配置文件地址的概念)
|
||||
`path` VARCHAR(96) NOT NULL, # 配置路径 (ConfigPath)
|
||||
`type` TINYINT UNSIGNED NOT NULL DEFAULT 0, # 数据类型 (Integer/Byte/List/Map/...)
|
||||
`value` MEDIUMTEXT, # 配置项的值 (可能为JSON格式)
|
||||
`inline_comment` TEXT comment 'usage', # 配置项的用法,本质是行内注释
|
||||
`header_comment` MEDIUMTEXT comment 'description', # 配置项的描述,本质是顶部注释
|
||||
`footer_comment` MEDIUMTEXT comment 'example', # 配置项的参考,本质是底部注释
|
||||
`version` MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, # 配置项的版本
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, # 创建时间
|
||||
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`namespace`, `path`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4;
|
||||
|
||||
+20
-5
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.0</version>
|
||||
<version>4.0.8</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -15,7 +15,8 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
|
||||
<log4j.version>2.24.3</log4j.version>
|
||||
<deps.mysql-driver.version>8.0.26</deps.mysql-driver.version>
|
||||
<deps.log4j.version>2.24.3</deps.log4j.version>
|
||||
</properties>
|
||||
<artifactId>easyconfiguration-sql</artifactId>
|
||||
|
||||
@@ -77,21 +78,35 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<version>${deps.log4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<version>${deps.log4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<version>${deps.log4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-gson</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${deps.mysql-driver.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
package cc.carm.lib.configuration.source.sql;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.commentable.Commentable;
|
||||
import cc.carm.lib.configuration.function.DataFunction;
|
||||
import cc.carm.lib.configuration.source.ConfigurationFactory;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.easysql.api.SQLManager;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SQLConfigFactory extends ConfigurationFactory<SQLSource, ConfigurationHolder<SQLSource>, SQLConfigFactory> {
|
||||
|
||||
public static SQLConfigFactory from(@NotNull Supplier<@NotNull SQLManager> managerSupplier) {
|
||||
return new SQLConfigFactory(managerSupplier);
|
||||
}
|
||||
|
||||
public static SQLConfigFactory from(@NotNull SQLManager manager) {
|
||||
return from(() -> manager);
|
||||
}
|
||||
|
||||
protected @NotNull Supplier<SQLManager> managerSupplier;
|
||||
protected Supplier<Gson> gsonSupplier = () -> SQLSource.DEFAULT_GSON;
|
||||
|
||||
protected HashMap<Integer, SQLValueResolver<?>> resolvers = new HashMap<>(SQLValueResolver.STANDARD_RESOLVERS);
|
||||
protected String tableName = "configs";
|
||||
protected String namespace = "default";
|
||||
|
||||
public SQLConfigFactory(@NotNull Supplier<SQLManager> managerSupplier) {
|
||||
this.managerSupplier = managerSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLConfigFactory self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLConfigFactory manager(@NotNull Supplier<SQLManager> managerSupplier) {
|
||||
this.managerSupplier = managerSupplier;
|
||||
return self();
|
||||
}
|
||||
|
||||
public SQLConfigFactory manager(@NotNull SQLManager manager) {
|
||||
return manager(() -> manager);
|
||||
}
|
||||
|
||||
public SQLConfigFactory gson(@NotNull Supplier<Gson> gsonSupplier) {
|
||||
this.gsonSupplier = gsonSupplier;
|
||||
return self();
|
||||
}
|
||||
|
||||
public SQLConfigFactory gson(@NotNull Consumer<GsonBuilder> builder) {
|
||||
return gson(() -> {
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
builder.accept(gsonBuilder);
|
||||
return gsonBuilder.create();
|
||||
});
|
||||
}
|
||||
|
||||
public SQLConfigFactory gson(@NotNull Gson gson) {
|
||||
return gson(() -> gson);
|
||||
}
|
||||
|
||||
public SQLConfigFactory resolver(@Range(from = 0, to = 255) int type, @NotNull SQLValueResolver<?> resolver) {
|
||||
this.resolvers.put(type, resolver);
|
||||
return self();
|
||||
}
|
||||
|
||||
public <T> SQLConfigFactory resolver(@Range(from = 0, to = 255) int id, @NotNull Class<T> clazz,
|
||||
@NotNull DataFunction<String, T> parser) {
|
||||
return resolver(id, ValueType.of(clazz), parser);
|
||||
}
|
||||
|
||||
public <T> SQLConfigFactory resolver(@Range(from = 0, to = 255) int id, @NotNull ValueType<T> type,
|
||||
@NotNull DataFunction<String, T> parser) {
|
||||
return resolver(id, new SQLValueResolver<T>(type) {
|
||||
@Override
|
||||
public @NotNull T resolve(@NotNull ConfigurationHolder<? extends SQLSource> holder, String data) throws Exception {
|
||||
return parser.handle(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public <T> SQLConfigFactory resolver(@Range(from = 0, to = 255) int id, @NotNull Class<T> clazz,
|
||||
@NotNull DataFunction<String, T> parser,
|
||||
@NotNull DataFunction<Object, String> serializer) {
|
||||
return resolver(id, ValueType.of(clazz), parser, serializer);
|
||||
}
|
||||
|
||||
public <T> SQLConfigFactory resolver(@Range(from = 0, to = 255) int id, @NotNull ValueType<T> type,
|
||||
@NotNull DataFunction<String, T> parser,
|
||||
@NotNull DataFunction<Object, String> serializer) {
|
||||
return resolver(id, new SQLValueResolver<T>(type) {
|
||||
@Override
|
||||
public @NotNull T resolve(@NotNull ConfigurationHolder<? extends SQLSource> holder, String data) throws Exception {
|
||||
return parser.handle(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String serialize(@NotNull ConfigurationHolder<? extends SQLSource> holder, Object value) throws Exception {
|
||||
return serializer.handle(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public SQLConfigFactory tableName(@NotNull String tableName) {
|
||||
this.tableName = tableName;
|
||||
return self();
|
||||
}
|
||||
|
||||
public SQLConfigFactory namespace(@NotNull String namespace) {
|
||||
this.namespace = namespace;
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfigurationHolder<SQLSource> build() {
|
||||
Gson gson = gsonSupplier.get();
|
||||
if (gson == null) throw new NullPointerException("No Gson instance provided.");
|
||||
|
||||
SQLManager manager = this.managerSupplier.get();
|
||||
if (manager == null) throw new NullPointerException("No SQLManager instance provided.");
|
||||
|
||||
Commentable.registerMeta(this.initializer);
|
||||
|
||||
return new ConfigurationHolder<SQLSource>(this.adapters, this.options, this.metadata, this.initializer) {
|
||||
final SQLSource source = new SQLSource(
|
||||
this, System.currentTimeMillis(),
|
||||
gson, manager, resolvers, tableName, namespace
|
||||
);
|
||||
|
||||
@Override
|
||||
public @NotNull SQLSource config() {
|
||||
return source;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,53 +1,63 @@
|
||||
package cc.carm.lib.configuration.source.sql;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.commentable.Commentable;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.section.ConfigureSource;
|
||||
import cc.carm.lib.configuration.source.section.MemorySection;
|
||||
import cc.carm.lib.configuration.source.section.SourcedSection;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.versioned.VersionedMetaTypes;
|
||||
import cc.carm.lib.easysql.api.SQLManager;
|
||||
import cc.carm.lib.easysql.api.SQLQuery;
|
||||
import cc.carm.lib.easysql.api.SQLTable;
|
||||
import cc.carm.lib.easysql.api.enums.IndexType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
public class SQLSource extends ConfigureSource<MemorySection, Map<?, ?>, SQLSource> {
|
||||
public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Object>, SQLSource> {
|
||||
|
||||
protected static final @NotNull Gson DEFAULT_GSON = new GsonBuilder()
|
||||
.serializeNulls().disableHtmlEscaping().setPrettyPrinting()
|
||||
.create();
|
||||
.serializeNulls().disableHtmlEscaping().create();
|
||||
|
||||
protected final @NotNull Gson gson;
|
||||
protected final @NotNull SQLManager sqlManager;
|
||||
protected final @NotNull String namespace;
|
||||
protected final @NotNull SQLTable table;
|
||||
|
||||
protected final @NotNull Set<String> updated = new HashSet<>();
|
||||
protected MemorySection rootSection;
|
||||
protected final @NotNull Map<Integer, SQLValueResolver<?>> resolvers;
|
||||
protected SourcedSection rootSection;
|
||||
|
||||
public SQLSource(@NotNull ConfigurationHolder<? extends SQLSource> holder, long lastUpdateMillis,
|
||||
@NotNull Gson gson, @NotNull SQLManager sqlManager, @NotNull String tableName, @NotNull String namespace) {
|
||||
@NotNull Gson gson, @NotNull SQLManager sqlManager,
|
||||
@NotNull Map<Integer, SQLValueResolver<?>> resolvers,
|
||||
@NotNull String tableName, @NotNull String namespace) {
|
||||
super(holder, lastUpdateMillis);
|
||||
this.gson = gson;
|
||||
this.sqlManager = sqlManager;
|
||||
this.resolvers = resolvers;
|
||||
this.namespace = namespace;
|
||||
this.table = SQLTable.of(tableName, builder -> {
|
||||
|
||||
builder.addColumn("namespace", "VARCHAR(32) NOT NULL");
|
||||
builder.addColumn("path", "VARCHAR(96) NOT NULL");
|
||||
|
||||
builder.addColumn("type", "TINYINT NOT NULL DEFAULT 0");
|
||||
builder.addColumn("value", "TEXT");
|
||||
|
||||
builder.addColumn("inline_comment", "TEXT");
|
||||
builder.addColumn("header_comments", "MEDIUMTEXT");
|
||||
builder.addColumn("footer_comments", "MEDIUMTEXT");
|
||||
|
||||
builder.addColumn("type", "TINYINT NOT NULL DEFAULT 0");
|
||||
builder.addColumn("version", "MEDIUMINT UNSIGNED NOT NULL DEFAULT 0");
|
||||
|
||||
builder.addColumn("create_time", "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
|
||||
builder.addColumn("update_time", "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
|
||||
builder.addColumn("create_time", "TIMESTAMP NOT NULL");
|
||||
builder.addColumn("update_time", "TIMESTAMP NOT NULL");
|
||||
|
||||
builder.setIndex(
|
||||
IndexType.PRIMARY_KEY, "pk_" + tableName.toLowerCase(),
|
||||
@@ -55,82 +65,131 @@ public class SQLSource extends ConfigureSource<MemorySection, Map<?, ?>, SQLSour
|
||||
);
|
||||
builder.setTableSettings("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
||||
});
|
||||
|
||||
try {
|
||||
this.table.create(this.sqlManager);
|
||||
onReload();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLSource self() {
|
||||
protected @NotNull SQLSource self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Gson gson() {
|
||||
return gson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Map<?, ?> original() {
|
||||
public @NotNull Map<String, Object> original() {
|
||||
return section().data();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull MemorySection section() {
|
||||
public @NotNull SourcedSection section() {
|
||||
return Objects.requireNonNull(this.rootSection, "Root section is not initialized.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws Exception {
|
||||
if (this.updated.isEmpty()) return; // Nothing to save
|
||||
LocalDateTime time = LocalDateTime.now(); // Update time
|
||||
List<Object[]> dataValues = new ArrayList<>();
|
||||
|
||||
Date date = new Date(); // Update time
|
||||
List<Object[]> values = new ArrayList<>();
|
||||
SourcedSection section = section();
|
||||
Map<String, ConfigValue<?>> values = holder().registeredValues();
|
||||
for (Map.Entry<String, ConfigValue<?>> entry : values.entrySet()) {
|
||||
@NotNull String path = entry.getKey();
|
||||
@NotNull ConfigValue<?> value = entry.getValue();
|
||||
|
||||
for (String path : this.updated) {
|
||||
Object value = get(path);
|
||||
try {
|
||||
int typeID = typeOf(entry.getValue());
|
||||
String data = null;
|
||||
|
||||
// if (value instanceof SQLConfigWrapper) {
|
||||
// value = getSourceMap(((SQLConfigWrapper) value).getSource());
|
||||
// }
|
||||
//
|
||||
// SQLValueResolver<?> type = SQLValueTypes.get(value.getClass());
|
||||
// if (type != null) {
|
||||
// values.add(new Object[]{
|
||||
// this.namespace, path, date,
|
||||
// type.getID(), type.serializeObject(value),
|
||||
// getComments().getInlineComment(path),
|
||||
// GSON.toJson(getComments().getHeaderComment(path))
|
||||
// });
|
||||
// }
|
||||
if (value != null) {
|
||||
if (value instanceof SourcedSection) {
|
||||
data = serialize(typeID, ((SourcedSection) value).rawMap());
|
||||
} else if (value instanceof List) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
for (Object obj : (List<?>) value) {
|
||||
if (obj instanceof SourcedSection) {
|
||||
list.add(((SourcedSection) obj).rawMap());
|
||||
} else {
|
||||
list.add(obj);
|
||||
}
|
||||
}
|
||||
data = serialize(typeID, list);
|
||||
} else {
|
||||
data = serialize(typeID, value);
|
||||
}
|
||||
}
|
||||
|
||||
int version = holder().metadata(path).get(VersionedMetaTypes.VERSION, 0);
|
||||
dataValues.add(new Object[]{
|
||||
namespace, path, time, version, typeID, data,
|
||||
Commentable.getInlineComment(holder(), path),
|
||||
gson.toJson(Commentable.getHeaderComments(holder(), path)),
|
||||
gson.toJson(Commentable.getFooterComments(holder(), path))
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
this.updated.clear();
|
||||
|
||||
this.table.createReplaceBatch()
|
||||
.setColumnNames("namespace", "path", "update_time", "type", "value", "inline_comment", "header_comments")
|
||||
.setAllParams(values)
|
||||
.execute();
|
||||
.setColumnNames(
|
||||
"namespace", "path", "update_time", "version", "type", "value",
|
||||
"inline_comment", "header_comments", "footer_comments"
|
||||
).setAllParams(dataValues).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReload() throws Exception {
|
||||
LinkedHashMap<String, Object> values = new LinkedHashMap<>();
|
||||
|
||||
// try (SQLQuery query = this.table.createQuery()
|
||||
// .addCondition("namespace", namespace)
|
||||
// .build().execute()) {
|
||||
// ResultSet rs = query.getResultSet();
|
||||
// while (rs.next()) {
|
||||
// String path = rs.getString("path");
|
||||
// int type = rs.getInt("type");
|
||||
// try {
|
||||
// SQLValueResolver<?> resolver = SQLValueTypes.get(type);
|
||||
// if (resolver == null) throw new IllegalStateException("No resolver for type #" + type);
|
||||
// String value = rs.getString("value");
|
||||
// values.put(path, resolver.resolve(value));
|
||||
//
|
||||
// loadInlineComment(path, rs.getString("inline_comment"));
|
||||
// loadHeaderComment(path, rs.getString("header_comments"));
|
||||
// } catch (Exception ex) {
|
||||
// ex.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// this.rootConfiguration = new SQLConfigWrapper(this, values);
|
||||
Map<String, Object> loaded = new LinkedHashMap<>();
|
||||
try (SQLQuery query = this.table.createQuery()
|
||||
.addCondition("namespace", namespace)
|
||||
.build().execute()) {
|
||||
ResultSet rs = query.getResultSet();
|
||||
while (rs.next()) {
|
||||
String path = rs.getString("path");
|
||||
if (path == null) continue; // Path should be not null
|
||||
int ver = rs.getInt("version");
|
||||
try {
|
||||
Object val = parse(rs.getInt("type"), rs.getString("value"));
|
||||
System.out.println("Path <" + path + "> Value = " + val);
|
||||
loaded.put(path, val);
|
||||
if (ver != 0) {
|
||||
holder().metadata(path).set(VersionedMetaTypes.VERSION, ver);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
this.rootSection = SourcedSection.root(this, loaded);
|
||||
}
|
||||
|
||||
|
||||
protected @Nullable Object parse(int type, String value) throws Exception {
|
||||
SQLValueResolver<?> function = this.resolvers.get(type);
|
||||
if (function == null) throw new IllegalStateException("No resolvers for type #" + type);
|
||||
return function.resolve(holder(), value);
|
||||
}
|
||||
|
||||
protected @Nullable String serialize(int type, @NotNull Object value) throws Exception {
|
||||
SQLValueResolver<?> function = this.resolvers.get(type);
|
||||
if (function == null) throw new IllegalStateException("No resolvers for type #" + type);
|
||||
return function.serialize(holder(), value);
|
||||
}
|
||||
|
||||
protected int typeOf(@NotNull ValueType<?> value) {
|
||||
return this.resolvers.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().isTypeOf(value))
|
||||
.findFirst().map(Map.Entry::getKey)
|
||||
.orElseThrow(() -> new IllegalStateException("No resolvers for value " + value));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package cc.carm.lib.configuration.source.sql;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.function.DataFunction;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class SQLValueResolver<T> {
|
||||
|
||||
public static final @NotNull SQLValueResolver<String> STRING = SQLValueResolver.of(ValueType.STRING, s -> s);
|
||||
public static final @NotNull SQLValueResolver<Byte> BYTE = SQLValueResolver.of(ValueType.BYTE, Byte::parseByte);
|
||||
public static final @NotNull SQLValueResolver<Short> SHORT = SQLValueResolver.of(ValueType.SHORT, Short::parseShort);
|
||||
public static final @NotNull SQLValueResolver<Integer> INTEGER = SQLValueResolver.of(ValueType.INTEGER, Integer::parseInt);
|
||||
public static final @NotNull SQLValueResolver<Long> LONG = SQLValueResolver.of(ValueType.LONG, Long::parseLong);
|
||||
public static final @NotNull SQLValueResolver<Float> FLOAT = SQLValueResolver.of(ValueType.FLOAT, Float::parseFloat);
|
||||
public static final @NotNull SQLValueResolver<Double> DOUBLE = SQLValueResolver.of(ValueType.DOUBLE, Double::parseDouble);
|
||||
public static final @NotNull SQLValueResolver<Boolean> BOOLEAN = SQLValueResolver.of(ValueType.BOOLEAN, Boolean::parseBoolean);
|
||||
public static final @NotNull SQLValueResolver<Character> CHAR = SQLValueResolver.of(ValueType.CHAR, s -> s.charAt(0));
|
||||
|
||||
public static final @NotNull SQLValueResolver<List<?>> LIST = new SQLValueResolver<List<?>>(new ValueType<List<?>>() {
|
||||
}) {
|
||||
@Override
|
||||
public @Nullable List<?> resolve(@NotNull ConfigurationHolder<? extends SQLSource> holder, String data) throws Exception {
|
||||
return holder.config().gson().fromJson(data, List.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String serialize(@NotNull ConfigurationHolder<? extends SQLSource> holder, Object value) {
|
||||
return holder.config().gson().toJson(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final @NotNull SQLValueResolver<Map<?, ?>> MAP = new SQLValueResolver<Map<?, ?>>(new ValueType<Map<?, ?>>() {
|
||||
}) {
|
||||
@Override
|
||||
public @Nullable Map<?, ?> resolve(@NotNull ConfigurationHolder<? extends SQLSource> holder, String data) throws Exception {
|
||||
return holder.config().gson().fromJson(data, LinkedHashMap.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String serialize(@NotNull ConfigurationHolder<? extends SQLSource> holder, Object value) {
|
||||
return holder.config().gson().toJson(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final @NotNull Map<Integer, SQLValueResolver<?>> STANDARD_RESOLVERS = Collections.unmodifiableMap(standards());
|
||||
|
||||
static Map<Integer, SQLValueResolver<?>> standards() {
|
||||
Map<Integer, SQLValueResolver<?>> map = new LinkedHashMap<>();
|
||||
map.put(0, STRING);
|
||||
map.put(1, BYTE);
|
||||
map.put(2, SHORT);
|
||||
map.put(3, INTEGER);
|
||||
map.put(4, LONG);
|
||||
map.put(5, FLOAT);
|
||||
map.put(6, DOUBLE);
|
||||
map.put(7, BOOLEAN);
|
||||
map.put(8, CHAR);
|
||||
map.put(10, LIST);
|
||||
map.put(11, MAP);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <V> SQLValueResolver<V> of(@NotNull ValueType<V> type, @NotNull DataFunction<String, V> resolver) {
|
||||
return new SQLValueResolver<V>(type) {
|
||||
@Override
|
||||
public @NotNull V resolve(@NotNull ConfigurationHolder<? extends SQLSource> holder, String data) throws Exception {
|
||||
return resolver.handle(data);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected final @NotNull ValueType<T> type;
|
||||
|
||||
protected SQLValueResolver(@NotNull ValueType<T> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public @NotNull ValueType<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean isTypeOf(@NotNull Class<?> clazz) {
|
||||
return type.isSubtypeOf(clazz);
|
||||
}
|
||||
|
||||
public boolean isTypeOf(@NotNull ValueType<?> valueType) {
|
||||
return valueType.equals(type);
|
||||
}
|
||||
|
||||
public abstract @Nullable T resolve(@NotNull ConfigurationHolder<? extends SQLSource> holder, String data) throws Exception;
|
||||
|
||||
public @Nullable String serialize(@NotNull ConfigurationHolder<? extends SQLSource> holder, Object value) throws Exception {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +1,45 @@
|
||||
package config;
|
||||
|
||||
import cc.carm.lib.configuration.demo.DatabaseConfiguration;
|
||||
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
|
||||
import cc.carm.lib.configuration.source.sql.SQLConfigFactory;
|
||||
import cc.carm.lib.easysql.EasySQL;
|
||||
import cc.carm.lib.easysql.api.SQLManager;
|
||||
import cc.carm.lib.easysql.beecp.BeeDataSourceConfig;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class SQLConfigTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
ConfigurationHolder<?> gsonHolder = JSONConfigFactory.from(new File("target/sql.json")).build();
|
||||
gsonHolder.initialize(DatabaseConfiguration.class);
|
||||
|
||||
BeeDataSourceConfig config = new BeeDataSourceConfig();
|
||||
config.setDriverClassName("org.h2.Driver");
|
||||
config.setJdbcUrl("jdbc:h2:file:target/test;DB_CLOSE_DELAY=-1;MODE=MySQL;");
|
||||
config.setDriverClassName(DatabaseConfiguration.DRIVER_NAME.resolve());
|
||||
config.setJdbcUrl(DatabaseConfiguration.buildJDBC());
|
||||
config.setUsername(DatabaseConfiguration.USERNAME.resolve());
|
||||
config.setPassword(DatabaseConfiguration.PASSWORD.resolve());
|
||||
|
||||
SQLManager manager = EasySQL.createManager(config);
|
||||
manager.setDebugMode(true);
|
||||
|
||||
// SQLConfigProvider provider = EasyConfiguration.from(manager, "conf_test", "TESTING");
|
||||
//
|
||||
// ConfigurationTest.testDemo(provider);
|
||||
// ConfigurationTest.testInner(provider);
|
||||
//
|
||||
// ConfigurationTest.save(provider);
|
||||
//
|
||||
// EasySQL.shutdownManager(manager);
|
||||
ConfigurationHolder<?> holder = SQLConfigFactory.from(manager)
|
||||
.tableName("test_configs")
|
||||
.namespace("testing")
|
||||
.build();
|
||||
|
||||
ConfigurationTest.testDemo(holder);
|
||||
ConfigurationTest.testInner(holder);
|
||||
|
||||
ConfigurationTest.save(holder);
|
||||
|
||||
EasySQL.shutdownManager(manager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user