Port to jdk17 and spring 3.0.0 (#1279)

This also allows support of repository methods that return a simple type.
i.e.
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
@Query("SELECT iata, \"\" as __id, 0 as __cas from #{#n1ql.bucket} WHERE #{#n1ql.filter}")
List<String> getStrings();

Closes #1278.
This commit is contained in:
Michael Reiche
2021-12-09 15:50:52 -08:00
committed by GitHub
parent 9f2d7ee6b5
commit 49e7de06d8
25 changed files with 307 additions and 206 deletions

View File

@@ -349,20 +349,15 @@ class CouchbaseTemplateQueryCollectionIntegrationTests extends CollectionAwareIn
assertEquals(7, airports2.size());
// count( distinct icao )
// not currently possible to have multiple fields in COUNT(DISTINCT field1, field2, ... ) due to MB43475
Long count1 = reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] { "icao" })
.as(Airport.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).inCollection(collectionName).count()
.block();
assertEquals(2, count1);
// count( distinct (all fields in icaoClass) // which only has one field
// not currently possible to have multiple fields in COUNT(DISTINCT field1, field2, ... ) due to MB43475
Class icaoClass = (new Object() {
String icao;
}).getClass();
long count2 = (long) reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] {}).as(icaoClass)
// count (distinct { iata, icao } )
Long count2 = reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] {"iata", "icao"})
.withConsistency(QueryScanConsistency.REQUEST_PLUS).inCollection(collectionName).count().block();
assertEquals(2, count2);
assertEquals(7, count2);
} finally {
reactiveCouchbaseTemplate.removeById().inCollection(collectionName)

View File

@@ -265,15 +265,6 @@ class CouchbaseTemplateQueryIntegrationTests extends JavaIntegrationTests {
.as(Airport.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).count();
assertEquals(7, count1);
// count( distinct (all fields in icaoClass)
Class icaoClass = (new Object() {
String iata;
String icao;
}).getClass();
long count2 = couchbaseTemplate.findByQuery(Airport.class).distinct(new String[] {}).as(icaoClass)
.withConsistency(QueryScanConsistency.REQUEST_PLUS).count();
assertEquals(7, count2);
} finally {
couchbaseTemplate.removeById()
.all(Arrays.stream(iatas).map((iata) -> "airports::" + iata).collect(Collectors.toSet()));
@@ -305,19 +296,14 @@ class CouchbaseTemplateQueryIntegrationTests extends JavaIntegrationTests {
assertEquals(7, airports2.size());
// count( distinct icao )
// not currently possible to have multiple fields in COUNT(DISTINCT field1, field2, ... ) due to MB43475
long count1 = reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] { "icao" })
Long count1 = reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] { "icao" })
.as(Airport.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).count().block();
assertEquals(2, count1);
// count( distinct (all fields in icaoClass) // which only has one field
// not currently possible to have multiple fields in COUNT(DISTINCT field1, field2, ... ) due to MB43475
Class icaoClass = (new Object() {
String icao;
}).getClass();
long count2 = (long) reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] {}).as(icaoClass)
// count( distinct { icao, iata } )
Long count2 = reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] { "icao", "iata" })
.withConsistency(QueryScanConsistency.REQUEST_PLUS).count().block();
assertEquals(2, count2);
assertEquals(7, count2);
} finally {
reactiveCouchbaseTemplate.removeById()

View File

@@ -24,12 +24,12 @@ import static org.springframework.data.couchbase.core.query.N1QLExpression.x;
import static org.springframework.data.couchbase.core.query.QueryCriteria.where;
import static org.springframework.data.couchbase.repository.query.support.N1qlUtils.escapedBucket;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import com.couchbase.client.java.json.JsonArray;
import java.util.Arrays;
/**
* @author Mauro Monti
*/
@@ -85,8 +85,9 @@ class QueryCriteriaTests {
void testNestedNotIn() {
QueryCriteria c = where(i("name")).is("Bubba").or(where(i("age")).gt(12).or(i("country")).is("Austria"))
.and(where(i("state")).notIn(new String[] { "Alabama", "Florida" }));
assertEquals("`name` = \"Bubba\" or (`age` > 12 or `country` = \"Austria\") and "
+ "(not( (`state` in ( [\"Alabama\",\"Florida\"] )) ))", c.export());
JsonArray parameters = JsonArray.create();
assertEquals("`name` = $1 or (`age` > $2 or `country` = $3) and (not( (`state` in ( $4, $5 )) ))",
c.export(new int[1], parameters, null));
}
@Test
@@ -224,21 +225,22 @@ class QueryCriteriaTests {
@Test
void testIn() {
String[] args = new String[] { "gump", "davis" };
QueryCriteria c = where(i("name")).in((Object)args);
assertEquals("`name` in ( [\"gump\",\"davis\"] )", c.export());
QueryCriteria c = where(i("name")).in((Object) args);
assertEquals("`name` in ( \"gump\", \"davis\" )", c.export());
JsonArray parameters = JsonArray.create();
assertEquals("`name` in ( $1 )", c.export(new int[1], parameters, null));
assertEquals(arrayToString(args), parameters.get(0).toString());
assertEquals("`name` in ( $1, $2 )", c.export(new int[1], parameters, null));
assertEquals(arrayToString(args), parameters.toString());
}
@Test
void testNotIn() {
String[] args = new String[] { "gump", "davis" };
QueryCriteria c = where(i("name")).notIn((Object)args);
assertEquals("not( (`name` in ( [\"gump\",\"davis\"] )) )", c.export());
QueryCriteria c = where(i("name")).notIn((Object) args);
assertEquals("not( (`name` in ( \"gump\", \"davis\" )) )", c.export());
// this tests creating parameters from the args.
JsonArray parameters = JsonArray.create();
assertEquals("not( (`name` in ( $1 )) )", c.export(new int[1], parameters, null));
assertEquals(arrayToString(args), parameters.get(0).toString());
assertEquals("not( (`name` in ( $1, $2 )) )", c.export(new int[1], parameters, null));
assertEquals(arrayToString(args), parameters.toString());
}
@Test
@@ -261,7 +263,6 @@ class QueryCriteriaTests {
assertEquals(" USE KEYS []", expression.keys(Arrays.asList()).toString());
}
@Test // https://github.com/spring-projects/spring-data-couchbase/issues/1066
void testCriteriaCorrectlyEscapedWhenUsingMetaOnLHS() {
final String bucketName = "sample-bucket";

View File

@@ -344,20 +344,15 @@ class ReactiveCouchbaseTemplateQueryCollectionIntegrationTests extends Collectio
assertEquals(7, airports2.size());
// count( distinct icao )
// not currently possible to have multiple fields in COUNT(DISTINCT field1, field2, ... ) due to MB43475
Long count1 = reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] { "icao" })
.as(Airport.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).inCollection(collectionName).count()
.block();
assertEquals(2, count1);
// count( distinct (all fields in icaoClass) // which only has one field
// not currently possible to have multiple fields in COUNT(DISTINCT field1, field2, ... ) due to MB43475
Class icaoClass = (new Object() {
String icao;
}).getClass();
long count2 = (long) reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] {}).as(icaoClass)
// count( distinct { iata, icao } )
Long count2 = reactiveCouchbaseTemplate.findByQuery(Airport.class).distinct(new String[] {"iata","icao"})
.withConsistency(QueryScanConsistency.REQUEST_PLUS).inCollection(collectionName).count().block();
assertEquals(2, count2);
assertEquals(7, count2);
} finally {
reactiveCouchbaseTemplate.removeById().inCollection(collectionName)

View File

@@ -16,6 +16,7 @@
package org.springframework.data.couchbase.domain;
import jakarta.validation.constraints.Max;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
@@ -24,8 +25,6 @@ import org.springframework.data.annotation.Version;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.mapping.Expiration;
import javax.validation.constraints.Max;
/**
* Airport entity
*

View File

@@ -129,6 +129,18 @@ public interface AirportRepository extends CouchbaseRepository<Airport, String>,
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND iata != $1")
Page<Airport> getAllByIataNot(String iata, Pageable pageable);
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
@Query("SELECT iata, \"\" as __id, 0 as __cas from #{#n1ql.bucket} WHERE #{#n1ql.filter} order by meta().id")
List<String> getStrings();
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
@Query("SELECT length(iata), \"\" as __id, 0 as __cas from #{#n1ql.bucket} WHERE #{#n1ql.filter} order by meta().id")
List<Long> getLongs();
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
@Query("SELECT iata, icao, \"\" as __id, 0 as __cas from #{#n1ql.bucket} WHERE #{#n1ql.filter} order by meta().id")
List<String[]> getStringArrays();
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
Optional<Airport> findByIdAndIata(String id, String iata);

View File

@@ -29,6 +29,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.springframework.data.couchbase.config.BeanNames.COUCHBASE_TEMPLATE;
import jakarta.validation.ConstraintViolationException;
import junit.framework.AssertionFailedError;
import java.lang.reflect.Method;
@@ -45,8 +46,6 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolationException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
@@ -101,7 +100,6 @@ import com.couchbase.client.core.error.IndexFailureException;
import com.couchbase.client.java.env.ClusterEnvironment;
import com.couchbase.client.java.json.JsonArray;
import com.couchbase.client.java.kv.GetResult;
import com.couchbase.client.java.kv.MutationState;
import com.couchbase.client.java.kv.UpsertOptions;
import com.couchbase.client.java.query.QueryOptions;
import com.couchbase.client.java.query.QueryScanConsistency;
@@ -317,16 +315,17 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
// the Config class has been modified, these need to be loaded again
CouchbaseTemplate couchbaseTemplateRP = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
AirportRepositoryScanConsistencyTest airportRepositoryRP = (AirportRepositoryScanConsistencyTest) ac.getBean("airportRepositoryScanConsistencyTest");
AirportRepositoryScanConsistencyTest airportRepositoryRP = (AirportRepositoryScanConsistencyTest) ac
.getBean("airportRepositoryScanConsistencyTest");
List<Airport> sizeBeforeTest = airportRepositoryRP.findAll();
assertEquals(0, sizeBeforeTest.size());
Airport vie = new Airport("airports::vie", "vie" , "low9");
Airport vie = new Airport("airports::vie", "vie", "low9");
Airport saved = airportRepositoryRP.save(vie);
List<Airport> allSaved = airportRepositoryRP.findAll();
couchbaseTemplate.removeById(Airport.class).one(saved.getId());
assertNotEquals( 1, allSaved.size(),"should not have found 1 airport");
assertNotEquals(1, allSaved.size(), "should not have found 1 airport");
}
@Test
@@ -334,19 +333,19 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
ApplicationContext ac = new AnnotationConfigApplicationContext(ConfigRequestPlus.class);
// the Config class has been modified, these need to be loaded again
AirportRepositoryScanConsistencyTest airportRepositoryRP = (AirportRepositoryScanConsistencyTest) ac.getBean("airportRepositoryScanConsistencyTest");
AirportRepositoryScanConsistencyTest airportRepositoryRP = (AirportRepositoryScanConsistencyTest) ac
.getBean("airportRepositoryScanConsistencyTest");
List<Airport> sizeBeforeTest = airportRepositoryRP.findAll();
assertEquals(0, sizeBeforeTest.size());
Airport vie = new Airport("airports::vie", "vie" , "low9");
Airport vie = new Airport("airports::vie", "vie", "low9");
Airport saved = airportRepositoryRP.save(vie);
List<Airport> allSaved = airportRepositoryRP.findAll();
couchbaseTemplate.removeById(Airport.class).one(saved.getId());
assertEquals( 1, allSaved.size(),"should have found 1 airport");
assertEquals(1, allSaved.size(), "should have found 1 airport");
}
@Test
void findByTypeAlias() {
Airport vie = null;
@@ -545,6 +544,25 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
assertThrows(DataRetrievalFailureException.class, () -> userRepository.delete(user));
}
@Test
void stringQueryReturnsSimpleType(){
Airport airport1 = new Airport("1", "myIata1", "MyIcao");
airportRepository.save(airport1);
Airport airport2 = new Airport("2", "myIata2__", "MyIcao");
airportRepository.save(airport2);
List<String> iatas = airportRepository.getStrings();
assertEquals(Arrays.asList(airport1.getIata(), airport2.getIata()), iatas);
List<Long> iataLengths = airportRepository.getLongs();
assertEquals(Arrays.asList(airport1.getIata().length(), airport2.getIata().length()).toString(), iataLengths.toString());
// this is somewhat broken, because decode is told that each "row" is just a String instead of a String[]
// As such, only the first element is returned. (QueryExecutionConverts.unwrapWrapperTypes)
List<String[]> iataAndIcaos = airportRepository.getStringArrays();
assertEquals(airport1.getIata(), iataAndIcaos.get(0)[0]);
assertEquals(airport2.getIata(), iataAndIcaos.get(1)[0]);
airportRepository.deleteById(airport1.getId());
airportRepository.deleteById(airport2.getId());
}
@Test
void count() {
String[] iatas = { "JFK", "IAD", "SFO", "SJC", "SEA", "LAX", "PHX" };
@@ -886,13 +904,13 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
@Bean
public ValidatingCouchbaseEventListener validationEventListener() {
return new ValidatingCouchbaseEventListener(validator());
return new ValidatingCouchbaseEventListener( validator());
}
}
@Configuration
@EnableCouchbaseRepositories("org.springframework.data.couchbase")
@EnableCouchbaseAuditing(auditorAwareRef = "auditorAwareRef", dateTimeProviderRef = "dateTimeProviderRef")
// @EnableCouchbaseAuditing(auditorAwareRef = "auditorAwareRef", dateTimeProviderRef = "dateTimeProviderRef")
static class ConfigRequestPlus extends AbstractCouchbaseConfiguration {
@Override

View File

@@ -109,7 +109,7 @@ class N1qlQueryCreatorTests {
Query query = creator.createQuery();
// Query expected = (new Query()).addCriteria(where("firstname").in("Oliver", "Charles"));
assertEquals(expected.export(new int[1]), query.export(new int[1]));
assertEquals(" WHERE `firstname` in ( $1, $2 )", query.export(new int[1]));
JsonObject expectedOptions = JsonObject.create();
expected.buildQueryOptions(null, null).build().injectParams(expectedOptions);
JsonObject actualOptions = JsonObject.create();
@@ -132,7 +132,7 @@ class N1qlQueryCreatorTests {
Query query = creator.createQuery();
Query expected = (new Query()).addCriteria(where(i("firstname")).in("Oliver", "Charles"));
assertEquals(expected.export(new int[1]), query.export(new int[1]));
assertEquals(" WHERE `firstname` in ( $1, $2 )", query.export(new int[1]));
JsonObject expectedOptions = JsonObject.create();
expected.buildQueryOptions(null, null).build().injectParams(expectedOptions);
JsonObject actualOptions = JsonObject.create();
@@ -156,7 +156,7 @@ class N1qlQueryCreatorTests {
Query expected = (new Query()).addCriteria(where(i("firstname")).in("Oliver", "Charles"));
assertEquals(expected.export(new int[1]), query.export(new int[1]));
assertEquals(" WHERE `firstname` in ( $1, $2 )", query.export(new int[1]));
JsonObject expectedOptions = JsonObject.create();
expected.buildQueryOptions(null, null).build().injectParams(expectedOptions);
JsonObject actualOptions = JsonObject.create();

View File

@@ -85,7 +85,7 @@ class StringN1qlQueryCreatorMockedTests extends ClusterAwareIntegrationTests {
Query query = creator.createQuery();
assertEquals(
"SELECT META(`travel-sample`).id AS __id, META(`travel-sample`).cas AS __cas, `travel-sample`.* FROM `travel-sample` where `_class` = \"org.springframework.data.couchbase.domain.User\" and firstname = $1 and lastname = $2",
"SELECT META(`travel-sample`).id AS __id, META(`travel-sample`).cas AS __cas, `firstname`, `lastname`, `createdBy`, `createdDate`, `lastModifiedBy`, `lastModifiedDate` FROM `travel-sample` where `_class` = \"org.springframework.data.couchbase.domain.User\" and firstname = $1 and lastname = $2",
query.toN1qlSelectString(couchbaseTemplate.reactive(), User.class, false));
}
@@ -104,7 +104,7 @@ class StringN1qlQueryCreatorMockedTests extends ClusterAwareIntegrationTests {
Query query = creator.createQuery();
assertEquals(
"SELECT META(`travel-sample`).id AS __id, META(`travel-sample`).cas AS __cas, `travel-sample`.* FROM `travel-sample` where `_class` = \"org.springframework.data.couchbase.domain.User\" and (firstname = $first or lastname = $last)",
"SELECT META(`travel-sample`).id AS __id, META(`travel-sample`).cas AS __cas, `firstname`, `lastname`, `createdBy`, `createdDate`, `lastModifiedBy`, `lastModifiedDate` FROM `travel-sample` where `_class` = \"org.springframework.data.couchbase.domain.User\" and (firstname = $first or lastname = $last)",
query.toN1qlSelectString(couchbaseTemplate.reactive(), User.class, false));
}