add table convenience routines, clean code

This commit is contained in:
Jörg Prante 2022-10-28 17:11:40 +02:00
parent 625c8999a3
commit 1409d0e42d
20 changed files with 684 additions and 431 deletions

View file

@ -15,12 +15,10 @@ public interface Config extends Function<String, String>, Supplier<Config> {
* *
* @return a builder for specifying from where configuration should be loaded * @return a builder for specifying from where configuration should be loaded
*/ */
static ConfigFrom from() { static ConfigSupplier from() {
return new ConfigFromImpl(); return new ConfigSupplierImpl();
} }
// TODO add: String originalKey(String key) to find out the key before prefixing or other manipulation
/** /**
* @return a trimmed, non-empty string, or null * @return a trimmed, non-empty string, or null
*/ */
@ -47,59 +45,27 @@ public interface Config extends Function<String, String>, Supplier<Config> {
default Config get() { default Config get() {
return this; return this;
} }
Integer getInteger(String key); Integer getInteger(String key);
int getInteger(String key, int defaultValue); int getInteger(String key, int defaultValue);
/**
* @throws ConfigMissingException if no value could be read for the specified key
*/
int getIntegerOrThrow(String key);
Long getLong(String key); Long getLong(String key);
long getLong(String key, long defaultValue); long getLong(String key, long defaultValue);
/**
* @throws ConfigMissingException if no value could be read for the specified key
*/
long getLongOrThrow(String key);
Float getFloat(String key); Float getFloat(String key);
float getFloat(String key, float defaultValue); float getFloat(String key, float defaultValue);
/**
* @throws ConfigMissingException if no value could be read for the specified key
*/
float getFloatOrThrow(String key);
Double getDouble(String key); Double getDouble(String key);
double getDouble(String key, double defaultValue); double getDouble(String key, double defaultValue);
/**
* @throws ConfigMissingException if no value could be read for the specified key
*/
double getDoubleOrThrow(String key);
BigDecimal getBigDecimal(String key); BigDecimal getBigDecimal(String key);
BigDecimal getBigDecimal(String key, BigDecimal defaultValue); BigDecimal getBigDecimal(String key, BigDecimal defaultValue);
/**
* @throws ConfigMissingException if no value could be read for the specified key
*/
BigDecimal getBigDecimalOrThrow(String key);
/** /**
* Read a boolean value from the configuration. The value is not case-sensitivie, * Read a boolean value from the configuration. The value is not case-sensitivie,
* and may be either true/false or yes/no. If no value was provided or an invalid * and may be either true/false or yes/no. If no value was provided or an invalid
@ -114,11 +80,6 @@ public interface Config extends Function<String, String>, Supplier<Config> {
*/ */
boolean getBooleanOrTrue(String key); boolean getBooleanOrTrue(String key);
/**
* @throws ConfigMissingException if no value could be read for the specified key
*/
boolean getBooleanOrThrow(String key);
/** /**
* Show where configuration is coming from. This is useful to drop in your logs * Show where configuration is coming from. This is useful to drop in your logs
* for troubleshooting. * for troubleshooting.

View file

@ -13,7 +13,7 @@ import java.util.logging.Logger;
*/ */
public class ConfigImpl implements Config { public class ConfigImpl implements Config {
private static final Logger log = Logger.getLogger(ConfigFromImpl.class.getName()); private static final Logger log = Logger.getLogger(ConfigSupplierImpl.class.getName());
private final Function<String, String> provider; private final Function<String, String> provider;
@ -71,12 +71,6 @@ public class ConfigImpl implements Config {
Integer value = getInteger(key); Integer value = getInteger(key);
return value == null ? defaultValue : value; return value == null ? defaultValue : value;
} }
@Override
public int getIntegerOrThrow(String key) {
return nonnull(key, getInteger(key));
}
@Override @Override
public Long getLong(String key) { public Long getLong(String key) {
@ -97,12 +91,6 @@ public class ConfigImpl implements Config {
Long value = getLong(key); Long value = getLong(key);
return value == null ? defaultValue : value; return value == null ? defaultValue : value;
} }
@Override
public long getLongOrThrow(String key) {
return nonnull(key, getLong(key));
}
@Override @Override
public Float getFloat(String key) { public Float getFloat(String key) {
@ -123,12 +111,6 @@ public class ConfigImpl implements Config {
Float value = getFloat(key); Float value = getFloat(key);
return value == null ? defaultValue : value; return value == null ? defaultValue : value;
} }
@Override
public float getFloatOrThrow(String key) {
return nonnull(key, getFloat(key));
}
@Override @Override
public Double getDouble(String key) { public Double getDouble(String key) {
@ -149,12 +131,6 @@ public class ConfigImpl implements Config {
Double value = getDouble(key); Double value = getDouble(key);
return value == null ? defaultValue : value; return value == null ? defaultValue : value;
} }
@Override
public double getDoubleOrThrow(String key) {
return nonnull(key, getDouble(key));
}
@Override @Override
public BigDecimal getBigDecimal(String key) { public BigDecimal getBigDecimal(String key) {
@ -176,11 +152,6 @@ public class ConfigImpl implements Config {
return value == null ? defaultValue : value; return value == null ? defaultValue : value;
} }
@Override
public BigDecimal getBigDecimalOrThrow(String key) {
return nonnull(key, getBigDecimal(key));
}
@Override @Override
public boolean getBooleanOrFalse(String key) { public boolean getBooleanOrFalse(String key) {
return parseBoolean(cleanString(key), false); return parseBoolean(cleanString(key), false);
@ -191,19 +162,6 @@ public class ConfigImpl implements Config {
return parseBoolean(cleanString(key), true); return parseBoolean(cleanString(key), true);
} }
@Override
public boolean getBooleanOrThrow(String key) {
String value = nonnull(key, cleanString(key));
value = value.toLowerCase();
if (value.equals("yes") || value.equals("true")) {
return true;
}
if (value.equals("no") || value.equals("false")) {
return false;
}
throw new ConfigMissingException("Unrecognized boolean value for config key: " + key);
}
@Override @Override
public String sources() { public String sources() {
return sources; return sources;

View file

@ -9,36 +9,36 @@ import java.util.function.Supplier;
/** /**
* Pull configuration properties from various sources and filter/manipulate them. * Pull configuration properties from various sources and filter/manipulate them.
*/ */
public interface ConfigFrom extends Supplier<Config> { public interface ConfigSupplier extends Supplier<Config> {
/** /**
* Convenience method for fluent syntax. * Convenience method for fluent syntax.
* *
* @return a builder for specifying from where configuration should be loaded * @return a builder for specifying from where configuration should be loaded
*/ */
static ConfigFrom firstOf() { static ConfigSupplier of() {
return new ConfigFromImpl(); return new ConfigSupplierImpl();
} }
static Config other(Function<String, String> other) { static Config other(Function<String, String> other) {
if (other instanceof Config) { if (other instanceof Config) {
return (Config) other; return (Config) other;
} }
return new ConfigFromImpl().custom(other::apply).get(); return new ConfigSupplierImpl().custom(other::apply).get();
} }
ConfigFrom custom(Function<String, String> keyValueLookup); ConfigSupplier custom(Function<String, String> keyValueLookup);
ConfigFrom value(String key, String value); ConfigSupplier value(String key, String value);
ConfigFrom systemProperties(); ConfigSupplier systemProperties();
ConfigFrom env(); ConfigSupplier env();
ConfigFrom properties(Properties properties); ConfigSupplier properties(Properties properties);
ConfigFrom config(Config config); ConfigSupplier config(Config config);
ConfigFrom config(Supplier<Config> config); ConfigSupplier config(Supplier<Config> config);
/** /**
* Adds a set of properties files to read from, which can be overridden by a system property "properties". * Adds a set of properties files to read from, which can be overridden by a system property "properties".
@ -47,7 +47,7 @@ public interface ConfigFrom extends Supplier<Config> {
* defaultPropertyFiles("properties", "conf/app.properties", "local.properties", "sample.properties") * defaultPropertyFiles("properties", "conf/app.properties", "local.properties", "sample.properties")
* </pre> * </pre>
*/ */
ConfigFrom defaultProperties(); ConfigSupplier defaultProperties();
/** /**
* Adds a set of properties files to read from, which can be overridden by a specified system property. * Adds a set of properties files to read from, which can be overridden by a specified system property.
@ -56,7 +56,7 @@ public interface ConfigFrom extends Supplier<Config> {
* defaultPropertyFiles(systemPropertyKey, Charset.defaultCharset().newDecoder(), filenames) * defaultPropertyFiles(systemPropertyKey, Charset.defaultCharset().newDecoder(), filenames)
* </pre> * </pre>
*/ */
ConfigFrom defaultProperties(String systemPropertyKey, String... filenames); ConfigSupplier defaultProperties(String systemPropertyKey, String... filenames);
/** /**
* Adds a set of properties files to read from, which can be overridden by a specified system property. * Adds a set of properties files to read from, which can be overridden by a specified system property.
@ -67,36 +67,35 @@ public interface ConfigFrom extends Supplier<Config> {
* .split(File.pathSeparator)); * .split(File.pathSeparator));
* </pre> * </pre>
*/ */
ConfigFrom defaultProperties(String systemPropertyKey, CharsetDecoder decoder, String... filenames); ConfigSupplier defaultProperties(String systemPropertyKey, CharsetDecoder decoder, String... filenames);
ConfigFrom properties(String... filenames); ConfigSupplier properties(String... filenames);
ConfigFrom properties(CharsetDecoder decoder, String... filenames); ConfigSupplier properties(CharsetDecoder decoder, String... filenames);
ConfigFrom properties(InputStream... inputStreams); ConfigSupplier properties(InputStream... inputStreams);
ConfigFrom properties(CharsetDecoder decoder, InputStream... inputStreams); ConfigSupplier properties(CharsetDecoder decoder, InputStream... inputStreams);
ConfigFrom rename(String key, String newKey); ConfigSupplier rename(String key, String newKey);
ConfigFrom includeKeys(String... keys); ConfigSupplier includeKeys(String... keys);
ConfigFrom includePrefix(String... prefixes); ConfigSupplier includePrefix(String... prefixes);
ConfigFrom includeRegex(String regex); ConfigSupplier includeRegex(String regex);
ConfigFrom excludeKeys(String... keys); ConfigSupplier excludeKeys(String... keys);
ConfigFrom excludePrefix(String... prefixes); ConfigSupplier excludePrefix(String... prefixes);
ConfigFrom excludeRegex(String regex); ConfigSupplier excludeRegex(String regex);
ConfigFrom removePrefix(String... prefixes); ConfigSupplier removePrefix(String... prefixes);
ConfigFrom addPrefix(String prefix); ConfigSupplier addPrefix(String prefix);
ConfigFrom substitutions(Config config); ConfigSupplier substitutions(Config config);
Config get(); Config get();
} }

View file

@ -15,8 +15,6 @@ import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -24,86 +22,84 @@ import java.util.regex.Pattern;
* Access configuration properties from a variety of standard sources, * Access configuration properties from a variety of standard sources,
* and provide some basic filtering and mapping of property keys. * and provide some basic filtering and mapping of property keys.
*/ */
public class ConfigFromImpl implements ConfigFrom { public class ConfigSupplierImpl implements ConfigSupplier {
private static final Logger logger = Logger.getLogger(ConfigFromImpl.class.getName());
private static final String SEPARATOR = FileSystems.getDefault().getSeparator(); private static final String SEPARATOR = FileSystems.getDefault().getSeparator();
private final List<Config> searchPath = new ArrayList<>(); private final List<Config> searchPath = new ArrayList<>();
public ConfigFromImpl() { public ConfigSupplierImpl() {
super(); super();
} }
public ConfigFromImpl(Config first) { public ConfigSupplierImpl(Config first) {
searchPath.add(first); searchPath.add(first);
} }
@Override @Override
public ConfigFrom custom(Function<String, String> keyValueLookup) { public ConfigSupplier custom(Function<String, String> keyValueLookup) {
return custom(keyValueLookup, "custom()"); return custom(keyValueLookup, "custom()");
} }
private ConfigFrom custom(Function<String, String> keyValueLookup, String source) { private ConfigSupplier custom(Function<String, String> keyValueLookup, String source) {
searchPath.add(new ConfigImpl(keyValueLookup, source)); searchPath.add(new ConfigImpl(keyValueLookup, source));
return this; return this;
} }
@Override @Override
public ConfigFrom value(String key, String value) { public ConfigSupplier value(String key, String value) {
return custom(k -> k.equals(key) ? value : null, "value(" + key + ")"); return custom(k -> k.equals(key) ? value : null, "value(" + key + ")");
} }
@Override @Override
public ConfigFrom config(Config config) { public ConfigSupplier config(Config config) {
searchPath.add(config); searchPath.add(config);
return this; return this;
} }
@Override @Override
public ConfigFrom config(Supplier<Config> config) { public ConfigSupplier config(Supplier<Config> config) {
return config(config.get()); return config(config.get());
} }
@Override @Override
public ConfigFrom systemProperties() { public ConfigSupplier systemProperties() {
return custom(System::getProperty, "systemProperties()"); return custom(System::getProperty, "systemProperties()");
} }
@Override @Override
public ConfigFrom env() { public ConfigSupplier env() {
return custom(System::getenv, "env()"); return custom(System::getenv, "env()");
} }
@Override @Override
public ConfigFrom properties(Properties properties) { public ConfigSupplier properties(Properties properties) {
return custom(properties::getProperty, "properties()"); return custom(properties::getProperty, "properties()");
} }
@Override @Override
public ConfigFrom defaultProperties() { public ConfigSupplier defaultProperties() {
return defaultProperties("properties", "conf/app.properties", "local.properties", "sample.properties"); return defaultProperties("properties", "conf/app.properties", "local.properties", "sample.properties");
} }
@Override @Override
public ConfigFrom defaultProperties(String systemPropertyKey, String... filenames) { public ConfigSupplier defaultProperties(String systemPropertyKey, String... filenames) {
return defaultProperties(systemPropertyKey, Charset.defaultCharset().newDecoder(), filenames); return defaultProperties(systemPropertyKey, Charset.defaultCharset().newDecoder(), filenames);
} }
@Override @Override
public ConfigFrom defaultProperties(String systemPropertyKey, CharsetDecoder decoder, String... filenames) { public ConfigSupplier defaultProperties(String systemPropertyKey, CharsetDecoder decoder, String... filenames) {
String properties = System.getProperty(systemPropertyKey, String.join(SEPARATOR, filenames)); String properties = System.getProperty(systemPropertyKey, String.join(SEPARATOR, filenames));
return properties(Charset.defaultCharset().newDecoder(), properties.split(SEPARATOR)); return properties(Charset.defaultCharset().newDecoder(), properties.split(SEPARATOR));
} }
@Override @Override
public ConfigFrom properties(String... filenames) { public ConfigSupplier properties(String... filenames) {
return properties(Charset.defaultCharset().newDecoder(), filenames); return properties(Charset.defaultCharset().newDecoder(), filenames);
} }
@Override @Override
public ConfigFrom properties(CharsetDecoder decoder, String... filenames) { public ConfigSupplier properties(CharsetDecoder decoder, String... filenames) {
for (String filename : filenames) { for (String filename : filenames) {
if (filename != null) { if (filename != null) {
Path path = Paths.get(filename); Path path = Paths.get(filename);
@ -122,12 +118,12 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom properties(InputStream... inputStreams) { public ConfigSupplier properties(InputStream... inputStreams) {
return properties(Charset.defaultCharset().newDecoder(), inputStreams); return properties(Charset.defaultCharset().newDecoder(), inputStreams);
} }
@Override @Override
public ConfigFrom properties(CharsetDecoder decoder, InputStream... inputStreams) { public ConfigSupplier properties(CharsetDecoder decoder, InputStream... inputStreams) {
for (InputStream inputStream : inputStreams) { for (InputStream inputStream : inputStreams) {
Properties properties = new Properties(); Properties properties = new Properties();
try (InputStreamReader reader = new InputStreamReader(inputStream, decoder)) { try (InputStreamReader reader = new InputStreamReader(inputStream, decoder)) {
@ -141,8 +137,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom rename(String configKey, String newKey) { public ConfigSupplier rename(String configKey, String newKey) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
if (key.equals(configKey)) { if (key.equals(configKey)) {
return null; return null;
} }
@ -154,8 +150,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom includeKeys(String... keys) { public ConfigSupplier includeKeys(String... keys) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
for (String k : keys) { for (String k : keys) {
if (key.equals(k)) { if (key.equals(k)) {
return lookup(key); return lookup(key);
@ -166,8 +162,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom includePrefix(String... prefixes) { public ConfigSupplier includePrefix(String... prefixes) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
for (String prefix : prefixes) { for (String prefix : prefixes) {
if (key.startsWith(prefix)) { if (key.startsWith(prefix)) {
return lookup(key); return lookup(key);
@ -178,8 +174,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom includeRegex(String regex) { public ConfigSupplier includeRegex(String regex) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
if (key.matches(regex)) { if (key.matches(regex)) {
return lookup(key); return lookup(key);
} }
@ -188,8 +184,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom excludeKeys(String... keys) { public ConfigSupplier excludeKeys(String... keys) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
for (String k : keys) { for (String k : keys) {
if (key.equals(k)) { if (key.equals(k)) {
return null; return null;
@ -200,8 +196,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom excludePrefix(String... prefixes) { public ConfigSupplier excludePrefix(String... prefixes) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
for (String prefix : prefixes) { for (String prefix : prefixes) {
if (key.startsWith(prefix)) { if (key.startsWith(prefix)) {
return null; return null;
@ -212,8 +208,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom excludeRegex(String regex) { public ConfigSupplier excludeRegex(String regex) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
if (key.matches(regex)) { if (key.matches(regex)) {
return null; return null;
} }
@ -222,8 +218,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom removePrefix(String... prefixes) { public ConfigSupplier removePrefix(String... prefixes) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
// Give precedence to ones that already lacked the prefix, // Give precedence to ones that already lacked the prefix,
// do an include*() first if you don't want that // do an include*() first if you don't want that
String value = lookup(key); String value = lookup(key);
@ -242,8 +238,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom addPrefix(String prefix) { public ConfigSupplier addPrefix(String prefix) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
if (key.startsWith(prefix)) { if (key.startsWith(prefix)) {
return lookup(key.substring(prefix.length())); return lookup(key.substring(prefix.length()));
} else { } else {
@ -253,8 +249,8 @@ public class ConfigFromImpl implements ConfigFrom {
} }
@Override @Override
public ConfigFrom substitutions(Config config) { public ConfigSupplier substitutions(Config config) {
return new ConfigFromImpl(new ConfigImpl(key -> { return new ConfigSupplierImpl(new ConfigImpl(key -> {
String value = lookup(key); String value = lookup(key);
if (value != null) { if (value != null) {
// matches ${ENV_VAR_NAME} or $ENV_VAR_NAME // matches ${ENV_VAR_NAME} or $ENV_VAR_NAME

View file

@ -2,6 +2,7 @@ package org.xbib.jdbc.query;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -87,7 +88,7 @@ public interface Database extends Supplier<Database> {
* Read the next value from a sequence. This method helps smooth over the * Read the next value from a sequence. This method helps smooth over the
* syntax differences across databases. * syntax differences across databases.
*/ */
Long nextSequenceValue( String sequenceName); Long nextSequenceValue(String sequenceName);
/** /**
* Cause the underlying connection to commit its transaction immediately. This * Cause the underlying connection to commit its transaction immediately. This
@ -159,7 +160,7 @@ public interface Database extends Supplier<Database> {
* @param tableName the table to be checked * @param tableName the table to be checked
* @return true if the table or view exists * @return true if the table or view exists
*/ */
boolean tableExists( String tableName); boolean tableExists(String tableName);
/** /**
* Convenience method to check whether a table or view exists or not. * Convenience method to check whether a table or view exists or not.
@ -171,7 +172,7 @@ public interface Database extends Supplier<Database> {
* @param schemaName the schema expected to contain the table * @param schemaName the schema expected to contain the table
* @return true if the table or view exists * @return true if the table or view exists
*/ */
boolean tableExists( String tableName, String schemaName); boolean tableExists(String tableName, String schemaName);
/** /**
* Convenience method to get all column sizes from a table. * Convenience method to get all column sizes from a table.
@ -213,6 +214,32 @@ public interface Database extends Supplier<Database> {
*/ */
void assertTimeSynchronized(); void assertTimeSynchronized();
Table getPagedRows(Table table);
long getRowsCount(Table table);
long countRows(String statement, Map<String, Object> params);
Table getSingleRow(String statement, Map<String, Object> params);
Table getUnlimitedRows(String statement, Map<String, Object> params);
Table getLimitedRows(String statement, Map<String, Object> params, int limit, int fetchSize, int timeoutSeconds);
void insert(String statement, Map<String, Object> params);
void insert(String statement, List<Map<String, Object>> params);
void update(String statement, Map<String, Object> params);
void update(String statement, List<Map<String, Object>> params);
void upsert(String insertStatement, String updateStatement, Map<String, Object> params);
void delete(String statement, Map<String, Object> params);
void delete(String statement, List<Map<String, Object>> params);
/** /**
* Write data into a queue table, select a channel, and consume the returned primary keys. * Write data into a queue table, select a channel, and consume the returned primary keys.
* *

View file

@ -1,5 +1,6 @@
package org.xbib.jdbc.query; package org.xbib.jdbc.query;
import java.math.BigDecimal;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -9,10 +10,15 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
@ -276,6 +282,253 @@ public class DatabaseImpl implements Database {
assertTimeSynchronized(10000, 30000); assertTimeSynchronized(10000, 30000);
} }
@Override
public Table getPagedRows(Table table) {
if (table == null) {
return table;
}
Map<String, Object> params = table.getParams() != null ?
new HashMap<>(table.getParams()) : new HashMap<>();
if (table.getOffset() != null && table.getSize() != null) {
params.put("offset", table.getOffset());
params.put("limit", table.getSize());
}
String where = table.getWhereClause() != null ? table.getWhereClause() : "";
String groupby = table.getGroupByClause() != null ? table.getGroupByClause() : "";
String orderby = !table.getSort().isEmpty() ? "order by " + table.getSort() : "";
String statement = table.getStatement() + " " + where + " " + groupby + " " + orderby;
if (table.getOffset() != null && table.getSize() != null) {
statement = statement + " offset :offset rows fetch next :limit rows only";
}
return getUnlimitedRows(statement, params);
}
@Override
public long getRowsCount(Table table) {
Map<String, Object> params = new HashMap<>(table.getParams());
String statement = table.getStatement() + " " + table.getWhereClause();
return countRows(statement, params);
}
@Override
public long countRows(String statement, Map<String, Object> params) {
String countStatament = "select count(*) as \"cnt\" from (" + statement + ")";
Table table = getSingleRow(countStatament, params);
if (!table.isEmpty()) {
BigDecimal bigDecimal = table.getValue(0,"cnt");
return bigDecimal.longValue();
} else {
return -1L;
}
}
@Override
public Table getSingleRow(String statement, Map<String, Object> params) {
return getLimitedRows(statement, params, 1, options().fetchSize(), options().timeoutSeconds());
}
@Override
public Table getUnlimitedRows(String statement, Map<String, Object> params) {
return getLimitedRows(statement, params, 0, options().fetchSize(), options().timeoutSeconds());
}
@Override
public Table getLimitedRows(String statement, Map<String, Object> params,
int limit, int fetchSize, int timeoutSeconds) {
SqlSelect sql = toSelect(statement).fetchSize(fetchSize).withTimeoutSeconds(timeoutSeconds);
selectParams(sql, params);
Table table = new Table();
sql.query(rows -> {
ResultSetMetaData md = rows.getMetadata();
List<Object> columnNames = new ArrayList<>();
List<Object> classNames = new ArrayList<>();
for (int i = 1; i <= md.getColumnCount(); i++) {
columnNames.add(md.getColumnName(i).toLowerCase(Locale.ROOT));
classNames.add(md.getColumnClassName(i));
}
table.add(columnNames);
table.add(classNames);
int i = 0;
while (rows.next() && (limit <= 0 || i++ < limit)) {
table.add(getRow(rows, classNames));
}
table.setTotal(rows.rowCount());
return true;
});
return table;
}
@Override
public void insert(String statement, Map<String, Object> params) {
SqlInsert sql = toInsert(statement);
insertParams(sql, params);
sql.insert(1);
}
@Override
public void insert(String statement, List<Map<String, Object>> params) {
SqlInsert sqlInsert = toInsert(statement);
for (Map<String, Object> param : params) {
insertParams(sqlInsert, param);
sqlInsert.batch();
}
sqlInsert.insertBatch();
}
@Override
public void update(String statement, Map<String, Object> params) {
SqlUpdate sql = toUpdate(statement);
updateParams(sql, params);
sql.update();
}
@Override
public void update(String statement, List<Map<String, Object>> params) {
SqlUpdate sqlUpdate = toUpdate(statement);
for (Map<String, Object> param : params) {
updateParams(sqlUpdate, param);
sqlUpdate.update();
}
}
@Override
public void upsert(String insertStatement, String updateStatement, Map<String, Object> params) {
// try insert then update if error
try {
SqlInsert sql = toInsert(insertStatement);
insertParams(sql, params);
sql.insert(1);
} catch (Exception e) {
logger.log(Level.WARNING, e.getMessage(), e);
SqlUpdate sql = toUpdate(updateStatement);
updateParams(sql, params);
sql.update();
}
}
@Override
public void delete(String statement, Map<String, Object> params) {
SqlUpdate sql = toDelete(statement);
updateParams(sql, params);
sql.update();
}
@Override
public void delete(String statement, List<Map<String, Object>> params) {
SqlUpdate sqlUpdate = toDelete(statement);
for (Map<String, Object> param : params) {
updateParams(sqlUpdate, param);
sqlUpdate.update();
}
}
private void selectParams(SqlSelect sql, Map<String, Object> params) {
if (params == null) {
return;
}
params.forEach((k, v) -> {
if (v instanceof String) {
sql.argString(k, (String) v);
} else if (v instanceof Integer) {
sql.argInteger(k, (Integer) v);
} else if (v instanceof Long) {
sql.argLong(k, (Long) v);
} else if (v instanceof Boolean) {
sql.argBoolean(k, (Boolean) v);
} else if (v instanceof LocalDate) {
sql.argLocalDate(k, (LocalDate) v);
} else if (v instanceof LocalDateTime) {
sql.argLocalDateTime(k, (LocalDateTime) v);
} else {
throw new DatabaseException("unknown type for param: " + (v != null ? v.getClass() : "null"));
}
});
}
private void insertParams(SqlInsert sql, Map<String, Object> params) {
if (params == null) {
return;
}
params.forEach((k, v) -> {
if (v instanceof String) {
sql.argString(k, (String) v);
} else if (v instanceof Integer) {
sql.argInteger(k, (Integer) v);
} else if (v instanceof Long) {
sql.argLong(k, (Long) v);
} else if (v instanceof Boolean) {
sql.argBoolean(k, (Boolean) v);
} else if (v instanceof LocalDate) {
sql.argLocalDate(k, (LocalDate) v);
} else if (v instanceof LocalDateTime) {
sql.argLocalDateTime(k, (LocalDateTime) v);
} else {
throw new DatabaseException("unknown type for param: " + (v != null ? v.getClass() : "null"));
}
});
}
private void updateParams(SqlUpdate sql, Map<String, Object> params) {
if (params == null) {
return;
}
params.forEach((k, v) -> {
if (v instanceof String) {
sql.argString(k, (String) v);
} else if (v instanceof Integer) {
sql.argInteger(k, (Integer) v);
} else if (v instanceof Long) {
sql.argLong(k, (Long) v);
} else if (v instanceof Boolean) {
sql.argBoolean(k, (Boolean) v);
} else if (v instanceof LocalDate) {
sql.argLocalDate(k, (LocalDate) v);
} else if (v instanceof LocalDateTime) {
sql.argLocalDateTime(k, (LocalDateTime) v);
} else {
throw new DatabaseException("unknown type for param: " + (v != null ? v.getClass() : "null"));
}
});
}
private List<Object> getRow(Rows rows, List<Object> classNames) {
List<Object> row = new ArrayList<>();
for (int i = 0; i < classNames.size(); i++) {
String className = classNames.get(i).toString();
switch (className) {
case "java.lang.String":
row.add(rows.getStringOrEmpty(i + 1));
break;
case "java.lang.Integer":
row.add(rows.getIntegerOrNull(i + 1));
break;
case "java.lang.Long":
row.add(rows.getLongOrNull(i + 1));
break;
case "java.lang.Boolean":
row.add(rows.getBooleanOrFalse(i + 1));
break;
case "java.sql.Clob":
case "oracle.jdbc.OracleClob":
row.add(rows.getClobStringOrEmpty(i + 1));
break;
case "java.sql.Date":
row.add(rows.getLocalDateOrNull(i + 1));
break;
case "java.sql.Timestamp":
case "oracle.sql.TIMESTAMP":
row.add(rows.getLocalDateTimeOrNull(i + 1));
break;
case "java.math.BigDecimal":
row.add(rows.getBigDecimalOrNull(i + 1));
break;
default:
throw new DatabaseException("unexpected column class name: " + className);
}
}
return row;
}
@Override @Override
public void writeQueue(String table, String channel, String data, Consumer<Long> consumer) throws SQLException { public void writeQueue(String table, String channel, String data, Consumer<Long> consumer) throws SQLException {
writeNextIntoQueue(connection, table, channel, data, consumer); writeNextIntoQueue(connection, table, channel, data, consumer);

View file

@ -29,7 +29,6 @@ public class MixedParameterSql {
if (nameToArg == null) { if (nameToArg == null) {
nameToArg = new HashMap<>(); nameToArg = new HashMap<>();
} }
StringBuilder newSql = new StringBuilder(sql.length()); StringBuilder newSql = new StringBuilder(sql.length());
List<String> argNamesList = new ArrayList<>(); List<String> argNamesList = new ArrayList<>();
List<String> rewrittenArgs = new ArrayList<>(); List<String> rewrittenArgs = new ArrayList<>();
@ -39,26 +38,19 @@ public class MixedParameterSql {
while (searchIndex < sql.length()) { while (searchIndex < sql.length()) {
int nextColonIndex = sql.indexOf(':', searchIndex); int nextColonIndex = sql.indexOf(':', searchIndex);
int nextQmIndex = sql.indexOf('?', searchIndex); int nextQmIndex = sql.indexOf('?', searchIndex);
if (nextColonIndex < 0 && nextQmIndex < 0) { if (nextColonIndex < 0 && nextQmIndex < 0) {
newSql.append(sql.substring(searchIndex)); newSql.append(sql.substring(searchIndex));
break; break;
} }
if (nextColonIndex >= 0 && (nextQmIndex == -1 || nextColonIndex < nextQmIndex)) { if (nextColonIndex >= 0 && (nextQmIndex == -1 || nextColonIndex < nextQmIndex)) {
// The next parameter we found is a named parameter (":foo")
if (nextColonIndex > sql.length() - 2) { if (nextColonIndex > sql.length() - 2) {
// Probably illegal sql, but handle boundary condition
break; break;
} }
// Allow :: as escape for :
if (sql.charAt(nextColonIndex + 1) == ':') { if (sql.charAt(nextColonIndex + 1) == ':') {
newSql.append(sql, searchIndex, nextColonIndex + 1); newSql.append(sql, searchIndex, nextColonIndex + 1);
searchIndex = nextColonIndex + 2; searchIndex = nextColonIndex + 2;
continue; continue;
} }
int endOfNameIndex = nextColonIndex + 1; int endOfNameIndex = nextColonIndex + 1;
while (endOfNameIndex < sql.length() && Character.isJavaIdentifierPart(sql.charAt(endOfNameIndex))) { while (endOfNameIndex < sql.length() && Character.isJavaIdentifierPart(sql.charAt(endOfNameIndex))) {
endOfNameIndex++; endOfNameIndex++;
@ -83,15 +75,11 @@ public class MixedParameterSql {
} }
searchIndex = endOfNameIndex; searchIndex = endOfNameIndex;
} else { } else {
// The next parameter we found is a positional parameter ("?")
// Allow ?? as escape for ?
if (nextQmIndex < sql.length() - 1 && sql.charAt(nextQmIndex + 1) == '?') { if (nextQmIndex < sql.length() - 1 && sql.charAt(nextQmIndex + 1) == '?') {
newSql.append(sql, searchIndex, nextQmIndex + 1); newSql.append(sql, searchIndex, nextQmIndex + 1);
searchIndex = nextQmIndex + 2; searchIndex = nextQmIndex + 2;
continue; continue;
} }
newSql.append(sql, searchIndex, nextQmIndex); newSql.append(sql, searchIndex, nextQmIndex);
if (currentPositionalArg >= positionalArgs.size()) { if (currentPositionalArg >= positionalArgs.size()) {
throw new DatabaseException("Not enough positional parameters (" + positionalArgs.size() + ") were provided"); throw new DatabaseException("Not enough positional parameters (" + positionalArgs.size() + ") were provided");
@ -108,8 +96,6 @@ public class MixedParameterSql {
} }
this.sqlToExecute = newSql.toString(); this.sqlToExecute = newSql.toString();
args = argsList.toArray(new Object[argsList.size()]); args = argsList.toArray(new Object[argsList.size()]);
// Sanity check number of arguments to provide a better error message
if (currentPositionalArg != positionalArgs.size()) { if (currentPositionalArg != positionalArgs.size()) {
throw new DatabaseException("Wrong number of positional parameters were provided (expected: " throw new DatabaseException("Wrong number of positional parameters were provided (expected: "
+ currentPositionalArg + ", actual: " + positionalArgs.size() + ")"); + currentPositionalArg + ", actual: " + positionalArgs.size() + ")");
@ -131,5 +117,4 @@ public class MixedParameterSql {
public Object[] getArgs() { public Object[] getArgs() {
return args; return args;
} }
} }

View file

@ -4,9 +4,14 @@ package org.xbib.jdbc.query;
* Control various optional behavior for the database interactions. * Control various optional behavior for the database interactions.
*/ */
public interface Options { public interface Options {
int fetchSize();
int timeoutSeconds();
/** /**
* Control whether the Database object will allow calls to commitNow() * Control whether the Database object will allow calls to commit()
* and rollbackNow(). By default it will throw exceptions if you try to * and rollback(). By default it will throw exceptions if you try to
* call those. * call those.
*/ */
boolean allowTransactionControl(); boolean allowTransactionControl();

View file

@ -13,6 +13,16 @@ public class OptionsDefault implements Options {
this.flavor = flavor; this.flavor = flavor;
} }
@Override
public int fetchSize() {
return 10;
}
@Override
public int timeoutSeconds() {
return 5;
}
@Override @Override
public boolean allowTransactionControl() { public boolean allowTransactionControl() {
return false; return false;

View file

@ -2,7 +2,6 @@ package org.xbib.jdbc.query;
import org.xbib.jdbc.query.flavor.Postgresql; import org.xbib.jdbc.query.flavor.Postgresql;
/** /**
* Base class for selectively overriding another Options object. * Base class for selectively overriding another Options object.
*/ */
@ -41,6 +40,16 @@ public class OptionsOverride implements Options {
return this; return this;
} }
@Override
public int fetchSize() {
return parent.fetchSize();
}
@Override
public int timeoutSeconds() {
return parent.timeoutSeconds();
}
@Override @Override
public boolean allowTransactionControl() { public boolean allowTransactionControl() {
return parent.allowTransactionControl(); return parent.allowTransactionControl();

View file

@ -16,7 +16,7 @@ import java.time.ZoneId;
/** /**
* Safely wrap a ResultSet and provide access to the data it contains. * Safely wrap a ResultSet and provide access to the data it contains.
*/ */
class RowsAdaptor implements Rows { class RowsAdapter implements Rows {
private final ResultSet rs; private final ResultSet rs;
@ -24,7 +24,7 @@ class RowsAdaptor implements Rows {
private int column = 1; private int column = 1;
public RowsAdaptor(ResultSet rs, Options options) { public RowsAdapter(ResultSet rs, Options options) {
this.rs = rs; this.rs = rs;
this.options = options; this.options = options;
} }
@ -71,7 +71,16 @@ class RowsAdaptor implements Rows {
public Boolean getBooleanOrNull(int columnOneBased) { public Boolean getBooleanOrNull(int columnOneBased) {
try { try {
column = columnOneBased + 1; column = columnOneBased + 1;
return toBoolean(rs, columnOneBased); String val = rs.getString(columnOneBased);
if (val == null) {
return null;
} else if (val.equals("Y") || val.equals("1")) {
return Boolean.TRUE;
} else if (val.equals("N") || val.equals("0")) {
return Boolean.FALSE;
} else {
throw new DatabaseException("Reading boolean from column " + columnOneBased + " but the value was not 'Y' or 'N'");
}
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -81,7 +90,16 @@ class RowsAdaptor implements Rows {
public Boolean getBooleanOrNull(String columnName) { public Boolean getBooleanOrNull(String columnName) {
try { try {
column = rs.findColumn(columnName) + 1; column = rs.findColumn(columnName) + 1;
return toBoolean(rs, columnName); String val = rs.getString(columnName);
if (val == null) {
return null;
} else if (val.equals("Y") || val.equals("1")) {
return Boolean.TRUE;
} else if (val.equals("N") || val.equals("0")) {
return Boolean.FALSE;
} else {
throw new DatabaseException("Reading boolean from column \"" + columnName + "\" but the value was not 'Y' or 'N'");
}
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -133,7 +151,6 @@ class RowsAdaptor implements Rows {
return result; return result;
} }
@Override @Override
public Integer getIntegerOrNull() { public Integer getIntegerOrNull() {
return getIntegerOrNull(column++); return getIntegerOrNull(column++);
@ -143,7 +160,8 @@ class RowsAdaptor implements Rows {
public Integer getIntegerOrNull(int columnOneBased) { public Integer getIntegerOrNull(int columnOneBased) {
try { try {
column = columnOneBased + 1; column = columnOneBased + 1;
return toInteger(rs, columnOneBased); int val = rs.getInt(columnOneBased);
return rs.wasNull() ? null : val;
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -153,7 +171,8 @@ class RowsAdaptor implements Rows {
public Integer getIntegerOrNull(String columnName) { public Integer getIntegerOrNull(String columnName) {
try { try {
column = rs.findColumn(columnName) + 1; column = rs.findColumn(columnName) + 1;
return toInteger(rs, columnName); int val = rs.getInt(columnName);
return rs.wasNull() ? null : val;
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -181,7 +200,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public Long getLongOrNull() { public Long getLongOrNull() {
@ -192,7 +210,8 @@ class RowsAdaptor implements Rows {
public Long getLongOrNull(int columnOneBased) { public Long getLongOrNull(int columnOneBased) {
try { try {
column = columnOneBased + 1; column = columnOneBased + 1;
return toLong(rs, columnOneBased); long val = rs.getLong(columnOneBased);
return rs.wasNull() ? null : val;
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -202,7 +221,8 @@ class RowsAdaptor implements Rows {
public Long getLongOrNull(String columnName) { public Long getLongOrNull(String columnName) {
try { try {
column = rs.findColumn(columnName) + 1; column = rs.findColumn(columnName) + 1;
return toLong(rs, columnName); long val = rs.getLong(columnName);
return rs.wasNull() ? null : val;
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -230,7 +250,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public Float getFloatOrNull() { public Float getFloatOrNull() {
@ -241,7 +260,8 @@ class RowsAdaptor implements Rows {
public Float getFloatOrNull(int columnOneBased) { public Float getFloatOrNull(int columnOneBased) {
try { try {
column = columnOneBased + 1; column = columnOneBased + 1;
return toFloat(rs, columnOneBased); float val = rs.getFloat(columnOneBased);
return rs.wasNull() ? null : val;
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -251,7 +271,8 @@ class RowsAdaptor implements Rows {
public Float getFloatOrNull(String columnName) { public Float getFloatOrNull(String columnName) {
try { try {
column = rs.findColumn(columnName) + 1; column = rs.findColumn(columnName) + 1;
return toFloat(rs, columnName); float val = rs.getFloat(columnName);
return rs.wasNull() ? null : val;
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -279,7 +300,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public Double getDoubleOrNull() { public Double getDoubleOrNull() {
@ -290,7 +310,8 @@ class RowsAdaptor implements Rows {
public Double getDoubleOrNull(int columnOneBased) { public Double getDoubleOrNull(int columnOneBased) {
try { try {
column = columnOneBased + 1; column = columnOneBased + 1;
return toDouble(rs, columnOneBased); double val = rs.getDouble(columnOneBased);
return rs.wasNull() ? null : val;
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -300,7 +321,8 @@ class RowsAdaptor implements Rows {
public Double getDoubleOrNull(String columnName) { public Double getDoubleOrNull(String columnName) {
try { try {
column = rs.findColumn(columnName) + 1; column = rs.findColumn(columnName) + 1;
return toDouble(rs, columnName); double val = rs.getDouble(columnName);
return rs.wasNull() ? null : val;
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -328,7 +350,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public BigDecimal getBigDecimalOrNull() { public BigDecimal getBigDecimalOrNull() {
@ -339,7 +360,8 @@ class RowsAdaptor implements Rows {
public BigDecimal getBigDecimalOrNull(int columnOneBased) { public BigDecimal getBigDecimalOrNull(int columnOneBased) {
try { try {
column = columnOneBased + 1; column = columnOneBased + 1;
return toBigDecimal(rs, columnOneBased); BigDecimal val = rs.getBigDecimal(columnOneBased);
return val == null ? null : fixBigDecimal(val);
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -349,18 +371,17 @@ class RowsAdaptor implements Rows {
public BigDecimal getBigDecimalOrNull(String columnName) { public BigDecimal getBigDecimalOrNull(String columnName) {
try { try {
column = rs.findColumn(columnName) + 1; column = rs.findColumn(columnName) + 1;
return toBigDecimal(rs, columnName); BigDecimal val = rs.getBigDecimal(columnName);
return val == null ? null : fixBigDecimal(val);
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
} }
@Override @Override
public BigDecimal getBigDecimalOrZero() { public BigDecimal getBigDecimalOrZero() {
return getBigDecimalOrZero(column++); return getBigDecimalOrZero(column++);
} }
@Override @Override
public BigDecimal getBigDecimalOrZero(int columnOneBased) { public BigDecimal getBigDecimalOrZero(int columnOneBased) {
@ -370,7 +391,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public BigDecimal getBigDecimalOrZero(String columnName) { public BigDecimal getBigDecimalOrZero(String columnName) {
@ -380,7 +400,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public String getStringOrNull() { public String getStringOrNull() {
@ -414,13 +433,11 @@ class RowsAdaptor implements Rows {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
} }
@Override @Override
public String getStringOrEmpty() { public String getStringOrEmpty() {
return getStringOrEmpty(column++); return getStringOrEmpty(column++);
} }
@Override @Override
public String getStringOrEmpty(int columnOneBased) { public String getStringOrEmpty(int columnOneBased) {
@ -430,7 +447,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public String getStringOrEmpty(String columnName) { public String getStringOrEmpty(String columnName) {
@ -440,7 +456,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public String getClobStringOrNull() { public String getClobStringOrNull() {
@ -475,13 +490,11 @@ class RowsAdaptor implements Rows {
} }
} }
@Override @Override
public String getClobStringOrEmpty() { public String getClobStringOrEmpty() {
return getClobStringOrEmpty(column++); return getClobStringOrEmpty(column++);
} }
@Override @Override
public String getClobStringOrEmpty(int columnOneBased) { public String getClobStringOrEmpty(int columnOneBased) {
String result = getClobStringOrNull(columnOneBased); String result = getClobStringOrNull(columnOneBased);
@ -490,7 +503,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public String getClobStringOrEmpty(String columnName) { public String getClobStringOrEmpty(String columnName) {
@ -500,7 +512,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public Reader getClobReaderOrNull() { public Reader getClobReaderOrNull() {
@ -526,13 +537,11 @@ class RowsAdaptor implements Rows {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
} }
@Override @Override
public Reader getClobReaderOrEmpty() { public Reader getClobReaderOrEmpty() {
return getClobReaderOrEmpty(column++); return getClobReaderOrEmpty(column++);
} }
@Override @Override
public Reader getClobReaderOrEmpty(int columnOneBased) { public Reader getClobReaderOrEmpty(int columnOneBased) {
@ -542,7 +551,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public Reader getClobReaderOrEmpty(String columnName) { public Reader getClobReaderOrEmpty(String columnName) {
@ -552,7 +560,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public byte[] getBlobBytesOrNull() { public byte[] getBlobBytesOrNull() {
@ -578,13 +585,11 @@ class RowsAdaptor implements Rows {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
} }
@Override @Override
public byte[] getBlobBytesOrZeroLen() { public byte[] getBlobBytesOrZeroLen() {
return getBlobBytesOrZeroLen(column++); return getBlobBytesOrZeroLen(column++);
} }
@Override @Override
public byte[] getBlobBytesOrZeroLen(int columnOneBased) { public byte[] getBlobBytesOrZeroLen(int columnOneBased) {
@ -594,7 +599,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public byte[] getBlobBytesOrZeroLen(String columnName) { public byte[] getBlobBytesOrZeroLen(String columnName) {
@ -604,7 +608,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public InputStream getBlobInputStreamOrNull() { public InputStream getBlobInputStreamOrNull() {
@ -630,13 +633,11 @@ class RowsAdaptor implements Rows {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
} }
@Override @Override
public InputStream getBlobInputStreamOrEmpty() { public InputStream getBlobInputStreamOrEmpty() {
return getBlobInputStreamOrEmpty(column++); return getBlobInputStreamOrEmpty(column++);
} }
@Override @Override
public InputStream getBlobInputStreamOrEmpty(int columnOneBased) { public InputStream getBlobInputStreamOrEmpty(int columnOneBased) {
@ -646,7 +647,6 @@ class RowsAdaptor implements Rows {
} }
return result; return result;
} }
@Override @Override
public InputStream getBlobInputStreamOrEmpty(String columnName) { public InputStream getBlobInputStreamOrEmpty(String columnName) {
@ -718,7 +718,8 @@ class RowsAdaptor implements Rows {
public LocalDate getLocalDateOrNull(int columnOneBased) { public LocalDate getLocalDateOrNull(int columnOneBased) {
try { try {
column = columnOneBased + 1; column = columnOneBased + 1;
return toLocalDate(rs, columnOneBased); java.sql.Date val = rs.getDate(columnOneBased);
return val == null ? null : val.toLocalDate();
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -728,7 +729,8 @@ class RowsAdaptor implements Rows {
public LocalDate getLocalDateOrNull(String columnName) { public LocalDate getLocalDateOrNull(String columnName) {
try { try {
column = rs.findColumn(columnName) + 1; column = rs.findColumn(columnName) + 1;
return toLocalDate(rs, columnName); java.sql.Date val = rs.getDate(columnName);
return val == null ? null : val.toLocalDate();
} catch (SQLException e) { } catch (SQLException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} }
@ -744,82 +746,6 @@ class RowsAdaptor implements Rows {
} }
} }
private LocalDate toLocalDate(ResultSet rs, int col) throws SQLException {
java.sql.Date val = rs.getDate(col);
return val == null ? null : val.toLocalDate();
}
private LocalDate toLocalDate(ResultSet rs, String col) throws SQLException {
java.sql.Date val = rs.getDate(col);
return val == null ? null : val.toLocalDate();
}
private Boolean toBoolean(ResultSet rs, int col) throws SQLException {
String val = rs.getString(col);
if (val == null) {
return null;
} else if (val.equals("Y") || val.equals("1")) {
return Boolean.TRUE;
} else if (val.equals("N") || val.equals("0")) {
return Boolean.FALSE;
} else {
throw new DatabaseException("Reading boolean from column " + col + " but the value was not 'Y' or 'N'");
}
}
private Boolean toBoolean(ResultSet rs, String col) throws SQLException {
String val = rs.getString(col);
if (val == null) {
return null;
} else if (val.equals("Y") || val.equals("1")) {
return Boolean.TRUE;
} else if (val.equals("N") || val.equals("0")) {
return Boolean.FALSE;
} else {
throw new DatabaseException("Reading boolean from column \"" + col + "\" but the value was not 'Y' or 'N'");
}
}
private Integer toInteger(ResultSet rs, int col) throws SQLException {
int val = rs.getInt(col);
return rs.wasNull() ? null : val;
}
private Integer toInteger(ResultSet rs, String col) throws SQLException {
int val = rs.getInt(col);
return rs.wasNull() ? null : val;
}
private Long toLong(ResultSet rs, int col) throws SQLException {
long val = rs.getLong(col);
return rs.wasNull() ? null : val;
}
private Long toLong(ResultSet rs, String col) throws SQLException {
long val = rs.getLong(col);
return rs.wasNull() ? null : val;
}
private Float toFloat(ResultSet rs, int col) throws SQLException {
float val = rs.getFloat(col);
return rs.wasNull() ? null : val;
}
private Float toFloat(ResultSet rs, String col) throws SQLException {
float val = rs.getFloat(col);
return rs.wasNull() ? null : val;
}
private Double toDouble(ResultSet rs, int col) throws SQLException {
double val = rs.getDouble(col);
return rs.wasNull() ? null : val;
}
private Double toDouble(ResultSet rs, String col) throws SQLException {
double val = rs.getDouble(col);
return rs.wasNull() ? null : val;
}
private BigDecimal fixBigDecimal(BigDecimal val) { private BigDecimal fixBigDecimal(BigDecimal val) {
if (val.scale() > 0) { if (val.scale() > 0) {
val = val.stripTrailingZeros(); val = val.stripTrailingZeros();
@ -829,14 +755,4 @@ class RowsAdaptor implements Rows {
} }
return val; return val;
} }
private BigDecimal toBigDecimal(ResultSet rs, int col) throws SQLException {
BigDecimal val = rs.getBigDecimal(col);
return val == null ? null : fixBigDecimal(val);
}
private BigDecimal toBigDecimal(ResultSet rs, String col) throws SQLException {
BigDecimal val = rs.getBigDecimal(col);
return val == null ? null : fixBigDecimal(val);
}
} }

View file

@ -14,9 +14,13 @@ import java.util.Stack;
* various arg*() calls and replay them later via the apply(sqlArgs) methods. * various arg*() calls and replay them later via the apply(sqlArgs) methods.
*/ */
public class Sql implements SqlInsert.Apply, SqlUpdate.Apply, SqlSelect.Apply { public class Sql implements SqlInsert.Apply, SqlUpdate.Apply, SqlSelect.Apply {
private final StringBuilder sql = new StringBuilder(); private final StringBuilder sql = new StringBuilder();
private final Stack<Boolean> listFirstItem = new Stack<>(); private final Stack<Boolean> listFirstItem = new Stack<>();
private List<SqlArgs> batched; private List<SqlArgs> batched;
private SqlArgs sqlArgs = new SqlArgs(); private SqlArgs sqlArgs = new SqlArgs();
public Sql() { public Sql() {
@ -207,7 +211,6 @@ public class Sql implements SqlInsert.Apply, SqlUpdate.Apply, SqlSelect.Apply {
} }
} }
public Sql listEnd(String sql) { public Sql listEnd(String sql) {
listFirstItem.pop(); listFirstItem.pop();
return append(sql); return append(sql);
@ -220,6 +223,7 @@ public class Sql implements SqlInsert.Apply, SqlUpdate.Apply, SqlSelect.Apply {
/** /**
* Same as sql(), provided for drop-in compatibility with StringBuilder. * Same as sql(), provided for drop-in compatibility with StringBuilder.
*/ */
@Override
public String toString() { public String toString() {
return sql(); return sql();
} }
@ -313,13 +317,11 @@ public class Sql implements SqlInsert.Apply, SqlUpdate.Apply, SqlSelect.Apply {
sqlArgs.argLocalDateTimeNowPerDb(argName); sqlArgs.argLocalDateTimeNowPerDb(argName);
return this; return this;
} }
public Sql argBlobBytes(byte[] arg) { public Sql argBlobBytes(byte[] arg) {
sqlArgs.argBlobBytes(arg); sqlArgs.argBlobBytes(arg);
return this; return this;
} }
public Sql argBlobBytes(String argName, byte[] arg) { public Sql argBlobBytes(String argName, byte[] arg) {
sqlArgs.argBlobBytes(argName, arg); sqlArgs.argBlobBytes(argName, arg);
@ -350,7 +352,6 @@ public class Sql implements SqlInsert.Apply, SqlUpdate.Apply, SqlSelect.Apply {
sqlArgs.argClobReader(arg); sqlArgs.argClobReader(arg);
return this; return this;
} }
public Sql argClobReader( String argName, Reader arg) { public Sql argClobReader( String argName, Reader arg) {
sqlArgs.argClobReader(argName, arg); sqlArgs.argClobReader(argName, arg);
@ -385,9 +386,4 @@ public class Sql implements SqlInsert.Apply, SqlUpdate.Apply, SqlSelect.Apply {
} }
sqlArgs.apply(update); sqlArgs.apply(update);
} }
public enum ColumnType {
Integer, Long, Float, Double, BigDecimal, String, ClobString, ClobStream,
BlobBytes, BlobStream, Date, DateNowPerApp, DateNowPerDb, Boolean
}
} }

View file

@ -140,7 +140,7 @@ public interface SqlInsert {
* unable to return the value from the insert (such as Derby) this will be simulated * unable to return the value from the insert (such as Derby) this will be simulated
* first issuing a select to read the sequence, then an insert. * first issuing a select to read the sequence, then an insert.
*/ */
SqlInsert argPkSeq( String argName, String sequenceName); SqlInsert argPkSeq(String argName, String sequenceName);
SqlInsert argPkLong(Long pkValue); SqlInsert argPkLong(Long pkValue);

View file

@ -602,7 +602,7 @@ public class SqlInsertImpl implements SqlInsert {
} }
rs = ps.getGeneratedKeys(); rs = ps.getGeneratedKeys();
final ResultSet finalRs = rs; final ResultSet finalRs = rs;
T result = handler.process(new RowsAdaptor(finalRs, options)); T result = handler.process(new RowsAdapter(finalRs, options));
metric.checkpoint("read"); metric.checkpoint("read");
isSuccess = true; isSuccess = true;
return result; return result;

View file

@ -608,7 +608,7 @@ public class SqlSelectImpl implements SqlSelect {
rs = ps.executeQuery(); rs = ps.executeQuery();
metric.checkpoint("exec"); metric.checkpoint("exec");
final ResultSet finalRs = rs; final ResultSet finalRs = rs;
T result = handler.process(new RowsAdaptor(finalRs, options)); T result = handler.process(new RowsAdapter(finalRs, options));
metric.checkpoint("read"); metric.checkpoint("read");
isSuccess = true; isSuccess = true;
return result; return result;

View file

@ -0,0 +1,202 @@
package org.xbib.jdbc.query;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@SuppressWarnings("serial")
public class Table extends ArrayList<List<Object>> implements List<List<Object>> {
private String statement;
private Map<String, Object> params;
private String search;
private LocalDateTime from;
private LocalDateTime to;
private Integer offset;
private Integer size;
private List<String> where;
private String whereClause;
private String groupByClause;
private final List<Map.Entry<String, Boolean>> sort = new ArrayList<>();
private long total;
public Table() {
}
public void setStatement(String statement) {
this.statement = statement;
}
public String getStatement() {
return statement;
}
public void setParams(Map<String, Object> params) {
this.params = params;
}
public Map<String, Object> getParams() {
return params;
}
public void setSearch(String search) {
this.search = search;
}
public String getSearch() {
return search;
}
public void setFromDate(LocalDateTime from) {
this.from = from;
}
public LocalDateTime getFromDate() {
return from;
}
public void setToDate(LocalDateTime to) {
this.to = to;
}
public LocalDateTime getToDate() {
return to;
}
public void setOffset(Integer offset) {
this.offset = offset;
}
public Integer getOffset() {
return offset;
}
public void setSize(Integer size) {
this.size = size;
}
public Integer getSize() {
return size;
}
public void setWhere(List<String> where) {
this.where = where;
}
public List<String> getWhere() {
return where;
}
public void setWhereClause(String whereClause) {
this.whereClause = whereClause;
}
public String getWhereClause() {
return whereClause;
}
public void setGroupByClause(String groupByClause) {
this.groupByClause = groupByClause;
}
public String getGroupByClause() {
return groupByClause;
}
public void addSort(String sort) {
addSort(sort, true);
}
public void addSort(String sort, Boolean asc) {
this.sort.add(Map.entry(sort, asc));
}
public String getSort() {
return sort.stream().map(e -> "\"" + e.getKey() + "\"" + " " + (e.getValue() ? "asc" : "desc"))
.collect(Collectors.joining(","));
}
public List<String> getColumnNames() {
return get(0).stream().map(Object::toString).collect(Collectors.toList());
}
public int getColumn(String columnName) {
return get(0).indexOf(columnName);
}
public List<String> getColumnClassNames() {
return get(1).stream().map(Object::toString).collect(Collectors.toList());
}
public String getColumnName(int i) {
return (String) get(0).get(i);
}
public String getColumnClassName(int i) {
return (String) get(1).get(i);
}
public int getRowCount() {
return size() - 2;
}
public int getColumnCount() {
return get(0).size();
}
public List<Object> getRow(int i) {
return get(i + 2);
}
public void getRow(Map<String, Object> map, int i) {
List<Object> row = getRow(i);
for (int c = 0; c < getColumnCount(); c++) {
map.put(getColumnName(c), row.get(c));
}
}
public Object getObject(int row, int col) {
return get(row + 2).get(col);
}
public Object getObject(int row, String columnName) {
int col = getColumn(columnName);
return col >= 0 ? get(row + 2).get(col) : null;
}
@SuppressWarnings("unchecked")
public <T> T getValue(int row, int col) {
return (T) getObject(row, col);
}
@SuppressWarnings("unchecked")
public <T> T getValue(int row, String columnName) {
return (T) getObject(row, columnName);
}
public void setTotal(long total) {
this.total = total;
}
public long getTotal() {
return total;
}
@Override
public boolean isEmpty() {
return super.isEmpty() || size() <= 2;
}
}

View file

@ -2,7 +2,7 @@ package org.xbib.jdbc.query.test;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.jdbc.query.Config; import org.xbib.jdbc.query.Config;
import org.xbib.jdbc.query.ConfigFrom; import org.xbib.jdbc.query.ConfigSupplier;
import java.io.FileWriter; import java.io.FileWriter;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -21,7 +21,7 @@ public class ConfigTest {
@Test @Test
public void testSystemProperties() { public void testSystemProperties() {
System.setProperty("foo", "bar"); System.setProperty("foo", "bar");
Config config = ConfigFrom.firstOf().systemProperties().get(); Config config = ConfigSupplier.of().systemProperties().get();
assertEquals("bar", config.getString("foo")); assertEquals("bar", config.getString("foo"));
assertNull(config.getString("unknown")); assertNull(config.getString("unknown"));
assertEquals("default", config.getString("unknown", "default")); assertEquals("default", config.getString("unknown", "default"));
@ -32,7 +32,7 @@ public class ConfigTest {
Properties properties = new Properties(); Properties properties = new Properties();
properties.setProperty("foo", "bar"); properties.setProperty("foo", "bar");
Config config = ConfigFrom.firstOf().properties(properties).get(); Config config = ConfigSupplier.of().properties(properties).get();
assertEquals("bar", config.getString("foo")); assertEquals("bar", config.getString("foo"));
assertNull(config.getString("unknown")); assertNull(config.getString("unknown"));
@ -53,7 +53,7 @@ public class ConfigTest {
properties.store(new FileWriter(filename2), null); properties.store(new FileWriter(filename2), null);
// Throw a null in here just to make sure it doesn't blow up // Throw a null in here just to make sure it doesn't blow up
Config config = ConfigFrom.firstOf().properties(filename1, null, filename2).get(); Config config = ConfigSupplier.of().properties(filename1, null, filename2).get();
assertEquals(Integer.valueOf(1), config.getInteger("foo")); assertEquals(Integer.valueOf(1), config.getInteger("foo"));
assertEquals(Integer.valueOf(-2), config.getInteger("foo2")); assertEquals(Integer.valueOf(-2), config.getInteger("foo2"));
@ -61,12 +61,12 @@ public class ConfigTest {
assertEquals(5, config.getInteger("unknown", 5)); assertEquals(5, config.getInteger("unknown", 5));
// Now flip the order and verify precedence works // Now flip the order and verify precedence works
config = ConfigFrom.firstOf().properties(filename2, null, filename1).get(); config = ConfigSupplier.of().properties(filename2, null, filename1).get();
assertEquals(Integer.valueOf(2), config.getInteger("foo")); assertEquals(Integer.valueOf(2), config.getInteger("foo"));
assertEquals(Integer.valueOf(-2), config.getInteger("foo2")); assertEquals(Integer.valueOf(-2), config.getInteger("foo2"));
// Same as above tests, but using File version rather than filename String // Same as above tests, but using File version rather than filename String
config = ConfigFrom.firstOf().properties(filename1, "does not exist", filename2).get(); config = ConfigSupplier.of().properties(filename1, "does not exist", filename2).get();
assertEquals(Integer.valueOf(1), config.getInteger("foo")); assertEquals(Integer.valueOf(1), config.getInteger("foo"));
assertEquals(Integer.valueOf(-2), config.getInteger("foo2")); assertEquals(Integer.valueOf(-2), config.getInteger("foo2"));
@ -74,44 +74,44 @@ public class ConfigTest {
assertEquals(5, config.getInteger("unknown", 5)); assertEquals(5, config.getInteger("unknown", 5));
// Now flip the order and verify precedence works // Now flip the order and verify precedence works
config = ConfigFrom.firstOf().properties(filename2, null, filename1).get(); config = ConfigSupplier.of().properties(filename2, null, filename1).get();
assertEquals(Integer.valueOf(2), config.getInteger("foo")); assertEquals(Integer.valueOf(2), config.getInteger("foo"));
assertEquals(Integer.valueOf(-2), config.getInteger("foo2")); assertEquals(Integer.valueOf(-2), config.getInteger("foo2"));
} }
@Test @Test
public void testNested() { public void testNested() {
Config config = ConfigFrom.firstOf() Config config = ConfigSupplier.of()
.config(ConfigFrom.firstOf().custom(key -> key.equals("foo") ? "a" : null)) .config(ConfigSupplier.of().custom(key -> key.equals("foo") ? "a" : null))
.config(ConfigFrom.firstOf().custom(key -> key.equals("foo") ? "b" : null)).get(); .config(ConfigSupplier.of().custom(key -> key.equals("foo") ? "b" : null)).get();
assertEquals("a", config.getString("foo")); assertEquals("a", config.getString("foo"));
// Re-mapping prefix in nested config // Re-mapping prefix in nested config
config = ConfigFrom.firstOf() config = ConfigSupplier.of()
.config(ConfigFrom.firstOf().custom(key -> key.equals("a.foo") ? "a" : null).removePrefix("a.")) .config(ConfigSupplier.of().custom(key -> key.equals("a.foo") ? "a" : null).removePrefix("a."))
.config(ConfigFrom.firstOf().custom(key -> key.equals("foo") ? "b" : null)).get(); .config(ConfigSupplier.of().custom(key -> key.equals("foo") ? "b" : null)).get();
assertEquals("a", config.getString("foo")); assertEquals("a", config.getString("foo"));
// Excluding nested config, should skip to next // Excluding nested config, should skip to next
config = ConfigFrom.firstOf() config = ConfigSupplier.of()
.config(ConfigFrom.firstOf().custom(key -> key.equals("a.foo") ? "a" : null).removePrefix("a.").excludeRegex("fo{2}")) .config(ConfigSupplier.of().custom(key -> key.equals("a.foo") ? "a" : null).removePrefix("a.").excludeRegex("fo{2}"))
.config(ConfigFrom.firstOf().custom(key -> key.equals("foo") ? "b" : null)).get(); .config(ConfigSupplier.of().custom(key -> key.equals("foo") ? "b" : null)).get();
assertEquals("b", config.getString("foo")); assertEquals("b", config.getString("foo"));
assertNull(config.getString("foooo")); assertNull(config.getString("foooo"));
config = ConfigFrom.firstOf() config = ConfigSupplier.of()
.config(ConfigFrom.firstOf().custom(key -> key.equals("a.foo") ? "a" : null).excludePrefix("a.", "other.")) .config(ConfigSupplier.of().custom(key -> key.equals("a.foo") ? "a" : null).excludePrefix("a.", "other."))
.config(ConfigFrom.firstOf().custom(key -> key.equals("foo") ? "b" : null).addPrefix("a.")).get(); .config(ConfigSupplier.of().custom(key -> key.equals("foo") ? "b" : null).addPrefix("a.")).get();
assertEquals("b", config.getString("a.foo")); assertEquals("b", config.getString("a.foo"));
assertNull(config.getString("foo")); assertNull(config.getString("foo"));
config = ConfigFrom.firstOf() config = ConfigSupplier.of()
.config(ConfigFrom.firstOf().custom(key -> key.equals("a.foo") ? "a" : null).includePrefix("other.")) .config(ConfigSupplier.of().custom(key -> key.equals("a.foo") ? "a" : null).includePrefix("other."))
.config(ConfigFrom.firstOf().custom(key -> key.equals("foo") ? "b" : null).addPrefix("a.").includeRegex("a.*f.*")).get(); .config(ConfigSupplier.of().custom(key -> key.equals("foo") ? "b" : null).addPrefix("a.").includeRegex("a.*f.*")).get();
assertEquals("b", config.getString("a.foo")); assertEquals("b", config.getString("a.foo"));
assertNull(config.getString("foo")); assertNull(config.getString("foo"));
@ -120,14 +120,14 @@ public class ConfigTest {
@Test @Test
public void testStripPrefixConflict() { public void testStripPrefixConflict() {
Config config = ConfigFrom.firstOf().value("a.foo", "a").value("foo", "bar").removePrefix("a.").get(); Config config = ConfigSupplier.of().value("a.foo", "a").value("foo", "bar").removePrefix("a.").get();
assertEquals("bar", config.getString("foo")); assertEquals("bar", config.getString("foo"));
} }
@Test @Test
public void testException() { public void testException() {
Config config = ConfigFrom.firstOf().custom(key -> { Config config = ConfigSupplier.of().custom(key -> {
throw new SecurityException("Pretending security policy is in place"); throw new SecurityException("Pretending security policy is in place");
}).get(); }).get();
@ -138,12 +138,12 @@ public class ConfigTest {
@Test @Test
public void testTidyValues() { public void testTidyValues() {
Config config = ConfigFrom.firstOf().value("foo", " a ").get(); Config config = ConfigSupplier.of().value("foo", " a ").get();
// Strip whitespace // Strip whitespace
assertEquals("a", config.getString("foo")); assertEquals("a", config.getString("foo"));
config = ConfigFrom.firstOf().value("foo", " ").value("foo", "").value("foo", null).value("foo", "a").get(); config = ConfigSupplier.of().value("foo", " ").value("foo", "").value("foo", null).value("foo", "a").get();
// Skip over the garbage ones // Skip over the garbage ones
assertEquals("a", config.getString("foo")); assertEquals("a", config.getString("foo"));
@ -152,35 +152,35 @@ public class ConfigTest {
@Test @Test
public void testBoolean() { public void testBoolean() {
// Case insensitive, allow either true/false or yes/no // Case insensitive, allow either true/false or yes/no
Config config = ConfigFrom.firstOf().value("foo", "tRuE").get(); Config config = ConfigSupplier.of().value("foo", "tRuE").get();
assertTrue(config.getBooleanOrFalse("foo")); assertTrue(config.getBooleanOrFalse("foo"));
assertTrue(config.getBooleanOrTrue("foo")); assertTrue(config.getBooleanOrTrue("foo"));
assertFalse(config.getBooleanOrFalse("unknown")); assertFalse(config.getBooleanOrFalse("unknown"));
assertTrue(config.getBooleanOrTrue("unknown")); assertTrue(config.getBooleanOrTrue("unknown"));
config = ConfigFrom.firstOf().value("foo", "yEs").get(); config = ConfigSupplier.of().value("foo", "yEs").get();
assertTrue(config.getBooleanOrFalse("foo")); assertTrue(config.getBooleanOrFalse("foo"));
assertTrue(config.getBooleanOrTrue("foo")); assertTrue(config.getBooleanOrTrue("foo"));
assertFalse(config.getBooleanOrFalse("unknown")); assertFalse(config.getBooleanOrFalse("unknown"));
assertTrue(config.getBooleanOrTrue("unknown")); assertTrue(config.getBooleanOrTrue("unknown"));
config = ConfigFrom.firstOf().value("foo", "fAlSe").get(); config = ConfigSupplier.of().value("foo", "fAlSe").get();
assertFalse(config.getBooleanOrFalse("foo")); assertFalse(config.getBooleanOrFalse("foo"));
assertFalse(config.getBooleanOrTrue("foo")); assertFalse(config.getBooleanOrTrue("foo"));
assertFalse(config.getBooleanOrFalse("unknown")); assertFalse(config.getBooleanOrFalse("unknown"));
assertTrue(config.getBooleanOrTrue("unknown")); assertTrue(config.getBooleanOrTrue("unknown"));
config = ConfigFrom.firstOf().value("foo", "nO").get(); config = ConfigSupplier.of().value("foo", "nO").get();
assertFalse(config.getBooleanOrFalse("foo")); assertFalse(config.getBooleanOrFalse("foo"));
assertFalse(config.getBooleanOrTrue("foo")); assertFalse(config.getBooleanOrTrue("foo"));
assertFalse(config.getBooleanOrFalse("unknown")); assertFalse(config.getBooleanOrFalse("unknown"));
assertTrue(config.getBooleanOrTrue("unknown")); assertTrue(config.getBooleanOrTrue("unknown"));
config = ConfigFrom.firstOf().value("foo", "bad value").get(); config = ConfigSupplier.of().value("foo", "bad value").get();
assertFalse(config.getBooleanOrFalse("foo")); assertFalse(config.getBooleanOrFalse("foo"));
assertTrue(config.getBooleanOrTrue("foo")); assertTrue(config.getBooleanOrTrue("foo"));
@ -190,7 +190,7 @@ public class ConfigTest {
@Test @Test
public void testInteger() { public void testInteger() {
Config config = ConfigFrom.firstOf().value("good", "123").value("bad", "hi").get(); Config config = ConfigSupplier.of().value("good", "123").value("bad", "hi").get();
assertEquals(Integer.valueOf(123), config.getInteger("good")); assertEquals(Integer.valueOf(123), config.getInteger("good"));
assertNull(config.getInteger("bad")); assertNull(config.getInteger("bad"));
assertNull(config.getInteger("missing")); assertNull(config.getInteger("missing"));
@ -201,7 +201,7 @@ public class ConfigTest {
@Test @Test
public void testLong() { public void testLong() {
Config config = ConfigFrom.firstOf().value("good", "123").value("bad", "hi").get(); Config config = ConfigSupplier.of().value("good", "123").value("bad", "hi").get();
assertEquals(Long.valueOf(123), config.getLong("good")); assertEquals(Long.valueOf(123), config.getLong("good"));
assertNull(config.getLong("bad")); assertNull(config.getLong("bad"));
@ -213,7 +213,7 @@ public class ConfigTest {
@Test @Test
public void testFloat() { public void testFloat() {
Config config = ConfigFrom.firstOf().value("good", "123.45").value("bad", "hi").get(); Config config = ConfigSupplier.of().value("good", "123.45").value("bad", "hi").get();
assertEquals(Float.valueOf(123.45f), config.getFloat("good")); assertEquals(Float.valueOf(123.45f), config.getFloat("good"));
assertNull(config.getFloat("bad")); assertNull(config.getFloat("bad"));
@ -225,7 +225,7 @@ public class ConfigTest {
@Test @Test
public void testDouble() { public void testDouble() {
Config config = ConfigFrom.firstOf().value("good", "123.45").value("bad", "hi").get(); Config config = ConfigSupplier.of().value("good", "123.45").value("bad", "hi").get();
assertEquals(Double.valueOf(123.45), config.getDouble("good")); assertEquals(Double.valueOf(123.45), config.getDouble("good"));
assertNull(config.getDouble("bad")); assertNull(config.getDouble("bad"));
@ -237,7 +237,7 @@ public class ConfigTest {
@Test @Test
public void testBigDecimal() { public void testBigDecimal() {
Config config = ConfigFrom.firstOf().value("good", "123.45").value("bad", "hi").get(); Config config = ConfigSupplier.of().value("good", "123.45").value("bad", "hi").get();
assertEquals(new BigDecimal("123.45"), config.getBigDecimal("good")); assertEquals(new BigDecimal("123.45"), config.getBigDecimal("good"));
assertNull(config.getBigDecimal("bad")); assertNull(config.getBigDecimal("bad"));

View file

@ -4,7 +4,7 @@ import java.util.logging.Logger;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.jdbc.query.Config; import org.xbib.jdbc.query.Config;
import org.xbib.jdbc.query.ConfigFrom; import org.xbib.jdbc.query.ConfigSupplier;
import org.xbib.jdbc.query.DatabaseProvider; import org.xbib.jdbc.query.DatabaseProvider;
import org.xbib.jdbc.query.OptionsOverride; import org.xbib.jdbc.query.OptionsOverride;
import org.xbib.jdbc.query.Schema; import org.xbib.jdbc.query.Schema;
@ -28,7 +28,7 @@ public class HsqldbTest extends CommonTest {
@Override @Override
protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception { protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception {
String propertiesFile = "hsqldb.properties"; String propertiesFile = "hsqldb.properties";
Config config = ConfigFrom.firstOf() Config config = ConfigSupplier.of()
.properties(getClass().getResourceAsStream(propertiesFile)) .properties(getClass().getResourceAsStream(propertiesFile))
.get(); .get();
return DatabaseProvider.builder(config) return DatabaseProvider.builder(config)

View file

@ -237,24 +237,21 @@ public class RowStub {
return i == null || i; return i == null || i;
} }
@Override @Override
public Integer getIntegerOrNull() { public Integer getIntegerOrNull() {
return toInteger(rows.get(row)[++col]); return (Integer) (rows.get(row)[++col]);
} }
@Override @Override
public Integer getIntegerOrNull(int columnOneBased) { public Integer getIntegerOrNull(int columnOneBased) {
col = columnOneBased; col = columnOneBased;
return toInteger(rows.get(row)[columnOneBased - 1]); return (Integer) (rows.get(row)[columnOneBased - 1]);
} }
@Override @Override
public Integer getIntegerOrNull(String columnName) { public Integer getIntegerOrNull(String columnName) {
col = columnIndexByName(columnName) + 1; col = columnIndexByName(columnName) + 1;
return toInteger(rows.get(row)[columnIndexByName(columnName)]); return (Integer) (rows.get(row)[columnIndexByName(columnName)]);
} }
@Override @Override
@ -275,20 +272,17 @@ public class RowStub {
return i == null ? 0 : i; return i == null ? 0 : i;
} }
@Override @Override
public Long getLongOrNull() { public Long getLongOrNull() {
return toLong(rows.get(row)[++col]); return toLong(rows.get(row)[++col]);
} }
@Override @Override
public Long getLongOrNull(int columnOneBased) { public Long getLongOrNull(int columnOneBased) {
col = columnOneBased; col = columnOneBased;
return toLong(rows.get(row)[columnOneBased - 1]); return toLong(rows.get(row)[columnOneBased - 1]);
} }
@Override @Override
public Long getLongOrNull(String columnName) { public Long getLongOrNull(String columnName) {
col = columnIndexByName(columnName) + 1; col = columnIndexByName(columnName) + 1;
@ -313,20 +307,17 @@ public class RowStub {
return i == null ? 0 : i; return i == null ? 0 : i;
} }
@Override @Override
public Float getFloatOrNull() { public Float getFloatOrNull() {
return toFloat(rows.get(row)[++col]); return toFloat(rows.get(row)[++col]);
} }
@Override @Override
public Float getFloatOrNull(int columnOneBased) { public Float getFloatOrNull(int columnOneBased) {
col = columnOneBased; col = columnOneBased;
return toFloat(rows.get(row)[columnOneBased - 1]); return toFloat(rows.get(row)[columnOneBased - 1]);
} }
@Override @Override
public Float getFloatOrNull(String columnName) { public Float getFloatOrNull(String columnName) {
col = columnIndexByName(columnName) + 1; col = columnIndexByName(columnName) + 1;
@ -351,20 +342,17 @@ public class RowStub {
return i == null ? 0 : i; return i == null ? 0 : i;
} }
@Override @Override
public Double getDoubleOrNull() { public Double getDoubleOrNull() {
return toDouble(rows.get(row)[++col]); return toDouble(rows.get(row)[++col]);
} }
@Override @Override
public Double getDoubleOrNull(int columnOneBased) { public Double getDoubleOrNull(int columnOneBased) {
col = columnOneBased; col = columnOneBased;
return toDouble(rows.get(row)[columnOneBased - 1]); return toDouble(rows.get(row)[columnOneBased - 1]);
} }
@Override @Override
public Double getDoubleOrNull(String columnName) { public Double getDoubleOrNull(String columnName) {
col = columnIndexByName(columnName) + 1; col = columnIndexByName(columnName) + 1;
@ -389,250 +377,212 @@ public class RowStub {
return i == null ? 0 : i; return i == null ? 0 : i;
} }
@Override @Override
public BigDecimal getBigDecimalOrNull() { public BigDecimal getBigDecimalOrNull() {
return toBigDecimal(rows.get(row)[++col]); return toBigDecimal(rows.get(row)[++col]);
} }
@Override @Override
public BigDecimal getBigDecimalOrNull(int columnOneBased) { public BigDecimal getBigDecimalOrNull(int columnOneBased) {
col = columnOneBased; col = columnOneBased;
return toBigDecimal(rows.get(row)[columnOneBased - 1]); return toBigDecimal(rows.get(row)[columnOneBased - 1]);
} }
@Override @Override
public BigDecimal getBigDecimalOrNull(String columnName) { public BigDecimal getBigDecimalOrNull(String columnName) {
col = columnIndexByName(columnName) + 1; col = columnIndexByName(columnName) + 1;
return toBigDecimal(rows.get(row)[columnIndexByName(columnName)]); return toBigDecimal(rows.get(row)[columnIndexByName(columnName)]);
} }
@Override @Override
public BigDecimal getBigDecimalOrZero() { public BigDecimal getBigDecimalOrZero() {
BigDecimal i = getBigDecimalOrNull(); BigDecimal i = getBigDecimalOrNull();
return i == null ? new BigDecimal(0) : i; return i == null ? new BigDecimal(0) : i;
} }
@Override @Override
public BigDecimal getBigDecimalOrZero(int columnOneBased) { public BigDecimal getBigDecimalOrZero(int columnOneBased) {
BigDecimal i = getBigDecimalOrNull(columnOneBased); BigDecimal i = getBigDecimalOrNull(columnOneBased);
return i == null ? new BigDecimal(0) : i; return i == null ? new BigDecimal(0) : i;
} }
@Override @Override
public BigDecimal getBigDecimalOrZero(String columnName) { public BigDecimal getBigDecimalOrZero(String columnName) {
BigDecimal i = getBigDecimalOrNull(columnName); BigDecimal i = getBigDecimalOrNull(columnName);
return i == null ? new BigDecimal(0) : i; return i == null ? new BigDecimal(0) : i;
} }
@Override @Override
public String getStringOrNull() { public String getStringOrNull() {
return toString(rows.get(row)[++col]); return (String) rows.get(row)[++col];
} }
@Override @Override
public String getStringOrNull(int columnOneBased) { public String getStringOrNull(int columnOneBased) {
col = columnOneBased; col = columnOneBased;
return toString(rows.get(row)[columnOneBased - 1]); return (String) rows.get(row)[columnOneBased - 1];
} }
@Override @Override
public String getStringOrNull(String columnName) { public String getStringOrNull(String columnName) {
col = columnIndexByName(columnName) + 1; col = columnIndexByName(columnName) + 1;
return toString(rows.get(row)[columnIndexByName(columnName)]); return (String) rows.get(row)[columnIndexByName(columnName)];
} }
@Override @Override
public String getStringOrEmpty() { public String getStringOrEmpty() {
String i = getStringOrNull(); String i = getStringOrNull();
return i == null ? "" : i; return i == null ? "" : i;
} }
@Override @Override
public String getStringOrEmpty(int columnOneBased) { public String getStringOrEmpty(int columnOneBased) {
String i = getStringOrNull(columnOneBased); String i = getStringOrNull(columnOneBased);
return i == null ? "" : i; return i == null ? "" : i;
} }
@Override @Override
public String getStringOrEmpty(String columnName) { public String getStringOrEmpty(String columnName) {
String i = getStringOrNull(columnName); String i = getStringOrNull(columnName);
return i == null ? "" : i; return i == null ? "" : i;
} }
@Override @Override
public String getClobStringOrNull() { public String getClobStringOrNull() {
return getStringOrNull(); return getStringOrNull();
} }
@Override @Override
public String getClobStringOrNull(int columnOneBased) { public String getClobStringOrNull(int columnOneBased) {
return getStringOrNull(columnOneBased); return getStringOrNull(columnOneBased);
} }
@Override @Override
public String getClobStringOrNull(String columnName) { public String getClobStringOrNull(String columnName) {
return getStringOrNull(columnName); return getStringOrNull(columnName);
} }
@Override @Override
public String getClobStringOrEmpty() { public String getClobStringOrEmpty() {
return getStringOrEmpty(); return getStringOrEmpty();
} }
@Override @Override
public String getClobStringOrEmpty(int columnOneBased) { public String getClobStringOrEmpty(int columnOneBased) {
return getStringOrEmpty(columnOneBased); return getStringOrEmpty(columnOneBased);
} }
@Override @Override
public String getClobStringOrEmpty(String columnName) { public String getClobStringOrEmpty(String columnName) {
return getStringOrEmpty(columnName); return getStringOrEmpty(columnName);
} }
@Override @Override
public Reader getClobReaderOrNull() { public Reader getClobReaderOrNull() {
String s = getStringOrNull(); String s = getStringOrNull();
return s == null ? null : new StringReader(s); return s == null ? null : new StringReader(s);
} }
@Override @Override
public Reader getClobReaderOrNull(int columnOneBased) { public Reader getClobReaderOrNull(int columnOneBased) {
String s = getStringOrNull(columnOneBased); String s = getStringOrNull(columnOneBased);
return s == null ? null : new StringReader(s); return s == null ? null : new StringReader(s);
} }
@Override @Override
public Reader getClobReaderOrNull(String columnName) { public Reader getClobReaderOrNull(String columnName) {
String s = getStringOrNull(columnName); String s = getStringOrNull(columnName);
return s == null ? null : new StringReader(s); return s == null ? null : new StringReader(s);
} }
@Override @Override
public Reader getClobReaderOrEmpty() { public Reader getClobReaderOrEmpty() {
return new StringReader(getStringOrEmpty()); return new StringReader(getStringOrEmpty());
} }
@Override @Override
public Reader getClobReaderOrEmpty(int columnOneBased) { public Reader getClobReaderOrEmpty(int columnOneBased) {
return new StringReader(getStringOrEmpty(columnOneBased)); return new StringReader(getStringOrEmpty(columnOneBased));
} }
@Override @Override
public Reader getClobReaderOrEmpty(String columnName) { public Reader getClobReaderOrEmpty(String columnName) {
return new StringReader(getStringOrEmpty(columnName)); return new StringReader(getStringOrEmpty(columnName));
} }
@Override @Override
public byte[] getBlobBytesOrNull() { public byte[] getBlobBytesOrNull() {
return toBytes(rows.get(row)[++col]); return (byte []) (rows.get(row)[++col]);
} }
@Override @Override
public byte[] getBlobBytesOrNull(int columnOneBased) { public byte[] getBlobBytesOrNull(int columnOneBased) {
col = columnOneBased; col = columnOneBased;
return toBytes(rows.get(row)[columnOneBased - 1]); return (byte []) (rows.get(row)[columnOneBased - 1]);
} }
@Override @Override
public byte[] getBlobBytesOrNull(String columnName) { public byte[] getBlobBytesOrNull(String columnName) {
col = columnIndexByName(columnName) + 1; col = columnIndexByName(columnName) + 1;
return toBytes(rows.get(row)[columnIndexByName(columnName)]); return (byte []) (rows.get(row)[columnIndexByName(columnName)]);
} }
@Override @Override
public byte[] getBlobBytesOrZeroLen() { public byte[] getBlobBytesOrZeroLen() {
byte[] a = getBlobBytesOrNull(); byte[] a = getBlobBytesOrNull();
return a == null ? new byte[0] : a; return a == null ? new byte[0] : a;
} }
@Override @Override
public byte[] getBlobBytesOrZeroLen(int columnOneBased) { public byte[] getBlobBytesOrZeroLen(int columnOneBased) {
byte[] a = getBlobBytesOrNull(columnOneBased); byte[] a = getBlobBytesOrNull(columnOneBased);
return a == null ? new byte[0] : a; return a == null ? new byte[0] : a;
} }
@Override @Override
public byte[] getBlobBytesOrZeroLen(String columnName) { public byte[] getBlobBytesOrZeroLen(String columnName) {
byte[] a = getBlobBytesOrNull(columnName); byte[] a = getBlobBytesOrNull(columnName);
return a == null ? new byte[0] : a; return a == null ? new byte[0] : a;
} }
@Override @Override
public InputStream getBlobInputStreamOrNull() { public InputStream getBlobInputStreamOrNull() {
byte[] a = getBlobBytesOrNull(); byte[] a = getBlobBytesOrNull();
return a == null ? null : new ByteArrayInputStream(a); return a == null ? null : new ByteArrayInputStream(a);
} }
@Override @Override
public InputStream getBlobInputStreamOrNull(int columnOneBased) { public InputStream getBlobInputStreamOrNull(int columnOneBased) {
byte[] a = getBlobBytesOrNull(columnOneBased); byte[] a = getBlobBytesOrNull(columnOneBased);
return a == null ? null : new ByteArrayInputStream(a); return a == null ? null : new ByteArrayInputStream(a);
} }
@Override @Override
public InputStream getBlobInputStreamOrNull(String columnName) { public InputStream getBlobInputStreamOrNull(String columnName) {
byte[] a = getBlobBytesOrNull(columnName); byte[] a = getBlobBytesOrNull(columnName);
return a == null ? null : new ByteArrayInputStream(a); return a == null ? null : new ByteArrayInputStream(a);
} }
@Override @Override
public InputStream getBlobInputStreamOrEmpty() { public InputStream getBlobInputStreamOrEmpty() {
return new ByteArrayInputStream(getBlobBytesOrZeroLen()); return new ByteArrayInputStream(getBlobBytesOrZeroLen());
} }
@Override @Override
public InputStream getBlobInputStreamOrEmpty(int columnOneBased) { public InputStream getBlobInputStreamOrEmpty(int columnOneBased) {
return new ByteArrayInputStream(getBlobBytesOrZeroLen(columnOneBased)); return new ByteArrayInputStream(getBlobBytesOrZeroLen(columnOneBased));
} }
@Override @Override
public InputStream getBlobInputStreamOrEmpty(String columnName) { public InputStream getBlobInputStreamOrEmpty(String columnName) {
return new ByteArrayInputStream(getBlobBytesOrZeroLen(columnName)); return new ByteArrayInputStream(getBlobBytesOrZeroLen(columnName));
} }
@Override @Override
public LocalDateTime getLocalDateTimeOrNull() { public LocalDateTime getLocalDateTimeOrNull() {
return toLocalDateTime(rows.get(row)[++col]); return toLocalDateTime(rows.get(row)[++col]);
} }
@Override @Override
public LocalDateTime getLocalDateTimeOrNull(int columnOneBased) { public LocalDateTime getLocalDateTimeOrNull(int columnOneBased) {
col = columnOneBased; col = columnOneBased;
@ -645,7 +595,6 @@ public class RowStub {
return toLocalDateTime(rows.get(row)[columnOneBased - 1], zoneId); return toLocalDateTime(rows.get(row)[columnOneBased - 1], zoneId);
} }
@Override @Override
public LocalDateTime getLocalDateTimeOrNull(String columnName) { public LocalDateTime getLocalDateTimeOrNull(String columnName) {
col = columnIndexByName(columnName) + 1; col = columnIndexByName(columnName) + 1;
@ -718,10 +667,6 @@ public class RowStub {
return (Boolean) o; return (Boolean) o;
} }
private Integer toInteger(Object o) {
return (Integer) o;
}
private Long toLong(Object o) { private Long toLong(Object o) {
if (o instanceof Integer) { if (o instanceof Integer) {
return ((Integer) o).longValue(); return ((Integer) o).longValue();
@ -762,14 +707,6 @@ public class RowStub {
return (BigDecimal) o; return (BigDecimal) o;
} }
private byte[] toBytes(Object o) {
return (byte[]) o;
}
private String toString(Object o) {
return (String) o;
}
private LocalDateTime toLocalDateTime(Object o) { private LocalDateTime toLocalDateTime(Object o) {
return toLocalDateTime(o, ZoneId.systemDefault()); return toLocalDateTime(o, ZoneId.systemDefault());
} }
@ -800,7 +737,6 @@ public class RowStub {
if (o instanceof String) { if (o instanceof String) {
return LocalDate.parse((String) o); return LocalDate.parse((String) o);
} }
return (LocalDate) o; return (LocalDate) o;
} }
}; };

View file

@ -3,7 +3,7 @@ package org.xbib.jdbc.query.test;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.jdbc.query.Config; import org.xbib.jdbc.query.Config;
import org.xbib.jdbc.query.ConfigFrom; import org.xbib.jdbc.query.ConfigSupplier;
import org.xbib.jdbc.query.DatabaseProvider; import org.xbib.jdbc.query.DatabaseProvider;
import org.xbib.jdbc.query.OptionsOverride; import org.xbib.jdbc.query.OptionsOverride;
import org.xbib.jdbc.query.Schema; import org.xbib.jdbc.query.Schema;
@ -18,7 +18,7 @@ public class SqlServerTest extends CommonTest {
@Override @Override
protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception { protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception {
String propertiesFile = System.getProperty("local.properties", "local.properties"); String propertiesFile = System.getProperty("local.properties", "local.properties");
Config config = ConfigFrom.firstOf() Config config = ConfigSupplier.of()
.systemProperties() .systemProperties()
.properties(propertiesFile) .properties(propertiesFile)
.excludePrefix("database.") .excludePrefix("database.")