mappingInterface, @NotNull StatementMappingOptions options);
- public abstract boolean buildEntitySchema(String tableName, Class> entityClass);
-
- /**
- * Synchronizes proxy mapping models with database.
- * Warning: This tries to update all tables that are part of mapping
- * proxies. Should be used carefully.
- *
- * @return True if synchronization was successful
- */
- @ApiStatus.Experimental
- public abstract boolean synchronizeModel();
-
- /**
- * Synchronizes provided entity schema with the database
- * In other words, it tries to update database schema (table) to match
- * the provided entity schema.
- *
- * @param entitySchema Entity schema
- * @param table Table name
- * @return True if synchronization was successful
- */
- @ApiStatus.Experimental
- public abstract boolean synchronizeModel(TableSchema entitySchema, String table);
- /**
- * Synchronizes provided entity class with the database
- * In other words, it tries to update database schema (table) to match
- * the provided entity schema. This method uses synchronizeModel method
- * with schema generated from the provided entity class.
- *
- * @param entity The entity (model) class
- * @param table Table name
- * @return True if synchronization was successful
- */
- @ApiStatus.Experimental
- public abstract boolean synchronizeModel(Class> entity, String table);
-
- /**
- * Performs new query and returns the result. This result is never null.
- * See: {@link QueryRowsResult#isSuccessful()}
- *
- * Examples:
- *
- * query(Select.of().from("players"), Player.class)
- * .stream()
- * .map(Player::getNickname)
- * .forEach(System.out::println);
- *
- * query(() -> "SELECT * FROM players;");
- *
- * @param query The query to use while constructing query string.
- * @param typeClass Type class of object which will be instantiated and
- * populated with column values.
- * @param Type of objects in result.
- *
- * @return Collection of row objects.
- */
- public abstract QueryRowsResult query(Query query, Class typeClass);
- public abstract QueryRowsResult query(Query query);
- public abstract QueryRowsResult query(String query);
-
- /**
- * Executes given query and returns execution result.
- * This result does not contain any rows. If you want to
- * execute query return result of rows, see method
- * {@link SQLDatabaseConnection#query(Query)}
- *
- * @param query Query to use for building query string.
- * @return Blank rows result that only informs
- * about success state of the request.
- */
- public abstract QueryResult exec(Query query);
- public abstract QueryResult exec(String query);
- @ApiStatus.Experimental
- public abstract Transaction beginTransaction();
- @ApiStatus.Experimental
- public abstract void closeTransaction();
- @ApiStatus.Experimental
- @Nullable
- public abstract Transaction getTransaction();
- /**
- * Enabled caching for this connection.
- *
- * @param cacheManager Cache manager to use.
- */
- @ApiStatus.Experimental
- public abstract void enableCaching(CacheManager cacheManager);
- public abstract boolean isTransactionActive();
- protected abstract DefsVals buildDefsVals(Object obj);
- public abstract boolean isLogSqlErrors();
- public abstract boolean isDebug();
- @ApiStatus.Experimental
- public abstract TableSchemaBuilder getSchemaBuilder(String table);
- @ApiStatus.Experimental
- public abstract SchemaSynchronizer getSchemaSynchronizer();
-
- public UpsertQuery save(final @NotNull String table, final @NotNull Object obj) {
- if(buildDefsVals(obj) == null) throw new IllegalArgumentException("Cannot create save query! (defsVals == null)");
- return save(obj).table(table);
- }
-
- public UpsertQuery save(final @NotNull Object obj) {
- DefsVals defsVals = buildDefsVals(obj);
- if(defsVals == null) return null;
- String[] defs = defsVals.getDefs();
- SQLDatabaseConnectionImpl.UnknownValueWrapper[] vals = defsVals.getVals();
- UpsertQuery upsertQuery = upsert().into(null, defs);
- for(SQLDatabaseConnectionImpl.UnknownValueWrapper wrapper : vals) {
- upsertQuery.appendVal(wrapper.getObject());
- }
- SetStatement setStatement = upsertQuery.onDuplicateKey();
- for(int i = 0; i < defs.length; i++) {
- setStatement.and(defs[i], vals[i].getObject());
- }
-
- return (UpsertQuery) setStatement.getAncestor();
- }
-
- public QueryResult insert(final @NotNull String table, final @NotNull Object obj) {
- DefsVals defsVals = buildDefsVals(obj);
- if (defsVals == null) return new QueryResultImpl(false);
-
- InsertQuery query = insert().into(table, defsVals.getDefs());
- for (SQLDatabaseConnectionImpl.UnknownValueWrapper valueWrapper : defsVals.getVals()) {
- query.appendVal(valueWrapper.getObject());
- }
-
- return query.execute();
- }
-
- // --***-- Query builders --***--
-
- public SelectQuery select(String... cols) {
- return new SelectQuery(this, cols);
+ private final SQLConnectionFactory connectionFactory;
+ @Getter(onMethod_ = {@Nullable})
+ private Connection connection;
+ @Getter(onMethod_ = {@Nullable})
+ private SQLException lastError = null;
+
+ public SQLDatabaseConnection(final @NotNull SQLConnectionFactory connectionFactory) {
+ this.connectionFactory = connectionFactory;
+ this.connection = null;
+
+ SQLConnectionRegistry.register(this);
+ }
+
+ /**
+ * Sets a mapping to use when using {@link SQLDatabaseConnection#createProxy(Class, StatementMappingOptions)}.
+ *
+ * @param mappingFactory Mapping factory to use.
+ */
+ public abstract void setProxyMapping(final @NotNull StatementMappingFactory mappingFactory);
+
+ /**
+ * Sets the schema synchronizer to use with synchronizeModel methods.
+ *
+ * @param synchronizer Schema synchronizer to use
+ */
+ @ApiStatus.Experimental
+ public abstract void setSchemaSynchronizer(SchemaSynchronizer synchronizer);
+
+ @ApiStatus.Experimental
+ public abstract StatementMappingRegistry getMappingRegistry();
+
+ /**
+ * @deprecated Use {@link SQLDatabaseConnection#createProxy(Class)} instead.
+ */
+ @Deprecated
+ public abstract T createGate(Class mappingInterface);
+
+ /**
+ * Constructs a mapping repository based on provided interface.
+ * The interface should follow rules for creating mapping repositories
+ * in this library.
+ *
+ * Example:
+ *
+ * @Table("users")
+ * public interface MyRepository {
+ * @Select("*")
+ * @Where(@Where.Condition(column = "firstname", value = "{First Name}"))
+ * @Limit(1)
+ * Optional<User> getUser(@Placeholder("First Name") String firstName);
+ *
+ * @Select
+ * List<User> getUsers();
+ *
+ * @Delete
+ * QueryResult deleteUsers();
+ * }
+ *
+ * SQLDatabaseConnection connection = ...;
+ * MyRepository repository = connection.createGate(MyRepository.class);
+ *
+ * Optional<User> user = repository.getUser("John");
+ *
+ *
+ * @param mappingInterface Interface to create mapping repository for.
+ * @param Type of mapping repository.
+ * @return Mapping repository.
+ */
+ public abstract T createProxy(Class mappingInterface);
+
+ public abstract T createProxy(Class mappingInterface, @NotNull StatementMappingOptions options);
+
+ public abstract boolean buildEntitySchema(String tableName, Class> entityClass);
+
+ /**
+ * Synchronizes proxy mapping models with database.
+ * Warning: This tries to update all tables that are part of mapping
+ * proxies. Should be used carefully.
+ *
+ * @return True if synchronization was successful
+ */
+ @ApiStatus.Experimental
+ public abstract boolean synchronizeModel();
+
+ /**
+ * Synchronizes provided entity schema with the database
+ * In other words, it tries to update database schema (table) to match
+ * the provided entity schema.
+ *
+ * @param entitySchema Entity schema
+ * @param table Table name
+ * @return True if synchronization was successful
+ */
+ @ApiStatus.Experimental
+ public abstract boolean synchronizeModel(TableSchema entitySchema, String table);
+
+ /**
+ * Synchronizes provided entity class with the database
+ * In other words, it tries to update database schema (table) to match
+ * the provided entity schema. This method uses synchronizeModel method
+ * with schema generated from the provided entity class.
+ *
+ * @param entity The entity (model) class
+ * @param table Table name
+ * @return True if synchronization was successful
+ */
+ @ApiStatus.Experimental
+ public abstract boolean synchronizeModel(Class> entity, String table);
+
+ /**
+ * Performs new query and returns the result. This result is never null.
+ * See: {@link QueryRowsResult#isSuccessful()}
+ *
+ * Examples:
+ *
+ * query(Select.of().from("players"), Player.class)
+ * .stream()
+ * .map(Player::getNickname)
+ * .forEach(System.out::println);
+ *
+ * query(() -> "SELECT * FROM players;");
+ *
+ * @param query The query to use while constructing query string.
+ * @param typeClass Type class of object which will be instantiated and
+ * populated with column values.
+ * @param Type of objects in result.
+ * @return Collection of row objects.
+ */
+ public abstract QueryRowsResult query(Query query, Class typeClass);
+
+ public abstract QueryRowsResult query(Query query);
+
+ public abstract QueryRowsResult query(String query);
+
+ /**
+ * Executes given query and returns execution result.
+ * This result does not contain any rows. If you want to
+ * execute query return result of rows, see method
+ * {@link SQLDatabaseConnection#query(Query)}
+ *
+ * @param query Query to use for building query string.
+ * @return Blank rows result that only informs
+ * about success state of the request.
+ */
+ public abstract QueryResult exec(Query query);
+
+ public abstract QueryResult exec(String query);
+
+ @ApiStatus.Experimental
+ public abstract Transaction beginTransaction();
+
+ @ApiStatus.Experimental
+ public abstract void closeTransaction();
+
+ @ApiStatus.Experimental
+ @Nullable
+ public abstract Transaction getTransaction();
+
+ /**
+ * Enabled caching for this connection.
+ *
+ * @param cacheManager Cache manager to use.
+ */
+ @ApiStatus.Experimental
+ public abstract void enableCaching(CacheManager cacheManager);
+
+ public abstract boolean isTransactionActive();
+
+ protected abstract DefsVals buildDefsVals(Object obj);
+
+ public abstract boolean isLogSqlErrors();
+
+ public abstract boolean isDebug();
+
+ @ApiStatus.Experimental
+ public abstract TableSchemaBuilder getSchemaBuilder(String table);
+
+ @ApiStatus.Experimental
+ public abstract SchemaSynchronizer getSchemaSynchronizer();
+
+ /**
+ * Enables caching for provided milliseconds.
+ * This uses {@link ExpirableEntriesCacheManager} cache manager.
+ *
+ * @param millis The entries expiration in milliseconds
+ * @return This instance
+ */
+ public SQLDatabaseConnection cacheFor(long millis) {
+ enableCaching(new ExpirableEntriesCacheManager(millis));
+ return this;
+ }
+
+ public UpsertQuery save(final @NotNull String table, final @NotNull Object obj) {
+ if (buildDefsVals(obj) == null) throw new IllegalArgumentException("Cannot create save query! (defsVals == null)");
+ return save(obj).table(table);
+ }
+
+ public UpsertQuery save(final @NotNull Object obj) {
+ DefsVals defsVals = buildDefsVals(obj);
+ if (defsVals == null) return null;
+ String[] defs = defsVals.getDefs();
+ SQLDatabaseConnectionImpl.UnknownValueWrapper[] vals = defsVals.getVals();
+ UpsertQuery upsertQuery = upsert().into(null, defs);
+ for (SQLDatabaseConnectionImpl.UnknownValueWrapper wrapper : vals) {
+ upsertQuery.appendVal(wrapper.getObject());
}
-
- public UpdateQuery update() {
- return update(null);
+ SetStatement setStatement = upsertQuery.onDuplicateKey();
+ for (int i = 0; i < defs.length; i++) {
+ setStatement.and(defs[i], vals[i].getObject());
}
- public UpdateQuery update(@Nullable String table) {
- return new UpdateQuery(this, table);
- }
+ return (UpsertQuery) setStatement.getAncestor();
+ }
- public InsertQuery insert() {
- return insert(null);
- }
+ public QueryResult insert(final @NotNull String table, final @NotNull Object obj) {
+ DefsVals defsVals = buildDefsVals(obj);
+ if (defsVals == null) return new QueryResultImpl(false);
- public InsertQuery insert(@Nullable String table) {
- return new InsertQuery(this, table);
+ InsertQuery query = insert().into(table, defsVals.getDefs());
+ for (SQLDatabaseConnectionImpl.UnknownValueWrapper valueWrapper : defsVals.getVals()) {
+ query.appendVal(valueWrapper.getObject());
}
- public UpsertQuery upsert() {
- return upsert(null);
+ return query.execute();
+ }
+
+ // --***-- Query builders --***--
+
+ public SelectQuery select(String... cols) {
+ return new SelectQuery(this, cols);
+ }
+
+ public UpdateQuery update() {
+ return update(null);
+ }
+
+ public UpdateQuery update(@Nullable String table) {
+ return new UpdateQuery(this, table);
+ }
+
+ public InsertQuery insert() {
+ return insert(null);
+ }
+
+ public InsertQuery insert(@Nullable String table) {
+ return new InsertQuery(this, table);
+ }
+
+ public UpsertQuery upsert() {
+ return upsert(null);
+ }
+
+ public UpsertQuery upsert(@Nullable String table) {
+ return new UpsertQuery(this, table);
+ }
+
+ public DeleteQuery delete() {
+ return new DeleteQuery(this);
+ }
+
+ @Override
+ public final boolean connect() {
+ if (isConnected()) disconnect();
+ try {
+ connection = connectionFactory.connect();
+ lastError = null;
+ } catch (SQLException e) {
+ logSqlError(e);
+ connection = null;
+ lastError = e;
}
-
- public UpsertQuery upsert(@Nullable String table) {
- return new UpsertQuery(this, table);
- }
-
- public DeleteQuery delete() {
- return new DeleteQuery(this);
- }
-
- @Override
- public final boolean connect() {
- if(isConnected()) disconnect();
- try {
- connection = connectionFactory.connect();
- lastError = null;
- } catch (SQLException e) {
- logSqlError(e);
- connection = null;
- lastError = e;
- }
- return isConnected();
- }
-
- @Override
- public final void disconnect() {
- if (!isConnected()) return;
- try {
- connection.close();
- lastError = null;
- } catch (SQLException e) {
- logSqlError(e);
- lastError = e;
- }
- }
-
- @Override
- public void close() {
- disconnect();
- }
-
- protected void logSqlError(Exception e) {
- if(isLogSqlErrors()) e.printStackTrace();
- }
-
- @AllArgsConstructor
- @Getter
- protected static class DefsVals {
- private final String[] defs;
- private final SQLDatabaseConnectionImpl.UnknownValueWrapper[] vals;
- }
-
- @AllArgsConstructor
- @Data
- public static class UnknownValueWrapper {
- private Object object;
+ return isConnected();
+ }
+
+ @Override
+ public final void disconnect() {
+ if (!isConnected()) return;
+ try {
+ connection.close();
+ lastError = null;
+ } catch (SQLException e) {
+ logSqlError(e);
+ lastError = e;
}
+ }
+
+ @Override
+ public void close() {
+ disconnect();
+ }
+
+ protected void logSqlError(Exception e) {
+ if (isLogSqlErrors()) e.printStackTrace();
+ }
+
+ @AllArgsConstructor
+ @Getter
+ protected static class DefsVals {
+ private final String[] defs;
+ private final SQLDatabaseConnectionImpl.UnknownValueWrapper[] vals;
+ }
+
+ @AllArgsConstructor
+ @Data
+ public static class UnknownValueWrapper {
+ private Object object;
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/SQLDatabaseConnectionImpl.java b/core/src/main/java/me/zort/sqllib/SQLDatabaseConnectionImpl.java
index 0d34017..da35a24 100644
--- a/core/src/main/java/me/zort/sqllib/SQLDatabaseConnectionImpl.java
+++ b/core/src/main/java/me/zort/sqllib/SQLDatabaseConnectionImpl.java
@@ -62,600 +62,599 @@
@SuppressWarnings("unused")
public class SQLDatabaseConnectionImpl extends PooledSQLDatabaseConnection {
- @NotNull static SQLDatabaseOptions defaultOptions() {
- return new SQLDatabaseOptions(DEFAULT_AUTO_RECONNECT, DEFAULT_DEBUG, DEFAULT_LOG_SQL_ERRORS, DEFAULT_NAMING_STRATEGY, DEFAULT_GSON);
- }
-
- // --***-- Default Constants --***--
-
- public static final String DEFAULT_DRIVER = Defaults.DEFAULT_DRIVER;
- public static final boolean DEFAULT_AUTO_RECONNECT = Defaults.DEFAULT_AUTO_RECONNECT;
- public static final boolean DEFAULT_DEBUG = Defaults.DEFAULT_DEBUG;
- public static final boolean DEFAULT_LOG_SQL_ERRORS = Defaults.DEFAULT_LOG_SQL_ERRORS;
- public static final NamingStrategy DEFAULT_NAMING_STRATEGY = Defaults.DEFAULT_NAMING_STRATEGY;
- public static final Gson DEFAULT_GSON = Defaults.DEFAULT_GSON;
-
- // --***-- Options & Utilities --***--
-
- @Getter
- private final ISQLDatabaseOptions options;
- private final transient List errorStateHandlers;
- private final transient MappingRegistryImpl mappingRegistry;
- private transient StatementMappingFactory mappingFactory;
- private transient ObjectMapper objectMapper;
- private transient CacheManager cacheManager;
- @Setter
- private transient Logger logger;
- @Getter(onMethod_ = {@Nullable, @ApiStatus.Experimental})
- private transient Transaction transaction;
- private transient SchemaSynchronizer schemaSynchronizer;
- private int errorCount = 0;
-
- /**
- * Constructs new instance of this implementation with default
- * options.
- *
- * @see SQLDatabaseConnectionImpl#SQLDatabaseConnectionImpl(SQLConnectionFactory, ISQLDatabaseOptions)
- */
- public SQLDatabaseConnectionImpl(final @NotNull SQLConnectionFactory connectionFactory) {
- this(connectionFactory, null);
- }
-
- /**
- * Constructs new instance of this implementation.
- *
- * @param connectionFactory Factory to use while opening connection.
- * @param options Client options to use.
- */
- public SQLDatabaseConnectionImpl(final @NotNull SQLConnectionFactory connectionFactory, @Nullable ISQLDatabaseOptions options) {
- super(connectionFactory);
- this.options = options == null ? defaultOptions() : options;
- this.objectMapper = new DefaultObjectMapper(this);
- this.mappingFactory = new DefaultStatementMappingFactory();
- this.errorStateHandlers = new CopyOnWriteArrayList<>();
- this.transaction = null;
- this.logger = Logger.getGlobal();
- this.mappingRegistry = new MappingRegistryImpl(this);
-
- setSchemaSynchronizer(new SQLSchemaSynchronizer());
- enableCaching(CacheManager.noCache());
-
- // Default backup value resolvers.
- registerBackupValueResolver(new LinkedOneFieldResolver());
- registerBackupValueResolver(new ConstructorParameterResolver());
- }
-
- /**
- * Registers a backup value resolver to the registry.
- * Backup value resolvers are used when no value is found for mapped
- * field in {@link ObjectMapper}.
- *
- * @param resolver Resolver to register.
- */
- public void registerBackupValueResolver(final @NotNull ObjectMapper.FieldValueResolver resolver) {
- Objects.requireNonNull(resolver, "Resolver cannot be null!");
-
- objectMapper.registerBackupValueResolver(resolver);
- }
-
- /**
- * Sets the object mapper to use.
- * Object mapper maps queries to objects, as specified in {@link SQLDatabaseConnection#query(Query, Class)}.
- *
- * @param objectMapper Object mapper to use.
- */
- public void setObjectMapper(final @NotNull ObjectMapper objectMapper) {
- this.objectMapper = Objects.requireNonNull(objectMapper, "Object mapper cannot be null!");
- }
-
- /**
- * Sets a mapping to use when using {@link SQLDatabaseConnection#createProxy(Class, StatementMappingOptions)}.
- *
- * @param mappingFactory Mapping factory to use.
- */
- public void setProxyMapping(final @NotNull StatementMappingFactory mappingFactory) {
- this.mappingFactory = Objects.requireNonNull(mappingFactory, "Mapping factory cannot be null!");
- }
-
- /**
- * Adds an error state observer to the list of observers to be
- * notified when a fatal error occurs.
- *
- * @param observer Observer to add.
- */
- public void addErrorHandler(final @NotNull ErrorStateObserver observer) {
- this.errorStateHandlers.add(observer);
- }
-
- /**
- * Enabled caching for this connection.
- *
- * @param cacheManager Cache manager to use.
- */
- @ApiStatus.Experimental
- @Override
- public void enableCaching(CacheManager cacheManager) {
- this.cacheManager = cacheManager;
- }
-
- /**
- * Synchronizes proxy mapping models with database.
- * Warning: This tries to update all tables that are part of mapping
- * proxies. Should be used carefully.
- *
- * @return True if there were any changes
- */
- @ApiStatus.Experimental
- @Override
- public boolean synchronizeModel() {
- return mappingRegistry.getProxyInstances()
- .stream().flatMap(i -> i.getTableSchemas(
- getOptions().getNamingStrategy(),
- this instanceof SQLiteDatabaseConnection).stream())
- .anyMatch(schema -> synchronizeModel(schema, schema.getTable()));
- }
-
- /**
- * Synchronizes provided entity schema with the database
- * In other words, it tries to update database schema (table) to match
- * the provided entity schema.
- *
- * @param entitySchema Entity schema
- * @param table Table name
- * @return True if there were any changes
- */
- @ApiStatus.Experimental
- @Override
- public boolean synchronizeModel(TableSchema entitySchema, String table) {
- QueryResult result = getSchemaSynchronizer().synchronize(this, entitySchema,
- getSchemaBuilder(table).buildTableSchema());
- return result != QueryResult.noChangesResult && result.isSuccessful();
- }
-
- /**
- * Synchronizes provided entity class with the database
- * In other words, it tries to update database schema (table) to match
- * the provided entity schema. This method uses synchronizeModel method
- * with schema generated from the provided entity class.
- *
- * @param entity The entity (model) class
- * @param table Table name
- * @return True if there were any changes
- */
- @ApiStatus.Experimental
- @Override
- public boolean synchronizeModel(Class> entity, String table) {
- return synchronizeModel(new EntitySchemaBuilder(table, entity,
- getOptions().getNamingStrategy(),
- this instanceof SQLiteDatabaseConnection).buildTableSchema(), table);
- }
-
- /**
- * Sets the schema synchronizer to use with synchronizeModel methods.
- *
- * @param synchronizer Schema synchronizer to use
- */
- @ApiStatus.Experimental
- @Override
- public void setSchemaSynchronizer(SchemaSynchronizer synchronizer) {
- this.schemaSynchronizer = synchronizer;
- }
-
- @ApiStatus.Experimental
- @Override
- public SchemaSynchronizer getSchemaSynchronizer() {
- return schemaSynchronizer;
- }
-
- @ApiStatus.Experimental
- @Override
- public StatementMappingRegistry getMappingRegistry() {
- return mappingRegistry;
- }
-
- /**
- * Constructs a mapping proxy based on provided interface.
- * The interface should follow rules for creating mapping repositories
- * in this library.
- *
- * @param mappingInterface Interface to create mapping repository for.
- * @return Mapping repository.
- * @param Type of mapping repository.
- *
- * @see SQLDatabaseConnection#createProxy(Class, StatementMappingOptions)
- */
- public T createProxy(Class mappingInterface) {
- return createProxy(mappingInterface, new StatementMappingOptions.Builder().build());
- }
-
- /**
- * Replaced with {@link SQLDatabaseConnection#createProxy(Class)}.
- *
- * @deprecated Will be removed in future releases.
- */
- @Deprecated
- @Override
- public T createGate(Class mappingInterface) {
- return createProxy(mappingInterface);
- }
-
- /**
- * Constructs a mapping repository based on provided interface.
- * The interface should follow rules for creating mapping repositories
- * in this library.
- *
- * Example:
- *
- * @Table("users")
- * public interface MyRepository {
- * @Select("*")
- * @Where(@Where.Condition(column = "firstname", value = "{First Name}"))
- * @Limit(1)
- * Optional<User> getUser(@Placeholder("First Name") String firstName);
- *
- * @Select
- * List<User> getUsers();
- *
- * @Delete
- * QueryResult deleteUsers();
- * }
- *
- * SQLDatabaseConnection connection = ...;
- * MyRepository repository = connection.createGate(MyRepository.class);
- *
- * Optional<User> user = repository.getUser("John");
- *
- *
- * @param mappingInterface Interface to create mapping repository for.
- * @return Mapping repository.
- * @param Type of mapping repository.
- */
- @SuppressWarnings("unchecked")
- public final T createProxy(final @NotNull Class mappingInterface, final @NotNull StatementMappingOptions options) {
- Objects.requireNonNull(mappingInterface, "Mapping interface cannot be null!");
- Objects.requireNonNull(options, "Options cannot be null!");
-
- AtomicReference> instanceReference = new AtomicReference<>();
- T rawInstance = (T) Proxy.newProxyInstance(mappingInterface.getClassLoader(),
- new Class[]{mappingInterface}, (proxy, method, args) -> instanceReference.get().invoke(proxy, method, args));
- instanceReference.set(new ProxyInstanceImpl<>(mappingInterface,
- options,
- mappingFactory.strategy(mappingInterface, this),
- mappingFactory.resultAdapter()));
-
- MappingProxyInstance proxyInstanceWrapper = instanceReference.get();
- mappingRegistry.registerProxy(proxyInstanceWrapper);
- return rawInstance;
- }
-
- @ApiStatus.Experimental
- public final boolean buildEntitySchema(final @NotNull String tableName, final @NotNull Class> entityClass) {
- Objects.requireNonNull(entityClass, "Entity class cannot be null!");
-
- EntitySchemaBuilder converter = new EntitySchemaBuilder(tableName, entityClass, options.getNamingStrategy(), this instanceof SQLiteDatabaseConnection);
- String query = converter.buildTableQuery();
-
- return exec(() -> query).isSuccessful();
- }
-
- /**
- * Performs new query and returns the result. This result is never null.
- * This method also maps the result to the specified type using {@link ObjectMapper}.
- * See: {@link QueryRowsResult#isSuccessful()}
- *
- * Examples:
- *
- * query(Select.of().from("players"), Player.class)
- * .stream()
- * .map(Player::getNickname)
- * .forEach(System.out::println);
- *
- * query(() -> "SELECT * FROM players;");
- *
- * @param query The query to use while constructing query string.
- * @param typeClass Type class of object which will be instantiated and
- * populated with column values.
- * @param Type of objects in result.
- *
- * @return Collection of row objects.
- */
- @NotNull
- @Override
- public QueryRowsResult query(final @NotNull Query query, final @NotNull Class typeClass) {
- Objects.requireNonNull(query);
- Objects.requireNonNull(typeClass);
-
- QueryRowsResult resultRows = query(query.getAncestor());
- QueryRowsResult result = new QueryRowsResult<>(resultRows.isSuccessful());
-
- for(Row row : resultRows) {
- Optional.ofNullable(objectMapper.assignValues(row, typeClass))
- .ifPresent(result::add);
+ @NotNull
+ static SQLDatabaseOptions defaultOptions() {
+ return new SQLDatabaseOptions(DEFAULT_AUTO_RECONNECT, DEFAULT_DEBUG, DEFAULT_LOG_SQL_ERRORS, DEFAULT_NAMING_STRATEGY, DEFAULT_GSON);
+ }
+
+ // --***-- Default Constants --***--
+
+ public static final String DEFAULT_DRIVER = Defaults.DEFAULT_DRIVER;
+ public static final boolean DEFAULT_AUTO_RECONNECT = Defaults.DEFAULT_AUTO_RECONNECT;
+ public static final boolean DEFAULT_DEBUG = Defaults.DEFAULT_DEBUG;
+ public static final boolean DEFAULT_LOG_SQL_ERRORS = Defaults.DEFAULT_LOG_SQL_ERRORS;
+ public static final NamingStrategy DEFAULT_NAMING_STRATEGY = Defaults.DEFAULT_NAMING_STRATEGY;
+ public static final Gson DEFAULT_GSON = Defaults.DEFAULT_GSON;
+
+ // --***-- Options & Utilities --***--
+
+ @Getter
+ private final ISQLDatabaseOptions options;
+ private final transient List errorStateHandlers;
+ private final transient StatementMappingRegistry mappingRegistry;
+ private transient StatementMappingFactory mappingFactory;
+ private transient ObjectMapper objectMapper;
+ private transient CacheManager cacheManager;
+ @Setter
+ private transient Logger logger;
+ @Getter(onMethod_ = {@Nullable, @ApiStatus.Experimental})
+ private transient Transaction transaction;
+ private transient SchemaSynchronizer schemaSynchronizer;
+ private int errorCount = 0;
+
+ /**
+ * Constructs new instance of this implementation with default
+ * options.
+ *
+ * @see SQLDatabaseConnectionImpl#SQLDatabaseConnectionImpl(SQLConnectionFactory, ISQLDatabaseOptions)
+ */
+ public SQLDatabaseConnectionImpl(final @NotNull SQLConnectionFactory connectionFactory) {
+ this(connectionFactory, null);
+ }
+
+ /**
+ * Constructs new instance of this implementation.
+ *
+ * @param connectionFactory Factory to use while opening connection.
+ * @param options Client options to use.
+ */
+ public SQLDatabaseConnectionImpl(final @NotNull SQLConnectionFactory connectionFactory, @Nullable ISQLDatabaseOptions options) {
+ super(connectionFactory);
+ this.options = options == null ? defaultOptions() : options;
+ this.objectMapper = new DefaultObjectMapper(this);
+ this.mappingFactory = new DefaultStatementMappingFactory();
+ this.errorStateHandlers = new CopyOnWriteArrayList<>();
+ this.transaction = null;
+ this.logger = Logger.getGlobal();
+ this.mappingRegistry = new MappingRegistryImpl(this);
+
+ setSchemaSynchronizer(new SQLSchemaSynchronizer());
+ enableCaching(CacheManager.noCache());
+
+ // Default backup value resolvers.
+ registerBackupValueResolver(new LinkedOneFieldResolver());
+ registerBackupValueResolver(new ConstructorParameterResolver());
+ }
+
+ /**
+ * Registers a backup value resolver to the registry.
+ * Backup value resolvers are used when no value is found for mapped
+ * field in {@link ObjectMapper}.
+ *
+ * @param resolver Resolver to register.
+ */
+ public void registerBackupValueResolver(final @NotNull ObjectMapper.FieldValueResolver resolver) {
+ Objects.requireNonNull(resolver, "Resolver cannot be null!");
+
+ objectMapper.registerBackupValueResolver(resolver);
+ }
+
+ /**
+ * Sets the object mapper to use.
+ * Object mapper maps queries to objects, as specified in {@link SQLDatabaseConnection#query(Query, Class)}.
+ *
+ * @param objectMapper Object mapper to use.
+ */
+ public void setObjectMapper(final @NotNull ObjectMapper objectMapper) {
+ this.objectMapper = Objects.requireNonNull(objectMapper, "Object mapper cannot be null!");
+ }
+
+ /**
+ * Sets a mapping to use when using {@link SQLDatabaseConnection#createProxy(Class, StatementMappingOptions)}.
+ *
+ * @param mappingFactory Mapping factory to use.
+ */
+ public void setProxyMapping(final @NotNull StatementMappingFactory mappingFactory) {
+ this.mappingFactory = Objects.requireNonNull(mappingFactory, "Mapping factory cannot be null!");
+ }
+
+ /**
+ * Adds an error state observer to the list of observers to be
+ * notified when a fatal error occurs.
+ *
+ * @param observer Observer to add.
+ */
+ public void addErrorHandler(final @NotNull ErrorStateObserver observer) {
+ this.errorStateHandlers.add(observer);
+ }
+
+ /**
+ * Enabled caching for this connection.
+ *
+ * @param cacheManager Cache manager to use.
+ */
+ @ApiStatus.Experimental
+ @Override
+ public void enableCaching(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ }
+
+ /**
+ * Synchronizes proxy mapping models with database.
+ * Warning: This tries to update all tables that are part of mapping
+ * proxies. Should be used carefully.
+ *
+ * @return True if there were any changes
+ */
+ @ApiStatus.Experimental
+ @Override
+ public boolean synchronizeModel() {
+ return mappingRegistry.getProxyInstances()
+ .stream().flatMap(i -> i.getTableSchemas(
+ getOptions().getNamingStrategy(),
+ this instanceof SQLiteDatabaseConnection).stream())
+ .anyMatch(schema -> synchronizeModel(schema, schema.getTable()));
+ }
+
+ /**
+ * Synchronizes provided entity schema with the database
+ * In other words, it tries to update database schema (table) to match
+ * the provided entity schema.
+ *
+ * @param entitySchema Entity schema
+ * @param table Table name
+ * @return True if there were any changes
+ */
+ @ApiStatus.Experimental
+ @Override
+ public boolean synchronizeModel(TableSchema entitySchema, String table) {
+ QueryResult result = getSchemaSynchronizer().synchronize(this, entitySchema,
+ getSchemaBuilder(table).buildTableSchema());
+ return result != QueryResult.noChangesResult && result.isSuccessful();
+ }
+
+ /**
+ * Synchronizes provided entity class with the database
+ * In other words, it tries to update database schema (table) to match
+ * the provided entity schema. This method uses synchronizeModel method
+ * with schema generated from the provided entity class.
+ *
+ * @param entity The entity (model) class
+ * @param table Table name
+ * @return True if there were any changes
+ */
+ @ApiStatus.Experimental
+ @Override
+ public boolean synchronizeModel(Class> entity, String table) {
+ return synchronizeModel(new EntitySchemaBuilder(table, entity,
+ getOptions().getNamingStrategy(),
+ this instanceof SQLiteDatabaseConnection).buildTableSchema(), table);
+ }
+
+ /**
+ * Sets the schema synchronizer to use with synchronizeModel methods.
+ *
+ * @param synchronizer Schema synchronizer to use
+ */
+ @ApiStatus.Experimental
+ @Override
+ public void setSchemaSynchronizer(SchemaSynchronizer synchronizer) {
+ this.schemaSynchronizer = synchronizer;
+ }
+
+ @ApiStatus.Experimental
+ @Override
+ public SchemaSynchronizer getSchemaSynchronizer() {
+ return schemaSynchronizer;
+ }
+
+ @ApiStatus.Experimental
+ @Override
+ public StatementMappingRegistry getMappingRegistry() {
+ return mappingRegistry;
+ }
+
+ /**
+ * Constructs a mapping proxy based on provided interface.
+ * The interface should follow rules for creating mapping repositories
+ * in this library.
+ *
+ * @param mappingInterface Interface to create mapping repository for.
+ * @param Type of mapping repository.
+ * @return Mapping repository.
+ * @see SQLDatabaseConnection#createProxy(Class, StatementMappingOptions)
+ */
+ public T createProxy(Class mappingInterface) {
+ return createProxy(mappingInterface, new StatementMappingOptions.Builder().build());
+ }
+
+ /**
+ * Replaced with {@link SQLDatabaseConnection#createProxy(Class)}.
+ *
+ * @deprecated Will be removed in future releases.
+ */
+ @Deprecated
+ @Override
+ public T createGate(Class mappingInterface) {
+ return createProxy(mappingInterface);
+ }
+
+ /**
+ * Constructs a mapping repository based on provided interface.
+ * The interface should follow rules for creating mapping repositories
+ * in this library.
+ *
+ * Example:
+ *
+ * @Table("users")
+ * public interface MyRepository {
+ * @Select("*")
+ * @Where(@Where.Condition(column = "firstname", value = "{First Name}"))
+ * @Limit(1)
+ * Optional<User> getUser(@Placeholder("First Name") String firstName);
+ *
+ * @Select
+ * List<User> getUsers();
+ *
+ * @Delete
+ * QueryResult deleteUsers();
+ * }
+ *
+ * SQLDatabaseConnection connection = ...;
+ * MyRepository repository = connection.createGate(MyRepository.class);
+ *
+ * Optional<User> user = repository.getUser("John");
+ *
+ *
+ * @param mappingInterface Interface to create mapping repository for.
+ * @param Type of mapping repository.
+ * @return Mapping repository.
+ */
+ @SuppressWarnings("unchecked")
+ public final T createProxy(final @NotNull Class mappingInterface, final @NotNull StatementMappingOptions options) {
+ Objects.requireNonNull(mappingInterface, "Mapping interface cannot be null!");
+ Objects.requireNonNull(options, "Options cannot be null!");
+
+ AtomicReference> instanceReference = new AtomicReference<>();
+ T rawInstance = (T) Proxy.newProxyInstance(mappingInterface.getClassLoader(),
+ new Class[]{mappingInterface}, (proxy, method, args) -> instanceReference.get().invoke(proxy, method, args));
+ instanceReference.set(new ProxyInstanceImpl<>(mappingInterface,
+ options,
+ mappingFactory.strategy(mappingInterface, this),
+ mappingFactory.resultAdapter()));
+
+ MappingProxyInstance proxyInstanceWrapper = instanceReference.get();
+ mappingRegistry.registerProxy(proxyInstanceWrapper);
+ return rawInstance;
+ }
+
+ @ApiStatus.Experimental
+ public final boolean buildEntitySchema(final @NotNull String tableName, final @NotNull Class> entityClass) {
+ Objects.requireNonNull(entityClass, "Entity class cannot be null!");
+
+ EntitySchemaBuilder converter = new EntitySchemaBuilder(tableName, entityClass, options.getNamingStrategy(), this instanceof SQLiteDatabaseConnection);
+ String query = converter.buildTableQuery();
+
+ return exec(() -> query).isSuccessful();
+ }
+
+ /**
+ * Performs new query and returns the result. This result is never null.
+ * This method also maps the result to the specified type using {@link ObjectMapper}.
+ * See: {@link QueryRowsResult#isSuccessful()}
+ *
+ * Examples:
+ *
+ * query(Select.of().from("players"), Player.class)
+ * .stream()
+ * .map(Player::getNickname)
+ * .forEach(System.out::println);
+ *
+ * query(() -> "SELECT * FROM players;");
+ *
+ * @param query The query to use while constructing query string.
+ * @param typeClass Type class of object which will be instantiated and
+ * populated with column values.
+ * @param Type of objects in result.
+ * @return Collection of row objects.
+ */
+ @NotNull
+ @Override
+ public QueryRowsResult query(final @NotNull Query query, final @NotNull Class typeClass) {
+ Objects.requireNonNull(query);
+ Objects.requireNonNull(typeClass);
+
+ QueryRowsResult resultRows = query(query.getAncestor());
+ QueryRowsResult result = new QueryRowsResult<>(resultRows.isSuccessful());
+
+ for (Row row : resultRows) {
+ Optional.ofNullable(objectMapper.assignValues(row, typeClass))
+ .ifPresent(result::add);
+ }
+ return result;
+ }
+
+ /**
+ * Performs new query and returns the result. This result is never null.
+ *
+ * @param query The query to use
+ */
+ @NotNull
+ @Override
+ public QueryRowsResult query(final @NotNull Query query) {
+ return query(query, false);
+ }
+
+ public QueryRowsResult query(final @NotNull String query) {
+ return query(() -> query);
+ }
+
+ @SuppressWarnings("unchecked")
+ @NotNull
+ QueryRowsResult query(final @NotNull Query query, boolean isRetry) {
+ Objects.requireNonNull(query);
+ if (!handleAutoReconnect())
+ return new QueryRowsResult<>(false, "Cannot connect to database!");
+
+ QueryResult cachedResult = cacheManager.get(query, false);
+ if (cachedResult instanceof QueryRowsResult) return (QueryRowsResult) cachedResult;
+
+ try (PreparedStatement stmt = buildStatement(query);
+ ResultSet resultSet = stmt.executeQuery()) {
+ QueryRowsResult result = new QueryRowsResult<>(true);
+ while (resultSet.next()) {
+ ResultSetMetaData meta = resultSet.getMetaData();
+ Row row = new Row();
+ for (int i = 1; i <= meta.getColumnCount(); i++) {
+ Object obj = resultSet.getObject(i);
+ if (obj instanceof String) obj = ((String) obj).replaceAll("''", "'");
+ row.put(meta.getColumnName(i), obj);
}
- return result;
- }
-
- /**
- * Performs new query and returns the result. This result is never null.
- *
- * @param query The query to use
- */
- @NotNull
- @Override
- public QueryRowsResult query(final @NotNull Query query) {
- return query(query, false);
- }
-
- public QueryRowsResult query(final @NotNull String query) {
- return query(() -> query);
- }
-
- @SuppressWarnings("unchecked")
- @NotNull
- QueryRowsResult query(final @NotNull Query query, boolean isRetry) {
- Objects.requireNonNull(query);
- if(!handleAutoReconnect())
- return new QueryRowsResult<>(false, "Cannot connect to database!");
-
- QueryResult cachedResult = cacheManager.get(query, false);
- if (cachedResult instanceof QueryRowsResult) return (QueryRowsResult) cachedResult;
-
- try(PreparedStatement stmt = buildStatement(query);
- ResultSet resultSet = stmt.executeQuery()) {
- QueryRowsResult result = new QueryRowsResult<>(true);
- while(resultSet.next()) {
- ResultSetMetaData meta = resultSet.getMetaData();
- Row row = new Row();
- for(int i = 1; i <= meta.getColumnCount(); i++) {
- Object obj = resultSet.getObject(i);
- if(obj instanceof String) obj = ((String) obj).replaceAll("''", "'");
- row.put(meta.getColumnName(i), obj);
- }
- result.add(row);
- }
-
- cacheManager.set(query, result);
- debug(result);
- return result;
- } catch (SQLException e) {
- if (!isRetry && e.getMessage().contains("database connection closed")) {
- reconnect();
- return query(query, true);
- }
-
- logSqlError(e);
- notifyError(ErrorCode.QUERY_FATAL);
- query.errorSignal(e);
- return new QueryRowsResult<>(false, e.getMessage());
+ result.add(row);
+ }
+
+ cacheManager.set(query, result);
+ debug(result);
+ return result;
+ } catch (SQLException e) {
+ if (!isRetry && e.getMessage().contains("database connection closed")) {
+ reconnect();
+ return query(query, true);
+ }
+
+ logSqlError(e);
+ notifyError(ErrorCode.QUERY_FATAL);
+ query.errorSignal(e);
+ return new QueryRowsResult<>(false, e.getMessage());
+ }
+ }
+
+ /**
+ * Executes given query and returns execution result.
+ * This result does not contain any rows. If you want to
+ * execute query return result of rows, see method
+ * {@link SQLDatabaseConnection#query(Query)}
+ *
+ * @param query Query to use for building query string.
+ * @return Blank rows result that only informs
+ * about success state of the request.
+ */
+ public QueryResult exec(final @NotNull Query query) {
+ return exec(query, false);
+ }
+
+ public QueryResult exec(final @NotNull String query) {
+ return exec(() -> query);
+ }
+
+ @NotNull QueryResult exec(final @NotNull Query query, boolean isRetry) {
+ if (!handleAutoReconnect()) {
+ return new QueryResultImpl(false, "Cannot connect to database!");
+ }
+
+ QueryResult cachedResult = cacheManager.get(query, true);
+ if (cachedResult != null) return cachedResult;
+
+ try (PreparedStatement stmt = buildStatement(query)) {
+ stmt.execute();
+ QueryResultImpl result = new QueryResultImpl(true);
+ cacheManager.set(query, result);
+ debug(result);
+ return result;
+ } catch (SQLException e) {
+ if (!isRetry && e.getMessage().contains("database connection closed")) {
+ reconnect();
+ return exec(query, true);
+ }
+
+ logSqlError(e);
+ notifyError(ErrorCode.QUERY_FATAL);
+ query.errorSignal(e);
+ return new QueryResultImpl(false, e.getMessage());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nullable
+ protected final DefsVals buildDefsVals(Object obj) {
+ Objects.requireNonNull(obj);
+
+ Class> aClass = obj.getClass();
+
+ Map fields = new HashMap<>();
+ for (Field field : aClass.getDeclaredFields()) {
+
+ if (Modifier.isTransient(field.getModifiers())) {
+ // Transient fields are ignored.
+ continue;
+ }
+
+ try {
+ field.setAccessible(true);
+ Object o = field.get(obj);
+ if (field.isAnnotationPresent(JsonField.class)) {
+ o = options.getGson().toJson(o);
+ } else if (Validator.validateAutoIncrement(field) && field.get(obj) == null) {
+ // If field is PrimaryKey and autoIncrement true and is null,
+ // We will skip this to use auto increment strategy on SQL server.
+ continue;
}
- }
-
- /**
- * Executes given query and returns execution result.
- * This result does not contain any rows. If you want to
- * execute query return result of rows, see method
- * {@link SQLDatabaseConnection#query(Query)}
- *
- * @param query Query to use for building query string.
- * @return Blank rows result that only informs
- * about success state of the request.
- */
- public QueryResult exec(final @NotNull Query query) {
- return exec(query, false);
- }
-
- public QueryResult exec(final @NotNull String query) {
- return exec(() -> query);
- }
-
- @NotNull QueryResult exec(final @NotNull Query query, boolean isRetry) {
- if(!handleAutoReconnect()) {
- return new QueryResultImpl(false, "Cannot connect to database!");
- }
-
- QueryResult cachedResult = cacheManager.get(query, true);
- if (cachedResult != null) return cachedResult;
-
- try(PreparedStatement stmt = buildStatement(query)) {
- stmt.execute();
- QueryResultImpl result = new QueryResultImpl(true);
- cacheManager.set(query, result);
- debug(result);
- return result;
- } catch (SQLException e) {
- if (!isRetry && e.getMessage().contains("database connection closed")) {
- reconnect();
- return exec(query, true);
- }
-
- logSqlError(e);
- notifyError(ErrorCode.QUERY_FATAL);
- query.errorSignal(e);
- return new QueryResultImpl(false, e.getMessage());
- }
- }
-
- @SuppressWarnings("unchecked")
- @Nullable
- protected final DefsVals buildDefsVals(Object obj) {
- Objects.requireNonNull(obj);
-
- Class> aClass = obj.getClass();
-
- Map fields = new HashMap<>();
- for(Field field : aClass.getDeclaredFields()) {
-
- if(Modifier.isTransient(field.getModifiers())) {
- // Transient fields are ignored.
- continue;
- }
-
- try {
- field.setAccessible(true);
- Object o = field.get(obj);
- if(field.isAnnotationPresent(JsonField.class)) {
- o = options.getGson().toJson(o);
- } else if(Validator.validateAutoIncrement(field) && field.get(obj) == null) {
- // If field is PrimaryKey and autoIncrement true and is null,
- // We will skip this to use auto increment strategy on SQL server.
- continue;
- }
- fields.put(options.getNamingStrategy().fieldNameToColumn(field.getName()), o);
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- return null;
- }
- }
- // I make entry array for indexing safety.
- Map.Entry[] entryArray = fields.entrySet().toArray(new Map.Entry[0]);
- String[] defs = new String[entryArray.length];
- UnknownValueWrapper[] vals = new UnknownValueWrapper[entryArray.length];
- for(int i = 0; i < entryArray.length; i++) {
- defs[i] = entryArray[i].getKey();
- vals[i] = new UnknownValueWrapper(entryArray[i].getValue());
- }
- return new DefsVals(defs, vals);
- }
-
- @ApiStatus.Experimental
- @SneakyThrows(SQLException.class)
- public final Transaction beginTransaction() {
- Connection rawConnection = getConnection();
- if (transaction != null && transaction.isActive()) {
- throw new IllegalStateException("There is already an active transaction!");
- } else if(rawConnection == null) {
- throw new IllegalStateException("Connection is not established!");
- }
- rawConnection.setAutoCommit(false);
- return transaction = new Transaction(this);
- }
-
- @ApiStatus.Experimental
- @SneakyThrows
- public final void closeTransaction() {
- Transaction transaction = getTransaction();
- if (transaction != null && transaction.isActive()) transaction.commit();
- this.transaction = null;
- }
-
- public final void rollback() throws SQLException {
- if (transaction == null || !transaction.isActive()) {
- throw new IllegalStateException("There is no active transaction!");
- }
- transaction.rollback();
- }
-
- @SuppressWarnings("all")
- private boolean handleAutoReconnect() {
- if(options.isAutoReconnect() && !isConnected()) {
- return reconnect();
- }
- return true;
- }
-
- private boolean reconnect() {
- debug("Trying to make a new connection with the database!");
- if(!connect()) {
- debug("Cannot make new connection!");
- return false;
- }
- return true;
- }
-
- public void debug(String message) {
- if(options.isDebug()) logger.info(message);
- }
-
- private void debug(QueryResult result) {
- debug("Query result: " + result);
- if (result instanceof QueryRowsResult) {
- debug("Rows: " + ((QueryRowsResult>) result).size());
- }
- }
-
- @Override
- public void close() {
- if (errorCount > 0 && getAssignedPool() != null) {
- // If there was any error and this connection is part of a pool,
- // we won't return object to the pool, but disconnect.
- disconnect();
- return;
- }
-
- super.close();
- }
+ fields.put(options.getNamingStrategy().fieldNameToColumn(field.getName()), o);
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+ // I make entry array for indexing safety.
+ Map.Entry[] entryArray = fields.entrySet().toArray(new Map.Entry[0]);
+ String[] defs = new String[entryArray.length];
+ UnknownValueWrapper[] vals = new UnknownValueWrapper[entryArray.length];
+ for (int i = 0; i < entryArray.length; i++) {
+ defs[i] = entryArray[i].getKey();
+ vals[i] = new UnknownValueWrapper(entryArray[i].getValue());
+ }
+ return new DefsVals(defs, vals);
+ }
+
+ @ApiStatus.Experimental
+ @SneakyThrows(SQLException.class)
+ public final Transaction beginTransaction() {
+ Connection rawConnection = getConnection();
+ if (transaction != null && transaction.isActive()) {
+ throw new IllegalStateException("There is already an active transaction!");
+ } else if (rawConnection == null) {
+ throw new IllegalStateException("Connection is not established!");
+ }
+ rawConnection.setAutoCommit(false);
+ return transaction = new Transaction(this);
+ }
+
+ @ApiStatus.Experimental
+ @SneakyThrows
+ public final void closeTransaction() {
+ Transaction transaction = getTransaction();
+ if (transaction != null && transaction.isActive()) transaction.commit();
+ this.transaction = null;
+ }
+
+ public final void rollback() throws SQLException {
+ if (transaction == null || !transaction.isActive()) {
+ throw new IllegalStateException("There is no active transaction!");
+ }
+ transaction.rollback();
+ }
+
+ @SuppressWarnings("all")
+ private boolean handleAutoReconnect() {
+ if (options.isAutoReconnect() && !isConnected()) {
+ return reconnect();
+ }
+ return true;
+ }
+
+ private boolean reconnect() {
+ debug("Trying to make a new connection with the database!");
+ if (!connect()) {
+ debug("Cannot make new connection!");
+ return false;
+ }
+ return true;
+ }
+
+ public void debug(String message) {
+ if (options.isDebug()) logger.info(message);
+ }
+
+ private void debug(QueryResult result) {
+ debug("Query result: " + result);
+ if (result instanceof QueryRowsResult) {
+ debug("Rows: " + ((QueryRowsResult>) result).size());
+ }
+ }
+
+ @Override
+ public void close() {
+ if (errorCount > 0 && getAssignedPool() != null) {
+ // If there was any error and this connection is part of a pool,
+ // we won't return object to the pool, but disconnect.
+ disconnect();
+ return;
+ }
+
+ super.close();
+ }
+
+ @Override
+ public final boolean isLogSqlErrors() {
+ return options.isLogSqlErrors();
+ }
+
+ @Override
+ public final boolean isDebug() {
+ return options.isDebug();
+ }
+
+ @Override
+ public final boolean isTransactionActive() {
+ return transaction != null && transaction.isActive();
+ }
+
+ @Override
+ public TableSchemaBuilder getSchemaBuilder(String table) {
+ return new DatabaseSchemaBuilder(q -> {
+ try {
+ return buildStatement(() -> q);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }, table);
+ }
+
+ @SuppressWarnings("all")
+ private void notifyError(int code) {
+ errorCount++;
+ this.errorStateHandlers.forEach(handler -> runCatching(() -> handler.onErrorState(code)));
+ }
+
+ public final SQLDatabaseOptions cloneOptions() {
+ SQLDatabaseOptions cloned = new SQLDatabaseOptions();
+ cloned.setDebug(options.isDebug());
+ cloned.setLogSqlErrors(options.isLogSqlErrors());
+ cloned.setNamingStrategy(options.getNamingStrategy());
+ cloned.setGson(options.getGson());
+ cloned.setAutoReconnect(options.isAutoReconnect());
+ return cloned;
+ }
+
+ @SuppressWarnings("unchecked")
+ private PreparedStatement buildStatement(Query query) throws SQLException {
+ StatementFactory factory = new DefaultStatementFactory(query);
+ if (query instanceof StatementFactory)
+ factory = (StatementFactory) query;
+
+ return factory.prepare(getConnection());
+ }
+
+ @RequiredArgsConstructor
+ static class DefaultStatementFactory implements StatementFactory {
+
+ private final Query query;
@Override
- public final boolean isLogSqlErrors() {
- return options.isLogSqlErrors();
- }
+ public PreparedStatement prepare(Connection connection) throws SQLException {
+ String queryString = query.getAncestor().buildQuery();
- @Override
- public final boolean isDebug() {
- return options.isDebug();
+ SQLConnectionRegistry.debug(connection, "Query: " + queryString);
+ return connection.prepareStatement(queryString);
}
+ }
- @Override
- public final boolean isTransactionActive() {
- return transaction != null && transaction.isActive();
- }
-
- @Override
- public TableSchemaBuilder getSchemaBuilder(String table) {
- return new DatabaseSchemaBuilder(q -> {
- try {
- return buildStatement(() -> q);
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
- }, table);
- }
-
- @SuppressWarnings("all")
- private void notifyError(int code) {
- errorCount++;
- this.errorStateHandlers.forEach(handler -> runCatching(() -> handler.onErrorState(code)));
- }
+ public interface ErrorStateObserver {
+ void onErrorState(int code);
+ }
- public final SQLDatabaseOptions cloneOptions() {
- SQLDatabaseOptions cloned = new SQLDatabaseOptions();
- cloned.setDebug(options.isDebug());
- cloned.setLogSqlErrors(options.isLogSqlErrors());
- cloned.setNamingStrategy(options.getNamingStrategy());
- cloned.setGson(options.getGson());
- cloned.setAutoReconnect(options.isAutoReconnect());
- return cloned;
- }
-
- @SuppressWarnings("unchecked")
- private PreparedStatement buildStatement(Query query) throws SQLException {
- StatementFactory factory = new DefaultStatementFactory(query);
- if (query instanceof StatementFactory)
- factory = (StatementFactory) query;
-
- return factory.prepare(getConnection());
- }
-
- @RequiredArgsConstructor
- static class DefaultStatementFactory implements StatementFactory {
-
- private final Query query;
-
- @Override
- public PreparedStatement prepare(Connection connection) throws SQLException {
- String queryString = query.getAncestor().buildQuery();
-
- SQLConnectionRegistry.debug(connection, "Query: " + queryString);
- return connection.prepareStatement(queryString);
- }
- }
-
- public interface ErrorStateObserver {
- void onErrorState(int code);
- }
-
- public static final class ErrorCode {
- public static final int QUERY_FATAL = 0;
- }
+ public static final class ErrorCode {
+ public static final int QUERY_FATAL = 0;
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/SQLDatabaseOptions.java b/core/src/main/java/me/zort/sqllib/SQLDatabaseOptions.java
index cc5ca30..3424b9a 100644
--- a/core/src/main/java/me/zort/sqllib/SQLDatabaseOptions.java
+++ b/core/src/main/java/me/zort/sqllib/SQLDatabaseOptions.java
@@ -15,25 +15,25 @@
@Data
public final class SQLDatabaseOptions implements ISQLDatabaseOptions {
- private boolean autoReconnect = true;
- private boolean debug = false;
- private boolean logSqlErrors = true;
- private transient NamingStrategy namingStrategy = SQLDatabaseConnectionImpl.DEFAULT_NAMING_STRATEGY;
- private transient Gson gson = Defaults.DEFAULT_GSON;
+ private boolean autoReconnect = true;
+ private boolean debug = false;
+ private boolean logSqlErrors = true;
+ private transient NamingStrategy namingStrategy = SQLDatabaseConnectionImpl.DEFAULT_NAMING_STRATEGY;
+ private transient Gson gson = Defaults.DEFAULT_GSON;
- /**
- * Loads options from a connection.
- *
- * @param connection The connection to load options from.
- */
- @SuppressWarnings("unused")
- public void load(final @NotNull SQLDatabaseConnectionImpl connection) {
- ISQLDatabaseOptions options = connection.getOptions();
- this.autoReconnect = options.isAutoReconnect();
- this.debug = options.isDebug();
- this.logSqlErrors = options.isLogSqlErrors();
- this.namingStrategy = options.getNamingStrategy();
- this.gson = options.getGson();
- }
+ /**
+ * Loads options from a connection.
+ *
+ * @param connection The connection to load options from.
+ */
+ @SuppressWarnings("unused")
+ public void load(final @NotNull SQLDatabaseConnectionImpl connection) {
+ ISQLDatabaseOptions options = connection.getOptions();
+ this.autoReconnect = options.isAutoReconnect();
+ this.debug = options.isDebug();
+ this.logSqlErrors = options.isLogSqlErrors();
+ this.namingStrategy = options.getNamingStrategy();
+ this.gson = options.getGson();
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/SQLiteDatabaseConnection.java b/core/src/main/java/me/zort/sqllib/SQLiteDatabaseConnection.java
index ddb9422..422674f 100644
--- a/core/src/main/java/me/zort/sqllib/SQLiteDatabaseConnection.java
+++ b/core/src/main/java/me/zort/sqllib/SQLiteDatabaseConnection.java
@@ -26,162 +26,166 @@
* @author ZorTik
*/
public class SQLiteDatabaseConnection extends SQLDatabaseConnectionImpl {
- private final SQLiteDatabaseConnection identity = this;
-
- @SuppressWarnings("unused")
- public SQLiteDatabaseConnection(final @NotNull SQLConnectionFactory connectionFactory) {
- super(connectionFactory);
- setup();
+ private final SQLiteDatabaseConnection identity = this;
+
+ @SuppressWarnings("unused")
+ public SQLiteDatabaseConnection(final @NotNull SQLConnectionFactory connectionFactory) {
+ super(connectionFactory);
+ setup();
+ }
+
+ public SQLiteDatabaseConnection(final @NotNull SQLConnectionFactory connectionFactory, @Nullable ISQLDatabaseOptions options) {
+ super(connectionFactory, options);
+ setup();
+ }
+
+ // Adjust behaviour to be compatible with SQLite
+ private void setup() {
+ if (getSchemaSynchronizer() instanceof SQLSchemaSynchronizer) {
+ SQLSchemaSynchronizer schemaSynchronizer = (SQLSchemaSynchronizer) getSchemaSynchronizer();
+ schemaSynchronizer.setColumnQueryBuilder(new SQLiteColumnQueryBuilder(this));
+ schemaSynchronizer.setColumnTypeAdjuster(new SQLiteColumnTypeAdjuster());
+ schemaSynchronizer.setSeparateQueries(true);
+ }
+ }
+
+ /**
+ * Performs an upsert query for defined object
+ * as stated in {@link SQLDatabaseConnection#save(String, Object)}.
+ *
+ * Object needs to have {@link me.zort.sqllib.internal.annotation.PrimaryKey} annotation
+ * set to determine which column is a primary key.
+ *
+ * @param table Table to save into.
+ * @param obj The object to save.
+ * @return Result of the query.
+ */
+ @NotNull
+ @Override
+ public final UpsertQuery save(@NotNull String table, @NotNull Object obj) {
+ DefsVals defsVals = buildDefsVals(obj);
+ if (defsVals == null) throw new IllegalArgumentException("Cannot create save query! (defsVals == null)");
+ String[] defs = defsVals.getDefs();
+ UnknownValueWrapper[] vals = defsVals.getVals();
+
+ debug("Saving object into table " + table + " with definitions " + Arrays.toString(defs) + " and values " + Arrays.toString(vals));
+
+ PrimaryKey primaryKey = null;
+ for (Field field : obj.getClass().getDeclaredFields()) {
+ if (Modifier.isTransient(field.getModifiers())) {
+ continue;
+ }
+ if (field.isAnnotationPresent(me.zort.sqllib.internal.annotation.PrimaryKey.class)) {
+ String colName = getOptions().getNamingStrategy().fieldNameToColumn(field.getName());
+ //int index = Arrays.binarySearch(defs, colName);
+ int index = -1;
+ int i = 0;
+ for (String def : defs) {
+ if (def.equals(colName)) {
+ index = i;
+ break;
+ }
+ i++;
+ }
+ if (index >= 0) {
+ primaryKey = new PrimaryKey(colName, vals[index].getObject() instanceof String
+ ? (String) vals[index].getObject() : String.valueOf(vals[index].getObject()));
+ break;
+ }
+ }
+ }
+ InsertQuery insert = insert().into(table, defs);
+ for (UnknownValueWrapper val : vals) {
+ insert.appendVal(val.getObject());
}
- public SQLiteDatabaseConnection(final @NotNull SQLConnectionFactory connectionFactory, @Nullable ISQLDatabaseOptions options) {
- super(connectionFactory, options);
- setup();
+ if (primaryKey == null) {
+ debug("No primary key found for object " + obj.getClass().getName() + ", so we can't build update condition.");
+ debug("Performing insert query instead: " + insert.buildQuery());
+ return new UpsertQueryDecorator(insert);
}
- private void setup() {
- if (getSchemaSynchronizer() instanceof SQLSchemaSynchronizer) {
- SQLSchemaSynchronizer schemaSynchronizer = (SQLSchemaSynchronizer) getSchemaSynchronizer();
- schemaSynchronizer.setColumnQueryBuilder(new SQLiteColumnQueryBuilder(this));
- schemaSynchronizer.setColumnTypeAdjuster(new SQLiteColumnTypeAdjuster());
- schemaSynchronizer.setSeparateQueries(true);
- }
+ SetStatement setStmt = update().table(table).set();
+ for (int i = 0; i < defs.length; i++) {
+ setStmt.and(defs[i], vals[i].getObject());
+ }
+ UpdateQuery update = setStmt.also()
+ .where().isEqual(primaryKey.getColumn(), primaryKey.getValue())
+ .also();
+ return new UpsertQueryDecorator(upsert(table, primaryKey, insert, update));
+ }
+
+ /**
+ * Builds an upsert query for defined table and primary key.
+ * This returns either a provided insert or update query depending
+ * on upsert situation.
+ *
+ * @param table Table to upsert into.
+ * @param primaryKey Primary key to use.
+ * @param insert Insert query to use.
+ * @param update Update query to use.
+ * @return Either insert or update query.
+ */
+ @Nullable
+ public final QueryNode> upsert(final @NotNull String table,
+ final @NotNull PrimaryKey primaryKey,
+ final @NotNull InsertQuery insert,
+ final @NotNull UpdateQuery update) {
+
+ QueryRowsResult selectResult = select("*")
+ .from(table)
+ .where().isEqual(primaryKey.getColumn(), primaryKey.getValue())
+ .also().limit(1)
+ .obtainAll();
+ if (!selectResult.isSuccessful()) {
+ // Not successful, we'll skip other queries.
+ return null;
}
+ return selectResult.isEmpty() ? insert : update;
+ }
- /**
- * Performs an upsert query for defined object
- * as stated in {@link SQLDatabaseConnection#save(String, Object)}.
- *
- * Object needs to have {@link me.zort.sqllib.internal.annotation.PrimaryKey} annotation
- * set to determine which column is a primary key.
- *
- * @param table Table to save into.
- * @param obj The object to save.
- * @return Result of the query.
- */
- @NotNull
- @Override
- public final UpsertQuery save(@NotNull String table, @NotNull Object obj) {
- DefsVals defsVals = buildDefsVals(obj);
- if(defsVals == null) throw new IllegalArgumentException("Cannot create save query! (defsVals == null)");
- String[] defs = defsVals.getDefs();
- UnknownValueWrapper[] vals = defsVals.getVals();
-
- debug("Saving object into table " + table + " with definitions " + Arrays.toString(defs) + " and values " + Arrays.toString(vals));
-
- PrimaryKey primaryKey = null;
- for(Field field : obj.getClass().getDeclaredFields()) {
- if(Modifier.isTransient(field.getModifiers())) {
- continue;
- }
- if(field.isAnnotationPresent(me.zort.sqllib.internal.annotation.PrimaryKey.class)) {
- String colName = getOptions().getNamingStrategy().fieldNameToColumn(field.getName());
- //int index = Arrays.binarySearch(defs, colName);
- int index = -1;
- int i = 0;
- for (String def : defs) {
- if(def.equals(colName)) {
- index = i;
- break;
- }
- i++;
- }
- if(index >= 0) {
- primaryKey = new PrimaryKey(colName, vals[index].getObject() instanceof String
- ? (String)vals[index].getObject() : String.valueOf(vals[index].getObject()));
- break;
- }
- }
- }
- InsertQuery insert = insert().into(table, defs);
- for(UnknownValueWrapper val : vals) {
- insert.appendVal(val.getObject());
- }
+ @NotNull
+ @Override
+ public QueryResult exec(@NotNull Query query) {
+ if (query instanceof UpsertQuery && ((UpsertQuery) query).getAssignedSaveObject() != null)
+ query = save(((UpsertQuery) query).getTable(), ((UpsertQuery) query).getAssignedSaveObject());
- if(primaryKey == null) {
- debug("No primary key found for object " + obj.getClass().getName() + ", so we can't build update condition.");
- debug("Performing insert query instead: " + insert.buildQuery());
- return new UpsertQueryDecorator(insert);
- }
+ return super.exec(query);
+ }
- SetStatement setStmt = update().table(table).set();
- for(int i = 0; i < defs.length; i++) {
- setStmt.and(defs[i], vals[i].getObject());
- }
- UpdateQuery update = setStmt.also()
- .where().isEqual(primaryKey.getColumn(), primaryKey.getValue())
- .also();
- return new UpsertQueryDecorator(upsert(table, primaryKey, insert, update));
- }
+ final class UpsertQueryDecorator extends UpsertQuery {
+ private final QueryNode> query;
- /**
- * Builds an upsert query for defined table and primary key.
- * This returns either a provided insert or update query depending
- * on upsert situation.
- *
- * @param table Table to upsert into.
- * @param primaryKey Primary key to use.
- * @param insert Insert query to use.
- * @param update Update query to use.
- * @return Either insert or update query.
- */
- @Nullable
- public final QueryNode> upsert(final @NotNull String table,
- final @NotNull PrimaryKey primaryKey,
- final @NotNull InsertQuery insert,
- final @NotNull UpdateQuery update) {
-
- QueryRowsResult selectResult = select("*")
- .from(table)
- .where().isEqual(primaryKey.getColumn(), primaryKey.getValue())
- .also().limit(1)
- .obtainAll();
- if(!selectResult.isSuccessful()) {
- // Not successful, we'll skip other queries.
- return null;
- }
- return selectResult.isEmpty() ? insert : update;
+ public UpsertQueryDecorator(QueryNode> query) {
+ super(identity);
+ this.query = query;
}
- @NotNull
@Override
- public QueryResult exec(@NotNull Query query) {
- if (query instanceof UpsertQuery && ((UpsertQuery) query).getAssignedSaveObject() != null)
- query = save(((UpsertQuery) query).getTable(), ((UpsertQuery) query).getAssignedSaveObject());
-
- return super.exec(query);
+ public QueryDetails buildQueryDetails() {
+ return query.buildQueryDetails();
}
- final class UpsertQueryDecorator extends UpsertQuery {
- private final QueryNode> query;
+ @Override
+ public UpsertQuery into(String table, String... defs) {
+ notAvailable();
+ return null;
+ }
- public UpsertQueryDecorator(QueryNode> query) {
- super(identity);
- this.query = query;
- }
+ @Override
+ public UpsertQuery table(String table) {
+ notAvailable();
+ return null;
+ }
- @Override
- public QueryDetails buildQueryDetails() {
- return query.buildQueryDetails();
- }
+ @Override
+ public UpsertQuery values(Object... values) {
+ notAvailable();
+ return null;
+ }
- @Override
- public UpsertQuery into(String table, String... defs) {
- notAvailable();
- return null;
- }
- @Override
- public UpsertQuery table(String table) {
- notAvailable();
- return null;
- }
- @Override
- public UpsertQuery values(Object... values) {
- notAvailable();
- return null;
- }
- private void notAvailable() {
- throw new UnsupportedOperationException("You can't modify upsert query in SQLite mode!");
- }
+ private void notAvailable() {
+ throw new UnsupportedOperationException("You can't modify upsert query in SQLite mode!");
}
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/api/provider/Delete.java b/core/src/main/java/me/zort/sqllib/api/provider/Delete.java
index 4a644fb..0a621b5 100644
--- a/core/src/main/java/me/zort/sqllib/api/provider/Delete.java
+++ b/core/src/main/java/me/zort/sqllib/api/provider/Delete.java
@@ -4,12 +4,12 @@
public final class Delete {
- public static DeleteQuery of() {
- return new DeleteQuery(null);
- }
+ public static DeleteQuery of() {
+ return new DeleteQuery(null);
+ }
- public static DeleteQuery of(String table) {
- return new DeleteQuery(null, table);
- }
+ public static DeleteQuery of(String table) {
+ return new DeleteQuery(null, table);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/api/provider/Select.java b/core/src/main/java/me/zort/sqllib/api/provider/Select.java
index 7658c98..c850e61 100644
--- a/core/src/main/java/me/zort/sqllib/api/provider/Select.java
+++ b/core/src/main/java/me/zort/sqllib/api/provider/Select.java
@@ -4,8 +4,8 @@
public final class Select {
- public static SelectQuery of(String... columns) {
- return new SelectQuery(null, columns);
- }
+ public static SelectQuery of(String... columns) {
+ return new SelectQuery(null, columns);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/cache/ExpirableEntriesCacheManager.java b/core/src/main/java/me/zort/sqllib/cache/ExpirableEntriesCacheManager.java
index 17e6765..2234348 100644
--- a/core/src/main/java/me/zort/sqllib/cache/ExpirableEntriesCacheManager.java
+++ b/core/src/main/java/me/zort/sqllib/cache/ExpirableEntriesCacheManager.java
@@ -12,27 +12,27 @@
public class ExpirableEntriesCacheManager implements CacheManager {
- private final Cache cache;
+ private final Cache cache;
- /**
- * Creates a new cache manager with provided expiration duration
- * in milliseconds.
- *
- * @param expirationDuration The expiration duration
- */
- public ExpirableEntriesCacheManager(long expirationDuration) {
- cache = CacheBuilder.newBuilder()
- .expireAfterWrite(expirationDuration, TimeUnit.MILLISECONDS)
- .build();
- }
+ /**
+ * Creates a new cache manager with provided expiration duration
+ * in milliseconds.
+ *
+ * @param expirationDuration The expiration duration
+ */
+ public ExpirableEntriesCacheManager(long expirationDuration) {
+ cache = CacheBuilder.newBuilder()
+ .expireAfterWrite(expirationDuration, TimeUnit.MILLISECONDS)
+ .build();
+ }
- @Override
- public void set(@NotNull Query query, @NotNull QueryResult result) {
- cache.put(query, result);
- }
+ @Override
+ public void set(@NotNull Query query, @NotNull QueryResult result) {
+ cache.put(query, result);
+ }
- @Override
- public @Nullable QueryResult get(@NotNull Query query, boolean isExec) {
- return cache.getIfPresent(query);
- }
+ @Override
+ public @Nullable QueryResult get(@NotNull Query query, boolean isExec) {
+ return cache.getIfPresent(query);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/Defaults.java b/core/src/main/java/me/zort/sqllib/internal/Defaults.java
index 6beafd7..29503ac 100644
--- a/core/src/main/java/me/zort/sqllib/internal/Defaults.java
+++ b/core/src/main/java/me/zort/sqllib/internal/Defaults.java
@@ -7,14 +7,14 @@
public final class Defaults {
- public static final String DEFAULT_DRIVER = "com.mysql.jdbc.Driver";
- public static final boolean DEFAULT_AUTO_RECONNECT = true;
- public static final boolean DEFAULT_DEBUG = false;
- public static final boolean DEFAULT_LOG_SQL_ERRORS = true;
- public static final NamingStrategy DEFAULT_NAMING_STRATEGY = new SymbolSeparatedNamingStrategy('_');
+ public static final String DEFAULT_DRIVER = "com.mysql.jdbc.Driver";
+ public static final boolean DEFAULT_AUTO_RECONNECT = true;
+ public static final boolean DEFAULT_DEBUG = false;
+ public static final boolean DEFAULT_LOG_SQL_ERRORS = true;
+ public static final NamingStrategy DEFAULT_NAMING_STRATEGY = new SymbolSeparatedNamingStrategy('_');
- public static final Gson DEFAULT_GSON = new GsonBuilder()
- .enableComplexMapKeySerialization()
- .create();
+ public static final Gson DEFAULT_GSON = new GsonBuilder()
+ .enableComplexMapKeySerialization()
+ .create();
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/fieldResolver/ConstructorParameterResolver.java b/core/src/main/java/me/zort/sqllib/internal/fieldResolver/ConstructorParameterResolver.java
index 564fc9a..0e196c4 100644
--- a/core/src/main/java/me/zort/sqllib/internal/fieldResolver/ConstructorParameterResolver.java
+++ b/core/src/main/java/me/zort/sqllib/internal/fieldResolver/ConstructorParameterResolver.java
@@ -13,41 +13,42 @@
@ApiStatus.AvailableSince("0.5.1")
public class ConstructorParameterResolver implements ObjectMapper.FieldValueResolver {
- private static final Pattern argumentPattern = Pattern.compile("(arg)(\\d+)");
-
- @Override
- public Object obtainValue(SQLConnection connection,
- AnnotatedElement element,
- Row row,
- String fieldName,
- String convertedName,
- Type type) {
- if (!(element instanceof Parameter) || !(((Parameter) element).getDeclaringExecutable() instanceof Constructor))
- return null;
-
- Parameter p = (Parameter) element;
- Matcher matcher = argumentPattern.matcher(p.getName());
-
- if (matcher.matches()) {
- try {
- Field[] fields = ((Constructor) p.getDeclaringExecutable()).getDeclaringClass().getDeclaredFields();
- int index = Integer.parseInt(matcher.group(2));
- if (index >= fields.length)
- return null;
-
- int i = -1;
- for (Field field : fields) {
- if (Validator.validateAssignableField(field))
- i++;
-
- if (i == index) {
- fieldName = field.getName();
- break;
- }
- }
- } catch (NumberFormatException ignored) {}
+ private static final Pattern argumentPattern = Pattern.compile("(arg)(\\d+)");
+
+ @Override
+ public Object obtainValue(SQLConnection connection,
+ AnnotatedElement element,
+ Row row,
+ String fieldName,
+ String convertedName,
+ Type type) {
+ if (!(element instanceof Parameter) || !(((Parameter) element).getDeclaringExecutable() instanceof Constructor))
+ return null;
+
+ Parameter p = (Parameter) element;
+ Matcher matcher = argumentPattern.matcher(p.getName());
+
+ if (matcher.matches()) {
+ try {
+ Field[] fields = ((Constructor) p.getDeclaringExecutable()).getDeclaringClass().getDeclaredFields();
+ int index = Integer.parseInt(matcher.group(2));
+ if (index >= fields.length)
+ return null;
+
+ int i = -1;
+ for (Field field : fields) {
+ if (Validator.validateAssignableField(field))
+ i++;
+
+ if (i == index) {
+ fieldName = field.getName();
+ break;
+ }
}
-
- return row.get(fieldName);
+ } catch (NumberFormatException ignored) {
+ }
}
+
+ return row.get(fieldName);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/fieldResolver/LinkedOneFieldResolver.java b/core/src/main/java/me/zort/sqllib/internal/fieldResolver/LinkedOneFieldResolver.java
index 4d3d9c8..031367c 100644
--- a/core/src/main/java/me/zort/sqllib/internal/fieldResolver/LinkedOneFieldResolver.java
+++ b/core/src/main/java/me/zort/sqllib/internal/fieldResolver/LinkedOneFieldResolver.java
@@ -15,62 +15,63 @@
/**
* Functionality class for {@link LinkedOne} annotation.
- * @see LinkedOne
+ *
* @author ZorTik
+ * @see LinkedOne
*/
public class LinkedOneFieldResolver implements ObjectMapper.FieldValueResolver {
- @Override
- public Object obtainValue(SQLConnection _connection,
- AnnotatedElement element,
- Row row,
- String fieldName,
- String convertedName,
- Type type) {
+ @Override
+ public Object obtainValue(SQLConnection _connection,
+ AnnotatedElement element,
+ Row row,
+ String fieldName,
+ String convertedName,
+ Type type) {
- if(!(_connection instanceof SQLDatabaseConnectionImpl))
- return null;
+ if (!(_connection instanceof SQLDatabaseConnectionImpl))
+ return null;
- SQLDatabaseConnectionImpl connection = (SQLDatabaseConnectionImpl) _connection;
+ SQLDatabaseConnectionImpl connection = (SQLDatabaseConnectionImpl) _connection;
- if(!element.isAnnotationPresent(LinkedOne.class)) {
- // This makes mapping function hop to the next resolver.
- return null;
- }
- Class> targetClass;
- if(element instanceof Field) {
- targetClass = ((Field) element).getType();
- } else {
- targetClass = ((Parameter) element).getType();
- }
- Field targetIdField = null;
- for(Field field : targetClass.getDeclaredFields()) {
- if(field.isAnnotationPresent(PrimaryKey.class)) {
- targetIdField = field;
- break;
- }
- }
- if(targetIdField == null) {
- // Target type has no primary key annotated!
- connection.debug(String.format("No primary key field set for target in @LinkedOne field %s.", fieldName));
- return null;
- }
+ if (!element.isAnnotationPresent(LinkedOne.class)) {
+ // This makes mapping function hop to the next resolver.
+ return null;
+ }
+ Class> targetClass;
+ if (element instanceof Field) {
+ targetClass = ((Field) element).getType();
+ } else {
+ targetClass = ((Parameter) element).getType();
+ }
+ Field targetIdField = null;
+ for (Field field : targetClass.getDeclaredFields()) {
+ if (field.isAnnotationPresent(PrimaryKey.class)) {
+ targetIdField = field;
+ break;
+ }
+ }
+ if (targetIdField == null) {
+ // Target type has no primary key annotated!
+ connection.debug(String.format("No primary key field set for target in @LinkedOne field %s.", fieldName));
+ return null;
+ }
- LinkedOne linkedOne = element.getAnnotation(LinkedOne.class);
- Object idObject = row.get(fieldName);
- if(idObject == null && (idObject = row.get(convertedName)) == null) {
- // No local column found with that name.
- connection.debug(String.format("No local column found for @LinkedOne field %s.", fieldName));
- return null;
- }
- return connection.query(Select.of("*")
- .from(linkedOne.targetTable())
- .where().isEqual(
- connection.getOptions().getNamingStrategy().fieldNameToColumn(targetIdField.getName()),
- idObject),
- targetClass)
- .stream()
- .findFirst().orElse(null);
+ LinkedOne linkedOne = element.getAnnotation(LinkedOne.class);
+ Object idObject = row.get(fieldName);
+ if (idObject == null && (idObject = row.get(convertedName)) == null) {
+ // No local column found with that name.
+ connection.debug(String.format("No local column found for @LinkedOne field %s.", fieldName));
+ return null;
}
+ return connection.query(Select.of("*")
+ .from(linkedOne.targetTable())
+ .where().isEqual(
+ connection.getOptions().getNamingStrategy().fieldNameToColumn(targetIdField.getName()),
+ idObject),
+ targetClass)
+ .stream()
+ .findFirst().orElse(null);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/impl/DefaultObjectMapper.java b/core/src/main/java/me/zort/sqllib/internal/impl/DefaultObjectMapper.java
index 6352845..9721458 100644
--- a/core/src/main/java/me/zort/sqllib/internal/impl/DefaultObjectMapper.java
+++ b/core/src/main/java/me/zort/sqllib/internal/impl/DefaultObjectMapper.java
@@ -16,115 +16,115 @@
public class DefaultObjectMapper implements ObjectMapper {
- // Resolvers used after no value is found for the field
- // in mapped object as backup.
- @Getter(AccessLevel.PROTECTED)
- private final List backupValueResolvers;
- private final SQLDatabaseConnectionImpl connectionWrapper;
+ // Resolvers used after no value is found for the field
+ // in mapped object as backup.
+ @Getter(AccessLevel.PROTECTED)
+ private final List backupValueResolvers;
+ private final SQLDatabaseConnectionImpl connectionWrapper;
- public DefaultObjectMapper(SQLDatabaseConnectionImpl connectionWrapper) {
- this.backupValueResolvers = new CopyOnWriteArrayList<>();
- this.connectionWrapper = connectionWrapper;
- }
+ public DefaultObjectMapper(SQLDatabaseConnectionImpl connectionWrapper) {
+ this.backupValueResolvers = new CopyOnWriteArrayList<>();
+ this.connectionWrapper = connectionWrapper;
+ }
- @Override
- public void registerBackupValueResolver(@NotNull FieldValueResolver resolver) {
- this.backupValueResolvers.add(resolver);
- }
+ @Override
+ public void registerBackupValueResolver(@NotNull FieldValueResolver resolver) {
+ this.backupValueResolvers.add(resolver);
+ }
- @Nullable
- public T assignValues(Row row, Class typeClass) {
- T instance = null;
- try {
+ @Nullable
+ public T assignValues(Row row, Class typeClass) {
+ T instance = null;
+ try {
+ try {
+ Constructor c = typeClass.getConstructor();
+ c.setAccessible(true);
+ instance = c.newInstance();
+ } catch (NoSuchMethodException e) {
+ for (Constructor> c : typeClass.getConstructors()) {
+ if (c.getParameterCount() == row.size()) {
+ Parameter[] params = c.getParameters();
+ Object[] vals = new Object[c.getParameterCount()];
+ for (int i = 0; i < row.size(); i++) {
+ Parameter param = params[i];
+ vals[i] = buildElementValue(param, row);
+ }
try {
- Constructor c = typeClass.getConstructor();
- c.setAccessible(true);
- instance = c.newInstance();
- } catch (NoSuchMethodException e) {
- for(Constructor> c : typeClass.getConstructors()) {
- if(c.getParameterCount() == row.size()) {
- Parameter[] params = c.getParameters();
- Object[] vals = new Object[c.getParameterCount()];
- for(int i = 0; i < row.size(); i++) {
- Parameter param = params[i];
- vals[i] = buildElementValue(param, row);
- }
- try {
- c.setAccessible(true);
- instance = (T) c.newInstance(vals);
- } catch(Exception ignored) {
- }
- }
- }
+ c.setAccessible(true);
+ instance = (T) c.newInstance(vals);
+ } catch (Exception ignored) {
}
- for(Field field : typeClass.getDeclaredFields()) {
-
- if(Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
- continue;
- }
+ }
+ }
+ }
+ for (Field field : typeClass.getDeclaredFields()) {
- try {
- field.setAccessible(true);
- field.set(instance, buildElementValue(field, row));
- } catch(SecurityException ignored) {
- debug(String.format("Field %s on class %s cannot be set accessible!",
- field.getName(),
- typeClass.getName()));
- } catch(Exception ignored) {
- }
- }
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
- debug("Cannot instantinate " + typeClass.getName() + " for assigning attributes from row!");
- e.printStackTrace();
- return null;
+ if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
+ continue;
}
- return instance;
- }
- @Nullable
- private Object buildElementValue(AnnotatedElement element, Row row) {
- String name;
- Type type;
- Class> declaringClass;
- if(element instanceof Field) {
- name = ((Field) element).getName();
- type = ((Field) element).getGenericType();
- declaringClass = ((Field) element).getDeclaringClass();
- } else if(element instanceof Parameter) {
- name = ((Parameter) element).getName();
- type = ((Parameter) element).getType();
- declaringClass = ((Parameter) element).getDeclaringExecutable().getDeclaringClass();
- } else {
- return null;
+ try {
+ field.setAccessible(true);
+ field.set(instance, buildElementValue(field, row));
+ } catch (SecurityException ignored) {
+ debug(String.format("Field %s on class %s cannot be set accessible!",
+ field.getName(),
+ typeClass.getName()));
+ } catch (Exception ignored) {
}
- Object obj = row.get(name);
- if(obj == null) {
- String converted;
- if((obj = row.get(converted = connectionWrapper.getOptions().getNamingStrategy().fieldNameToColumn(name))) == null) {
+ }
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ debug("Cannot instantinate " + typeClass.getName() + " for assigning attributes from row!");
+ e.printStackTrace();
+ return null;
+ }
+ return instance;
+ }
- // Now backup resolvers come.
- for(ObjectMapper.FieldValueResolver resolver : backupValueResolvers) {
- Object backupValue = resolver.obtainValue(connectionWrapper, element, row, name, converted, type);
- if(backupValue != null) {
- return backupValue;
- }
- }
+ @Nullable
+ private Object buildElementValue(AnnotatedElement element, Row row) {
+ String name;
+ Type type;
+ Class> declaringClass;
+ if (element instanceof Field) {
+ name = ((Field) element).getName();
+ type = ((Field) element).getGenericType();
+ declaringClass = ((Field) element).getDeclaringClass();
+ } else if (element instanceof Parameter) {
+ name = ((Parameter) element).getName();
+ type = ((Parameter) element).getType();
+ declaringClass = ((Parameter) element).getDeclaringExecutable().getDeclaringClass();
+ } else {
+ return null;
+ }
+ Object obj = row.get(name);
+ if (obj == null) {
+ String converted;
+ if ((obj = row.get(converted = connectionWrapper.getOptions().getNamingStrategy().fieldNameToColumn(name))) == null) {
- debug(String.format("Cannot find column for class %s target %s (%s)", declaringClass.getName(), name, converted));
- return null;
- }
+ // Now backup resolvers come.
+ for (ObjectMapper.FieldValueResolver resolver : backupValueResolvers) {
+ Object backupValue = resolver.obtainValue(connectionWrapper, element, row, name, converted, type);
+ if (backupValue != null) {
+ return backupValue;
+ }
}
- if(element.isAnnotationPresent(JsonField.class) && obj instanceof String) {
- String jsonString = (String) obj;
- Gson gson = connectionWrapper.getOptions().getGson();
- return gson.fromJson(jsonString, type);
- } else {
- return obj;
- }
- }
- private void debug(String message) {
- connectionWrapper.debug(message);
+ debug(String.format("Cannot find column for class %s target %s (%s)", declaringClass.getName(), name, converted));
+ return null;
+ }
}
+ if (element.isAnnotationPresent(JsonField.class) && obj instanceof String) {
+ String jsonString = (String) obj;
+ Gson gson = connectionWrapper.getOptions().getGson();
+ return gson.fromJson(jsonString, type);
+ } else {
+ return obj;
+ }
+ }
+
+ private void debug(String message) {
+ connectionWrapper.debug(message);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/impl/DefaultSQLEndpoint.java b/core/src/main/java/me/zort/sqllib/internal/impl/DefaultSQLEndpoint.java
index 126ed5e..2689cfe 100644
--- a/core/src/main/java/me/zort/sqllib/internal/impl/DefaultSQLEndpoint.java
+++ b/core/src/main/java/me/zort/sqllib/internal/impl/DefaultSQLEndpoint.java
@@ -2,8 +2,8 @@
public class DefaultSQLEndpoint extends SQLEndpointImpl {
- public DefaultSQLEndpoint(String url, String database, String username, String password) {
- super(String.format("jdbc:mysql://%s/%s", url, database), username, password);
- }
+ public DefaultSQLEndpoint(String url, String database, String username, String password) {
+ super(String.format("jdbc:mysql://%s/%s", url, database), username, password);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/impl/QueryResultImpl.java b/core/src/main/java/me/zort/sqllib/internal/impl/QueryResultImpl.java
index b292f0a..ceec1d5 100644
--- a/core/src/main/java/me/zort/sqllib/internal/impl/QueryResultImpl.java
+++ b/core/src/main/java/me/zort/sqllib/internal/impl/QueryResultImpl.java
@@ -9,27 +9,27 @@
@Getter
public class QueryResultImpl implements QueryResult {
- private final boolean successful;
- private String rejectMessage = null;
+ private final boolean successful;
+ private String rejectMessage = null;
- public QueryResultImpl(boolean successful, String rejectMessage) {
- this.successful = successful;
- rejectMessage(rejectMessage);
- }
+ public QueryResultImpl(boolean successful, String rejectMessage) {
+ this.successful = successful;
+ rejectMessage(rejectMessage);
+ }
- public QueryResultImpl rejectMessage(String message) {
- if (rejectMessage != null)
- throw new RuntimeException("Reject message is already set!");
+ public QueryResultImpl rejectMessage(String message) {
+ if (rejectMessage != null)
+ throw new RuntimeException("Reject message is already set!");
- this.rejectMessage = message;
- return this;
- }
+ this.rejectMessage = message;
+ return this;
+ }
- @Override
- public String toString() {
- return "QueryResultImpl{" +
- "successful=" + successful +
- ", rejectMessage='" + rejectMessage + '\'' +
- '}';
- }
+ @Override
+ public String toString() {
+ return "QueryResultImpl{" +
+ "successful=" + successful +
+ ", rejectMessage='" + rejectMessage + '\'' +
+ '}';
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/impl/SQLEndpointImpl.java b/core/src/main/java/me/zort/sqllib/internal/impl/SQLEndpointImpl.java
index d475084..6e0d2a9 100644
--- a/core/src/main/java/me/zort/sqllib/internal/impl/SQLEndpointImpl.java
+++ b/core/src/main/java/me/zort/sqllib/internal/impl/SQLEndpointImpl.java
@@ -8,13 +8,13 @@
@Getter
public class SQLEndpointImpl implements SQLEndpoint {
- private final String jdbc;
- private final String username;
- private final String password;
+ private final String jdbc;
+ private final String username;
+ private final String password;
- @Override
- public String buildJdbc() {
- return jdbc;
- }
+ @Override
+ public String buildJdbc() {
+ return jdbc;
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/Conditional.java b/core/src/main/java/me/zort/sqllib/internal/query/Conditional.java
index bdd808a..6f0bed9 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/Conditional.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/Conditional.java
@@ -7,17 +7,17 @@
public interface Conditional & Conditional
> { // P = self
- default WhereStatement
where() {
- return where(QueryPriority.CONDITION.getPrior());
- }
+ default WhereStatement
where() {
+ return where(QueryPriority.CONDITION.getPrior());
+ }
- default WhereStatement
where(int priority) {
- if(!(this instanceof QueryNode)) {
- throw new IllegalStatementOperationException("This instance is not query part!");
- }
- WhereStatement
stmt = new WhereStatement<>((P) this, new ArrayList<>(), priority);
- ((QueryNode>) this).then(stmt);
- return stmt;
+ default WhereStatement
where(int priority) {
+ if (!(this instanceof QueryNode)) {
+ throw new IllegalStatementOperationException("This instance is not query part!");
}
+ WhereStatement
stmt = new WhereStatement<>((P) this, new ArrayList<>(), priority);
+ ((QueryNode>) this).then(stmt);
+ return stmt;
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/DeleteQuery.java b/core/src/main/java/me/zort/sqllib/internal/query/DeleteQuery.java
index 70650f4..96900e6 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/DeleteQuery.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/DeleteQuery.java
@@ -11,47 +11,47 @@
public class DeleteQuery extends QueryNode> implements Executive, Conditional, Limitable {
- private String table;
-
- @Getter
- private final SQLDatabaseConnection connection;
-
- public DeleteQuery() {
- this(null);
- }
-
- public DeleteQuery(@Nullable SQLDatabaseConnection connection) {
- this(connection, null);
- }
-
- public DeleteQuery(@Nullable SQLDatabaseConnection connection, @Nullable String table) {
- super(null, new ArrayList<>(), QueryPriority.GENERAL);
- this.table = table;
- this.connection = connection;
- }
-
- public DeleteQuery from(String table) {
- this.table = table;
- return this;
- }
-
- public DeleteQuery limit(int limit) {
- then(new LimitStatement<>(this, new ArrayList<>(), limit));
- return this;
- }
-
- @Override
- public QueryDetails buildQueryDetails() {
- Objects.requireNonNull(table, "Table cannot be null!");
-
- return new QueryDetails.Builder("DELETE FROM " + table)
- .build()
- .append(buildInnerQuery());
- }
-
- @Override
- public DeleteQuery then(String part) {
- return (DeleteQuery) super.then(part);
- }
+ private String table;
+
+ @Getter
+ private final SQLDatabaseConnection connection;
+
+ public DeleteQuery() {
+ this(null);
+ }
+
+ public DeleteQuery(@Nullable SQLDatabaseConnection connection) {
+ this(connection, null);
+ }
+
+ public DeleteQuery(@Nullable SQLDatabaseConnection connection, @Nullable String table) {
+ super(null, new ArrayList<>(), QueryPriority.GENERAL);
+ this.table = table;
+ this.connection = connection;
+ }
+
+ public DeleteQuery from(String table) {
+ this.table = table;
+ return this;
+ }
+
+ public DeleteQuery limit(int limit) {
+ then(new LimitStatement<>(this, new ArrayList<>(), limit));
+ return this;
+ }
+
+ @Override
+ public QueryDetails buildQueryDetails() {
+ Objects.requireNonNull(table, "Table cannot be null!");
+
+ return new QueryDetails.Builder("DELETE FROM " + table)
+ .build()
+ .append(buildInnerQuery());
+ }
+
+ @Override
+ public DeleteQuery then(String part) {
+ return (DeleteQuery) super.then(part);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/InsertQuery.java b/core/src/main/java/me/zort/sqllib/internal/query/InsertQuery.java
index 282ad10..c9a3d08 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/InsertQuery.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/InsertQuery.java
@@ -13,110 +13,110 @@
public class InsertQuery extends QueryNode> implements Executive, Conditional {
- @Getter
- private String table;
- private String[] defs;
- private String[] values;
- private int currPhIndex = 0;
-
- @Getter
- private final SQLDatabaseConnection connection;
-
- public InsertQuery() {
- this(null);
- }
-
- public InsertQuery(@Nullable SQLDatabaseConnection connection) {
- this(connection, null);
- }
-
- public InsertQuery(@Nullable SQLDatabaseConnection connection, @Nullable String table) {
- super(null, new ArrayList<>(), QueryPriority.GENERAL);
- this.table = table;
- this.connection = connection;
- this.defs = new String[0];
- this.values = new String[0];
- }
-
- public InsertQuery into(String table, String... defs) {
- this.defs = defs;
- return table(table);
+ @Getter
+ private String table;
+ private String[] defs;
+ private String[] values;
+ private int currPhIndex = 0;
+
+ @Getter
+ private final SQLDatabaseConnection connection;
+
+ public InsertQuery() {
+ this(null);
+ }
+
+ public InsertQuery(@Nullable SQLDatabaseConnection connection) {
+ this(connection, null);
+ }
+
+ public InsertQuery(@Nullable SQLDatabaseConnection connection, @Nullable String table) {
+ super(null, new ArrayList<>(), QueryPriority.GENERAL);
+ this.table = table;
+ this.connection = connection;
+ this.defs = new String[0];
+ this.values = new String[0];
+ }
+
+ public InsertQuery into(String table, String... defs) {
+ this.defs = defs;
+ return table(table);
+ }
+
+ public InsertQuery table(String table) {
+ this.table = table;
+ return this;
+ }
+
+ // Used internally
+ public InsertQuery appendVal(Object val) {
+ String[] newValues = new String[values.length + 1];
+ System.arraycopy(values, 0, newValues, 0, values.length);
+ newValues[values.length] = handleVal(val);
+ this.values = newValues;
+ return this;
+ }
+
+ public InsertQuery values(Object... values) {
+ String[] vals = new String[values.length];
+ for (int i = 0; i < values.length; i++) {
+ Object obj = values[i];
+ vals[i] = handleVal(obj);
}
+ this.values = vals;
+ return this;
+ }
- public InsertQuery table(String table) {
- this.table = table;
- return this;
+ private String handleVal(Object obj) {
+ if (obj instanceof String) {
+ obj = Encoding.handleTo((String) obj);
}
-
- // Used internally
- public InsertQuery appendVal(Object val) {
- String[] newValues = new String[values.length + 1];
- System.arraycopy(values, 0, newValues, 0, values.length);
- newValues[values.length] = handleVal(val);
- this.values = newValues;
- return this;
- }
-
- public InsertQuery values(Object... values) {
- String[] vals = new String[values.length];
- for(int i = 0; i < values.length; i++) {
- Object obj = values[i];
- vals[i] = handleVal(obj);
- }
- this.values = vals;
- return this;
- }
-
- private String handleVal(Object obj) {
- if(obj instanceof String) {
- obj = Encoding.handleTo((String) obj);
- }
- return Util.buildQuoted(obj);
+ return Util.buildQuoted(obj);
+ }
+
+ @Override
+ public QueryDetails buildQueryDetails() {
+ Objects.requireNonNull(table, "Table cannot be null!");
+ if (defs.length != values.length) {
+ throw new IllegalStatementOperationException("Definition count must be same as values count!");
}
- @Override
- public QueryDetails buildQueryDetails() {
- Objects.requireNonNull(table, "Table cannot be null!");
- if(defs.length != values.length) {
- throw new IllegalStatementOperationException("Definition count must be same as values count!");
- }
+ QueryDetails details = new QueryDetails.Builder(String.format("INSERT INTO %s ", table)).build();
- QueryDetails details = new QueryDetails.Builder(String.format("INSERT INTO %s ", table)).build();
+ insertArray(details, defs, false);
+ details.append(" VALUES ");
+ insertArray(details, values, true);
- insertArray(details, defs, false);
- details.append(" VALUES ");
- insertArray(details, values, true);
+ details.append(buildInnerQuery());
- details.append(buildInnerQuery());
+ return details;
+ }
- return details;
- }
+ private void insertArray(QueryDetails details, String[] array, boolean usePlaceholders) {
+ details.append("(");
+ for (String obj : array) {
+ String placeholder = nextPlaceholder();
+ if (!details.getQueryStr().endsWith("("))
+ details.append(", ");
- private void insertArray(QueryDetails details, String[] array, boolean usePlaceholders) {
- details.append("(");
- for (String obj : array) {
- String placeholder = nextPlaceholder();
- if (!details.getQueryStr().endsWith("("))
- details.append(", ");
-
- if (usePlaceholders) {
- details.append(new QueryDetails.Builder("<" + placeholder + ">")
- .placeholder(placeholder, obj)
- .build());
- } else {
- details.append(obj);
- }
- }
- details.append(")");
+ if (usePlaceholders) {
+ details.append(new QueryDetails.Builder("<" + placeholder + ">")
+ .placeholder(placeholder, obj)
+ .build());
+ } else {
+ details.append(obj);
+ }
}
+ details.append(")");
+ }
- private String nextPlaceholder() {
- return "insert_" + currPhIndex++;
- }
+ private String nextPlaceholder() {
+ return "insert_" + currPhIndex++;
+ }
- @Override
- public InsertQuery then(String part) {
- return (InsertQuery) super.then(part);
- }
+ @Override
+ public InsertQuery then(String part) {
+ return (InsertQuery) super.then(part);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/Limitable.java b/core/src/main/java/me/zort/sqllib/internal/query/Limitable.java
index bfea311..6f0513e 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/Limitable.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/Limitable.java
@@ -2,6 +2,6 @@
public interface Limitable & Limitable
> { // P = self
- P limit(int limit);
+ P limit(int limit);
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/QueryDetails.java b/core/src/main/java/me/zort/sqllib/internal/query/QueryDetails.java
index e2c403d..aa8dbbf 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/QueryDetails.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/QueryDetails.java
@@ -19,141 +19,142 @@
@Getter
public class QueryDetails {
- public static QueryDetails empty() {
- return new QueryDetails();
+ public static QueryDetails empty() {
+ return new QueryDetails();
+ }
+
+ @Setter(AccessLevel.PROTECTED)
+ private String queryStr;
+ private final Map values;
+
+ public QueryDetails() { // Equiv to empty()
+ this("", new HashMap<>());
+ }
+
+ public QueryDetails append(QueryDetails other) {
+ return append("", other);
+ }
+
+ public QueryDetails append(String prefix, QueryDetails other) {
+ Objects.requireNonNull(other, "QueryDetails cannot be null!");
+
+ append(prefix + other.queryStr);
+ other.values.forEach(values::putIfAbsent);
+ return this;
+ }
+
+ public QueryDetails append(String s) {
+ queryStr += s;
+ return this;
+ }
+
+ // Creates prepared statement for execution in SQlDatabaseConnectionImpl class.
+ protected PreparedStatement prepare(Connection connection) throws SQLException {
+ Pair requirements = buildStatementDetails();
+
+ // Shows plain query for prepared statement.
+ SQLConnectionRegistry.debug(connection, String.format("P-Query: %s", requirements.getFirst()));
+ SQLConnectionRegistry.debug(connection, String.format("P-Values: %s", Arrays.toString(requirements.getSecond())));
+
+ PreparedStatement statement = connection.prepareStatement(requirements.getFirst());
+ Object[] values = requirements.getSecond();
+ for (int i = 0; i < values.length; i++) {
+ set(statement, i + 1, values[i]);
}
+ return statement;
+ }
- @Setter(AccessLevel.PROTECTED)
- private String queryStr;
- private final Map values;
+ protected Pair buildStatementDetails() {
+ String query = queryStr;
+ Map valuesUnsorted = new HashMap<>();
- public QueryDetails() { // Equiv to empty()
- this("", new HashMap<>());
- }
+ int i = 0;
+ String queryCloned = query;
+ for (String placeholder : this.values.keySet()) {
+ Object value = this.values.get(placeholder);
- public QueryDetails append(QueryDetails other) {
- return append("", other);
- }
+ placeholder = String.format("<%s>", placeholder);
- public QueryDetails append(String prefix, QueryDetails other) {
- Objects.requireNonNull(other, "QueryDetails cannot be null!");
+ if (Util.count(queryStr, placeholder) != 1)
+ throw new RuntimeException("Placeholder " + placeholder + " is not unique in query " + queryStr);
- append(prefix + other.queryStr);
- other.values.forEach(values::putIfAbsent);
- return this;
- }
+ valuesUnsorted.put(queryCloned.indexOf(placeholder), value);
+ query = query.replaceAll(placeholder, "?");
- public QueryDetails append(String s) {
- queryStr += s;
- return this;
+ i++;
}
- // Creates prepared statement for execution in SQlDatabaseConnectionImpl class.
- protected PreparedStatement prepare(Connection connection) throws SQLException {
- Pair requirements = buildStatementDetails();
-
- // Shows plain query for prepared statement.
- SQLConnectionRegistry.debug(connection, String.format("P-Query: %s", requirements.getFirst()));
- SQLConnectionRegistry.debug(connection, String.format("P-Values: %s", Arrays.toString(requirements.getSecond())));
-
- PreparedStatement statement = connection.prepareStatement(requirements.getFirst());
- Object[] values = requirements.getSecond();
- for (int i = 0; i < values.length; i++) {
- set(statement, i + 1, values[i]);
- }
- return statement;
+ Object[] values = new Object[valuesUnsorted.size()];
+ valuesUnsorted.keySet()
+ .stream()
+ .mapToInt(Integer::intValue)
+ .sorted().forEach(new IntConsumer() {
+ private int index = 0;
+
+ @Override
+ public void accept(int value) {
+ values[index] = valuesUnsorted.get(value);
+ index++;
+ }
+ });
+
+ return new Pair<>(query, values);
+ }
+
+ private static void set(PreparedStatement statement, int index, Object value) throws SQLException {
+ String type = value != null ? value.getClass().getSimpleName().toLowerCase() : "null";
+ switch (type) {
+ case "string":
+ statement.setString(index, (String) value);
+ break;
+ case "integer":
+ case "int":
+ statement.setInt(index, (int) value);
+ break;
+ case "long":
+ statement.setLong(index, (long) value);
+ break;
+ case "double":
+ statement.setDouble(index, (double) value);
+ break;
+ case "float":
+ statement.setFloat(index, (float) value);
+ break;
+ case "boolean":
+ statement.setBoolean(index, (boolean) value);
+ break;
+ default:
+ statement.setObject(index, value);
}
+ }
- protected Pair buildStatementDetails() {
- String query = queryStr;
- Map valuesUnsorted = new HashMap<>();
+ public int length() {
+ return queryStr.length();
+ }
- int i = 0;
- String queryCloned = query;
- for (String placeholder : this.values.keySet()) {
- Object value = this.values.get(placeholder);
+ public String toString() {
+ return "QueryDetails{str=" + queryStr + ", values=" + new Gson().toJson(values) + "}";
+ }
- placeholder = String.format("<%s>", placeholder);
+ @RequiredArgsConstructor
+ public static class Builder {
- if (Util.count(queryStr, placeholder) != 1)
- throw new RuntimeException("Placeholder " + placeholder + " is not unique in query " + queryStr);
+ private final String query;
+ private final Map values = new HashMap<>();
- valuesUnsorted.put(queryCloned.indexOf(placeholder), value);
- query = query.replaceAll(placeholder, "?");
-
- i++;
- }
-
- Object[] values = new Object[valuesUnsorted.size()];
- valuesUnsorted.keySet()
- .stream()
- .mapToInt(Integer::intValue)
- .sorted().forEach(new IntConsumer() {
- private int index = 0;
- @Override
- public void accept(int value) {
- values[index] = valuesUnsorted.get(value);
- index++;
- }
- });
-
- return new Pair<>(query, values);
- }
+ // Name without brackets
+ public Builder placeholder(String name, Object value) {
+ if (!query.contains("<" + name + ">"))
+ throw new IllegalArgumentException("Placeholder <" + name + "> not found in query!");
- private static void set(PreparedStatement statement, int index, Object value) throws SQLException {
- String type = value != null ? value.getClass().getSimpleName().toLowerCase() : "null";
- switch(type) {
- case "string":
- statement.setString(index, (String) value);
- break;
- case "integer":
- case "int":
- statement.setInt(index, (int) value);
- break;
- case "long":
- statement.setLong(index, (long) value);
- break;
- case "double":
- statement.setDouble(index, (double) value);
- break;
- case "float":
- statement.setFloat(index, (float) value);
- break;
- case "boolean":
- statement.setBoolean(index, (boolean) value);
- break;
- default:
- statement.setObject(index, value);
- }
+ values.put(name, value);
+ return this;
}
- public int length() {
- return queryStr.length();
+ public QueryDetails build() {
+ return new QueryDetails(query, values);
}
- public String toString() {
- return "QueryDetails{str=" + queryStr + ", values=" + new Gson().toJson(values) + "}";
- }
-
- @RequiredArgsConstructor
- public static class Builder {
-
- private final String query;
- private final Map values = new HashMap<>();
-
- // Name without brackets
- public Builder placeholder(String name, Object value) {
- if(!query.contains("<" + name + ">"))
- throw new IllegalArgumentException("Placeholder <" + name + "> not found in query!");
-
- values.put(name, value);
- return this;
- }
-
- public QueryDetails build() {
- return new QueryDetails(query, values);
- }
-
- }
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/QueryNode.java b/core/src/main/java/me/zort/sqllib/internal/query/QueryNode.java
index 1a5cfda..0aa14fa 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/QueryNode.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/QueryNode.java
@@ -28,185 +28,185 @@
@Getter
public abstract class QueryNode> implements Query, StatementFactory {
- @Getter(onMethod_ = {@Nullable})
- private final transient P parent;
- private final List> children;
- private final Map details;
- private final int priority;
-
- public QueryNode(@Nullable P parent, List> initial, QueryPriority priority) {
- this(parent, initial, priority.getPrior());
- }
-
- public QueryNode(@Nullable P parent, List> initial, int priority) {
- this.parent = parent;
- this.children = initial;
- this.priority = priority;
- this.details = new ConcurrentHashMap<>();
- }
-
- /**
- * Builds the query string with placeholders containing values
- * for passing into PreparedStatement.
- *
- * Query example: SELECT * FROM table WHERE id = <id>;
- * Values example: [AnyId]
- *
- * @return QueryDetails object.
- */
- public abstract QueryDetails buildQueryDetails();
-
- @Override
- public PreparedStatement prepare(Connection connection) throws SQLException {
- return details.remove(buildQuery()).prepare(connection);
- }
-
- @Override
- public String buildQuery() {
- QueryDetails queryDetails = buildQueryDetails();
-
- if (isAncestor())
- debug(String.format("Query: %s", queryDetails.getQueryStr()));
-
- String uuid = UUID.randomUUID().toString();
- details.put(uuid, queryDetails);
- return uuid;
- }
-
- public QueryDetails buildInnerQuery() {
- List> children = new ArrayList<>(this.children);
- children.sort(Comparator.comparingInt(QueryNode::getPriority));
-
- QueryDetails details = new QueryDetails("", new HashMap<>());
-
- if (children.isEmpty()) {
- return QueryDetails.empty();
- }
-
- for (QueryNode> inner : children) {
- if (details.length() > 0)
- details.append(" ");
-
- QueryDetails innerDetails = inner.getDetails().get(inner.buildQuery());
- details.append(innerDetails);
- }
-
- return details;
- }
-
- @Nullable
- protected T invokeToConnection(Function func)
- throws NoLinkedConnectionException, InvalidConnectionInstanceException {
- QueryNode> current = this;
- while(current.getParent() != null && !(current instanceof Executive)) {
- current = current.getParent();
- }
- T result;
- if(current instanceof Executive) {
- SQLConnection connection = ((Executive) current).getConnection();
- if(!(connection instanceof SQLDatabaseConnection)) {
- throw new InvalidConnectionInstanceException(connection);
- }
-
- result = func.apply((SQLDatabaseConnection) connection);
- } else {
- throw new NoLinkedConnectionException(this);
- }
- return result;
- }
-
- public QueryNode> then(String part) {
- int maxPriority = children.stream()
- .map(QueryNode::getPriority)
- .max(Comparator.naturalOrder())
- .orElse(0);
-
- then(new QueryNode>(parent, Collections.emptyList(), maxPriority + 1) {
- @Override
- public QueryDetails buildQueryDetails() {
- return new QueryDetails(part, new HashMap<>());
- }
- });
- return this;
- }
-
- public > QueryNode then(QueryNode part) {
- this.children.add(part);
- return part;
- }
-
- public P also() {
- return parent;
- }
-
- public QueryResult execute() {
- return invokeToConnection(connection -> connection.exec(getAncestor()));
- }
-
- public Optional obtainOne() {
- QueryRowsResult resultList = obtainAll();
-
- return resultList.isEmpty()
- ? Optional.empty()
- : Optional.ofNullable(resultList.get(0));
- }
-
- public Optional obtainOne(Class mapTo) {
- QueryRowsResult resultList = obtainAll(mapTo);
-
- return resultList.isEmpty()
- ? Optional.empty()
- : Optional.ofNullable(resultList.get(0));
- }
-
- public QueryRowsResult obtainAll() {
- requireResultSetAware();
- return invokeToConnection(connection -> connection.query(getAncestor()));
- }
-
- public QueryRowsResult obtainAll(Class mapTo) {
- requireResultSetAware();
- return invokeToConnection(connection -> connection.query(getAncestor(), mapTo));
- }
-
- private void requireResultSetAware() {
- if (!generatesResultSet()) {
- throw new IllegalStateException("This query node is not ResultSetAware! (Did you mean execute()?)");
- }
- }
-
- public QueryNode> getAncestor() {
- QueryNode> current = this;
- while(current.getParent() != null) {
- current = current.getParent();
- }
- return current;
- }
-
- public boolean generatesResultSet() {
- return this instanceof ResultSetAware;
- }
-
- private void debug(String message) {
- if (getAncestor() instanceof Executive
- && ((Executive) getAncestor()).getConnection() instanceof SQLDatabaseConnectionImpl) {
- ((SQLDatabaseConnectionImpl) ((Executive) getAncestor()).getConnection()).debug(message);
- }
- }
-
- public String toString() {
- return "QueryNode{details=" + buildQueryDetails().toString() + "}";
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof QueryNode)) return false;
- QueryNode> other = (QueryNode>) obj;
- return toString().equals(other.toString());
- }
-
- @Override
- public int hashCode() {
- return toString().hashCode();
- }
+ @Getter(onMethod_ = {@Nullable})
+ private final transient P parent;
+ private final List> children;
+ private final Map details;
+ private final int priority;
+
+ public QueryNode(@Nullable P parent, List> initial, QueryPriority priority) {
+ this(parent, initial, priority.getPrior());
+ }
+
+ public QueryNode(@Nullable P parent, List> initial, int priority) {
+ this.parent = parent;
+ this.children = initial;
+ this.priority = priority;
+ this.details = new ConcurrentHashMap<>();
+ }
+
+ /**
+ * Builds the query string with placeholders containing values
+ * for passing into PreparedStatement.
+ *
+ * Query example: SELECT * FROM table WHERE id = <id>;
+ * Values example: [AnyId]
+ *
+ * @return QueryDetails object.
+ */
+ public abstract QueryDetails buildQueryDetails();
+
+ @Override
+ public PreparedStatement prepare(Connection connection) throws SQLException {
+ return details.remove(buildQuery()).prepare(connection);
+ }
+
+ @Override
+ public String buildQuery() {
+ QueryDetails queryDetails = buildQueryDetails();
+
+ if (isAncestor())
+ debug(String.format("Query: %s", queryDetails.getQueryStr()));
+
+ String uuid = UUID.randomUUID().toString();
+ details.put(uuid, queryDetails);
+ return uuid;
+ }
+
+ public QueryDetails buildInnerQuery() {
+ List> children = new ArrayList<>(this.children);
+ children.sort(Comparator.comparingInt(QueryNode::getPriority));
+
+ QueryDetails details = new QueryDetails("", new HashMap<>());
+
+ if (children.isEmpty()) {
+ return QueryDetails.empty();
+ }
+
+ for (QueryNode> inner : children) {
+ if (details.length() > 0)
+ details.append(" ");
+
+ QueryDetails innerDetails = inner.getDetails().get(inner.buildQuery());
+ details.append(innerDetails);
+ }
+
+ return details;
+ }
+
+ @Nullable
+ protected T invokeToConnection(Function func)
+ throws NoLinkedConnectionException, InvalidConnectionInstanceException {
+ QueryNode> current = this;
+ while (current.getParent() != null && !(current instanceof Executive)) {
+ current = current.getParent();
+ }
+ T result;
+ if (current instanceof Executive) {
+ SQLConnection connection = ((Executive) current).getConnection();
+ if (!(connection instanceof SQLDatabaseConnection)) {
+ throw new InvalidConnectionInstanceException(connection);
+ }
+
+ result = func.apply((SQLDatabaseConnection) connection);
+ } else {
+ throw new NoLinkedConnectionException(this);
+ }
+ return result;
+ }
+
+ public QueryNode> then(String part) {
+ int maxPriority = children.stream()
+ .map(QueryNode::getPriority)
+ .max(Comparator.naturalOrder())
+ .orElse(0);
+
+ then(new QueryNode>(parent, Collections.emptyList(), maxPriority + 1) {
+ @Override
+ public QueryDetails buildQueryDetails() {
+ return new QueryDetails(part, new HashMap<>());
+ }
+ });
+ return this;
+ }
+
+ public > QueryNode then(QueryNode part) {
+ this.children.add(part);
+ return part;
+ }
+
+ public P also() {
+ return parent;
+ }
+
+ public QueryResult execute() {
+ return invokeToConnection(connection -> connection.exec(getAncestor()));
+ }
+
+ public Optional obtainOne() {
+ QueryRowsResult resultList = obtainAll();
+
+ return resultList.isEmpty()
+ ? Optional.empty()
+ : Optional.ofNullable(resultList.get(0));
+ }
+
+ public Optional obtainOne(Class mapTo) {
+ QueryRowsResult resultList = obtainAll(mapTo);
+
+ return resultList.isEmpty()
+ ? Optional.empty()
+ : Optional.ofNullable(resultList.get(0));
+ }
+
+ public QueryRowsResult obtainAll() {
+ requireResultSetAware();
+ return invokeToConnection(connection -> connection.query(getAncestor()));
+ }
+
+ public QueryRowsResult obtainAll(Class mapTo) {
+ requireResultSetAware();
+ return invokeToConnection(connection -> connection.query(getAncestor(), mapTo));
+ }
+
+ private void requireResultSetAware() {
+ if (!generatesResultSet()) {
+ throw new IllegalStateException("This query node is not ResultSetAware! (Did you mean execute()?)");
+ }
+ }
+
+ public QueryNode> getAncestor() {
+ QueryNode> current = this;
+ while (current.getParent() != null) {
+ current = current.getParent();
+ }
+ return current;
+ }
+
+ public boolean generatesResultSet() {
+ return this instanceof ResultSetAware;
+ }
+
+ private void debug(String message) {
+ if (getAncestor() instanceof Executive
+ && ((Executive) getAncestor()).getConnection() instanceof SQLDatabaseConnectionImpl) {
+ ((SQLDatabaseConnectionImpl) ((Executive) getAncestor()).getConnection()).debug(message);
+ }
+ }
+
+ public String toString() {
+ return "QueryNode{details=" + buildQueryDetails().toString() + "}";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof QueryNode)) return false;
+ QueryNode> other = (QueryNode>) obj;
+ return toString().equals(other.toString());
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/QueryPriority.java b/core/src/main/java/me/zort/sqllib/internal/query/QueryPriority.java
index e985513..a16a502 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/QueryPriority.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/QueryPriority.java
@@ -7,23 +7,23 @@
public enum QueryPriority {
- GENERAL(0),
- CONDITION(1),
- OTHER(2),
- LAST(3);
-
- @Getter
- private final int prior;
-
- QueryPriority(int prior) {
- this.prior = prior;
- }
-
- public boolean isAncestor() {
- return prior == Arrays.stream(QueryPriority.values())
- .min(Comparator.comparingInt(QueryPriority::getPrior))
- .orElse(QueryPriority.GENERAL)
- .getPrior();
- }
+ GENERAL(0),
+ CONDITION(1),
+ OTHER(2),
+ LAST(3);
+
+ @Getter
+ private final int prior;
+
+ QueryPriority(int prior) {
+ this.prior = prior;
+ }
+
+ public boolean isAncestor() {
+ return prior == Arrays.stream(QueryPriority.values())
+ .min(Comparator.comparingInt(QueryPriority::getPrior))
+ .orElse(QueryPriority.GENERAL)
+ .getPrior();
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/ResultSetAware.java b/core/src/main/java/me/zort/sqllib/internal/query/ResultSetAware.java
index 844633f..a85ea1c 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/ResultSetAware.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/ResultSetAware.java
@@ -18,9 +18,12 @@
*/
public interface ResultSetAware extends Query {
- Optional obtainOne();
- Optional obtainOne(Class mapTo);
- QueryRowsResult obtainAll();
- QueryRowsResult obtainAll(Class mapTo);
+ Optional obtainOne();
+
+ Optional obtainOne(Class mapTo);
+
+ QueryRowsResult obtainAll();
+
+ QueryRowsResult obtainAll(Class mapTo);
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/SelectQuery.java b/core/src/main/java/me/zort/sqllib/internal/query/SelectQuery.java
index 0136518..4ec5660 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/SelectQuery.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/SelectQuery.java
@@ -13,51 +13,51 @@
public class SelectQuery extends QueryNode> implements Executive, Conditional, Limitable, ResultSetAware {
- private final List cols;
- private String table;
-
- @Getter
- private final SQLDatabaseConnection connection;
-
- public SelectQuery() {
- this(null);
- }
-
- public SelectQuery(@Nullable SQLDatabaseConnection connection, String... cols) {
- this(connection, null, Arrays.asList(cols));
- }
-
- public SelectQuery(@Nullable SQLDatabaseConnection connection, @Nullable String table, List cols) {
- super(null, new ArrayList<>(), QueryPriority.GENERAL);
- this.table = table;
- this.cols = cols;
- this.connection = connection;
- }
-
- public SelectQuery from(String table) {
- this.table = table;
- return this;
- }
-
- public SelectQuery limit(int limit) {
- then(new LimitStatement<>(this, new ArrayList<>(), limit));
- return this;
- }
-
- @Override
- public QueryDetails buildQueryDetails() {
- Objects.requireNonNull(table, "Table cannot be null!");
-
- QueryDetails details = new QueryDetails.Builder(String.format("SELECT %s FROM %s",
- this.cols.isEmpty() ? "*" : String.join(", ", this.cols),
- table))
- .build();
-
- return details.append(buildInnerQuery());
- }
-
- @Override
- public SelectQuery then(String part) {
- return (SelectQuery) super.then(part);
- }
+ private final List cols;
+ private String table;
+
+ @Getter
+ private final SQLDatabaseConnection connection;
+
+ public SelectQuery() {
+ this(null);
+ }
+
+ public SelectQuery(@Nullable SQLDatabaseConnection connection, String... cols) {
+ this(connection, null, Arrays.asList(cols));
+ }
+
+ public SelectQuery(@Nullable SQLDatabaseConnection connection, @Nullable String table, List cols) {
+ super(null, new ArrayList<>(), QueryPriority.GENERAL);
+ this.table = table;
+ this.cols = cols;
+ this.connection = connection;
+ }
+
+ public SelectQuery from(String table) {
+ this.table = table;
+ return this;
+ }
+
+ public SelectQuery limit(int limit) {
+ then(new LimitStatement<>(this, new ArrayList<>(), limit));
+ return this;
+ }
+
+ @Override
+ public QueryDetails buildQueryDetails() {
+ Objects.requireNonNull(table, "Table cannot be null!");
+
+ QueryDetails details = new QueryDetails.Builder(String.format("SELECT %s FROM %s",
+ this.cols.isEmpty() ? "*" : String.join(", ", this.cols),
+ table))
+ .build();
+
+ return details.append(buildInnerQuery());
+ }
+
+ @Override
+ public SelectQuery then(String part) {
+ return (SelectQuery) super.then(part);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/UpdateQuery.java b/core/src/main/java/me/zort/sqllib/internal/query/UpdateQuery.java
index 00103f9..0856bc8 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/UpdateQuery.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/UpdateQuery.java
@@ -12,57 +12,57 @@
public class UpdateQuery extends QueryNode> implements Executive, Conditional {
- private String table;
-
- @Getter
- private final SQLDatabaseConnection connection;
-
- public UpdateQuery() {
- this(null);
- }
-
- public UpdateQuery(@Nullable SQLDatabaseConnection connection) {
- this(connection, null);
- }
-
- public UpdateQuery(@Nullable SQLDatabaseConnection connection, @Nullable String table) {
- super(null, new ArrayList<>(), QueryPriority.GENERAL.getPrior());
- this.table = table;
- this.connection = connection;
- }
-
- public UpdateQuery table(String table) {
- this.table = table;
- return this;
- }
-
- public SetStatement set(String column, Object value) {
- SetStatement stmt = set();
- stmt.and(column, value);
- return stmt;
- }
-
- public SetStatement set() {
- SetStatement stmt = new SetStatement<>(this);
- then(stmt);
- return stmt;
- }
-
- @Override
- public WhereStatement where() {
- return Conditional.super.where(2);
- }
-
- @Override
- public QueryDetails buildQueryDetails() {
- Objects.requireNonNull(table, "Table cannot be null!");
-
- return new QueryDetails.Builder("UPDATE " + table).build().append(buildInnerQuery());
- }
-
- @Override
- public UpdateQuery then(String part) {
- return (UpdateQuery) super.then(part);
- }
+ private String table;
+
+ @Getter
+ private final SQLDatabaseConnection connection;
+
+ public UpdateQuery() {
+ this(null);
+ }
+
+ public UpdateQuery(@Nullable SQLDatabaseConnection connection) {
+ this(connection, null);
+ }
+
+ public UpdateQuery(@Nullable SQLDatabaseConnection connection, @Nullable String table) {
+ super(null, new ArrayList<>(), QueryPriority.GENERAL.getPrior());
+ this.table = table;
+ this.connection = connection;
+ }
+
+ public UpdateQuery table(String table) {
+ this.table = table;
+ return this;
+ }
+
+ public SetStatement set(String column, Object value) {
+ SetStatement stmt = set();
+ stmt.and(column, value);
+ return stmt;
+ }
+
+ public SetStatement set() {
+ SetStatement stmt = new SetStatement<>(this);
+ then(stmt);
+ return stmt;
+ }
+
+ @Override
+ public WhereStatement where() {
+ return Conditional.super.where(2);
+ }
+
+ @Override
+ public QueryDetails buildQueryDetails() {
+ Objects.requireNonNull(table, "Table cannot be null!");
+
+ return new QueryDetails.Builder("UPDATE " + table).build().append(buildInnerQuery());
+ }
+
+ @Override
+ public UpdateQuery then(String part) {
+ return (UpdateQuery) super.then(part);
+ }
}
diff --git a/core/src/main/java/me/zort/sqllib/internal/query/UpsertQuery.java b/core/src/main/java/me/zort/sqllib/internal/query/UpsertQuery.java
index cdb5ecd..e096eff 100644
--- a/core/src/main/java/me/zort/sqllib/internal/query/UpsertQuery.java
+++ b/core/src/main/java/me/zort/sqllib/internal/query/UpsertQuery.java
@@ -10,59 +10,59 @@
public class UpsertQuery extends InsertQuery {
- @Setter
- @Getter
- private Object assignedSaveObject = null; // Can be null, only relevant in SQLite mode.
+ @Setter
+ @Getter
+ private Object assignedSaveObject = null; // Can be null, only relevant in SQLite mode.
- public UpsertQuery(SQLDatabaseConnection connection) {
- super(connection);
- }
+ public UpsertQuery(SQLDatabaseConnection connection) {
+ super(connection);
+ }
- public UpsertQuery(SQLDatabaseConnection connection, @Nullable String table) {
- super(connection, table);
- }
+ public UpsertQuery(SQLDatabaseConnection connection, @Nullable String table) {
+ super(connection, table);
+ }
- @Override
- public UpsertQuery into(String table, String... defs) {
- return (UpsertQuery) super.into(table, defs);
- }
+ @Override
+ public UpsertQuery into(String table, String... defs) {
+ return (UpsertQuery) super.into(table, defs);
+ }
- @Override
- public UpsertQuery table(String table) {
- return (UpsertQuery) super.table(table);
- }
+ @Override
+ public UpsertQuery table(String table) {
+ return (UpsertQuery) super.table(table);
+ }
- @Override
- public UpsertQuery values(Object... values) {
- return (UpsertQuery) super.values(values);
- }
+ @Override
+ public UpsertQuery values(Object... values) {
+ return (UpsertQuery) super.values(values);
+ }
- public SetStatement onDuplicateKey(String column, Object value) {
- SetStatement stmt = onDuplicateKey();
- stmt.and(column, value);
- return stmt;
- }
+ public SetStatement onDuplicateKey(String column, Object value) {
+ SetStatement stmt = onDuplicateKey();
+ stmt.and(column, value);
+ return stmt;
+ }
- public SetStatement onDuplicateKey() {
- SetStatement stmt = new SetStatement(this, 3) {
- @Override
- public QueryDetails buildQueryDetails() {
- QueryDetails details = new QueryDetails(" ON DUPLICATE KEY UPDATE", new HashMap<>());
+ public SetStatement onDuplicateKey() {
+ SetStatement stmt = new SetStatement