1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-04 10:38:19 +08:00

feat(sql): Support SQL sources

This commit is contained in:
2025-03-03 18:51:21 +08:00
parent 844cbfab53
commit a699f6c164
13 changed files with 107 additions and 89 deletions
@@ -5,6 +5,7 @@ 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.configuration.versioned.VersionedMetaTypes;
import cc.carm.lib.easysql.api.SQLManager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -79,34 +80,19 @@ public class SQLConfigFactory extends ConfigurationFactory<SQLSource, Configurat
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);
}
});
return resolver(id, SQLValueResolver.of(type, parser));
}
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) {
@NotNull DataFunction<T, 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);
}
});
@NotNull DataFunction<T, String> serializer) {
return resolver(id, SQLValueResolver.of(type, parser, serializer));
}
public SQLConfigFactory tableName(@NotNull String tableName) {
@@ -128,6 +114,7 @@ public class SQLConfigFactory extends ConfigurationFactory<SQLSource, Configurat
if (manager == null) throw new NullPointerException("No SQLManager instance provided.");
Commentable.registerMeta(this.initializer);
VersionedMetaTypes.register(this.initializer);
return new ConfigurationHolder<SQLSource>(this.adapters, this.options, this.metadata, this.initializer) {
final SQLSource source = new SQLSource(
@@ -1,6 +1,12 @@
package cc.carm.lib.configuration.source.sql;
import cc.carm.lib.configuration.source.option.ConfigurationOption;
public interface SQLOptions {
/**
* Whether to purge the configuration's in-database data when saving.
*/
ConfigurationOption<Boolean> PURGE = ConfigurationOption.of( true);
}
@@ -1,6 +1,5 @@
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;
@@ -93,6 +92,10 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
return Objects.requireNonNull(this.rootSection, "Root section is not initialized.");
}
public int purge() throws Exception {
return this.table.createDelete().addCondition("namespace", namespace).build().execute();
}
@Override
public void save() throws Exception {
LocalDateTime time = LocalDateTime.now(); // Update time
@@ -102,29 +105,29 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
Map<String, ConfigValue<?>> values = holder().registeredValues();
for (Map.Entry<String, ConfigValue<?>> entry : values.entrySet()) {
@NotNull String path = entry.getKey();
@NotNull ConfigValue<?> value = entry.getValue();
@NotNull ConfigValue<?> config = entry.getValue();
@Nullable Object value = section.get(path);
try {
int typeID = typeOf(entry.getValue());
String data = null;
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);
if (value instanceof SourcedSection) {
value = ((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 {
data = serialize(typeID, value);
list.add(obj);
}
}
value = list;
}
if (value == null) continue;
try {
int typeID = typeIdOf(value);
String data = serialize(typeID, value);
if (data == null) continue;
int version = holder().metadata(path).get(VersionedMetaTypes.VERSION, 0);
dataValues.add(new Object[]{
@@ -138,6 +141,9 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
}
}
if (holder.option(SQLOptions.PURGE)) {
purge();
}
this.table.createReplaceBatch()
.setColumnNames(
"namespace", "path", "update_time", "version", "type", "value",
@@ -157,12 +163,8 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
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);
}
loaded.put(path, parse(rs.getInt("type"), rs.getString("value")));
if (ver != 0) holder().metadata(path).set(VersionedMetaTypes.VERSION, ver);
} catch (Exception e) {
e.printStackTrace();
}
@@ -175,20 +177,20 @@ public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Objec
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);
return function.resolve(this, 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);
return function.serialize(this, value);
}
protected int typeOf(@NotNull ValueType<?> value) {
protected int typeIdOf(@NotNull Object value) {
return this.resolvers.entrySet().stream()
.filter(entry -> entry.getValue().isTypeOf(value))
.filter(entry -> entry.getValue().isInstance(value))
.findFirst().map(Map.Entry::getKey)
.orElseThrow(() -> new IllegalStateException("No resolvers for value " + value));
.orElseThrow(() -> new IllegalStateException("No resolvers for value " + value.getClass().getName()));
}
@@ -2,7 +2,6 @@ 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;
@@ -26,26 +25,26 @@ public abstract class SQLValueResolver<T> {
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);
public @Nullable List<?> resolve(@NotNull SQLSource source, String data) throws Exception {
return source.gson().fromJson(data, List.class);
}
@Override
public @Nullable String serialize(@NotNull ConfigurationHolder<? extends SQLSource> holder, Object value) {
return holder.config().gson().toJson(value);
public @Nullable String serialize(@NotNull SQLSource source, Object value) {
return source.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);
public @Nullable Map<?, ?> resolve(@NotNull SQLSource source, String data) throws Exception {
return source.gson().fromJson(data, LinkedHashMap.class);
}
@Override
public @Nullable String serialize(@NotNull ConfigurationHolder<? extends SQLSource> holder, Object value) {
return holder.config().gson().toJson(value);
public @Nullable String serialize(@NotNull SQLSource source, Object value) {
return source.gson().toJson(value);
}
};
@@ -70,12 +69,29 @@ public abstract class SQLValueResolver<T> {
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 {
public @NotNull V resolve(@NotNull SQLSource source, String data) throws Exception {
return resolver.handle(data);
}
};
}
public static <V> SQLValueResolver<V> of(@NotNull ValueType<V> type,
@NotNull DataFunction<String, V> resolver,
@NotNull DataFunction<V, String> serializer) {
return new SQLValueResolver<V>(type) {
@Override
public @NotNull V resolve(@NotNull SQLSource source, String data) throws Exception {
return resolver.handle(data);
}
@Override
public @NotNull String serialize(@NotNull SQLSource source, Object value) throws Exception {
return serializer.handle(type.cast(value));
}
};
}
protected final @NotNull ValueType<T> type;
protected SQLValueResolver(@NotNull ValueType<T> type) {
@@ -86,17 +102,13 @@ public abstract class SQLValueResolver<T> {
return type;
}
public boolean isTypeOf(@NotNull Class<?> clazz) {
return type.isSubtypeOf(clazz);
public boolean isInstance(@NotNull Object obj) {
return getType().isInstance(obj);
}
public boolean isTypeOf(@NotNull ValueType<?> valueType) {
return valueType.equals(type);
}
public abstract @Nullable T resolve(@NotNull SQLSource source, String data) throws Exception;
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 {
public @Nullable String serialize(@NotNull SQLSource source, Object value) throws Exception {
return String.valueOf(value);
}