* In the above code, CommonOperations.DELETE_ALL and CommonOperations.INSERT_REFERENCE_DATA
* are operations shared by multiple test classes.
*
* Note that, to speed up test executions, a {@link DbSetupTracker} can be used, at the price of a slightly
* bigger complexity.
* @author JB Nizet
*/
public final class DbSetup {
private final Destination destination;
private final Operation operation;
private final BinderConfiguration binderConfiguration;
/**
* Constructor which uses the {@link DefaultBinderConfiguration#INSTANCE default binder configuration}.
* @param destination the destination of the sequence of database operations
* @param operation the operation to execute (most of the time, an instance of
* {@link com.ninja_squad.dbsetup.operation.CompositeOperation}
*/
public DbSetup(@Nonnull Destination destination, @Nonnull Operation operation) {
this(destination, operation, DefaultBinderConfiguration.INSTANCE);
}
/**
* Constructor allowing to use a custom {@link BinderConfiguration}.
* @param destination the destination of the sequence of database operations
* @param operation the operation to execute (most of the time, an instance of
* {@link com.ninja_squad.dbsetup.operation.CompositeOperation}
* @param binderConfiguration the binder configuration to use.
*/
public DbSetup(@Nonnull Destination destination,
@Nonnull Operation operation,
@Nonnull BinderConfiguration binderConfiguration) {
Preconditions.checkNotNull(destination, "destination may not be null");
Preconditions.checkNotNull(operation, "operation may not be null");
Preconditions.checkNotNull(binderConfiguration, "binderConfiguration may not be null");
this.destination = destination;
this.operation = operation;
this.binderConfiguration = binderConfiguration;
}
/**
* Executes the sequence of operations. All the operations use the same connection, and are grouped
* in a single transaction. The transaction is rolled back if any exception occurs.
*/
public void launch() {
try {
Connection connection = destination.getConnection();
try {
connection.setAutoCommit(false);
operation.execute(connection, binderConfiguration);
connection.commit();
}
catch (SQLException e) {
connection.rollback();
throw e;
}
catch (RuntimeException e) {
connection.rollback();
throw e;
}
finally {
connection.close();
}
}
catch (SQLException e) {
throw new DbSetupRuntimeException(e);
}
}
@Override
public String toString() {
return "DbSetup [destination="
+ destination
+ ", operation="
+ operation
+ ", binderConfiguration="
+ binderConfiguration
+ "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + binderConfiguration.hashCode();
result = prime * result + destination.hashCode();
result = prime * result + operation.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
DbSetup other = (DbSetup) obj;
return binderConfiguration.equals(other.binderConfiguration)
&& destination.equals(other.destination)
&& operation.equals(other.operation);
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/DbSetupRuntimeException.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup;
/**
* A runtime exception indicating that a DbSetup failed.
* @author JB Nizet
*/
public class DbSetupRuntimeException extends RuntimeException {
public DbSetupRuntimeException() {
super();
}
public DbSetupRuntimeException(String message, Throwable cause) {
super(message, cause);
}
public DbSetupRuntimeException(String message) {
super(message);
}
public DbSetupRuntimeException(Throwable cause) {
super(cause);
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/DbSetupTracker.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup;
import javax.annotation.Nonnull;
/**
*
* This class allows speeding up test execution, by avoiding re-executing the same sequence of database operations
* before each test method even if each of these test methods leaves the database as it is (and only performs read-only
* operations, which is the most frequent case).
*
*
Example usage:
*
* // the tracker is static because JUnit uses a separate Test instance for every test method.
* private static DbSetupTracker dbSetupTracker = new DbSetupTracker();
*
* @Before
* public void setUp() throws Exception {
* Operation operation =
* Operations.sequenceOf(
* CommonOperations.DELETE_ALL,
* CommonOperations.INSERT_REFERENCE_DATA,
* Operations.insertInto("CLIENT")
* .columns("CLIENT_ID", "FIRST_NAME", "LAST_NAME", "DATE_OF_BIRTH", "COUNTRY_ID")
* .values(1L, "John", "Doe", "1975-07-19", 1L)
* .values(2L, "Jack", "Smith", "1969-08-22", 2L)
* .build());
* DbSetup dbSetup = new DbSetup(new DataSourceDestination(dataSource), operation);
* dbSetupTracker.launchIfNecessary(dbSetup);
* }
*
* @Test
* public void readOnlyTest1() {
* dbSetupTracker.skipNextLaunch();
* ...
* }
*
* @Test
* public void readOnlyTest2() {
* dbSetupTracker.skipNextLaunch();
* ...
* }
*
* @Test
* public void readOnlyTest3() {
* dbSetupTracker.skipNextLaunch();
* ...
* }
*
* @Test
* public void readWriteTest1() {
* // No call to dbSetupTracker.skipNextLaunch();
* ...
* }
*
* @author JB Nizet
*/
public final class DbSetupTracker {
private DbSetup lastSetupLaunched;
private boolean nextLaunchSkipped;
/**
* Executes the given DbSetup unless all the following conditions are true:
*
*
{@link #skipNextLaunch()} has been called since the last call to this method;
*
the given dbSetup is equal to the last DbSetup launched by this method
*
* This method resets the skipNextLaunch flag to false.
* @param dbSetup the DbSetup to execute (or skip)
*/
public void launchIfNecessary(@Nonnull DbSetup dbSetup) {
boolean skipLaunch = nextLaunchSkipped && dbSetup.equals(lastSetupLaunched);
nextLaunchSkipped = false;
if (skipLaunch) {
return;
}
dbSetup.launch();
lastSetupLaunched = dbSetup;
}
/**
* Marks the current test method as read-only, and thus the need for the next test method to re-execute the same
* sequence of database setup operations.
*/
public void skipNextLaunch() {
this.nextLaunchSkipped = true;
}
@Override
public String toString() {
return "DbSetupTracker [lastSetupLaunched="
+ lastSetupLaunched
+ ", nextLaunchSkipped="
+ nextLaunchSkipped
+ "]";
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/Operations.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup;
import java.util.List;
import javax.annotation.Nonnull;
import com.ninja_squad.dbsetup.operation.CompositeOperation;
import com.ninja_squad.dbsetup.operation.DeleteAll;
import com.ninja_squad.dbsetup.operation.Insert;
import com.ninja_squad.dbsetup.operation.Operation;
import com.ninja_squad.dbsetup.operation.SqlOperation;
import com.ninja_squad.dbsetup.operation.Truncate;
/**
* A static factory class for operations. Static import of this class can help make the code more readable.
* @author JB Nizet
*/
public final class Operations {
private Operations() {
}
/**
* Creates a delete from table operation.
* @param table the table to delete all from
* @see DeleteAll
*/
public static DeleteAll deleteAllFrom(@Nonnull String table) {
return DeleteAll.from(table);
}
/**
* Creates a sequence of delete from table operations.
* @param tables the tables to delete all from
* @see DeleteAll
*/
public static Operation deleteAllFrom(@Nonnull String... tables) {
return DeleteAll.from(tables);
}
/**
* Creates a sequence of delete from ... operations.
* @param tables the tables to delete all from
* @see DeleteAll
*/
public static Operation deleteAllFrom(@Nonnull List tables) {
return DeleteAll.from(tables);
}
/**
* Creates a truncate table ... operation.
* @param table the table to truncate
* @see Truncate
*/
public static Truncate truncate(@Nonnull String table) {
return Truncate.table(table);
}
/**
* Creates a sequence of truncate table ... operations.
* @param tables the tables to truncate
* @see Truncate
*/
public static Operation truncate(@Nonnull String... tables) {
return Truncate.tables(tables);
}
/**
* Creates a sequence of truncate table ... operations.
* @param tables the tables to truncate
* @see Truncate
*/
public static Operation truncate(@Nonnull List tables) {
return Truncate.tables(tables);
}
/**
* Creates a SQL operation.
* @param sqlStatement the SQL statement to execute (using {@link java.sql.Statement#executeUpdate(String)})
* @see SqlOperation
*/
public static SqlOperation sql(@Nonnull String sqlStatement) {
return SqlOperation.of(sqlStatement);
}
/**
* Creates a sequence of SQL operations.
* @param sqlStatements the SQL statements to execute (using {@link java.sql.Statement#executeUpdate(String)})
* @see SqlOperation
*/
public static Operation sql(@Nonnull String... sqlStatements) {
return SqlOperation.of(sqlStatements);
}
/**
* Creates a sequence of SQL operations.
* @param sqlStatements the SQL statements to execute (using {@link java.sql.Statement#executeUpdate(String)})
* @see SqlOperation
*/
public static Operation sql(@Nonnull List sqlStatements) {
return SqlOperation.of(sqlStatements);
}
/**
* Creates a builder for a sequence of insert operations.
* @param table the table to insert into
* @see Insert
*/
public static Insert.Builder insertInto(@Nonnull String table) {
return Insert.into(table);
}
/**
* Creates a sequence of operations.
* @param operations the operations to put in a sequence
* @see CompositeOperation
*/
public static Operation sequenceOf(@Nonnull Operation... operations) {
return CompositeOperation.sequenceOf(operations);
}
/**
* Creates a sequence of operations.
* @param operations the operations to put in a sequence
* @see CompositeOperation
*/
public static Operation sequenceOf(@Nonnull List extends Operation> operations) {
return CompositeOperation.sequenceOf(operations);
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/bind/Binder.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.bind;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.ninja_squad.dbsetup.DbSetupTracker;
/**
* An object which binds a value to a prepared statement parameter. It's advised to make implementations of this
* interface immutable, and to make them implement equals and hashCode in order for {@link DbSetupTracker} to function
* properly, or to make them singletons.
* @author JB Nizet
*/
public interface Binder {
/**
* Binds the given value to the given parameter in the given prepared statement.
* @param statement the statement to bind the parameter to
* @param param The index of the parameter to bind in the statement
* @param value The value to bind (may be null)
* @throws SQLException if the binding throws a {@link SQLException}
*/
void bind(PreparedStatement statement, int param, Object value) throws SQLException;
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/bind/BinderConfiguration.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.bind;
import com.ninja_squad.dbsetup.DbSetup;
import com.ninja_squad.dbsetup.DbSetupTracker;
import javax.annotation.Nullable;
import java.sql.ParameterMetaData;
import java.sql.SQLException;
/**
* An object which returns the appropriate {@link Binder} based on the metadata of the prepared statement.
* The default instance of this interface is {@link DefaultBinderConfiguration}. If the binders returned by this
* default configuration don't fit for the particular database you're using, or if you would like the binders
* returned by the configuration to support additional data types, you might want to provide a different implementation
* of this interface to the {@link DbSetup}.
*
* It's advised to make implementations of this interface immutable, and to make them implement equals and hashCode
* in order for {@link DbSetupTracker} to function properly, or to make them singletons.
* @author JB Nizet
*/
public interface BinderConfiguration {
/**
* Returns the appropriate {@link Binder} for the given parameter, based on the given metadata.
* @param metadata the metadata allowing to decide which Binder to return. null if the Insert has been
* configured to not use metadata, or if the JDBC driver returned null metadata, or the JDBC driver threw a
* SQLException when asked for the metadata
* @param param the param for which a binder is requested
* @return the binder for the given param and its metadata
* @throws SQLException if a SQLException occurs while using the metadata
*/
Binder getBinder(@Nullable ParameterMetaData metadata, int param) throws SQLException;
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/bind/Binders.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012-2016, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.bind;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.TimeZone;
/**
* Utility class allowing to get various kinds of binders. The {@link DefaultBinderConfiguration} uses binders
* returned by this class, based on the type of the parameter.
* @author JB Nizet
*/
public final class Binders {
private static final Binder DEFAULT_BINDER = new DefaultBinder();
private static final Binder DATE_BINDER = new DateBinder();
private static final Binder TIMESTAMP_BINDER = new TimestampBinder();
private static final Binder DECIMAL_BINDER = new DecimalBinder();
private static final Binder INTEGER_BINDER = new IntegerBinder();
private static final Binder TIME_BINDER = new TimeBinder();
private static final Binder STRING_BINDER = new StringBinder();
private Binders() {
}
/**
* Returns the default binder. This binder is normally used for columns of a type that is not handled by the other
* binders. It is also used when the metadata are not used and the Insert thus doesn't know the type of the column.
* It simply uses stmt.setObject() to bind the parameter, except if the value being bound is of some
* some well-known type not handled by JDBC:
*
*
enum: the name of the enum is bound
*
java.util.Date: the date is transformed to a java.sql.Timestamp
*
java.util.Calendar: the calendar is transformed to a java.sql.Timestamp,
* and is passed as third argument of
* PreparedStatement.setTimestamp() to pass the timezone
*
java.time.LocalDate: transformed to a java.sql.Date
*
java.time.LocalTime: transformed to a java.sql.Time
*
java.time.LocalDateTime: transformed to a java.sql.Timestamp
*
java.time.Instant: transformed to a java.sql.Timestamp
*
java.time.ZonedDateTime and OffsetDateTime: transformed to a
* java.sql.Timestamp. The time zone is also used to create a Calendar passed as
* third argument of PreparedStatement.setTimestamp() to pass the timezone
*
java.time.OffsetTime: transformed to a
* java.sql.Time. The time zone is also used to create a Calendar passed as third
* argument of PreparedStatement.setTime() to pass the timezone
*
*/
public static Binder defaultBinder() {
return DEFAULT_BINDER;
}
/**
* Returns a binder suitable for columns of type CHAR and VARCHAR. The returned binder supports values of type
*
*
String
*
enum: the name of the enum is used as bound value
*
Object: the toString() of the object is used as bound value
*
*/
public static Binder stringBinder() {
return STRING_BINDER;
}
/**
* Returns a binder suitable for columns of type DATE. The returned binder supports values of type
*
*
java.sql.Date
*
java.util.Date: the milliseconds of the date are used to construct a
* java.sql.Date.
*
java.util.Calendar: the milliseconds of the calendar are used to construct a
* java.sql.Date, and the calendar is passed as third argument of
* PreparedStatement.setDate() to pass the timezone
*
*
String: the string is transformed to a java.sql.Date using the Date.valueOf()
* method
*
java.time.LocalDate: transformed to a java.sql.Date using
* Date.valueOf()
*
java.time.LocalDateTime: transformed to a LocalDate (and thus ignoring the time),
* and then transformed to a java.sql.Date using Date.valueOf()
*
java.time.Instantthe milliseconds of the instant are used to construct a
* java.sql.Date.
*
java.time.ZonedDateTime and java.time.OffsetDateTime: transformed to an Instant
* and then to a java.sql.Date. The time zone is also used to create a Calendar
* passed as third argument of PreparedStatement.setDate() to pass the timezone
*
* If the value is none of these types, stmt.setObject() is used to bind the value.
*/
public static Binder dateBinder() {
return DATE_BINDER;
}
/**
* Returns a binder suitable for columns of type TIMESTAMP and TIMESTAMP_WITH_TIMEZONE. The returned binder
* supports values of type
*
*
java.sql.Timestamp
*
java.util.Date: the milliseconds of the date are used to construct a
* java.sql.Timestamp
*
java.util.Calendar: the milliseconds of the calendar are used to construct a
* java.sql.Timestamp, and the calendar is passed as third argument of
* PreparedStatement.setTimestamp() to pass the timezone
*
String: the string is transformed to a java.sql.Timestamp using the
* Timestamp.valueOf() method, or using the java.sql.Date.valueOf() method if the
* string has less than 19 characters
*
java.time.LocalDateTime: transformed to a java.sql.Timestamp using
* Timestamp.valueOf()
*
java.time.LocalDate: transformed to a LocalDateTime with the time at start of day,
* and then transformed to a java.sql.Timestamp using Timestamp.valueOf()
*
java.time.Instant: transformed to a java.sql.Timestamp using
* Timestamp.from()
*
java.time.ZonedDateTime and java.time.OffsetDateTime: transformed to an Instant
* and then to a java.sql.Timestamp using Timestamp.from(). The time zone is also
* used to create a Calendar passed as third argument of
* PreparedStatement.setTimestamp() to pass the timezone
*
* If the value is none of these types, stmt.setObject() is used to bind the value.
*/
public static Binder timestampBinder() {
return TIMESTAMP_BINDER;
}
/**
* Returns a binder suitable for columns of type TIME or TIME_WITH_TIMEZONE. The returned binder supports values
* of type
*
*
java.sql.Time
*
java.util.Date: the milliseconds of the date are used to construct a
* java.sql.Time
*
java.util.Calendar: the milliseconds of the calendar are used to construct a
* java.sql.Time, and the calendar is passed as third argument of
* PreparedStatement.setTimestamp() to pass the timezone
*
*
String: the string is transformed to a java.sql.Time using the
* Time.valueOf() method
*
java.time.LocalTime: transformed to a java.sql.Time using
* Time.valueOf()
*
java.time.OffsetTime: transformed to a LocalTime and then to a
* java.sql.Time using Time.valueOf(). The time zone is also
* used to create a Calendar passed as third argument of
* PreparedStatement.setTime() to pass the timezone
*
* If the value is none of these types, stmt.setObject() is used to bind the value.
*/
public static Binder timeBinder() {
return TIME_BINDER;
}
/**
* Returns a binder suitable for numeric, decimal columns. The returned binder supports values of type
*
*
String: the string is transformed to a java.math.BigDecimal using its constructor
*
* If the value is none of these types, stmt.setObject() is used to bind the value.
*/
public static Binder decimalBinder() {
return DECIMAL_BINDER;
}
/**
* Returns a binder suitable for numeric, integer columns. The returned binder supports values of type
*
*
BigInteger: the object is transformed to a String and bound using
* stmt.setObject(), with BIGINT as target type.
*
*
enum: the enum is transformed into an integer by taking its ordinal
*
String: the string is bound using stmt.setObject(), with BIGINT as
* target type.
*
*
* If the value is none of these types, stmt.setObject() is used to bind the value.
*/
public static Binder integerBinder() {
return INTEGER_BINDER;
}
/**
* The implementation for {@link Binders#stringBinder()}
* @author JB Nizet
*/
private static final class StringBinder implements Binder {
@Override
public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException {
if (value instanceof String) {
stmt.setString(param, (String) value);
}
else if (value instanceof Enum>) {
stmt.setString(param, ((Enum>) value).name());
}
else if (value == null) {
stmt.setObject(param, null);
}
else {
stmt.setString(param, value.toString());
}
}
@Override
public String toString() {
return "Binders.stringBinder";
}
}
/**
* The implementation for {@link Binders#timeBinder()}
* @author JB Nizet
*/
private static final class TimeBinder implements Binder {
@Override
public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException {
if (value instanceof Time) {
stmt.setTime(param, (Time) value);
}
else if (value instanceof java.util.Date) {
stmt.setTime(param, new Time(((java.util.Date) value).getTime()));
}
else if (value instanceof Calendar) {
Calendar calendar = (Calendar) value;
stmt.setTime(param, new Time(calendar.getTimeInMillis()), calendar);
}
else if (value instanceof String) {
stmt.setTime(param, Time.valueOf((String) value));
}
else if (value instanceof LocalTime) {
stmt.setTime(param, Time.valueOf((LocalTime) value));
}
else if (value instanceof OffsetTime) {
OffsetTime offsetTime = (OffsetTime) value;
stmt.setTime(param,
Time.valueOf(offsetTime.toLocalTime()),
Calendar.getInstance(TimeZone.getTimeZone(offsetTime.getOffset())));
}
else {
stmt.setObject(param, value);
}
}
@Override
public String toString() {
return "Binders.timeBinder";
}
}
/**
* The implementation for {@link Binders#integerBinder()}
* @author JB Nizet
*/
private static final class IntegerBinder implements Binder {
@Override
public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException {
if (value instanceof BigInteger) {
stmt.setObject(param, value.toString(), Types.BIGINT);
}
else if (value instanceof Enum>) {
stmt.setInt(param, ((Enum>) value).ordinal());
}
else if (value instanceof String) {
stmt.setObject(param, value, Types.BIGINT);
}
else {
stmt.setObject(param, value);
}
}
@Override
public String toString() {
return "Binders.integerBinder";
}
}
/**
* The implementation for {@link Binders#decimalBinder()}
* @author JB Nizet
*/
private static final class DecimalBinder implements Binder {
@Override
public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException {
if (value instanceof String) {
stmt.setBigDecimal(param, new BigDecimal((String) value));
}
else {
stmt.setObject(param, value);
}
}
@Override
public String toString() {
return "Binders.decimalBinder";
}
}
/**
* The implementation for {@link Binders#timestampBinder()}
* @author JB Nizet
*/
private static final class TimestampBinder implements Binder {
// the number of chars in yyyy-mm-dd hh:mm:ss
private static final int MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP = 19;
@Override
public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException {
if (value instanceof Timestamp) {
stmt.setTimestamp(param, (Timestamp) value);
}
else if (value instanceof java.util.Date) {
stmt.setTimestamp(param, new Timestamp(((java.util.Date) value).getTime()));
}
else if (value instanceof Calendar) {
stmt.setTimestamp(param, new Timestamp(((Calendar) value).getTimeInMillis()), (Calendar) value);
}
else if (value instanceof String) {
String valueAsString = (String) value;
if (valueAsString.length() >= MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP) {
stmt.setTimestamp(param, Timestamp.valueOf(valueAsString));
}
else {
Date valueAsDate = Date.valueOf(valueAsString);
stmt.setTimestamp(param, new Timestamp(valueAsDate.getTime()));
}
}
else if (value instanceof LocalDateTime) {
LocalDateTime localDateTime = (LocalDateTime) value;
stmt.setTimestamp(param, Timestamp.valueOf(localDateTime));
}
else if (value instanceof Instant) {
Instant instant = (Instant) value;
stmt.setTimestamp(param, Timestamp.from(instant));
}
else if (value instanceof ZonedDateTime) {
ZonedDateTime zonedDateTime = (ZonedDateTime) value;
stmt.setTimestamp(param,
Timestamp.from(zonedDateTime.toInstant()),
Calendar.getInstance(TimeZone.getTimeZone(zonedDateTime.getZone())));
}
else if (value instanceof OffsetDateTime) {
OffsetDateTime offsetDateTime = (OffsetDateTime) value;
stmt.setTimestamp(param,
Timestamp.from(offsetDateTime.toInstant()),
Calendar.getInstance(TimeZone.getTimeZone(offsetDateTime.getOffset())));
}
else if (value instanceof LocalDate) {
LocalDate localDate = (LocalDate) value;
stmt.setTimestamp(param, Timestamp.valueOf(localDate.atStartOfDay()));
}
else {
stmt.setObject(param, value);
}
}
@Override
public String toString() {
return "Binders.timestampBinder";
}
}
/**
* The implementation for {@link Binders#dateBinder()}
* @author JB Nizet
*/
private static final class DateBinder implements Binder {
@Override
public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException {
if (value instanceof Date) {
stmt.setDate(param, (Date) value);
}
else if (value instanceof java.util.Date) {
stmt.setDate(param, new Date(((java.util.Date) value).getTime()));
}
else if (value instanceof Calendar) {
Calendar calendar = (Calendar) value;
stmt.setDate(param, new Date(calendar.getTimeInMillis()), calendar);
}
else if (value instanceof String) {
stmt.setDate(param, Date.valueOf((String) value));
}
else if (value instanceof LocalDate) {
LocalDate localDate = (LocalDate) value;
stmt.setDate(param, Date.valueOf(localDate));
}
else if (value instanceof LocalDateTime) {
LocalDateTime localDateTime = (LocalDateTime) value;
stmt.setDate(param, Date.valueOf(localDateTime.toLocalDate()));
}
else if (value instanceof Instant) {
Instant instant = (Instant) value;
stmt.setDate(param, new Date(instant.toEpochMilli()));
}
else if (value instanceof ZonedDateTime) {
ZonedDateTime zonedDateTime = (ZonedDateTime) value;
stmt.setDate(param,
new Date(zonedDateTime.toInstant().toEpochMilli()),
Calendar.getInstance(TimeZone.getTimeZone(zonedDateTime.getZone())));
}
else if (value instanceof OffsetDateTime) {
OffsetDateTime offsetDateTime = (OffsetDateTime) value;
stmt.setDate(param,
new Date(offsetDateTime.toInstant().toEpochMilli()),
Calendar.getInstance(TimeZone.getTimeZone(offsetDateTime.getOffset())));
}
else {
stmt.setObject(param, value);
}
}
@Override
public String toString() {
return "Binders.dateBinder";
}
}
/**
* The implementation for {@link Binders#defaultBinder()}
* @author JB Nizet
*/
private static final class DefaultBinder implements Binder {
@Override
public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException {
if (value instanceof Enum) {
stmt.setString(param, ((Enum) value).name());
}
else if (value instanceof java.util.Date) {
stmt.setTimestamp(param, new Timestamp(((java.util.Date) value).getTime()));
}
else if (value instanceof Calendar) {
Calendar calendar = (Calendar) value;
stmt.setTimestamp(param, new Timestamp(calendar.getTime().getTime()), calendar);
}
else if (value instanceof LocalDate) {
stmt.setDate(param, Date.valueOf((LocalDate) value));
}
else if (value instanceof LocalTime) {
stmt.setTime(param, Time.valueOf((LocalTime) value));
}
else if (value instanceof LocalDateTime) {
stmt.setTimestamp(param, Timestamp.valueOf((LocalDateTime) value));
}
else if (value instanceof Instant) {
stmt.setTimestamp(param, Timestamp.from((Instant) value));
}
else if (value instanceof ZonedDateTime) {
ZonedDateTime zonedDateTime = (ZonedDateTime) value;
stmt.setTimestamp(param,
Timestamp.from(zonedDateTime.toInstant()),
Calendar.getInstance(TimeZone.getTimeZone(zonedDateTime.getZone())));
}
else if (value instanceof OffsetDateTime) {
OffsetDateTime offsetDateTime = (OffsetDateTime) value;
stmt.setTimestamp(param,
Timestamp.from(offsetDateTime.toInstant()),
Calendar.getInstance(TimeZone.getTimeZone(offsetDateTime.getOffset())));
}
else if (value instanceof OffsetTime) {
OffsetTime offsetTime = (OffsetTime) value;
stmt.setTime(param,
Time.valueOf(offsetTime.toLocalTime()),
Calendar.getInstance(TimeZone.getTimeZone(offsetTime.getOffset())));
}
else {
stmt.setObject(param, value);
}
}
@Override
public String toString() {
return "Binders.defaultBinder";
}
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/bind/DefaultBinderConfiguration.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012-2016, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.bind;
import java.sql.ParameterMetaData;
import java.sql.SQLException;
import java.sql.Types;
import com.ninja_squad.dbsetup.DbSetup;
/**
* Default implementation of {@link BinderConfiguration}, used by default by {@link DbSetup}.
* @author JB Nizet
*/
public class DefaultBinderConfiguration implements BinderConfiguration {
/**
* A shareable, reusable instance of this class.
*/
public static final DefaultBinderConfiguration INSTANCE = new DefaultBinderConfiguration();
/**
* Constructor. Protected because it doesn't make much sense to instantiate this class,
* but extending it can be useful.
*/
protected DefaultBinderConfiguration() {
}
/**
* Uses the parameter type of the given parameter and returns the following Binders depending on the type
* got from the metadata.
*
*
null metadata (i.e. metadata not used or not returned): {@link Binders#defaultBinder()}
DECIMAL, DOUBLE, FLOAT, NUMERIC, REAL : {@link Binders#decimalBinder()}
*
other : {@link Binders#defaultBinder()}
*
*
* If the parameter type can't be obtained from the metadata, the default binder is returned.
*/
@Override
public Binder getBinder(ParameterMetaData metadata, int param) throws SQLException {
if (metadata == null) {
return Binders.defaultBinder();
}
try {
int sqlType = metadata.getParameterType(param);
if (sqlType == Types.DATE) {
return Binders.dateBinder();
}
if (sqlType == Types.TIME || sqlType == Types.TIME_WITH_TIMEZONE) {
return Binders.timeBinder();
}
if (sqlType == Types.TIMESTAMP || sqlType == Types.TIMESTAMP_WITH_TIMEZONE) {
return Binders.timestampBinder();
}
if (sqlType == Types.BIGINT
|| sqlType == Types.INTEGER
|| sqlType == Types.SMALLINT
|| sqlType == Types.TINYINT) {
return Binders.integerBinder();
}
if (sqlType == Types.DECIMAL
|| sqlType == Types.DOUBLE
|| sqlType == Types.FLOAT
|| sqlType == Types.NUMERIC
|| sqlType == Types.REAL) {
return Binders.decimalBinder();
}
if (sqlType == Types.VARCHAR
|| sqlType == Types.CHAR
|| sqlType == Types.LONGNVARCHAR
|| sqlType == Types.LONGVARCHAR
|| sqlType == Types.NCHAR
|| sqlType == Types.NVARCHAR) {
return Binders.stringBinder();
}
return Binders.defaultBinder();
}
catch (SQLException e) {
// the database can't return types from parameters. Fall back to default binder.
return Binders.defaultBinder();
}
}
@Override
public String toString() {
return "DefaultBinderConfiguration";
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/destination/DataSourceDestination.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.destination;
import com.ninja_squad.dbsetup.util.Preconditions;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* A destination which wraps a DataSource and gets its connection from the wrapped DataSource
* @author JB Nizet
*/
@Immutable
public final class DataSourceDestination implements Destination {
private final DataSource dataSource;
/**
* Constructor
* @param dataSource the wrapped DataSource
*/
public DataSourceDestination(@Nonnull DataSource dataSource) {
Preconditions.checkNotNull(dataSource, "dataSource may not be null");
this.dataSource = dataSource;
}
/**
* Factory method creating a new DataSourceDestination. This allows a more readable style than using the
* constructor:
*
*
* DbSetup dbSetup = new DbSetup(DataSourceDestination.with(dataSource), operation);
*
*
* or, if this method is statically imported:
*
*
* DbSetup dbSetup = new DbSetup(with(dataSource), operation);
*
*
* instead of
*
*
* DbSetup dbSetup = new DbSetup(new DataSourceDestination(dataSource), operation);
*
*
* @param dataSource the wrapped DataSource
*/
public static DataSourceDestination with(@Nonnull DataSource dataSource) {
return new DataSourceDestination(dataSource);
}
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public String toString() {
return "DataSourceDestination [dataSource=" + dataSource + "]";
}
@Override
public int hashCode() {
return dataSource.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
DataSourceDestination other = (DataSourceDestination) obj;
return dataSource.equals(other.dataSource);
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/destination/Destination.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.destination;
import java.sql.Connection;
import java.sql.SQLException;
import com.ninja_squad.dbsetup.DbSetupTracker;
/**
* The destination of a database setup. It's advised to make implementations of this
* interface immutable, and to make them implement equals and hashCode in order for {@link DbSetupTracker} to function
* properly, or to make them singletons.
* @author JB Nizet
*/
public interface Destination {
/**
* Returns a connection to the destination database
* @return a connection to the destination database
* @throws SQLException if a connection can't be returned
*/
Connection getConnection() throws SQLException;
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/destination/DriverManagerDestination.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.destination;
import com.ninja_squad.dbsetup.util.Preconditions;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* A destination which uses the {@link DriverManager} to get a connection
* @author JB Nizet
*/
@Immutable
public final class DriverManagerDestination implements Destination {
private final String url;
private final String user;
private final String password;
/**
* Constructor
* @param url the URL of the database
* @param user the user used to get a connection
* @param password the password used to get a connection
*/
public DriverManagerDestination(@Nonnull String url, String user, String password) {
Preconditions.checkNotNull(url, "url may not be null");
this.url = url;
this.user = user;
this.password = password;
}
/**
* Factory method creating a new DriverManagerDestination. This allows a more readable style than using the
* constructor:
*
*
* DbSetup dbSetup = new DbSetup(DriverManagerDestination.with(url, user, password), operation);
*
*
* or, if this method is statically imported:
*
*
* DbSetup dbSetup = new DbSetup(with(url, user, password), operation);
*
*
* @param url the URL of the database
* @param user the user used to get a connection
* @param password the password used to get a connection
*/
public static DriverManagerDestination with(@Nonnull String url, String user, String password) {
return new DriverManagerDestination(url, user, password);
}
@Override
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
@Override
public String toString() {
return "DriverManagerDestination [url="
+ url
+ ", user="
+ user
+ ", password="
+ password
+ "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + url.hashCode();
result = prime * result + ((password == null) ? 0 : password.hashCode());
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
DriverManagerDestination other = (DriverManagerDestination) obj;
if (password == null) {
if (other.password != null) {
return false;
}
}
else if (!password.equals(other.password)) {
return false;
}
if (!url.equals(other.url)) {
return false;
}
if (user == null) {
if (other.user != null) {
return false;
}
}
else if (!user.equals(other.user)) {
return false;
}
return true;
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/generator/DateSequenceValueGenerator.java
================================================
/*
* The MIT License
*
* Copyright (c) 2013-2016, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.generator;
import javax.annotation.Nonnull;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import com.ninja_squad.dbsetup.util.Preconditions;
/**
* A {@link ValueGenerator} that returns a sequence of dates, starting at a given zoned date time and incremented by a
* given time, specified as an increment and a temporal unit.
* @author JB
*/
public final class DateSequenceValueGenerator implements ValueGenerator {
// the number of chars in yyyy-mm-dd hh:mm:ss
private static final int MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP = 19;
/**
* The available units for the increment of this sequence
* @deprecated use ChronoField instead. This enum is only kept to maintain backward compatibility
*/
@Deprecated
public enum CalendarField {
YEAR(ChronoUnit.YEARS),
MONTH(ChronoUnit.MONTHS),
DAY(ChronoUnit.DAYS),
HOUR(ChronoUnit.HOURS),
MINUTE(ChronoUnit.MINUTES),
SECOND(ChronoUnit.SECONDS),
MILLISECOND(ChronoUnit.MILLIS);
private TemporalUnit unit;
CalendarField(TemporalUnit unit) {
this.unit = unit;
}
private TemporalUnit toTemporalUnit() {
return unit;
}
}
private ZonedDateTime next;
private int increment;
private TemporalUnit unit;
DateSequenceValueGenerator() {
this(LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()), 1, ChronoUnit.DAYS);
}
private DateSequenceValueGenerator(ZonedDateTime next, int increment, TemporalUnit unit) {
this.next = next;
this.increment = increment;
this.unit = unit;
}
/**
* Restarts the sequence at the given date, in the given time zone
* @return this instance, for chaining
* @deprecated use one of the other startingAt() methods taking java.time types as argument
*/
@Deprecated
public DateSequenceValueGenerator startingAt(@Nonnull Date startDate, @Nonnull TimeZone timeZone) {
Preconditions.checkNotNull(startDate, "startDate may not be null");
Preconditions.checkNotNull(timeZone, "timeZone may not be null");
next = startDate.toInstant().atZone(timeZone.toZoneId());
return this;
}
/**
* Restarts the sequence at the given date, in the default time zone
* @return this instance, for chaining
* @deprecated use one of the other startingAt() methods taking java.time types as argument
*/
@Deprecated
public DateSequenceValueGenerator startingAt(@Nonnull Date startDate) {
return startingAt(startDate, TimeZone.getDefault());
}
/**
* Restarts the sequence at the given date
* @return this instance, for chaining
* @deprecated use one of the other startingAt() methods taking java.time types as argument
*/
@Deprecated
public DateSequenceValueGenerator startingAt(@Nonnull Calendar startDate) {
Preconditions.checkNotNull(startDate, "startDate may not be null");
next = startDate.toInstant().atZone(startDate.getTimeZone().toZoneId());
return this;
}
/**
* Restarts the sequence at the given date, in the default time zone
* @param startDate the starting date, as a String. The supported formats are the same as the ones supported by
* {@link com.ninja_squad.dbsetup.bind.Binders#timestampBinder()}, i.e. the formats supported by
* java.sql.Timestamp.valueOf() and java.sql.Date.valueOf()
* @return this instance, for chaining
*/
public DateSequenceValueGenerator startingAt(@Nonnull String startDate) {
Preconditions.checkNotNull(startDate, "startDate may not be null");
if (startDate.length() >= MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP) {
return startingAt(new Date(Timestamp.valueOf(startDate).getTime()));
}
else {
return startingAt(new Date(java.sql.Date.valueOf(startDate).getTime()));
}
}
/**
* Restarts the sequence at the given local date, in the default time zone
* @return this instance, for chaining
*/
public DateSequenceValueGenerator startingAt(@Nonnull LocalDate startDate) {
return startingAt(startDate.atStartOfDay());
}
/**
* Restarts the sequence at the given local date time, in the default time zone
* @return this instance, for chaining
*/
public DateSequenceValueGenerator startingAt(@Nonnull LocalDateTime startDate) {
return startingAt(startDate.atZone(ZoneId.systemDefault()));
}
/**
* Restarts the sequence at the given zoned date time
* @return this instance, for chaining
*/
public DateSequenceValueGenerator startingAt(@Nonnull ZonedDateTime startDate) {
next = startDate;
return this;
}
/**
* Increments the date by the given increment of the given unit.
* @return this instance, for chaining
* @deprecated use the other {@link #incrementingBy(int, TemporalUnit)} method
*/
@Deprecated
public DateSequenceValueGenerator incrementingBy(int increment, @Nonnull CalendarField unit) {
Preconditions.checkNotNull(unit, "unit may not be null");
return incrementingBy(increment, unit.toTemporalUnit());
}
/**
* Increments the date by the given increment of the given unit. One of the constants of ChronoField is typically
* used for the unit.
* @return this instance, for chaining
*/
public DateSequenceValueGenerator incrementingBy(int increment, @Nonnull TemporalUnit unit) {
Preconditions.checkNotNull(unit, "unit may not be null");
this.increment = increment;
this.unit = unit;
return this;
}
@Override
public ZonedDateTime nextValue() {
ZonedDateTime result = next;
next = next.plus(increment, unit);
return result;
}
@Override
public String toString() {
return "DateSequenceValueGenerator["
+ "next=" + next
+ ", increment=" + increment
+ ", unit=" + unit
+ "]";
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/generator/SequenceValueGenerator.java
================================================
/*
* The MIT License
*
* Copyright (c) 2013, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.generator;
/**
* A {@link ValueGenerator} which generates a sequence of long values. By default, the sequence starts at 1 and
* increments by 1, but this can be customized. Instances of this class are created using
* {@link ValueGenerators#sequence()}.
* @author JB Nizet
*/
public final class SequenceValueGenerator implements ValueGenerator {
private long next = 1L;
private int increment = 1;
SequenceValueGenerator() {
this(1, 1);
}
private SequenceValueGenerator(long start, int increment) {
this.next = start;
this.increment = increment;
}
/**
* Restarts the sequence at the given value
* @param start the starting value of the created generator
* @return this instance, for chaining
*/
public SequenceValueGenerator startingAt(long start) {
this.next = start;
return this;
}
/**
* Increments the value by the given increment.
* @return this instance, for chaining
*/
public SequenceValueGenerator incrementingBy(int increment) {
this.increment = increment;
return this;
}
@Override
public Long nextValue() {
long result = next;
next += increment;
return result;
}
@Override
public String toString() {
return "SequenceValueGenerator["
+ "next="
+ next
+ ", increment="
+ increment
+ "]";
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/generator/StringSequenceValueGenerator.java
================================================
/*
* The MIT License
*
* Copyright (c) 2013-2016, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.generator;
import com.ninja_squad.dbsetup.util.Preconditions;
/**
* A {@link ValueGenerator} that returns a string prefix followed by a sequence number, optionally left-padded
* with 0 to ensure a correct ordering (for example: CODE_001, CODE_002, etc.). Instances of this generator
* are created by {@link ValueGenerators#stringSequence(String)}.
* @author JB
*/
public final class StringSequenceValueGenerator implements ValueGenerator {
private String prefix;
private long next;
private int increment;
/**
* The length of the number once padded. 0 if no padding must be applied
*/
private int paddedNumberLength;
StringSequenceValueGenerator(String prefix) {
this(prefix, 1L, 1, 0);
}
private StringSequenceValueGenerator(String prefix, long next, int increment, int paddedNumberLength) {
this.prefix = prefix;
this.next = next;
this.increment = increment;
this.paddedNumberLength = paddedNumberLength;
}
/**
* Tells the generator to left-pad the number it generates with 0 until the length of the number is the given
* length. For example, passing 3 to this method will generate numbers 001, 002, 003, 004, etc. If the generated
* number, before padding, has a length already equal or larger that the given length, the number is not padded.
* @param paddedNumberLength the length of the number once padded. Must be > 0.
* @return this instance, for chaining
*/
public StringSequenceValueGenerator withLeftPadding(int paddedNumberLength) {
Preconditions.checkArgument(paddedNumberLength > 0, "paddedNumberLength must be > 0");
this.paddedNumberLength = paddedNumberLength;
return this;
}
/**
* Tells the generator to avoid left-padding the number it generates with 0
* @return this instance, for chaining
*/
public StringSequenceValueGenerator withoutLeftPadding() {
this.paddedNumberLength = 0;
return this;
}
/**
* Restarts the sequence at the given value
* @param start the new starting value of the sequence
* @return this instance, for chaining
*/
public StringSequenceValueGenerator startingAt(long start) {
this.next = start;
return this;
}
/**
* Increments the number by the given increment.
* @return this instance, for chaining
*/
public StringSequenceValueGenerator incrementingBy(int increment) {
this.increment = increment;
return this;
}
@Override
public String nextValue() {
long number = next;
next += increment;
return prefix + leftPadIfNecessary(number);
}
private String leftPadIfNecessary(long number) {
String numberAsString = Long.toString(number);
if (numberAsString.length() >= paddedNumberLength) {
return numberAsString;
}
StringBuilder builder = new StringBuilder(paddedNumberLength);
for (int i = 0; i < paddedNumberLength - numberAsString.length(); i++) {
builder.append('0');
}
return builder.append(numberAsString).toString();
}
@Override
public String toString() {
return "StringSequenceValueGenerator["
+ "prefix='" + prefix + '\''
+ ", next=" + next
+ ", increment=" + increment
+ ", paddedNumberLength=" + paddedNumberLength
+ "]";
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/generator/ValueGenerator.java
================================================
/*
* The MIT License
*
* Copyright (c) 2013, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.generator;
/**
* A value generator allows generating values for a specific column in a sequence of inserts. This is useful when you
* don't want to specify a value for each of the inserted rows in a table, and when a default value is not an option
* either because, for example, the column has a unique constraint.
* @param the type of value that this generator generates
*
* @see ValueGenerators for useful implementations of this interface
* @author JB Nizet
*/
public interface ValueGenerator {
/**
* Called each time a new row is inserted, to get the value to insert in the column using this value generator.
* @return the value to insert in the column associated with this generator.
*/
T nextValue();
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/generator/ValueGenerators.java
================================================
/*
* The MIT License
*
* Copyright (c) 2013, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.generator;
import com.ninja_squad.dbsetup.util.Preconditions;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Utility class containing factory methods for {@link ValueGenerator}
* @author JB Nizet
*/
public final class ValueGenerators {
private ValueGenerators() {
}
/**
* Returns a value generator which generates a sequence of long values starting with 1, with an increment of 1.
* The starting value and increment can be customized using
*
*/
public static SequenceValueGenerator sequence() {
return new SequenceValueGenerator();
}
/**
* Returns a value generator which always returns the same, given value.
*/
public static ValueGenerator constant(@Nullable final T constant) {
return new ValueGenerator() {
@Override
public T nextValue() {
return constant;
}
@Override
public String toString() {
return "ValueGenerators.constant(" + constant + ")";
}
};
}
/**
* Returns a value generator that returns a string prefix followed by a sequence number, optionally left-padded
* with 0 to ensure a correct ordering (for example: CODE_001, CODE_002, etc.). The returned generator starts the
* sequence at 1 and increments by 1, and doesn't pad the numbers.
* @param prefix the prefix before the generated number (for example: "CODE_").
*/
public static StringSequenceValueGenerator stringSequence(@Nonnull String prefix) {
Preconditions.checkNotNull(prefix, "prefix may not be null");
return new StringSequenceValueGenerator(prefix);
}
/**
* Returns a value generator that returns a sequence of dates, starting at a given date and incremented by a given
* time, specified as an increment and a calendar field. The returned generator starts today at 00:00:00
* and increments by 1 day by default.
*/
public static DateSequenceValueGenerator dateSequence() {
return new DateSequenceValueGenerator();
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/operation/CompositeOperation.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.operation;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.ninja_squad.dbsetup.bind.BinderConfiguration;
/**
* A composite operation or, in other words, an operation which consists in executing a sequence of other operations.
* @author JB Nizet
*/
@Immutable
public final class CompositeOperation implements Operation {
private static final Operation NOP = new Operation() {
@Override
public void execute(Connection connection, BinderConfiguration configuration) {
// does nothing since it's a NOP
}
@Override
public String toString() {
return "NOP";
}
};
private final List operations;
private CompositeOperation(List extends Operation> operations) {
this.operations = new ArrayList(operations);
}
/**
* Creates a new Operation containing all the given operations
* @param operations the sequence of operations
*/
public static Operation sequenceOf(@Nonnull Operation... operations) {
return sequenceOf(Arrays.asList(operations));
}
/**
* Creates a new Operation containing all the given operations
* @param operations the sequence of operations
*/
public static Operation sequenceOf(@Nonnull List extends Operation> operations) {
if (operations.isEmpty()) {
return NOP;
}
else if (operations.size() == 1) {
return operations.get(0);
}
return new CompositeOperation(operations);
}
/**
* Executes the sequence of operations
* @throws SQLException as soon as one of the operations in the sequence throws a SQLException
*/
@Override
public void execute(Connection connection, BinderConfiguration configuration) throws SQLException {
for (Operation operation : operations) {
operation.execute(connection, configuration);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
boolean first = true;
for (Operation operation : operations) {
if (!first) {
builder.append('\n');
}
else {
first = false;
}
builder.append(operation);
}
return builder.toString();
}
@Override
public int hashCode() {
return operations.hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (getClass() != o.getClass()) {
return false;
}
CompositeOperation other = (CompositeOperation) o;
return this.operations.equals(other.operations);
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/operation/DeleteAll.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.operation;
import com.ninja_squad.dbsetup.bind.BinderConfiguration;
import com.ninja_squad.dbsetup.util.Preconditions;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* An operation which deletes everything from a given database table.
* @author JB Nizet
*/
@Immutable
public final class DeleteAll implements Operation {
private final String table;
private DeleteAll(String table) {
Preconditions.checkNotNull(table, "table may not be null");
this.table = table;
}
@Override
public void execute(Connection connection, BinderConfiguration configuration) throws SQLException {
Statement stmt = connection.createStatement();
try {
stmt.executeUpdate("delete from " + table);
}
finally {
stmt.close();
}
}
/**
* Returns an operation which deletes all the rows from the given table.
* @param table the table to delete everything from.
*/
public static DeleteAll from(@Nonnull String table) {
return new DeleteAll(table);
}
/**
* Returns a composite operation which deletes all the rows from the given tables, in the same order as the
* tables. If A has a foreign key to B, which has a foreign key to C, tables should be listed in the following
* order: A, B, C. Otherwise, referential constraint will break. If there is a cycle in the dependencies, you might
* want to use a sequence of {@link SqlOperation} to disable the foreign key constraints, then delete everything
* from the tables, then use another sequence of {@link SqlOperation} to re-enable the foreign key constraints.
* @param tables the tables to delete everything from.
*/
public static Operation from(@Nonnull String... tables) {
return from(Arrays.asList(tables));
}
/**
* Returns a composite operation which deletes all the rows from the given tables, in the same order as the
* tables. If A has a foreign key to B, which has a foreign key to C, tables should be listed in the following
* order: A, B, C. Otherwise, referential constraint will break. If there is a cycle in the dependencies, you might
* want to use a sequence of {@link SqlOperation} to disable the foreign key constraints, then delete everything
* from the tables, then use another sequence of {@link SqlOperation} to re-enable the foreign key constraints.
* @param tables the tables to delete everything from.
*/
public static Operation from(@Nonnull List tables) {
List operations = new ArrayList(tables.size());
for (String table : tables) {
operations.add(new DeleteAll(table));
}
return CompositeOperation.sequenceOf(operations);
}
@Override
public String toString() {
return "delete from " + table;
}
@Override
public int hashCode() {
return table.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
DeleteAll other = (DeleteAll) obj;
return this.table.equals(other.table);
}
}
================================================
FILE: DbSetup-core/src/main/java/com/ninja_squad/dbsetup/operation/Insert.java
================================================
/*
* The MIT License
*
* Copyright (c) 2012-2016, Ninja Squad
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.ninja_squad.dbsetup.operation;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.ninja_squad.dbsetup.bind.Binder;
import com.ninja_squad.dbsetup.bind.BinderConfiguration;
import com.ninja_squad.dbsetup.bind.Binders;
import com.ninja_squad.dbsetup.generator.ValueGenerator;
import com.ninja_squad.dbsetup.generator.ValueGenerators;
import com.ninja_squad.dbsetup.util.Preconditions;
/**
* Operation which inserts one or several rows into a table. Example usage:
*
*
* The above operation will insert two rows inside the CLIENT table. For each row, the column DELETED will be set to
* false and the column VERSION will be set to 1. For the column CLIENT_TYPE, instead of using the
* {@link Binder} associated to the type of the column found in the metadata of the table, a custom binder will be used.
*
* Instead of specifying values as an ordered sequence which must match the sequence of column names, some might prefer
* passing a map of column/value associations. This makes things more verbose, but can be more readable in some cases,
* when the number of columns is high. This also allows not specifying any value for columns that must stay null.
* The map can be constructed like any other map and passed to the builder, or it can be added using a fluent builder.
* The following snippet:
*
*
* Insert insert =
* Insert.into("CLIENT")
* .columns("CLIENT_ID", "FIRST_NAME", "LAST_NAME", "DATE_OF_BIRTH", "CLIENT_TYPE")
* .row().column("CLIENT_ID", 1L)
* .column("FIRST_NAME", "John")
* .column("LAST_NAME", "Doe")
* .column("DATE_OF_BIRTH", "1975-07-19")
* .end()
* .row().column("CLIENT_ID", 2L)
* .column("FIRST_NAME", "Jack")
* .column("LAST_NAME", "Smith")
* .end() // null date of birth, because it's not in the row
* .build();
*
*
* When building the Insert using column/value associations, it might seem redundant to specify the set of column names
* before inserting the rows. Remember, though, that all the rows of an Insert are inserted using the same
* parameterized SQL query. We thus need a robust and easy way to know all the columns to insert for every row of the
* insert. To be able to spot errors easily and early, and to avoid complex rules, the rule is thus simple: the set of
* columns (excluding the generated ones) is specified either by columns(), or by the columns of the first row. All the
* subsequent rows may not have additional columns. And null is inserted for all the absent columns of the
* subsequent rows. The above example can thus be written as
*
*
* Insert insert =
* Insert.into("CLIENT")
* .row().column("CLIENT_ID", 1L)
* .column("FIRST_NAME", "John")
* .column("LAST_NAME", "Doe")
* .column("DATE_OF_BIRTH", "1975-07-19")
* .end()
* .row().column("CLIENT_ID", 2L)
* .column("FIRST_NAME", "Jack")
* .column("LAST_NAME", "Smith")
* .end() // null date of birth, because it's not in the row
* .build();
*
*
* but the following will throw an exception, because the DATE_OF_BIRTH column is not part of the first row:
*
*