From 197a8c3b9023c56add0b67c81f4d118400398093 Mon Sep 17 00:00:00 2001 From: Elena Felder <41136058+elefeint@users.noreply.github.com> Date: Tue, 10 Aug 2021 11:15:36 -0400 Subject: [PATCH] Fix Datastore pageable return type compatibility (#569) Fix Datastore pageable return type compatibility; add placeholders for deleteAllById in repositories --- .../repository/query/DatastorePageable.java | 25 ++++++++++- .../support/SimpleDatastoreRepository.java | 5 +++ .../SimpleDatastoreRepositoryTests.java | 9 +++- .../SimpleFirestoreReactiveRepository.java | 6 +++ ...impleFirestoreReactiveRepositoryTests.java | 36 ++++++++++++++++ .../support/SimpleSpannerRepository.java | 6 +++ .../spanner/SimpleSpannerRepositoryTests.java | 42 +++++++++++++++++++ 7 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 spring-cloud-gcp-data-firestore/src/test/java/com/google/cloud/spring/data/firestore/SimpleFirestoreReactiveRepositoryTests.java create mode 100644 spring-cloud-gcp-data-spanner/src/test/java/com/google/cloud/spring/data/spanner/SimpleSpannerRepositoryTests.java diff --git a/spring-cloud-gcp-data-datastore/src/main/java/com/google/cloud/spring/data/datastore/repository/query/DatastorePageable.java b/spring-cloud-gcp-data-datastore/src/main/java/com/google/cloud/spring/data/datastore/repository/query/DatastorePageable.java index ae1b60d13e..f2f9ccfd21 100644 --- a/spring-cloud-gcp-data-datastore/src/main/java/com/google/cloud/spring/data/datastore/repository/query/DatastorePageable.java +++ b/spring-cloud-gcp-data-datastore/src/main/java/com/google/cloud/spring/data/datastore/repository/query/DatastorePageable.java @@ -24,6 +24,9 @@ /** * A pageable implementation for Cloud Datastore that uses the cursor for efficient reads. * + * The static methods can take either paged or unpaged {@link Pageable}, while instance methods only deal with a paged + * self object. + * * @author Dmitry Solomakha * @author Chengyuan Zhao */ @@ -42,10 +45,26 @@ private DatastorePageable(Pageable pageable, String urlSafeCursor, Long totalCou this(pageable, cursor.toUrlSafe(), totalCount); } + /** + * Creates a {@link DatastorePageable} wrapper for a paged request, but passes unpaged requests back unchanged. + * + * @param pageable The source {@link Pageable} that can be paged or unpaged + * @param cursor Current cursor; null if not applicable + * @param totalCount Total result count + * @return an instance of {@link DatastorePageable} or the original unpaged {@link Pageable}. + */ public static Pageable from(Pageable pageable, Cursor cursor, Long totalCount) { return from(pageable, cursor == null ? null : cursor.toUrlSafe(), totalCount); } + /** + * Creates a {@link DatastorePageable} wrapper for a paged request, but passes unpaged requests back unchanged. + * + * @param pageable The source {@link Pageable} that can be paged or unpaged + * @param urlSafeCursor Current cursor as ; null if not applicable + * @param totalCount Current cursor; null if not applicable + * @return an instance of {@link DatastorePageable} or the original unpaged {@link Pageable}. + */ public static Pageable from(Pageable pageable, String urlSafeCursor, Long totalCount) { if (pageable.isUnpaged()) { return pageable; @@ -58,8 +77,10 @@ public String getUrlSafeCursor() { } @Override - public Pageable next() { - return from(super.next(), this.urlSafeCursor, this.totalCount); + public PageRequest next() { + Pageable nextPage = PageRequest.of(getPageNumber() + 1, getPageSize(), getSort()); + // Cast is safe because from() either returns the original PageRequest or a DatastorePageable. + return (PageRequest) from(nextPage, this.urlSafeCursor, this.totalCount); } public Cursor toCursor() { diff --git a/spring-cloud-gcp-data-datastore/src/main/java/com/google/cloud/spring/data/datastore/repository/support/SimpleDatastoreRepository.java b/spring-cloud-gcp-data-datastore/src/main/java/com/google/cloud/spring/data/datastore/repository/support/SimpleDatastoreRepository.java index 4b78921ba2..830a2255ab 100644 --- a/spring-cloud-gcp-data-datastore/src/main/java/com/google/cloud/spring/data/datastore/repository/support/SimpleDatastoreRepository.java +++ b/spring-cloud-gcp-data-datastore/src/main/java/com/google/cloud/spring/data/datastore/repository/support/SimpleDatastoreRepository.java @@ -210,4 +210,9 @@ private static Cursor getCursor(Pageable pageable) { private static Long getOrComputeTotalCount(Pageable pageable, LongSupplier countCall) { return pageable instanceof DatastorePageable ? ((DatastorePageable) pageable).getTotalCount() : countCall.getAsLong(); } + + // TODO: Restore @Override when not supporting Spring Boot 2.4 anymore + public void deleteAllById(Iterable iterable) { + throw new UnsupportedOperationException(); + } } diff --git a/spring-cloud-gcp-data-datastore/src/test/java/com/google/cloud/spring/data/datastore/repository/support/SimpleDatastoreRepositoryTests.java b/spring-cloud-gcp-data-datastore/src/test/java/com/google/cloud/spring/data/datastore/repository/support/SimpleDatastoreRepositoryTests.java index 3b5ee972cf..dd6ace0665 100644 --- a/spring-cloud-gcp-data-datastore/src/test/java/com/google/cloud/spring/data/datastore/repository/support/SimpleDatastoreRepositoryTests.java +++ b/spring-cloud-gcp-data-datastore/src/test/java/com/google/cloud/spring/data/datastore/repository/support/SimpleDatastoreRepositoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-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. @@ -38,6 +38,7 @@ import org.springframework.data.domain.Sort; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; @@ -350,4 +351,10 @@ public void findAllSortAsc() { )).build(); verify(this.datastoreTemplate).findAll(Object.class, opts); } + + @Test + public void deleteAllByIdUnimplemented() { + assertThatThrownBy(() -> this.simpleDatastoreRepository.deleteAllById(new ArrayList<>())) + .isInstanceOf(UnsupportedOperationException.class); + } } diff --git a/spring-cloud-gcp-data-firestore/src/main/java/com/google/cloud/spring/data/firestore/SimpleFirestoreReactiveRepository.java b/spring-cloud-gcp-data-firestore/src/main/java/com/google/cloud/spring/data/firestore/SimpleFirestoreReactiveRepository.java index 4e0617b294..954bf6db64 100644 --- a/spring-cloud-gcp-data-firestore/src/main/java/com/google/cloud/spring/data/firestore/SimpleFirestoreReactiveRepository.java +++ b/spring-cloud-gcp-data-firestore/src/main/java/com/google/cloud/spring/data/firestore/SimpleFirestoreReactiveRepository.java @@ -120,4 +120,10 @@ public Mono deleteAll(Publisher entityStream) { public Mono deleteAll() { return this.firestoreTemplate.deleteAll(this.type); } + + // TODO: Restore @Override when not supporting Spring Boot 2.4 anymore + //@Override + public Mono deleteAllById(Iterable ids) { + throw new UnsupportedOperationException(); + } } diff --git a/spring-cloud-gcp-data-firestore/src/test/java/com/google/cloud/spring/data/firestore/SimpleFirestoreReactiveRepositoryTests.java b/spring-cloud-gcp-data-firestore/src/test/java/com/google/cloud/spring/data/firestore/SimpleFirestoreReactiveRepositoryTests.java new file mode 100644 index 0000000000..dbb704ef2b --- /dev/null +++ b/spring-cloud-gcp-data-firestore/src/test/java/com/google/cloud/spring/data/firestore/SimpleFirestoreReactiveRepositoryTests.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021-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 com.google.cloud.spring.data.firestore; + +import java.util.ArrayList; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +public class SimpleFirestoreReactiveRepositoryTests { + + @Test + public void deleteAllByIdUnimplemented() { + FirestoreTemplate mockTemplate = mock(FirestoreTemplate.class); + SimpleFirestoreReactiveRepository repository = + new SimpleFirestoreReactiveRepository<>(mockTemplate, String.class); + assertThatThrownBy(() -> repository.deleteAllById(new ArrayList<>())) + .isInstanceOf(UnsupportedOperationException.class); + } +} diff --git a/spring-cloud-gcp-data-spanner/src/main/java/com/google/cloud/spring/data/spanner/repository/support/SimpleSpannerRepository.java b/spring-cloud-gcp-data-spanner/src/main/java/com/google/cloud/spring/data/spanner/repository/support/SimpleSpannerRepository.java index e134f16066..d61ab47128 100644 --- a/spring-cloud-gcp-data-spanner/src/main/java/com/google/cloud/spring/data/spanner/repository/support/SimpleSpannerRepository.java +++ b/spring-cloud-gcp-data-spanner/src/main/java/com/google/cloud/spring/data/spanner/repository/support/SimpleSpannerRepository.java @@ -164,6 +164,12 @@ public Page findAll(Pageable pageable) { pageable, this.spannerTemplate.count(this.entityType)); } + // TODO: Restore @Override when not supporting Spring Boot 2.4 anymore + //@Override + public void deleteAllById(Iterable is) { + throw new UnsupportedOperationException(); + } + private Key toKey(Object id) { return this.spannerTemplate.getSpannerEntityProcessor().convertToKey(id); } diff --git a/spring-cloud-gcp-data-spanner/src/test/java/com/google/cloud/spring/data/spanner/SimpleSpannerRepositoryTests.java b/spring-cloud-gcp-data-spanner/src/test/java/com/google/cloud/spring/data/spanner/SimpleSpannerRepositoryTests.java new file mode 100644 index 0000000000..ea72cd2495 --- /dev/null +++ b/spring-cloud-gcp-data-spanner/src/test/java/com/google/cloud/spring/data/spanner/SimpleSpannerRepositoryTests.java @@ -0,0 +1,42 @@ +/* + * Copyright 2021-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 com.google.cloud.spring.data.spanner; + +import java.util.ArrayList; + +import com.google.cloud.spring.data.spanner.core.SpannerTemplate; +import com.google.cloud.spring.data.spanner.repository.support.SimpleSpannerRepository; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +public class SimpleSpannerRepositoryTests { + + @Test + public void deleteAllByIdUnimplemented() { + SpannerTemplate mockTemplate = mock(SpannerTemplate.class); + SimpleSpannerRepository repository = new SimpleSpannerRepository<>(mockTemplate, Book.class); + + assertThatThrownBy(() -> repository.deleteAllById(new ArrayList<>())) + .isInstanceOf(UnsupportedOperationException.class); + } + + static class Book { + String id; + } +}