Restore projection of class. (#1319)
Restore projection of class in queries. This is necessary for abstract repositories. Closes #1315.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2012-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 org.springframework.data.couchbase.domain;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* User entity for tests
|
||||
*
|
||||
* @author Michael Reiche
|
||||
*/
|
||||
|
||||
public abstract class AbstractUser extends ComparableEntity {
|
||||
|
||||
@Version protected long version;
|
||||
@Id protected String id;
|
||||
protected String firstname;
|
||||
protected String lastname;
|
||||
@Transient protected String transientInfo;
|
||||
@CreatedBy protected String createdBy;
|
||||
@CreatedDate protected long createdDate;
|
||||
@LastModifiedBy protected String lastModifiedBy;
|
||||
@LastModifiedDate protected long lastModifiedDate;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public long getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void setCreatedDate(long createdDate) {
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
public void setCreatedBy(String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
public long getLastModifiedDate() {
|
||||
return lastModifiedDate;
|
||||
}
|
||||
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getId(), firstname, lastname);
|
||||
}
|
||||
|
||||
public String getTransientInfo() {
|
||||
return transientInfo;
|
||||
}
|
||||
|
||||
public void setTransientInfo(String something) {
|
||||
transientInfo = something;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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 org.springframework.data.couchbase.domain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.couchbase.client.java.query.QueryScanConsistency;
|
||||
import org.springframework.data.couchbase.repository.CouchbaseRepository;
|
||||
import org.springframework.data.couchbase.repository.Query;
|
||||
import org.springframework.data.couchbase.repository.ScanConsistency;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.couchbase.client.java.json.JsonArray;
|
||||
|
||||
/**
|
||||
* AbstractUser Repository for tests
|
||||
*
|
||||
* @author Michael Reiche
|
||||
*/
|
||||
@Repository
|
||||
@ScanConsistency(query=QueryScanConsistency.REQUEST_PLUS)
|
||||
public interface AbstractUserRepository extends CouchbaseRepository<AbstractUser, String> {
|
||||
|
||||
@Query("#{#n1ql.selectEntity} where (meta().id = $1)")
|
||||
AbstractUser myFindById(String id);
|
||||
|
||||
List<User> findByFirstname(String firstname);
|
||||
|
||||
Stream<User> findByLastname(String lastname);
|
||||
|
||||
List<User> findByFirstnameIn(String... firstnames);
|
||||
|
||||
List<User> findByFirstnameIn(JsonArray firstnames);
|
||||
|
||||
List<User> findByFirstnameAndLastname(String firstname, String lastname);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} where #{#n1ql.filter} and firstname = $1 and lastname = $2")
|
||||
List<User> getByFirstnameAndLastname(String firstname, String lastname);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} where #{#n1ql.filter} and (firstname = $first or lastname = $last)")
|
||||
List<User> getByFirstnameOrLastname(@Param("first") String firstname, @Param("last") String lastname);
|
||||
|
||||
List<User> findByIdIsNotNullAndFirstnameEquals(String firstname);
|
||||
|
||||
List<User> findByVersionEqualsAndFirstnameEquals(Long version, String firstname);
|
||||
|
||||
}
|
||||
@@ -35,7 +35,7 @@ import javax.validation.constraints.Max;
|
||||
@Document
|
||||
@TypeAlias("airport")
|
||||
public class Airport extends ComparableEntity {
|
||||
@Id String id;
|
||||
@Id String key;
|
||||
|
||||
String iata;
|
||||
|
||||
@@ -49,14 +49,14 @@ public class Airport extends ComparableEntity {
|
||||
long size;
|
||||
|
||||
@PersistenceConstructor
|
||||
public Airport(String id, String iata, String icao) {
|
||||
this.id = id;
|
||||
public Airport(String key, String iata, String icao) {
|
||||
this.key = key;
|
||||
this.iata = iata;
|
||||
this.icao = icao;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getIata() {
|
||||
|
||||
@@ -174,6 +174,9 @@ public interface AirportRepository extends CouchbaseRepository<Airport, String>,
|
||||
+ " #{#planIds != null ? 'AND blahblah IN $2' : ''} " + " #{#active != null ? 'AND false = $3' : ''} ")
|
||||
Long countOne();
|
||||
|
||||
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
|
||||
Airport findByKey(String id);
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
// @Meta
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2022 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 org.springframework.data.couchbase.domain;
|
||||
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* OtherUser entity for tests. Both User and OtherUser extend AbstractUser
|
||||
*
|
||||
* @author Michael Reiche
|
||||
*/
|
||||
|
||||
@Document
|
||||
public class OtherUser extends AbstractUser {
|
||||
|
||||
@PersistenceConstructor
|
||||
public OtherUser(final String id, final String firstname, final String lastname) {
|
||||
this.id = id;
|
||||
this.firstname = firstname;
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
* Copyright 2012-2022 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.
|
||||
@@ -16,16 +16,7 @@
|
||||
|
||||
package org.springframework.data.couchbase.domain;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
|
||||
/**
|
||||
@@ -36,17 +27,7 @@ import org.springframework.data.couchbase.core.mapping.Document;
|
||||
*/
|
||||
|
||||
@Document
|
||||
public class User extends ComparableEntity {
|
||||
|
||||
@Version long version;
|
||||
@Id private String id;
|
||||
private String firstname;
|
||||
private String lastname;
|
||||
@Transient private String transientInfo;
|
||||
@CreatedBy private String createdBy;
|
||||
@CreatedDate private long createdDate;
|
||||
@LastModifiedBy private String lastModifiedBy;
|
||||
@LastModifiedDate private long lastModifiedDate;
|
||||
public class User extends AbstractUser {
|
||||
|
||||
@PersistenceConstructor
|
||||
public User(final String id, final String firstname, final String lastname) {
|
||||
@@ -55,60 +36,4 @@ public class User extends ComparableEntity {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public long getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void setCreatedDate(long createdDate) {
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
public void setCreatedBy(String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
public long getLastModifiedDate() {
|
||||
return lastModifiedDate;
|
||||
}
|
||||
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, firstname, lastname);
|
||||
}
|
||||
|
||||
public String getTransientInfo() {
|
||||
return transientInfo;
|
||||
}
|
||||
|
||||
public void setTransientInfo(String something) {
|
||||
transientInfo = something;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2017-2022 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 org.springframework.data.couchbase.repository;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.domain.AbstractUser;
|
||||
import org.springframework.data.couchbase.domain.AbstractUserRepository;
|
||||
import org.springframework.data.couchbase.domain.OtherUser;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
|
||||
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
|
||||
import org.springframework.data.couchbase.util.ClusterType;
|
||||
import org.springframework.data.couchbase.util.IgnoreWhen;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
/**
|
||||
* Abstract Repository tests
|
||||
*
|
||||
* @author Michael Reiche
|
||||
*/
|
||||
@SpringJUnitConfig(CouchbaseAbstractRepositoryIntegrationTests.Config.class)
|
||||
@IgnoreWhen(clusterTypes = ClusterType.MOCKED)
|
||||
public class CouchbaseAbstractRepositoryIntegrationTests extends ClusterAwareIntegrationTests {
|
||||
|
||||
@Autowired AbstractUserRepository abstractUserRepository;
|
||||
|
||||
@Test
|
||||
void saveAndFindAbstract() {
|
||||
// User extends AbstractUser
|
||||
// OtherUser extends Abstractuser
|
||||
AbstractUser user = null;
|
||||
{
|
||||
user = new User(UUID.randomUUID().toString(), "userFirstname", "userLastname");
|
||||
assertEquals(User.class, user.getClass());
|
||||
abstractUserRepository.save(user);
|
||||
{
|
||||
// Queries on repositories for abstract entities must be @Query and not include
|
||||
// #{#n1ql.filter} (i.e. _class = <classname> ) as the classname will not match any document
|
||||
AbstractUser found = abstractUserRepository.myFindById(user.getId());
|
||||
assertEquals(user, found);
|
||||
assertEquals(user.getClass(), found.getClass());
|
||||
}
|
||||
{
|
||||
Optional<AbstractUser> found = abstractUserRepository.findById(user.getId());
|
||||
assertEquals(user, found.get());
|
||||
}
|
||||
abstractUserRepository.delete(user);
|
||||
}
|
||||
{
|
||||
user = new OtherUser(UUID.randomUUID().toString(), "userFirstname", "userLastname");
|
||||
assertEquals(OtherUser.class, user.getClass());
|
||||
abstractUserRepository.save(user);
|
||||
{
|
||||
AbstractUser found = abstractUserRepository.myFindById(user.getId());
|
||||
assertEquals(user, found);
|
||||
assertEquals(user.getClass(), found.getClass());
|
||||
}
|
||||
{
|
||||
Optional<AbstractUser> found = abstractUserRepository.findById(user.getId());
|
||||
assertEquals(user, found.get());
|
||||
}
|
||||
abstractUserRepository.delete(user);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableCouchbaseRepositories("org.springframework.data.couchbase")
|
||||
static class Config extends AbstractCouchbaseConfiguration {
|
||||
|
||||
@Override
|
||||
public String getConnectionString() {
|
||||
return connectionString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserName() {
|
||||
return config().adminUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return config().adminPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBucketName() {
|
||||
return bucketName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -249,11 +249,11 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
java.util.Collection<String> icaos = new LinkedList<String>();
|
||||
icaos.add(vie.getIcao());
|
||||
icaos.add("blue");
|
||||
PageRequest pageable = PageRequest.of( 0, 1, Sort.by("iata"));
|
||||
List<Airport>airports = airportRepository.findByIataInAndIcaoIn(iatas, icaos, pageable);
|
||||
PageRequest pageable = PageRequest.of(0, 1, Sort.by("iata"));
|
||||
List<Airport> airports = airportRepository.findByIataInAndIcaoIn(iatas, icaos, pageable);
|
||||
assertEquals(1, airports.size());
|
||||
|
||||
List<Airport>airports2 = airportRepository.findByIataInAndIcaoIn(iatas, icaos, pageable);
|
||||
List<Airport> airports2 = airportRepository.findByIataInAndIcaoIn(iatas, icaos, pageable);
|
||||
assertEquals(1, airports2.size());
|
||||
|
||||
} finally {
|
||||
@@ -624,11 +624,12 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
airportRepository.saveAll(
|
||||
Arrays.stream(iatas).map((iata) -> new Airport("airports::" + iata, iata, iata.toLowerCase(Locale.ROOT)))
|
||||
.collect(Collectors.toSet()));
|
||||
List<Airport> airports = airportRepository.withOptions(QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS)).findAll(Sort.by("iata"));
|
||||
List<Airport> airports = airportRepository.withOptions(QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS))
|
||||
.findAll(Sort.by("iata"));
|
||||
String[] sortedIatas = iatas.clone();
|
||||
System.out.println(""+iatas.length+" "+sortedIatas.length);
|
||||
System.out.println("" + iatas.length + " " + sortedIatas.length);
|
||||
Arrays.sort(sortedIatas);
|
||||
for(int i=0; i< sortedIatas.length; i++){
|
||||
for (int i = 0; i < sortedIatas.length; i++) {
|
||||
assertEquals(sortedIatas[i], airports.get(i).getIata());
|
||||
}
|
||||
} finally {
|
||||
@@ -924,6 +925,15 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
.all(Arrays.asList(address1.getId(), address2.getId(), address3.getId(), user.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByKey() {
|
||||
Airport airport = new Airport(UUID.randomUUID().toString(), "iata1038", "icao");
|
||||
airportRepository.save(airport);
|
||||
Airport found = airportRepository.findByKey(airport.getId());
|
||||
assertEquals(airport, found);
|
||||
airportRepository.delete(airport);
|
||||
}
|
||||
|
||||
private void sleep(int millis) {
|
||||
try {
|
||||
Thread.sleep(millis); // so they are executed out-of-order
|
||||
|
||||
@@ -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, `firstname`, `lastname`, `createdBy`, `createdDate`, `lastModifiedBy`, `lastModifiedDate` 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, `_class`, `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, `firstname`, `lastname`, `createdBy`, `createdDate`, `lastModifiedBy`, `lastModifiedDate` 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, `_class`, `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));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user