Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Valxrie committed May 7, 2021
0 parents commit 484d07d
Show file tree
Hide file tree
Showing 37 changed files with 2,780 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
target
.idea
docs
*.iml
104 changes: 104 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.glyart</groupId>
<artifactId>Mystral</artifactId>
<version>1.0-SNAPSHOT</version>

<name>Mystral</name>

<description>Library that helps you avoiding JDBC code boilerplate.</description>

<contributors>
<contributor>
<name>xQuickGlare</name>
</contributor>
<contributor>
<name>Aerora</name>
</contributor>
</contributors>

<properties>
<encoding>UTF-8</encoding>
<java.version>8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>${encoding}</project.build.sourceEncoding>
<project.reporting.outputEncoding>${encoding}</project.reporting.outputEncoding>
</properties>

<build>
<finalName>${project.name}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/MANIFEST.MF</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<reportOutputDirectory>${project.basedir}/docs</reportOutputDirectory>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>20.1.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
218 changes: 218 additions & 0 deletions src/main/java/com/glyart/mystral/database/AsyncDatabase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package com.glyart.mystral.database;

import com.glyart.mystral.sql.*;
import com.google.common.base.Preconditions;
import com.glyart.mystral.exceptions.DataAccessException;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.sql.DataSource;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

/**
* Represents implementation of basic asynchronous operations for interacting with a data source.
* <p>An instance of {@code AsyncDatabase} is available by passing a valid {@link DataSource} and an implementation of
* the {@link Executor} interface.</p>
*
* <p>This class:
* <ul>
* <li>works asynchronously, without overhead on the main thread. This is done by using {@link Executor#execute(Runnable)}</li>
* <li>executes all the <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> operations on a data source</li>
* <li>handles exceptions and communicates the sql that generated the problem (if possible)</li>
* <li>gives not null <b>{@link CompletableFuture} objects that WILL STORE usable future results</b></li>
* <li>iterates over {@link java.sql.ResultSet}s</li>
* <li>deals with static and prepared statements</li>
* </ul>
*
* <p>Methods of this class use various callback interfaces. A reading of those is greatly suggested.
*
* <br> Since the callback interfaces make AsyncDatabase's methods parameterizable, there should be no need to subclass this class.</p>
* @see Executor
* @see CompletableFuture
* @see BatchSetter
* @see ParametrizedBatchSetter
* @see PreparedStatementFunction
* @see PreparedStatementCreator
* @see ResultSetExtractor
* @see ResultSetRowMapper
* @see StatementFunction
*/
public class AsyncDatabase implements AsyncDataOperations {

protected final DataOperations operations;
protected final Executor executor;

/**
* Constructs a new {@link AsyncDatabase} instance by wrapping the given {@link DataSource} object in the default {@link Database}
* implementation.
* @param dataSource a valid DataSource instance
* @param executor an implementation of {@link Executor} used to create new threads for executing the asynchronous JDBC operations.
* @see Executor
*/
public AsyncDatabase(@NotNull DataSource dataSource, @NotNull Executor executor) {
this(new Database(dataSource), executor);
}

/**
* Constructs a new {@link AsyncDatabase} that will use the given {@link DataOperations}'s implementations asynchronously via {@link Executor}.
* @param operations the implementation of JDBC operations
* @param executor an implementation of {@link Executor} used to create new threads for executing the asynchronous JDBC operations.
* @see Executor
*/
public AsyncDatabase(@NotNull DataOperations operations, @NotNull Executor executor) {
Preconditions.checkNotNull(operations, "DataOperations cannot be null.");
Preconditions.checkNotNull(executor, "The Executor cannot be null");
this.operations = operations;
this.executor = executor;
}

/**
* Returns the Database that wraps the given DataSource's instance.
* @return the {@link Database} (it can be used for synchronous operations).
* @throws IllegalStateException if there is no {@link Database} available
*/
@NotNull
public Database getDatabase() throws IllegalStateException {
Preconditions.checkState(operations instanceof Database, "No Database instance available.");
return (Database) operations;
}

/**
* Returns the {@link DataSource} used by this {@link AsyncDatabase}'s instance.
* @return the DataSource
* @throws IllegalStateException if there was a problem while trying to retrieve the {@link DataSource}'s instance
*/
@NotNull
public DataSource getDataSource() {
Preconditions.checkState(operations instanceof DatabaseAccessor, "The provided implementation of DataOperations cannot supply its DataSource.");
return ((DatabaseAccessor) operations).getDataSource();
}

@Override
public <T> CompletableFuture<T> execute(@NotNull StatementFunction<T> callback) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.execute(callback), executor);
}

@Override
public CompletableFuture<Integer> update(@Language("MySQL") @NotNull String sql, boolean getGeneratedKeys) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.update(sql, getGeneratedKeys), executor);
}

@Override
public <T> CompletableFuture<T> query(@Language("MySQL") @NotNull String sql, ResultSetExtractor<T> extractor) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.query(sql, extractor), executor);
}

@Override
public <T> CompletableFuture<List<T>> queryForList(@Language("MySQL") @NotNull String sql, ResultSetRowMapper<T> resultSetRowMapper) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.queryForList(sql, resultSetRowMapper), executor);
}

@Override
public <T> CompletableFuture<T> queryForObject(@Language("MySQL") @NotNull String sql, ResultSetRowMapper<T> resultSetRowMapper) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.queryForObject(sql, resultSetRowMapper), executor);
}

