Refactoring and added sql Helper
This commit is contained in:
parent
b289da801a
commit
e86b88f144
@ -10,7 +10,7 @@
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>inject</artifactId>
|
||||
<artifactId>core</artifactId>
|
||||
|
||||
<properties>
|
||||
<!-- Application Properties -->
|
||||
@ -1,6 +1,6 @@
|
||||
package de.neitzel.inject;
|
||||
package de.neitzel.core.inject;
|
||||
|
||||
import de.neitzel.inject.annotation.Component;
|
||||
import de.neitzel.core.inject.annotation.Component;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.inject.annotation;
|
||||
package de.neitzel.core.inject.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.inject.annotation;
|
||||
package de.neitzel.core.inject.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
231
core/src/main/java/de/neitzel/core/sql/Query.java
Normal file
231
core/src/main/java/de/neitzel/core/sql/Query.java
Normal file
@ -0,0 +1,231 @@
|
||||
package de.neitzel.core.sql;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* Helper class to build and execute parameterized SQL queries with factory-based result mapping.
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class Query<T> {
|
||||
|
||||
/**
|
||||
* An Integer Factory that can be used to read Integer Values of a ResultSet that only has Integers (e.g. a min oder max query)
|
||||
*/
|
||||
public static final Function<ResultSet, Integer> INTEGER_FACTORY = rs -> {
|
||||
try {
|
||||
return rs.getInt(1);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
private final Connection connection;
|
||||
private final List<ParameterSetter> parameterSetters = new ArrayList<>();
|
||||
private Function<ResultSet, T> factory;
|
||||
private String queryText;
|
||||
|
||||
public static void execute(final Connection connection, final String query) throws SQLException {
|
||||
new Query<Object>(connection)
|
||||
.setQueryText(query)
|
||||
.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the query.
|
||||
*/
|
||||
public Query<T> setQueryText(final String queryText) {
|
||||
this.queryText = queryText;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the query content from a resource URL.
|
||||
*/
|
||||
public Query<T> setQueryResource(final String resourcePath) {
|
||||
log.info("loading resource: {}", resourcePath);
|
||||
try (Scanner scanner = new Scanner(Objects.requireNonNull(getClass().getResourceAsStream(resourcePath)),
|
||||
StandardCharsets.UTF_8)) {
|
||||
this.queryText = scanner.useDelimiter("\\A").next();
|
||||
}
|
||||
log.info("query text: {}", this.queryText);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces placeholders in the query.
|
||||
*/
|
||||
public Query<T> replace(final String placeholder, final String value) {
|
||||
this.queryText = this.queryText.replace(placeholder, value);
|
||||
log.info("query text: {}", this.queryText);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another parameter setter
|
||||
*
|
||||
* @param index Index of parameter in prepared statement
|
||||
* @param value Value to set.
|
||||
* @param setter Setter to use on prepared statement.
|
||||
* @param <X> Type of the Parameter.
|
||||
* @return The Query.
|
||||
*/
|
||||
public <X> Query<T> addParameter(final int index, final X value, final TriSqlFunction<PreparedStatement, Integer, X> setter) {
|
||||
parameterSetters.add(ps -> setter.apply(ps, index, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a ParameterSetter/
|
||||
*
|
||||
* @param setter Setter for a parameter.
|
||||
* @return the Qyery.
|
||||
*/
|
||||
public Query<T> addParameter(ParameterSetter setter) {
|
||||
parameterSetters.add(setter);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a result factory by name.
|
||||
*/
|
||||
public Query<T> factory(final Function<ResultSet, T> factory) {
|
||||
this.factory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query and returns a stream of results. This Stream must be closed so that the underlying ResultSet is closed.
|
||||
*/
|
||||
private Stream<T> stream() throws SQLException {
|
||||
ResultSet rs = createPreparedStatement().executeQuery();
|
||||
TrimmingResultSet trimmingResultSet = new TrimmingResultSet(rs);
|
||||
return streamFromResultSet(trimmingResultSet, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PreparedStatement and applies all Parameter.
|
||||
*
|
||||
* @return the created PreparedStatement
|
||||
* @throws SQLException thrown if the PreparedStatement could not be created.
|
||||
*/
|
||||
private PreparedStatement createPreparedStatement() throws SQLException {
|
||||
PreparedStatement ps = connection.prepareStatement(queryText);
|
||||
for (ParameterSetter setter : parameterSetters) {
|
||||
setter.apply(ps);
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query wich has no result.
|
||||
*
|
||||
* @throws SQLException Thrown when query cannot be executed.
|
||||
*/
|
||||
public void execute() throws SQLException {
|
||||
try (PreparedStatement ps = createPreparedStatement()) {
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams the results of a ResultSet using a factory that creates instances for each row of the ResultSet
|
||||
*
|
||||
* @param rs ResultSet to stream from
|
||||
* @param factory Factory to create instances of T.
|
||||
* @return Stream of T instances.
|
||||
*/
|
||||
private Stream<T> streamFromResultSet(final ResultSet rs, final Function<ResultSet, T> factory) {
|
||||
Iterator<T> iterator = new Iterator<>() {
|
||||
private boolean hasNextChecked = false;
|
||||
private boolean hasNext;
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public boolean hasNext() {
|
||||
if (!hasNextChecked) {
|
||||
hasNext = rs.next();
|
||||
hasNextChecked = true;
|
||||
}
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
hasNextChecked = false;
|
||||
return factory.apply(rs);
|
||||
}
|
||||
};
|
||||
Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED);
|
||||
return StreamSupport.stream(spliterator, false)
|
||||
.onClose(() -> {
|
||||
try {
|
||||
rs.getStatement().close();
|
||||
} catch (SQLException ignored) {
|
||||
// Exception is ignored.
|
||||
}
|
||||
try {
|
||||
rs.close();
|
||||
} catch (SQLException ignored) {
|
||||
// Exception is ignored.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public <R> R withStream(Function<Stream<T>, R> handler) throws SQLException {
|
||||
try (Stream<T> stream = stream()) {
|
||||
return handler.apply(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function with three parameters and no result which can throw an SQLException
|
||||
*
|
||||
* @param <T> type of first parameter
|
||||
* @param <U> type of second parameter
|
||||
* @param <V> type of third parameter
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TriSqlFunction<T, U, V> {
|
||||
|
||||
/**
|
||||
* Calls the thre parameter function.
|
||||
*
|
||||
* @param t first parameter.
|
||||
* @param u second parameter.
|
||||
* @param v third parameter.
|
||||
* @throws SQLException Function could throw an SQLException.
|
||||
*/
|
||||
void apply(T t, U u, V v) throws SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* ParameterSetter is a function Interface that could be used to alter a PreparedStatement.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ParameterSetter {
|
||||
|
||||
/**
|
||||
* Does the required work on PreparedStatement.
|
||||
*
|
||||
* @param ps PreparedStatement to work on.
|
||||
* @throws SQLException Could be thrown when working on PreparedStatement.
|
||||
*/
|
||||
void apply(PreparedStatement ps) throws SQLException;
|
||||
}
|
||||
}
|
||||
2366
core/src/main/java/de/neitzel/core/sql/TrimmingResultSet.java
Normal file
2366
core/src/main/java/de/neitzel/core/sql/TrimmingResultSet.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,10 @@
|
||||
package de.neitzel.fx.injectfx;
|
||||
package de.neitzel.core.inject;
|
||||
|
||||
import de.neitzel.fx.injectfx.testcomponents.test1ok.SuperClass;
|
||||
import de.neitzel.fx.injectfx.testcomponents.test1ok.TestComponent1_1;
|
||||
import de.neitzel.fx.injectfx.testcomponents.test1ok.TestInterface1_1;
|
||||
import de.neitzel.fx.injectfx.testcomponents.test1ok.TestInterface1_2;
|
||||
import de.neitzel.fx.injectfx.testcomponents.test1ok.sub.TestComponent1_2;
|
||||
import de.neitzel.inject.InjectableComponentScanner;
|
||||
import de.neitzel.core.inject.testcomponents.test1ok.SuperClass;
|
||||
import de.neitzel.core.inject.testcomponents.test1ok.TestComponent1_1;
|
||||
import de.neitzel.core.inject.testcomponents.test1ok.TestInterface1_1;
|
||||
import de.neitzel.core.inject.testcomponents.test1ok.TestInterface1_2;
|
||||
import de.neitzel.core.inject.testcomponents.test1ok.sub.TestComponent1_2;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
@ -17,7 +16,7 @@ class InjectableComponentScannerTest {
|
||||
*/
|
||||
@Test
|
||||
void testLoadComponents() {
|
||||
InjectableComponentScanner scanner = new InjectableComponentScanner("de.neitzel.injectfx.testcomponents.test1ok");
|
||||
InjectableComponentScanner scanner = new InjectableComponentScanner("de.neitzel.core.inject.testcomponents.test1ok");
|
||||
var instantiableComponents = scanner.getInstantiableComponents();
|
||||
var nonUniqueTypes = scanner.getNotUniqueTypes();
|
||||
|
||||
@ -38,7 +37,7 @@ class InjectableComponentScannerTest {
|
||||
*/
|
||||
@Test
|
||||
void testComponentsFailWithUnknownParameters() {
|
||||
InjectableComponentScanner scanner = new InjectableComponentScanner("de.neitzel.injectfx.testcomponents.test2fail");
|
||||
InjectableComponentScanner scanner = new InjectableComponentScanner("de.neitzel.core.inject.testcomponents.test2fail");
|
||||
var instantiableComponents = scanner.getInstantiableComponents();
|
||||
var nonUniqueTypes = scanner.getNotUniqueTypes();
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
package de.neitzel.core.inject.testcomponents.test1ok;
|
||||
|
||||
public class SuperClass {
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package de.neitzel.fx.injectfx.testcomponents.test1ok;
|
||||
package de.neitzel.core.inject.testcomponents.test1ok;
|
||||
|
||||
import de.neitzel.inject.annotation.Component;
|
||||
import de.neitzel.core.inject.annotation.Component;
|
||||
|
||||
@Component
|
||||
public class TestComponent1_1 extends SuperClass implements TestInterface1_2 {
|
||||
@ -0,0 +1,4 @@
|
||||
package de.neitzel.core.inject.testcomponents.test1ok;
|
||||
|
||||
public interface TestInterface1_1 {
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
package de.neitzel.core.inject.testcomponents.test1ok;
|
||||
|
||||
public interface TestInterface1_2 {
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package de.neitzel.core.inject.testcomponents.test1ok.sub;
|
||||
|
||||
import de.neitzel.core.inject.testcomponents.test1ok.SuperClass;
|
||||
import de.neitzel.core.inject.testcomponents.test1ok.TestInterface1_1;
|
||||
import de.neitzel.core.inject.testcomponents.test1ok.TestInterface1_2;
|
||||
import de.neitzel.core.inject.annotation.Component;
|
||||
|
||||
@Component
|
||||
public class TestComponent1_2 extends SuperClass implements TestInterface1_1, TestInterface1_2 {
|
||||
public TestComponent1_2() {
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package de.neitzel.fx.injectfx.testcomponents.test2fail;
|
||||
package de.neitzel.core.inject.testcomponents.test2fail;
|
||||
|
||||
import de.neitzel.inject.annotation.Component;
|
||||
import de.neitzel.core.inject.annotation.Component;
|
||||
|
||||
/**
|
||||
* TestComponent1 that should fail.
|
||||
@ -16,7 +16,7 @@
|
||||
<link.name>${project.artifactId}</link.name>
|
||||
<launcher>${project.artifactId}</launcher>
|
||||
<appName>${project.artifactId}</appName>
|
||||
<main.class>de.neitzel.fx.injectfx.example.Main</main.class>
|
||||
<main.class>de.neitzel.core.fx.injectfx.example.Main</main.class>
|
||||
<jar.filename>${project.artifactId}-${project.version}</jar.filename>
|
||||
</properties>
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.component.example;
|
||||
package de.neitzel.core.fx.component.example;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -1,6 +1,6 @@
|
||||
package de.neitzel.fx.component.example;
|
||||
package de.neitzel.core.fx.component.example;
|
||||
|
||||
import de.neitzel.fx.component.ComponentLoader;
|
||||
import de.neitzel.core.fx.component.ComponentLoader;
|
||||
import javafx.application.Application;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.component.example;
|
||||
package de.neitzel.core.fx.component.example;
|
||||
|
||||
/**
|
||||
* Another Main class as workaround when the JavaFX Application ist started without
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.component.example;
|
||||
package de.neitzel.core.fx.component.example;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.injectfx.example;
|
||||
package de.neitzel.core.fx.injectfx.example;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.injectfx.example;
|
||||
package de.neitzel.core.fx.injectfx.example;
|
||||
|
||||
/**
|
||||
* Another Main class as workaround when the JavaFX Application ist started without
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.injectfx.example;
|
||||
package de.neitzel.core.fx.injectfx.example;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
@ -6,7 +6,7 @@
|
||||
<AnchorPane xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns:nfx="http://example.com/nfx"
|
||||
fx:controller="de.neitzel.fx.component.ComponentController"
|
||||
fx:controller="de.neitzel.core.fx.component.ComponentController"
|
||||
prefWidth="300" prefHeight="100">
|
||||
<children>
|
||||
<TextField layoutX="10" layoutY="10" prefWidth="280"
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<AnchorPane prefHeight="127.0" prefWidth="209.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.neitzel.fx.injectfx.example.MainWindow">
|
||||
<AnchorPane prefHeight="127.0" prefWidth="209.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.neitzel.core.fx.injectfx.example.MainWindow">
|
||||
<children>
|
||||
<Button fx:id="button" layoutX="44.0" layoutY="70.0" mnemonicParsing="false" onAction="#onButtonClick" text="Click Me" />
|
||||
<TextField fx:id="textField" layoutX="14.0" layoutY="24.0" />
|
||||
@ -6,7 +6,7 @@
|
||||
<AnchorPane xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns:nfx="http://example.com/nfx"
|
||||
fx:controller="de.neitzel.fx.component.ComponentController"
|
||||
fx:controller="de.neitzel.core.fx.component.ComponentController"
|
||||
prefWidth="300" prefHeight="180">
|
||||
<children>
|
||||
<TextField layoutX="10" layoutY="10" prefWidth="280"
|
||||
|
||||
@ -17,14 +17,13 @@
|
||||
<link.name>${project.artifactId}</link.name>
|
||||
<launcher>${project.artifactId}</launcher>
|
||||
<appName>${project.artifactId}</appName>
|
||||
<main.class>example.de.neitzel.fx.injectfx.Main</main.class>
|
||||
<jar.filename>${project.artifactId}-${project.version}</jar.filename>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>de.neitzel.lib</groupId>
|
||||
<artifactId>inject</artifactId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.component;
|
||||
package de.neitzel.core.fx.component;
|
||||
|
||||
import javafx.beans.property.*;
|
||||
import java.lang.reflect.*;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.component;
|
||||
package de.neitzel.core.fx.component;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.component;
|
||||
package de.neitzel.core.fx.component;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
@ -1,6 +1,6 @@
|
||||
package de.neitzel.fx.injectfx;
|
||||
package de.neitzel.core.fx.injectfx;
|
||||
|
||||
import de.neitzel.inject.InjectableComponentScanner;
|
||||
import de.neitzel.core.inject.InjectableComponentScanner;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.injectfx;
|
||||
package de.neitzel.core.fx.injectfx;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package de.neitzel.fx.injectfx;
|
||||
package de.neitzel.core.fx.injectfx;
|
||||
|
||||
import de.neitzel.inject.InjectableComponentScanner;
|
||||
import de.neitzel.core.inject.InjectableComponentScanner;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.mvvm;
|
||||
package de.neitzel.core.fx.mvvm;
|
||||
|
||||
/**
|
||||
* Enum representing the direction of data binding between a JavaFX control and a ViewModel property.
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.mvvm;
|
||||
package de.neitzel.core.fx.mvvm;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.StringProperty;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.mvvm;
|
||||
package de.neitzel.core.fx.mvvm;
|
||||
|
||||
import javafx.fxml.Initializable;
|
||||
import java.net.URL;
|
||||
@ -1,4 +1,4 @@
|
||||
package de.neitzel.fx.mvvm;
|
||||
package de.neitzel.core.fx.mvvm;
|
||||
|
||||
import javafx.beans.property.*;
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
package de.neitzel.fx.injectfx.testcomponents.test1ok;
|
||||
|
||||
public class SuperClass {
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
package de.neitzel.fx.injectfx.testcomponents.test1ok;
|
||||
|
||||
public interface TestInterface1_1 {
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
package de.neitzel.fx.injectfx.testcomponents.test1ok;
|
||||
|
||||
public interface TestInterface1_2 {
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package de.neitzel.fx.injectfx.testcomponents.test1ok.sub;
|
||||
|
||||
import de.neitzel.fx.injectfx.testcomponents.test1ok.SuperClass;
|
||||
import de.neitzel.fx.injectfx.testcomponents.test1ok.TestInterface1_1;
|
||||
import de.neitzel.fx.injectfx.testcomponents.test1ok.TestInterface1_2;
|
||||
import de.neitzel.inject.annotation.Component;
|
||||
|
||||
@Component
|
||||
public class TestComponent1_2 extends SuperClass implements TestInterface1_1, TestInterface1_2 {
|
||||
public TestComponent1_2() {
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user