#93 - Adding support for optimistic locking based on @Version column.
Original pull request: #314.
This commit is contained in:
committed by
Jens Schauder
parent
75e2ba3ede
commit
8e6797dd04
@@ -48,6 +48,7 @@ import org.springframework.util.Assert;
|
||||
* to create an instance.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Bogdan Ilchyshyn
|
||||
*/
|
||||
public interface DatabaseClient {
|
||||
|
||||
@@ -729,9 +730,9 @@ public interface DatabaseClient {
|
||||
*
|
||||
* @param objectToUpdate the object of which the attributes will provide the values for the update and the primary
|
||||
* key. Must not be {@literal null}.
|
||||
* @return a {@link UpdateSpec} for further configuration of the update. Guaranteed to be not {@literal null}.
|
||||
* @return a {@link UpdateMatchingSpec} for further configuration of the update. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
UpdateSpec using(T objectToUpdate);
|
||||
UpdateMatchingSpec using(T objectToUpdate);
|
||||
|
||||
/**
|
||||
* Use the given {@code tableName} as update target.
|
||||
|
||||
@@ -44,7 +44,6 @@ import java.util.stream.Collectors;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -59,6 +58,7 @@ import org.springframework.data.r2dbc.mapping.OutboundRow;
|
||||
import org.springframework.data.r2dbc.mapping.SettableValue;
|
||||
import org.springframework.data.r2dbc.query.Update;
|
||||
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
|
||||
import org.springframework.data.relational.core.query.Criteria;
|
||||
import org.springframework.data.relational.core.query.CriteriaDefinition;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -70,6 +70,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Mingyuan Wu
|
||||
* @author Bogdan Ilchyshyn
|
||||
*/
|
||||
class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
||||
|
||||
@@ -1198,7 +1199,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
||||
|
||||
assertRegularClass(table);
|
||||
|
||||
return new DefaultTypedUpdateSpec<>(table, null, null);
|
||||
return new DefaultTypedUpdateSpec<>(table, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1287,24 +1288,27 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultTypedUpdateSpec<T> implements TypedUpdateSpec<T>, UpdateSpec {
|
||||
class DefaultTypedUpdateSpec<T> implements TypedUpdateSpec<T>, UpdateMatchingSpec {
|
||||
|
||||
private final Class<T> typeToUpdate;
|
||||
private final @Nullable SqlIdentifier table;
|
||||
private final @Nullable T objectToUpdate;
|
||||
private final @Nullable CriteriaDefinition where;
|
||||
|
||||
DefaultTypedUpdateSpec(Class<T> typeToUpdate, @Nullable SqlIdentifier table, @Nullable T objectToUpdate) {
|
||||
DefaultTypedUpdateSpec(Class<T> typeToUpdate, @Nullable SqlIdentifier table, @Nullable T objectToUpdate,
|
||||
@Nullable CriteriaDefinition where) {
|
||||
this.typeToUpdate = typeToUpdate;
|
||||
this.table = table;
|
||||
this.objectToUpdate = objectToUpdate;
|
||||
this.where = where;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateSpec using(T objectToUpdate) {
|
||||
public UpdateMatchingSpec using(T objectToUpdate) {
|
||||
|
||||
Assert.notNull(objectToUpdate, "Object to update must not be null");
|
||||
|
||||
return new DefaultTypedUpdateSpec<>(this.typeToUpdate, this.table, objectToUpdate);
|
||||
return new DefaultTypedUpdateSpec<>(this.typeToUpdate, this.table, objectToUpdate, this.where);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1312,7 +1316,15 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
||||
|
||||
Assert.notNull(tableName, "Table name must not be null!");
|
||||
|
||||
return new DefaultTypedUpdateSpec<>(this.typeToUpdate, tableName, this.objectToUpdate);
|
||||
return new DefaultTypedUpdateSpec<>(this.typeToUpdate, tableName, this.objectToUpdate, this.where);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateSpec matching(CriteriaDefinition criteria) {
|
||||
|
||||
Assert.notNull(criteria, "Criteria must not be null!");
|
||||
|
||||
return new DefaultTypedUpdateSpec<>(this.typeToUpdate, this.table, this.objectToUpdate, criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1356,8 +1368,14 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
PreparedOperation<?> operation = mapper.getMappedObject(mapper.createUpdate(table, update).withCriteria(
|
||||
org.springframework.data.relational.core.query.Criteria.where(dataAccessStrategy.toSql(ids.get(0))).is(id)));
|
||||
Criteria updateCriteria = org.springframework.data.relational.core.query.Criteria
|
||||
.where(dataAccessStrategy.toSql(ids.get(0))).is(id);
|
||||
if (this.where != null) {
|
||||
updateCriteria = updateCriteria.and(this.where);
|
||||
}
|
||||
|
||||
PreparedOperation<?> operation = mapper
|
||||
.getMappedObject(mapper.createUpdate(table, update).withCriteria(updateCriteria));
|
||||
|
||||
return exchangeUpdate(operation);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.r2dbc.core;
|
||||
|
||||
import io.r2dbc.spi.Row;
|
||||
import io.r2dbc.spi.RowMetadata;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -30,10 +31,12 @@ import java.util.stream.Collectors;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.data.mapping.IdentifierAccessor;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.projection.ProjectionInformation;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
@@ -59,6 +62,7 @@ import org.springframework.util.Assert;
|
||||
* prepared in an application context and given to services as bean reference.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Bogdan Ilchyshyn
|
||||
* @since 1.1
|
||||
*/
|
||||
public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAware {
|
||||
@@ -373,6 +377,8 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
|
||||
|
||||
RelationalPersistentEntity<T> persistentEntity = getRequiredEntity(entity);
|
||||
|
||||
setVersionIfNecessary(persistentEntity, entity);
|
||||
|
||||
return this.databaseClient.insert() //
|
||||
.into(persistentEntity.getType()) //
|
||||
.table(tableName).using(entity) //
|
||||
@@ -381,6 +387,19 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
|
||||
.defaultIfEmpty(entity);
|
||||
}
|
||||
|
||||
private <T> void setVersionIfNecessary(RelationalPersistentEntity<T> persistentEntity, T entity) {
|
||||
RelationalPersistentProperty versionProperty = persistentEntity.getVersionProperty();
|
||||
if (versionProperty == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> versionPropertyType = versionProperty.getType();
|
||||
Long version = versionPropertyType.isPrimitive() ? 1L : 0L;
|
||||
ConversionService conversionService = this.dataAccessStrategy.getConverter().getConversionService();
|
||||
PersistentPropertyAccessor<?> propertyAccessor = persistentEntity.getPropertyAccessor(entity);
|
||||
propertyAccessor.setProperty(versionProperty, conversionService.convert(version, versionPropertyType));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.r2dbc.core.R2dbcEntityOperations#update(java.lang.Object)
|
||||
@@ -392,21 +411,78 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
|
||||
|
||||
RelationalPersistentEntity<T> persistentEntity = getRequiredEntity(entity);
|
||||
|
||||
return this.databaseClient.update() //
|
||||
DatabaseClient.UpdateMatchingSpec updateMatchingSpec = this.databaseClient.update() //
|
||||
.table(persistentEntity.getType()) //
|
||||
.table(persistentEntity.getTableName()).using(entity) //
|
||||
.fetch().rowsUpdated().handle((rowsUpdated, sink) -> {
|
||||
.table(persistentEntity.getTableName()) //
|
||||
.using(entity);
|
||||
|
||||
if (rowsUpdated == 0) {
|
||||
sink.error(new TransientDataAccessResourceException(
|
||||
String.format("Failed to update table [%s]. Row with Id [%s] does not exist.",
|
||||
persistentEntity.getTableName(), persistentEntity.getIdentifierAccessor(entity).getIdentifier())));
|
||||
DatabaseClient.UpdateSpec updateSpec = updateMatchingSpec;
|
||||
if (persistentEntity.hasVersionProperty()) {
|
||||
updateSpec = updateMatchingSpec.matching(createMatchingVersionCriteria(entity, persistentEntity));
|
||||
incrementVersion(entity, persistentEntity);
|
||||
}
|
||||
|
||||
return updateSpec.fetch() //
|
||||
.rowsUpdated() //
|
||||
.flatMap(rowsUpdated -> rowsUpdated == 0
|
||||
? handleMissingUpdate(entity, persistentEntity) : Mono.just(entity));
|
||||
}
|
||||
|
||||
private <T> Mono<? extends T> handleMissingUpdate(T entity, RelationalPersistentEntity<T> persistentEntity) {
|
||||
if (!persistentEntity.hasVersionProperty()) {
|
||||
return Mono.error(new TransientDataAccessResourceException(
|
||||
formatTransientEntityExceptionMessage(entity, persistentEntity)));
|
||||
}
|
||||
|
||||
return doCount(getByIdQuery(entity, persistentEntity), entity.getClass(), persistentEntity.getTableName())
|
||||
.map(count -> {
|
||||
if (count == 0) {
|
||||
throw new TransientDataAccessResourceException(
|
||||
formatTransientEntityExceptionMessage(entity, persistentEntity));
|
||||
} else {
|
||||
sink.next(entity);
|
||||
throw new OptimisticLockingFailureException(
|
||||
formatOptimisticLockingExceptionMessage(entity, persistentEntity));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private <T> String formatOptimisticLockingExceptionMessage(T entity, RelationalPersistentEntity<T> persistentEntity) {
|
||||
return String.format("Failed to update table [%s]. Version does not match for row with Id [%s].",
|
||||
persistentEntity.getTableName(), persistentEntity.getIdentifierAccessor(entity).getIdentifier());
|
||||
}
|
||||
|
||||
private <T> String formatTransientEntityExceptionMessage(T entity, RelationalPersistentEntity<T> persistentEntity) {
|
||||
return String.format("Failed to update table [%s]. Row with Id [%s] does not exist.",
|
||||
persistentEntity.getTableName(), persistentEntity.getIdentifierAccessor(entity).getIdentifier());
|
||||
}
|
||||
|
||||
private <T> void incrementVersion(T entity, RelationalPersistentEntity<T> persistentEntity) {
|
||||
PersistentPropertyAccessor<?> propertyAccessor = persistentEntity.getPropertyAccessor(entity);
|
||||
RelationalPersistentProperty versionProperty = persistentEntity.getVersionProperty();
|
||||
|
||||
ConversionService conversionService = this.dataAccessStrategy.getConverter().getConversionService();
|
||||
Object currentVersionValue = propertyAccessor.getProperty(versionProperty);
|
||||
long newVersionValue = 1L;
|
||||
if (currentVersionValue != null) {
|
||||
newVersionValue = conversionService.convert(currentVersionValue, Long.class) + 1;
|
||||
}
|
||||
Class<?> versionPropertyType = versionProperty.getType();
|
||||
propertyAccessor.setProperty(versionProperty, conversionService.convert(newVersionValue, versionPropertyType));
|
||||
}
|
||||
|
||||
private <T> Criteria createMatchingVersionCriteria(T entity, RelationalPersistentEntity<T> persistentEntity) {
|
||||
PersistentPropertyAccessor<?> propertyAccessor = persistentEntity.getPropertyAccessor(entity);
|
||||
RelationalPersistentProperty versionProperty = persistentEntity.getVersionProperty();
|
||||
|
||||
Object version = propertyAccessor.getProperty(versionProperty);
|
||||
Criteria.CriteriaStep versionColumn = Criteria.where(dataAccessStrategy.toSql(versionProperty.getColumnName()));
|
||||
if (version == null) {
|
||||
return versionColumn.isNull();
|
||||
} else {
|
||||
return versionColumn.is(version);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.r2dbc.core.R2dbcEntityOperations#delete(java.lang.Object)
|
||||
|
||||
@@ -33,10 +33,11 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.data.r2dbc.convert.MappingR2dbcConverter;
|
||||
import org.springframework.data.r2dbc.core.DatabaseClient;
|
||||
@@ -53,6 +54,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
* Abstract integration tests for {@link SimpleR2dbcRepository} to be ran against various databases.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Bogdan Ilchyshyn
|
||||
*/
|
||||
public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2dbcIntegrationTestSupport {
|
||||
|
||||
@@ -117,6 +119,42 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
assertThat(map).containsEntry("name", "SCHAUFELRADBAGGER").containsEntry("manual", 12).containsKey("id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSaveNewObjectAndSetVersionIfWrapperVersionPropertyExists() {
|
||||
|
||||
LegoSetVersionable legoSet = new LegoSetVersionable(null, "SCHAUFELRADBAGGER", 12, null);
|
||||
|
||||
repository.save(legoSet) //
|
||||
.as(StepVerifier::create) //
|
||||
.consumeNextWith(actual -> assertThat(actual.getVersion()).isEqualTo(0)) //
|
||||
.verifyComplete();
|
||||
|
||||
Map<String, Object> map = jdbc.queryForMap("SELECT * FROM legoset");
|
||||
assertThat(map) //
|
||||
.containsEntry("name", "SCHAUFELRADBAGGER") //
|
||||
.containsEntry("manual", 12) //
|
||||
.containsEntry("version", 0) //
|
||||
.containsKey("id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSaveNewObjectAndSetVersionIfPrimitiveVersionPropertyExists() {
|
||||
|
||||
LegoSetPrimitiveVersionable legoSet = new LegoSetPrimitiveVersionable(null, "SCHAUFELRADBAGGER", 12, -1);
|
||||
|
||||
repository.save(legoSet) //
|
||||
.as(StepVerifier::create) //
|
||||
.consumeNextWith(actual -> assertThat(actual.getVersion()).isEqualTo(1)) //
|
||||
.verifyComplete();
|
||||
|
||||
Map<String, Object> map = jdbc.queryForMap("SELECT * FROM legoset");
|
||||
assertThat(map) //
|
||||
.containsEntry("name", "SCHAUFELRADBAGGER") //
|
||||
.containsEntry("manual", 12) //
|
||||
.containsEntry("version", 1) //
|
||||
.containsKey("id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUpdateObject() {
|
||||
|
||||
@@ -135,6 +173,44 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
assertThat(map).containsEntry("name", "SCHAUFELRADBAGGER").containsEntry("manual", 14).containsKey("id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUpdateVersionableObjectAndIncreaseVersion() {
|
||||
|
||||
jdbc.execute("INSERT INTO legoset (name, manual, version) VALUES('SCHAUFELRADBAGGER', 12, 42)");
|
||||
Integer id = jdbc.queryForObject("SELECT id FROM legoset", Integer.class);
|
||||
|
||||
LegoSetVersionable legoSet = new LegoSetVersionable(id, "SCHAUFELRADBAGGER", 12, 42);
|
||||
legoSet.setManual(14);
|
||||
|
||||
repository.save(legoSet) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNextCount(1) //
|
||||
.verifyComplete();
|
||||
|
||||
assertThat(legoSet.getVersion()).isEqualTo(43);
|
||||
|
||||
Map<String, Object> map = jdbc.queryForMap("SELECT * FROM legoset");
|
||||
assertThat(map)
|
||||
.containsEntry("name", "SCHAUFELRADBAGGER") //
|
||||
.containsEntry("manual", 14) //
|
||||
.containsEntry("version", 43) //
|
||||
.containsKey("id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailWithOptimistickLockingWhenVersionDoesNotMatchOnUpdate() {
|
||||
|
||||
jdbc.execute("INSERT INTO legoset (name, manual, version) VALUES('SCHAUFELRADBAGGER', 12, 42)");
|
||||
Integer id = jdbc.queryForObject("SELECT id FROM legoset", Integer.class);
|
||||
|
||||
LegoSetVersionable legoSet = new LegoSetVersionable(id, "SCHAUFELRADBAGGER", 12, 0);
|
||||
|
||||
repository.save(legoSet) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectError(OptimisticLockingFailureException.class) //
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSaveObjectsUsingIterable() {
|
||||
|
||||
@@ -392,4 +468,28 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Table("legoset")
|
||||
@NoArgsConstructor
|
||||
static class LegoSetVersionable extends LegoSet {
|
||||
@Version Integer version;
|
||||
|
||||
public LegoSetVersionable(Integer id, String name, Integer manual, Integer version) {
|
||||
super(id, name, manual);
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Table("legoset")
|
||||
@NoArgsConstructor
|
||||
static class LegoSetPrimitiveVersionable extends LegoSet {
|
||||
@Version int version;
|
||||
|
||||
public LegoSetPrimitiveVersionable(Integer id, String name, Integer manual, int version) {
|
||||
super(id, name, manual);
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,13 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
* Utility class for testing against H2.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Bogdan Ilchyshyn
|
||||
*/
|
||||
public class H2TestSupport {
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET = "CREATE TABLE legoset (\n" //
|
||||
+ " id integer CONSTRAINT id PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " manual integer NULL\n," //
|
||||
+ " cert bytea NULL\n" //
|
||||
@@ -39,6 +41,7 @@ public class H2TestSupport {
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET_WITH_ID_GENERATION = "CREATE TABLE legoset (\n" //
|
||||
+ " id serial CONSTRAINT id PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " manual integer NULL\n" //
|
||||
+ ");";
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
|
||||
* Utility class for testing against MySQL.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Bogdan Ilchyshyn
|
||||
*/
|
||||
public class MySqlTestSupport {
|
||||
|
||||
@@ -42,6 +43,7 @@ public class MySqlTestSupport {
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET = "CREATE TABLE legoset (\n" //
|
||||
+ " id integer PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " manual integer NULL\n," //
|
||||
+ " cert varbinary(255) NULL\n" //
|
||||
@@ -49,6 +51,7 @@ public class MySqlTestSupport {
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET_WITH_ID_GENERATION = "CREATE TABLE legoset (\n" //
|
||||
+ " id integer AUTO_INCREMENT PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " manual integer NULL\n" //
|
||||
+ ") ENGINE=InnoDB;";
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.testcontainers.containers.PostgreSQLContainer;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
* @author Bogdan Ilchyshyn
|
||||
*/
|
||||
public class PostgresTestSupport {
|
||||
|
||||
@@ -25,6 +26,7 @@ public class PostgresTestSupport {
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET = "CREATE TABLE legoset (\n" //
|
||||
+ " id integer CONSTRAINT id PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " manual integer NULL\n," //
|
||||
+ " cert bytea NULL\n" //
|
||||
@@ -32,6 +34,7 @@ public class PostgresTestSupport {
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET_WITH_ID_GENERATION = "CREATE TABLE legoset (\n" //
|
||||
+ " id serial CONSTRAINT id PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " manual integer NULL\n" //
|
||||
+ ");";
|
||||
|
||||
@@ -12,11 +12,13 @@ import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
|
||||
* Utility class for testing against Microsoft SQL Server.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Bogdan Ilchyshyn
|
||||
*/
|
||||
public class SqlServerTestSupport {
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET = "CREATE TABLE legoset (\n" //
|
||||
+ " id integer PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " manual integer NULL\n," //
|
||||
+ " cert varbinary(255) NULL\n" //
|
||||
@@ -24,6 +26,7 @@ public class SqlServerTestSupport {
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET_WITH_ID_GENERATION = "CREATE TABLE legoset (\n" //
|
||||
+ " id integer IDENTITY(1,1) PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " manual integer NULL\n" //
|
||||
+ ");";
|
||||
|
||||
Reference in New Issue
Block a user