Support N1QL Join Annotations. (#1211)
* Support N1QL Join Annotations. Closes #1198.
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.data.couchbase.core.mapping.Document;
|
||||
@@ -7,6 +22,9 @@ public class Address extends ComparableEntity {
|
||||
|
||||
private String street;
|
||||
private String city;
|
||||
// for N1qlJoin
|
||||
private String id;
|
||||
private String parentId;
|
||||
|
||||
public Address() {}
|
||||
|
||||
@@ -26,4 +44,20 @@ public class Address extends ComparableEntity {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(String parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors
|
||||
* Copyright 2020-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.
|
||||
@@ -17,12 +17,14 @@
|
||||
package org.springframework.data.couchbase.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.annotation.TypeAlias;
|
||||
import org.springframework.data.couchbase.core.index.CompositeQueryIndex;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import org.springframework.data.couchbase.core.query.FetchType;
|
||||
import org.springframework.data.couchbase.core.query.N1qlJoin;
|
||||
|
||||
/**
|
||||
* UserSubmission entity for tests
|
||||
@@ -40,6 +42,8 @@ public class UserSubmission extends ComparableEntity {
|
||||
private String password;
|
||||
private List<String> roles;
|
||||
private Address address;
|
||||
@N1qlJoin(on = "meta(lks).id=rks.parentId", fetchType = FetchType.IMMEDIATE) List<Address> otherAddresses;
|
||||
|
||||
private int credits;
|
||||
private List<Submission> submissions;
|
||||
private List<Course> courses;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors
|
||||
* Copyright 2020-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.
|
||||
@@ -16,9 +16,14 @@
|
||||
|
||||
package org.springframework.data.couchbase.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.couchbase.repository.ScanConsistency;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.couchbase.client.java.query.QueryScanConsistency;
|
||||
|
||||
/**
|
||||
* UserSubmission Repository for tests
|
||||
*
|
||||
@@ -27,4 +32,7 @@ import org.springframework.stereotype.Repository;
|
||||
@Repository
|
||||
public interface UserSubmissionRepository extends PagingAndSortingRepository<UserSubmission, String> {
|
||||
|
||||
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
|
||||
List<UserSubmission> findByUsername(String username);
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -64,6 +65,8 @@ import org.springframework.data.couchbase.domain.PersonRepository;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.domain.UserAnnotated;
|
||||
import org.springframework.data.couchbase.domain.UserRepository;
|
||||
import org.springframework.data.couchbase.domain.UserSubmission;
|
||||
import org.springframework.data.couchbase.domain.UserSubmissionRepository;
|
||||
import org.springframework.data.couchbase.domain.time.AuditingDateTimeProvider;
|
||||
import org.springframework.data.couchbase.repository.auditing.EnableCouchbaseAuditing;
|
||||
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
|
||||
@@ -83,13 +86,14 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import com.couchbase.client.core.error.AmbiguousTimeoutException;
|
||||
import com.couchbase.client.core.error.CouchbaseException;
|
||||
import com.couchbase.client.core.error.IndexExistsException;
|
||||
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.manager.query.CreatePrimaryQueryIndexOptions;
|
||||
import com.couchbase.client.java.manager.query.CreateQueryIndexOptions;
|
||||
import com.couchbase.client.java.query.QueryOptions;
|
||||
import com.couchbase.client.java.query.QueryScanConsistency;
|
||||
|
||||
@@ -110,6 +114,8 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
|
||||
@Autowired UserRepository userRepository;
|
||||
|
||||
@Autowired UserSubmissionRepository userSubmissionRepository;
|
||||
|
||||
@Autowired CouchbaseTemplate couchbaseTemplate;
|
||||
|
||||
String scopeName = "_default";
|
||||
@@ -117,11 +123,14 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
try {
|
||||
clientFactory.getCluster().queryIndexes().createPrimaryIndex(bucketName());
|
||||
} catch (IndexExistsException ex) {
|
||||
// ignore, all good.
|
||||
}
|
||||
clientFactory.getCluster().queryIndexes().createPrimaryIndex(bucketName(),
|
||||
CreatePrimaryQueryIndexOptions.createPrimaryQueryIndexOptions().ignoreIfExists(true));
|
||||
// this is for the N1qlJoin test
|
||||
List<String> fieldList = new ArrayList<>();
|
||||
fieldList.add("parentId");
|
||||
clientFactory.getCluster().queryIndexes().createIndex(bucketName(), "parent_idx", fieldList,
|
||||
CreateQueryIndexOptions.createQueryIndexOptions().ignoreIfExists(true));
|
||||
// .with("_class", "org.springframework.data.couchbase.domain.Address"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -690,6 +699,53 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void findPlusN1qlJoin() throws Exception {
|
||||
|
||||
// needs an index for this N1ql Join
|
||||
// create index ix2 on my_bucket(parent_id) where `_class` = 'org.springframework.data.couchbase.domain.Address';
|
||||
|
||||
UserSubmission user = new UserSubmission();
|
||||
user.setId(UUID.randomUUID().toString());
|
||||
user.setUsername("dave");
|
||||
user = couchbaseTemplate.insertById(UserSubmission.class).one(user);
|
||||
|
||||
Address address1 = new Address();
|
||||
address1.setId(UUID.randomUUID().toString());
|
||||
address1.setStreet("3250 Olcott Street");
|
||||
address1.setParentId(user.getId());
|
||||
Address address2 = new Address();
|
||||
address2.setId(UUID.randomUUID().toString());
|
||||
address2.setStreet("148 Castro Street");
|
||||
address2.setParentId(user.getId());
|
||||
Address address3 = new Address();
|
||||
address3.setId(UUID.randomUUID().toString());
|
||||
address3.setStreet("123 Sesame Street");
|
||||
address3.setParentId(UUID.randomUUID().toString()); // does not belong to user
|
||||
address1 = couchbaseTemplate.insertById(Address.class).one(address1);
|
||||
address2 = couchbaseTemplate.insertById(Address.class).one(address2);
|
||||
address3 = couchbaseTemplate.insertById(Address.class).one(address3);
|
||||
|
||||
List<UserSubmission> users = userSubmissionRepository.findByUsername(user.getUsername());
|
||||
assertEquals(2, users.get(0).getOtherAddresses().size());
|
||||
for (Address a : users.get(0).getOtherAddresses()) {
|
||||
if (!(a.getStreet().equals(address1.getStreet()) || a.getStreet().equals(address2.getStreet()))) {
|
||||
throw new Exception("street does not match : " + a);
|
||||
}
|
||||
}
|
||||
|
||||
UserSubmission foundUser = userSubmissionRepository.findById(user.getId()).get();
|
||||
assertEquals(2, foundUser.getOtherAddresses().size());
|
||||
for (Address a : foundUser.getOtherAddresses()) {
|
||||
if (!(a.getStreet().equals(address1.getStreet()) || a.getStreet().equals(address2.getStreet()))) {
|
||||
throw new Exception("street does not match : " + a);
|
||||
}
|
||||
}
|
||||
|
||||
couchbaseTemplate.removeById(Address.class)
|
||||
.all(Arrays.asList(address1.getId(), address2.getId(), address3.getId(), user.getId()));
|
||||
}
|
||||
|
||||
private void sleep(int millis) {
|
||||
try {
|
||||
Thread.sleep(millis); // so they are executed out-of-order
|
||||
|
||||
Reference in New Issue
Block a user