Skip to content

Instantly share code, notes, and snippets.

@ToffeeLu
Created January 10, 2019 05:40
Show Gist options
  • Save ToffeeLu/27c0c80df72c552b22a1d63050de7eba to your computer and use it in GitHub Desktop.
Save ToffeeLu/27c0c80df72c552b22a1d63050de7eba to your computer and use it in GitHub Desktop.
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.r2dbc;
import io.r2dbc.spi.ConnectionFactory;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.Map;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.annotation.Id;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.function.TransactionalDatabaseClient;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
import org.springframework.data.r2dbc.testing.ExternalDatabase;
import org.springframework.data.r2dbc.testing.PostgresTestSupport;
import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport;
import org.springframework.data.relational.core.mapping.Table;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Mark Paluch
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
public class Repro extends R2dbcIntegrationTestSupport {
public static String CREATE_TABLE_LEGOSET_WITH_ID_GENERATION = "CREATE TABLE legoset (\n" //
+ " id serial CONSTRAINT id PRIMARY KEY,\n" //
+ " name varchar(255) NOT NULL,\n" //
+ " manual integer NULL\n" //
+ ");";
@ClassRule public static final ExternalDatabase database = PostgresTestSupport.database();
@Autowired LegoSetRepository legoSetRepository;
@Autowired TransactionalDatabaseClient client;
@EnableR2dbcRepositories(databaseClientRef = "transactionalDatabaseClient", considerNestedRepositories = true,
includeFilters = @Filter(value = LegoSetRepository.class, type = FilterType.ASSIGNABLE_TYPE))
static class MyConfig extends AbstractR2dbcConfiguration {
@Bean
@Override
public ConnectionFactory connectionFactory() {
return PostgresTestSupport.createConnectionFactory(database);
}
@Bean
public TransactionalDatabaseClient transactionalDatabaseClient(ReactiveDataAccessStrategy dataAccessStrategy,
R2dbcExceptionTranslator exceptionTranslator) {
return TransactionalDatabaseClient.builder() //
.connectionFactory(connectionFactory()) //
.dataAccessStrategy(dataAccessStrategy) //
.exceptionTranslator(exceptionTranslator) //
.build();
}
}
@Before
public void before() {
client.execute().sql("DROP TABLE IF EXISTS legoset;").then() //
.doOnSuccessOrError((aVoid, throwable) -> {}) //
.as(StepVerifier::create) //
.verifyComplete();
client.execute().sql(CREATE_TABLE_LEGOSET_WITH_ID_GENERATION).then() //
.as(StepVerifier::create) //
.verifyComplete();
}
@Test
public void reproducer() {
LegoSet legoSet1 = new LegoSet(null, "SCHAUFELRADBAGGER", 12);
LegoSet legoSet2 = new LegoSet(null, "SCHAUFELRADBAGGER", 13);
Flux<Map<String, Object>> transactional = client.inTransaction(db ->
legoSetRepository.save(legoSet1)
.then(legoSetRepository.save(legoSet2))
.then(Mono.empty()));
transactional.as(StepVerifier::create) //
.expectError(MyException.class) //
.verify();
legoSetRepository.count() //
.as(StepVerifier::create) //
.expectNext(0L) //
.verifyComplete();
}
interface LegoSetRepository extends ReactiveCrudRepository<LegoSet, Integer> {}
@Data
@Table("legoset")
@AllArgsConstructor
@NoArgsConstructor
static class LegoSet {
@Id Integer id;
String name;
Integer manual;
}
static class MyException extends RuntimeException {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment