Skip to content

Commit

Permalink
enable Jooq in spring rest.
Browse files Browse the repository at this point in the history
  • Loading branch information
rajadilipkolli committed Feb 15, 2020
1 parent aeeb0cc commit 7770307
Show file tree
Hide file tree
Showing 9 changed files with 367 additions and 32 deletions.
1 change: 1 addition & 0 deletions config/checkstyle-suppressions.xml
Expand Up @@ -7,4 +7,5 @@
<suppress files=".+Configuration\.java" checks="HideUtilityClassConstructor" />
<suppress files=".+Application\.java" checks="HideUtilityClassConstructor" />
<suppress files=".\.java" checks="SpringLambda" />
<suppress files=".+Test\.java" checks="AvoidStaticImport" />
</suppressions>
6 changes: 5 additions & 1 deletion spring-boot-rest/poc-spring-boot-rest-application/pom.xml
Expand Up @@ -17,7 +17,7 @@
<dependencies>
<dependency>
<groupId>com.example.poc</groupId>
<artifactId>poc-spring-boot-rest-entities</artifactId>
<artifactId>poc-spring-boot-rest-jooq</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
Expand All @@ -28,6 +28,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jooq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand Down
@@ -0,0 +1,25 @@
/*
* Copyright 2015-2020 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
*
* https://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 com.poc.restfulpoc.repository;

import com.poc.restfulpoc.entities.Address;

import org.springframework.data.jpa.repository.JpaRepository;

public interface AddressRepository extends JpaRepository<Address, Long> {

}
@@ -0,0 +1,137 @@
/*
* Copyright 2015-2020 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
*
* https://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 com.poc.restfulpoc.jooq;

import java.sql.Timestamp;
import java.util.List;

import com.poc.restfulpoc.AbstractRestFulPOCApplicationTest;
import com.poc.restfulpoc.data.DataBuilder;
import com.poc.restfulpoc.jooq.tables.Address;
import com.poc.restfulpoc.jooq.tables.Customer;
import com.poc.restfulpoc.jooq.tables.Orders;
import com.poc.restfulpoc.jooq.tables.records.AddressRecord;
import com.poc.restfulpoc.jooq.tables.records.CustomerRecord;
import com.poc.restfulpoc.jooq.tables.records.OrdersRecord;
import com.poc.restfulpoc.repository.CustomerRepository;
import org.jooq.DSLContext;
import org.jooq.Query;
import org.jooq.Record2;
import org.jooq.Record8;
import org.jooq.Result;
import org.jooq.SelectSeekStep1;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;

import static com.poc.restfulpoc.jooq.tables.Address.ADDRESS;
import static com.poc.restfulpoc.jooq.tables.Customer.CUSTOMER;
import static com.poc.restfulpoc.jooq.tables.Orders.ORDERS;
import static org.assertj.core.api.Assertions.assertThat;

@TestInstance(Lifecycle.PER_CLASS)
class JooqQueryTest extends AbstractRestFulPOCApplicationTest {

@Autowired
private DSLContext context;

@Autowired
private JdbcTemplate jdbc;

@Autowired
private CustomerRepository customerRepository;

@Autowired
private DataBuilder dataBuilder;

@BeforeAll
void setUp() throws Exception {
this.customerRepository.deleteAll();
this.dataBuilder.run();
}

@Test
void testJoinCustomerAddress() throws Exception {
// All of these tables were generated by jOOQ's Maven plugin
Customer c = CUSTOMER.as("c");
Address a = ADDRESS.as("a");

Result<Record2<String, String>> results = this.context.select(c.FIRST_NAME, c.LAST_NAME).from(c).join(a)
.on(a.CUSTOMER_ID.eq(c.ID)).orderBy(c.FIRST_NAME.desc()).fetch();

assertThat(results.size()).isEqualTo(3);
assertThat(results.getValue(0, c.FIRST_NAME)).isEqualTo("Steve");
assertThat(results.getValue(1, c.FIRST_NAME)).isEqualTo("Raja");
assertThat(results.getValue(2, c.FIRST_NAME)).isEqualTo("Paul");

assertThat(results.getValue(0, c.LAST_NAME)).isEqualTo("Toale");
assertThat(results.getValue(1, c.LAST_NAME)).isEqualTo("Kolli");
assertThat(results.getValue(2, c.LAST_NAME)).isEqualTo("Jones");

}

@Test
void testJoinAll() throws Exception {
// All of these tables were generated by jOOQ's Maven plugin
Customer c = CUSTOMER.as("c");
Address a = ADDRESS.as("a");
Orders o = ORDERS.as("o");

SelectSeekStep1<Record8<Long, String, String, Timestamp, Long, String, String, Long>, String> sql = this.context
.select(c.ID, c.FIRST_NAME, c.LAST_NAME, c.DATE_OF_BIRTH, o.ORDER_ID, o.ORDER_NUMBER, o.ORDER_STATUS,
a.CUSTOMER_ID)
.from(c).join(a).on(a.CUSTOMER_ID.eq(c.ID)).join(o).on(o.CUSTOMER_ID.eq(c.ID))
.where(o.ORDER_STATUS.eq("NEW")).orderBy(c.FIRST_NAME.desc());

CustomerRecord customer = sql.fetchOneInto(CUSTOMER);
AddressRecord address = sql.fetchOneInto(ADDRESS);
OrdersRecord order = sql.fetchOneInto(ORDERS);

assertThat(customer.getValue(c.LAST_NAME)).isEqualTo("Kolli");
assertThat(customer.getValue(c.FIRST_NAME)).isEqualTo("Raja");
assertThat(order.getValue(o.ORDER_ID)).isNotNull();
assertThat(address.getValue(a.CUSTOMER_ID)).isEqualTo(customer.getValue(c.ID));

}

@Test
void jooqSql() {
Query query = this.context
.select(CUSTOMER.ID, CUSTOMER.FIRST_NAME, CUSTOMER.LAST_NAME, CUSTOMER.DATE_OF_BIRTH, ORDERS.ORDER_ID,
ORDERS.ORDER_NUMBER, ORDERS.ORDER_STATUS, ADDRESS.COUNTY)
.from(CUSTOMER).join(ADDRESS).on(ADDRESS.CUSTOMER_ID.eq(CUSTOMER.ID)).join(ORDERS)
.on(ORDERS.CUSTOMER_ID.eq(CUSTOMER.ID)).where(ORDERS.ORDER_STATUS.eq("NEW"));
Object[] bind = query.getBindValues().toArray(new Object[0]);
List<String> list = this.jdbc.query(query.getSQL(), bind,
(rs, rowNum) -> rs.getLong(1) + " : " + rs.getString(2) + " " + rs.getString(3) + "-"
+ rs.getTimestamp(4) + "-" + rs.getLong(5) + "-" + rs.getString(6) + "-" + rs.getString(7) + "-"
+ rs.getString(8));
assertThat(list).size().isEqualTo(1);
}

@Test
void testActiveRecords() throws Exception {
Result<CustomerRecord> result = this.context.selectFrom(CUSTOMER).orderBy(CUSTOMER.ID).fetch();

assertThat(result.size()).isEqualTo(3);
}

}
@@ -0,0 +1,182 @@
/*
* Copyright 2015-2018 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
*
* https://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 com.poc.restfulpoc.jooq;

import java.util.concurrent.atomic.AtomicBoolean;

import com.poc.restfulpoc.AbstractRestFulPOCApplicationTest;
import com.poc.restfulpoc.data.DataBuilder;
import com.poc.restfulpoc.repository.CustomerRepository;
import org.jooq.DSLContext;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import static com.poc.restfulpoc.jooq.tables.Customer.CUSTOMER;
import static org.assertj.core.api.Assertions.assertThat;

@TestInstance(Lifecycle.PER_CLASS)
class JooqTransactionTest extends AbstractRestFulPOCApplicationTest {

@Autowired
private DSLContext dsl;

@Autowired
private CustomerRepository customerRepository;

@Autowired
private DataBuilder dataBuilder;

private DataSourceTransactionManager txMgr;

@BeforeAll
void init() {
this.txMgr = new DataSourceTransactionManager(
new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build());
}

@BeforeEach
void setUp() throws Exception {
this.customerRepository.deleteAll();
this.dataBuilder.run();
}

@Test
void testExplicitTransactions() {
boolean rollback = false;

TransactionStatus tx = this.txMgr.getTransaction(new DefaultTransactionDefinition());
try {

// This is a "bug". The same CUSTOMER is created twice, resulting in a
// constraint violation exception
for (int i = 0; i < 2; i++) {
this.dsl.insertInto(CUSTOMER).set(CUSTOMER.ID, 5L).set(CUSTOMER.LAST_NAME, "1")
.set(CUSTOMER.FIRST_NAME, "CUSTOMER 5").execute();
}
Assertions.fail();
}

// Upon the constraint violation, we explicitly roll back the transaction.
catch (DataAccessException ex) {
this.txMgr.rollback(tx);
rollback = true;
}

assertThat(this.dsl.fetchCount(CUSTOMER)).isGreaterThanOrEqualTo(3);
assertThat(rollback).isTrue();
}

@Test
@Disabled
void testJOOQTransactionsSimple() {
boolean rollback = false;

try {
this.dsl.transaction((c) -> {

// This is a "bug". The same CUSTOMER is created twice, resulting in a
// constraint violation exception
for (int i = 0; i < 2; i++) {
this.dsl.insertInto(CUSTOMER).set(CUSTOMER.ID, 5L).set(CUSTOMER.LAST_NAME, "1")
.set(CUSTOMER.FIRST_NAME, "CUSTOMER 5").execute();
}
Assertions.fail();
});
}

// Upon the constraint violation, the transaction must already have been rolled
// back
catch (DataAccessException ex) {
rollback = true;
}

assertThat(this.dsl.fetchCount(CUSTOMER)).isEqualTo(3);
assertThat(rollback).isTrue();
}

@Test
@Disabled
@DisplayName("As H2 doesn't support Nested Transaction we have disable it.")
void testJOOQTransactionsNested() {
AtomicBoolean rollback1 = new AtomicBoolean(false);
AtomicBoolean rollback2 = new AtomicBoolean(false);

try {

// If using Spring transactions, we don't need the c1 reference
this.dsl.transaction((c1) -> {

// The first insertion will work
this.dsl.insertInto(CUSTOMER).set(CUSTOMER.ID, 5L).set(CUSTOMER.LAST_NAME, "1")
.set(CUSTOMER.FIRST_NAME, "CUSTOMER 5").execute();

assertThat(this.dsl.fetchCount(CUSTOMER)).isEqualTo(4);

try {

// Nest transactions using Spring. This should create a savepoint,
// right here
// If using Spring transactions, we don't need the c2 reference
this.dsl.transaction((c2) -> {

// The second insertion shouldn't work
for (int i = 0; i < 2; i++) {
this.dsl.insertInto(CUSTOMER).set(CUSTOMER.ID, 6L).set(CUSTOMER.LAST_NAME, "1")
.set(CUSTOMER.FIRST_NAME, "CUSTOMER 6").execute();
}
Assertions.fail();
});
}

catch (DataAccessException ex) {
rollback1.set(true);
}

// We should've rolled back to the savepoint
assertThat(this.dsl.fetchCount(CUSTOMER)).isEqualTo(4);

throw new org.jooq.exception.DataAccessException("Rollback");
});
}

// Upon the constraint violation, the transaction must already have been rolled
// back
catch (org.jooq.exception.DataAccessException ex) {
assertThat(ex.getMessage()).isEqualTo("Rollback");
rollback2.set(true);
}

assertThat(this.dsl.fetchCount(CUSTOMER)).isEqualTo(4);
assertThat(rollback1.get()).isTrue();
assertThat(rollback2.get()).isTrue();
}

}

0 comments on commit 7770307

Please sign in to comment.