@Override
public <T> CompletableFuture<T> execute(@NotNull PreparedStatementCreator creator, @NotNull PreparedStatementFunction<T> callback) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.execute(creator, callback), executor);
}

@Override
public <T> CompletableFuture<T> execute(@Language("MySQL") @NotNull String sql, @NotNull PreparedStatementFunction<T> callback) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.execute(sql, callback), executor);
}

@Override
public CompletableFuture<Integer> update(@NotNull PreparedStatementCreator creator, @Nullable PreparedStatementSetter setter, boolean getGeneratedKey) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.update(creator, setter, getGeneratedKey), executor);
}

@Override
public CompletableFuture<Integer> update(@NotNull PreparedStatementCreator creator, boolean getGeneratedKeys) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.update(creator, getGeneratedKeys), executor);
}

@Override
public CompletableFuture<Integer> update(@Language("MySQL") @NotNull String sql, @Nullable PreparedStatementSetter setter, boolean getGeneratedKey) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.update(sql, setter, getGeneratedKey), executor);
}

@Override
public CompletableFuture<Integer> update(@Language("MySQL") @NotNull String sql, Object[] params, boolean getGeneratedKey, int... sqlTypes) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.update(sql, params, getGeneratedKey, sqlTypes), executor);
}

@Override
public CompletableFuture<Void> batchUpdate(@Language("MySQL") @NotNull String sql, @NotNull BatchSetter batchSetter) throws IllegalStateException {
return CompletableFuture.runAsync(() -> operations.batchUpdate(sql, batchSetter), executor);
}

@Override
public CompletableFuture<Void> batchUpdate(@Language("MySQL") @NotNull String sql, @Nullable List<Object[]> batchArgs, int... sqlTypes) throws IllegalStateException {
return CompletableFuture.runAsync(() -> operations.batchUpdate(sql, batchArgs, sqlTypes), executor);
}

@Override
public <T> CompletableFuture<Void> batchUpdate(@Language("MySQL") @NotNull String sql, @Nullable List<T> batchArgs, @NotNull ParametrizedBatchSetter<T> paramsBatchSetter) throws IllegalStateException {
return CompletableFuture.runAsync(() -> operations.batchUpdate(sql, batchArgs, paramsBatchSetter), executor);
}

@Override
public <T> CompletableFuture<T> query(@NotNull PreparedStatementCreator creator, @Nullable PreparedStatementSetter setter, @NotNull ResultSetExtractor<T> extractor) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.query(creator, setter, extractor), executor);
}

@Override
public <T> CompletableFuture<T> query(@NotNull PreparedStatementCreator creator, @NotNull ResultSetExtractor<T> extractor) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.query(creator, extractor), executor);
}

@Override
public <T> CompletableFuture<List<T>> query(@NotNull PreparedStatementCreator psc, @NotNull ResultSetRowMapper<T> resultSetRowMapper) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.query(psc, resultSetRowMapper), executor);
}

@Override
public <T> CompletableFuture<T> query(@Language("MySQL") @NotNull String sql, @Nullable PreparedStatementSetter setter, @NotNull ResultSetExtractor<T> extractor) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.query(sql, setter, extractor), executor);
}

@Override
public <T> CompletableFuture<List<T>> query(@Language("MySQL") @NotNull String sql, @Nullable PreparedStatementSetter pss, @NotNull ResultSetRowMapper<T> resultSetRowMapper) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.query(sql, pss, resultSetRowMapper));
}

@Override
public <T> CompletableFuture<T> query(@Language("MySQL") @NotNull String sql, @Nullable Object[] args, @NotNull ResultSetExtractor<T> extractor) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.query(sql, args, extractor));
}

@Override
public <T> CompletableFuture<T> query(@Language("MySQL") @NotNull String sql, @Nullable Object[] args, @NotNull ResultSetExtractor<T> extractor, int... sqlTypes) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.query(sql, args, extractor, sqlTypes), executor);
}

@Override
public <T> CompletableFuture<List<T>> queryForList(@Language("MySQL") @NotNull String sql, @Nullable Object[] args, @NotNull ResultSetRowMapper<T> resultSetRowMapper) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.queryForList(sql, args, resultSetRowMapper), executor);
}

@Override
public <T> CompletableFuture<List<T>> queryForList(@Language("MySQL") @NotNull String sql, @Nullable Object[] args, @NotNull ResultSetRowMapper<T> resultSetRowMapper, int... sqlTypes) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.queryForList(sql, args, resultSetRowMapper, sqlTypes), executor);
}

@Override
public <T> CompletableFuture<T> queryForObject(@Language("MySQL") @NotNull String sql, Object[] args, @NotNull ResultSetRowMapper<T> resultSetRowMapper) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.queryForObject(sql, args, resultSetRowMapper), executor);
}

@Override
public <T> CompletableFuture<T> queryForObject(@Language("MySQL") @NotNull String sql, Object[] args, ResultSetRowMapper<T> resultSetRowMapper, int... sqlTypes) throws DataAccessException {
return CompletableFuture.supplyAsync(() -> operations.queryForObject(sql, args, resultSetRowMapper, sqlTypes), executor);
}
}
Loading

0 comments on commit 484d07d

Please sign in to comment.