diff --git a/.github/keys/spine-dev-framework-ci.json.gpg b/.github/keys/spine-dev-framework-ci.json.gpg new file mode 100644 index 00000000..3041f37e Binary files /dev/null and b/.github/keys/spine-dev-framework-ci.json.gpg differ diff --git a/.github/keys/spine-dev.json.gpg b/.github/keys/spine-dev.json.gpg deleted file mode 100644 index 49f7fd52..00000000 Binary files a/.github/keys/spine-dev.json.gpg and /dev/null differ diff --git a/.github/workflows/build-on-ubuntu.yml b/.github/workflows/build-on-ubuntu.yml index e77b63c5..d7e73081 100644 --- a/.github/workflows/build-on-ubuntu.yml +++ b/.github/workflows/build-on-ubuntu.yml @@ -19,9 +19,9 @@ jobs: # This operation is specific to `gcloud-java` repository only. - name: Decrypt the credentials for the Spine-Dev service account - run: ./scripts/decrypt.sh "$SPINE_DEV_KEY" ./.github/keys/spine-dev.json.gpg ./spine-dev.json + run: ./config/scripts/decrypt.sh "$SPINE_DEV_CI_KEY" ./.github/keys/spine-dev-framework-ci.json.gpg ./spine-dev.json env: - SPINE_DEV_KEY: ${{ secrets.SPINE_DEV_KEY }} + SPINE_DEV_CI_KEY: ${{ secrets.SPINE_DEV_CI_KEY }} # The OS-managed Google Cloud SDK does not provide a Datastore emulator. - name: Remove the OS-managed Google Cloud SDK diff --git a/README.md b/README.md index 3f6780b9..a79bab99 100644 --- a/README.md +++ b/README.md @@ -16,16 +16,16 @@ Gradle: ```kotlin dependencies { // Datastore Storage support library. - implementation("io.spine.gcloud:spine-datastore:1.8.0") + implementation("io.spine.gcloud:spine-datastore:1.9.1") // Pub/Sub messaging support library. - implementation("io.spine.gcloud:spine-pubsub:1.8.0") + implementation("io.spine.gcloud:spine-pubsub:1.9.1") // Stackdriver Trace support library. - implementation("io.spine.gcloud:spine-stackdriver-trace:1.8.0") + implementation("io.spine.gcloud:spine-stackdriver-trace:1.9.1") // Datastore-related test utilities (if needed). - implementation("io.spine.gcloud:testutil-gcloud:1.8.0") + implementation("io.spine.gcloud:testutil-gcloud:1.9.1") } ``` diff --git a/datastore/src/main/java/io/spine/server/storage/datastore/DsColumnMapping.java b/datastore/src/main/java/io/spine/server/storage/datastore/DsColumnMapping.java index 847a2cda..b76a62ca 100644 --- a/datastore/src/main/java/io/spine/server/storage/datastore/DsColumnMapping.java +++ b/datastore/src/main/java/io/spine/server/storage/datastore/DsColumnMapping.java @@ -39,11 +39,16 @@ import com.google.protobuf.ByteString; import com.google.protobuf.Message; import com.google.protobuf.Timestamp; +import io.spine.annotation.SPI; import io.spine.core.Version; import io.spine.server.entity.storage.AbstractColumnMapping; +import io.spine.server.entity.storage.ColumnMapping; import io.spine.server.entity.storage.ColumnTypeMapping; import io.spine.string.Stringifiers; +import java.util.HashMap; +import java.util.Map; + import static com.google.cloud.Timestamp.ofTimeSecondsAndNanos; /** @@ -52,16 +57,57 @@ *

All column values are stored as Datastore {@link Value}-s. * *

Users of the storage can extend this class to specify their own column mapping for the - * selected types. + * selected types. See {@link DsColumnMapping#customMapping() DsColumnMapping.customMapping()}. + * + * @see DatastoreStorageFactory.Builder#setColumnMapping(ColumnMapping) */ public class DsColumnMapping extends AbstractColumnMapping> { + private static final Map, ColumnTypeMapping>> defaults + = ImmutableMap.of(Timestamp.class, ofTimestamp(), + Version.class, ofVersion()); + + /** + * {@inheritDoc} + * + *

Merges the default column mapping rules with those provided by SPI users. + * In case there are duplicate mappings for some column type, the value provided + * by SPI users is used. + * + * @apiNote This method is made {@code final}, as it is designed + * to use {@code ImmutableMap.Builder}, which does not allow to override values. + * Therefore, it is not possible for SPI users to provide their own mapping rules + * for types such as {@code Timestamp}, for which this class already has + * a default mapping. SPI users should override + * {@link #customMapping() DsColumnMapping.customMapping()} instead. + */ @Override - protected void + protected final void setupCustomMapping( ImmutableMap.Builder, ColumnTypeMapping>> builder) { - builder.put(Timestamp.class, ofTimestamp()); - builder.put(Version.class, ofVersion()); + Map, ColumnTypeMapping>> merged = new HashMap<>(); + ImmutableMap, ColumnTypeMapping>> custom = customMapping(); + merged.putAll(defaults); + merged.putAll(custom); + builder.putAll(merged); + } + + /** + * Returns the custom column mapping rules. + * + *

This method is designed for SPI users in order to be able to re-define + * and-or append their custom mapping. As by default, {@code DsColumnMapping} + * provides rules for {@link Timestamp} and {@link Version}, SPI users may + * choose to either override these defaults by returning their own mapping for these types, + * or supply even more mapping rules. + * + *

By default, this method returns an empty map. + * + * @return custom column mappings, per Java class of column + */ + @SPI + protected ImmutableMap, ColumnTypeMapping>> customMapping() { + return ImmutableMap.of(); } @Override @@ -120,16 +166,26 @@ protected ColumnTypeMapping ofMessage() { return o -> NullValue.of(); } - @SuppressWarnings({"ProtoTimestampGetSecondsGetNano", "UnnecessaryLambda"}) - // This behavior is intended. - private static ColumnTypeMapping ofTimestamp() { + /** + * Returns the default mapping from {@link Timestamp} to {@link TimestampValue}. + */ + @SuppressWarnings({ + "ProtoTimestampGetSecondsGetNano" /* In order to create exact value. */, + "UnnecessaryLambda" /* For brevity.*/, + "WeakerAccess" /* To allow access for SPI users. */}) + protected static ColumnTypeMapping ofTimestamp() { return timestamp -> TimestampValue.of( ofTimeSecondsAndNanos(timestamp.getSeconds(), timestamp.getNanos()) ); } - @SuppressWarnings("UnnecessaryLambda") - private static ColumnTypeMapping ofVersion() { + /** + * Returns the default mapping from {@link Version} to {@link LongValue}. + */ + @SuppressWarnings({ + "UnnecessaryLambda" /* For brevity.*/, + "WeakerAccess" /* To allow access for SPI users. */}) + protected static ColumnTypeMapping ofVersion() { return version -> LongValue.of(version.getNumber()); } } diff --git a/datastore/src/test/java/io/spine/server/storage/datastore/DsProjectionColumnsTest.java b/datastore/src/test/java/io/spine/server/storage/datastore/DsProjectionColumnsTest.java new file mode 100644 index 00000000..5244e618 --- /dev/null +++ b/datastore/src/test/java/io/spine/server/storage/datastore/DsProjectionColumnsTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2023, TeamDev. All rights reserved. + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.server.storage.datastore; + +import com.google.cloud.datastore.Key; +import com.google.protobuf.Timestamp; +import io.spine.core.Version; +import io.spine.server.ContextSpec; +import io.spine.server.projection.ProjectionStorage; +import io.spine.server.storage.datastore.given.DsProjectionColumnsTestEnv.CustomMapping; +import io.spine.test.datastore.College; +import io.spine.test.datastore.CollegeId; +import io.spine.testing.server.storage.datastore.TestDatastoreStorageFactory; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static com.google.common.truth.Truth.assertThat; +import static io.spine.server.storage.datastore.RecordId.ofEntityId; +import static io.spine.server.storage.datastore.given.DsProjectionColumnsTestEnv.COLLEGE_CLS; +import static io.spine.server.storage.datastore.given.DsProjectionColumnsTestEnv.COLLEGE_KIND; +import static io.spine.server.storage.datastore.given.DsProjectionColumnsTestEnv.clearAdmission; +import static io.spine.server.storage.datastore.given.DsProjectionColumnsTestEnv.futureFromNow; +import static io.spine.server.storage.datastore.given.DsProjectionColumnsTestEnv.newCollege; +import static io.spine.server.storage.datastore.given.DsProjectionColumnsTestEnv.newId; +import static io.spine.server.storage.datastore.given.DsProjectionColumnsTestEnv.someVersion; +import static io.spine.server.storage.datastore.given.DsProjectionColumnsTestEnv.writeAndReadDeadline; +import static io.spine.server.storage.datastore.given.TestEnvironment.singleTenantSpec; +import static io.spine.testing.server.storage.datastore.TestDatastoreStorageFactory.local; + +@DisplayName("When dealing with `Projection` columns, `DsProjectionStorage` should") +final class DsProjectionColumnsTest { + + private static final TestDatastoreStorageFactory datastoreFactory = local(new CustomMapping()); + + @Test + @DisplayName("allow clearing the column values " + + "if the column mapping used returns Datastore-specific `null` " + + "for their values") + void clearTimestampColumns() { + ContextSpec spec = singleTenantSpec(); + ProjectionStorage storage = + datastoreFactory.createProjectionStorage(spec, COLLEGE_CLS); + DatastoreWrapper datastore = datastoreFactory.createDatastoreWrapper(false); + + CollegeId id = newId(); + Key key = datastore.keyFor(COLLEGE_KIND, ofEntityId(id)); + Version version = someVersion(); + + Timestamp admissionDeadline = futureFromNow(); + College college = newCollege(id, admissionDeadline); + + com.google.cloud.Timestamp storedDeadline = + writeAndReadDeadline(college, version, storage, datastore, key); + assertThat(storedDeadline).isNotNull(); + + College collegeNoAdmission = clearAdmission(college); + com.google.cloud.Timestamp presumablyEmptyDeadline = + writeAndReadDeadline(collegeNoAdmission, version, storage, datastore, key); + assertThat(presumablyEmptyDeadline) + .isNull(); + } +} diff --git a/datastore/src/test/java/io/spine/server/storage/datastore/given/DsProjectionColumnsTestEnv.java b/datastore/src/test/java/io/spine/server/storage/datastore/given/DsProjectionColumnsTestEnv.java new file mode 100644 index 00000000..1bc7b38d --- /dev/null +++ b/datastore/src/test/java/io/spine/server/storage/datastore/given/DsProjectionColumnsTestEnv.java @@ -0,0 +1,175 @@ +/* + * Copyright 2023, TeamDev. All rights reserved. + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.server.storage.datastore.given; + +import com.google.cloud.datastore.Entity; +import com.google.cloud.datastore.Key; +import com.google.cloud.datastore.NullValue; +import com.google.cloud.datastore.TimestampValue; +import com.google.cloud.datastore.Value; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; +import io.spine.base.Time; +import io.spine.core.Version; +import io.spine.core.Versions; +import io.spine.server.entity.EntityRecord; +import io.spine.server.entity.given.Given; +import io.spine.server.entity.storage.ColumnTypeMapping; +import io.spine.server.entity.storage.EntityRecordWithColumns; +import io.spine.server.projection.ProjectionStorage; +import io.spine.server.storage.datastore.DatastoreWrapper; +import io.spine.server.storage.datastore.DsColumnMapping; +import io.spine.server.storage.datastore.Kind; +import io.spine.server.storage.datastore.tenant.given.CollegeProjection; +import io.spine.test.datastore.College; +import io.spine.test.datastore.CollegeId; +import io.spine.type.TypeUrl; + +import static com.google.cloud.Timestamp.ofTimeSecondsAndNanos; +import static io.spine.base.Identifier.newUuid; +import static io.spine.protobuf.AnyPacker.pack; + +/** + * A test environment for {@link DsProjectionColumnsTest}. + */ +public final class DsProjectionColumnsTestEnv { + + public static final Class COLLEGE_CLS = CollegeProjection.class; + public static final Kind COLLEGE_KIND = Kind.of(TypeUrl.from(College.getDescriptor())); + + /** + * Prevents this test environment from instantiation. + */ + private DsProjectionColumnsTestEnv() { + } + + public static com.google.cloud.Timestamp + writeAndReadDeadline(College college, + Version version, + ProjectionStorage storage, + DatastoreWrapper datastore, + Key key) { + EntityRecord record = toEntityRecord(college, version); + CollegeProjection projection = entityWith(college, version); + EntityRecordWithColumns recordWithCols = + EntityRecordWithColumns.create(record, projection, storage); + storage.write(college.getId(), recordWithCols); + Entity response = datastore.read(key); + com.google.cloud.Timestamp storedDeadline = readAdmissionDeadline(response); + return storedDeadline; + } + + public static College newCollege(CollegeId id, Timestamp admissionDeadline) { + College college = + College.newBuilder() + .setId(id) + .setName("Alma") + .setStudentCount(42) + .setAdmissionDeadline(admissionDeadline) + .setPassingGrade(4.2) + .setStateSponsored(false) + .setCreated(Time.currentTime()) + .addAllSubjects( + ImmutableList.of("English Literature", "Engineering","Psychology")) + .vBuild(); + return college; + } + + private static EntityRecord toEntityRecord(College college, Version version) { + EntityRecord recordNoAdmission = EntityRecord + .newBuilder() + .setState(pack(college)) + .setVersion(version) + .vBuild(); + return recordNoAdmission; + } + + public static College clearAdmission(College college) { + return college.toBuilder() + .clearAdmissionDeadline() + .vBuild(); + } + + private static CollegeProjection entityWith(College state, Version version) { + CollegeProjection projection = + Given.projectionOfClass(CollegeProjection.class) + .withId(state.getId()) + .withState(state) + .withVersion(version.getNumber()) + .build(); + return projection; + } + + public static Version someVersion() { + return Versions.newVersion(42, Time.currentTime()); + } + + public static Timestamp futureFromNow() { + return Timestamps.add(Time.currentTime(), Durations.fromDays(100)); + } + + public static CollegeId newId() { + return CollegeId.newBuilder() + .setValue(newUuid()) + .vBuild(); + } + + private static com.google.cloud.Timestamp readAdmissionDeadline(Entity response) { + com.google.cloud.Timestamp storedTimestamp = response.getTimestamp( + College.Column.admissionDeadline() + .name() + .value()); + return storedTimestamp; + } + + /** + * A mapping similar to the default one, + * but telling to store {@link Timestamp}s as {@code null}s. + */ + public static final class CustomMapping extends DsColumnMapping { + + @Override + protected ImmutableMap, ColumnTypeMapping>> customMapping() { + return ImmutableMap.of(Timestamp.class, ofNullableTimestamp()); + } + + @SuppressWarnings("UnnecessaryLambda" /* For brevity */) + private static ColumnTypeMapping> ofNullableTimestamp() { + return timestamp -> { + if (timestamp.equals(Timestamp.getDefaultInstance())) { + return NullValue.of(); + } + return TimestampValue.of( + ofTimeSecondsAndNanos(timestamp.getSeconds(), timestamp.getNanos()) + ); + }; + } + } +} diff --git a/datastore/src/test/java/io/spine/server/storage/datastore/tenant/NamespaceIndexTest.java b/datastore/src/test/java/io/spine/server/storage/datastore/tenant/NamespaceIndexTest.java index 430468ae..463c81bf 100644 --- a/datastore/src/test/java/io/spine/server/storage/datastore/tenant/NamespaceIndexTest.java +++ b/datastore/src/test/java/io/spine/server/storage/datastore/tenant/NamespaceIndexTest.java @@ -41,8 +41,9 @@ import io.spine.server.entity.EntityRecord; import io.spine.server.storage.RecordStorage; import io.spine.server.storage.datastore.DatastoreStorageFactory; -import io.spine.server.storage.datastore.tenant.given.TestProjection; +import io.spine.server.storage.datastore.tenant.given.CollegeProjection; import io.spine.test.datastore.College; +import io.spine.test.datastore.CollegeId; import io.spine.testing.TestValues; import io.spine.testing.server.storage.datastore.TestDatastores; import org.junit.jupiter.api.AfterEach; @@ -174,14 +175,16 @@ void findPrefixedNamespaces() { .use(storageFactory); storageFactory.configureTenantIndex(contextBuilder); BoundedContext context = contextBuilder.build(); - RecordStorage storage = storageFactory - .createRecordStorage(context.spec(), TestProjection.class); - String id = "ABC"; + RecordStorage storage = storageFactory + .createRecordStorage(context.spec(), CollegeProjection.class); + CollegeId id = CollegeId.newBuilder() + .setValue("ABC") + .vBuild(); EntityRecord record = EntityRecord .newBuilder() .setEntityId(Identifier.pack(id)) .setState(pack(College.newBuilder() - .setName(id) + .setName(id.getValue()) .build())) .build(); TenantId tenantId = TenantId diff --git a/datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/TestProjection.java b/datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/CollegeProjection.java similarity index 90% rename from datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/TestProjection.java rename to datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/CollegeProjection.java index 76f67a60..966439dc 100644 --- a/datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/TestProjection.java +++ b/datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/CollegeProjection.java @@ -28,6 +28,8 @@ import io.spine.server.projection.Projection; import io.spine.test.datastore.College; +import io.spine.test.datastore.CollegeId; -public final class TestProjection extends Projection { +public final class CollegeProjection + extends Projection { } diff --git a/license-report.md b/license-report.md index 3ec3e4d0..16043fc1 100644 --- a/license-report.md +++ b/license-report.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine.gcloud:spine-datastore:1.9.0` +# Dependencies of `io.spine.gcloud:spine-datastore:1.9.1` ## Runtime 1. **Group:** com.fasterxml.jackson **Name:** jackson-bom **Version:** 2.14.2 **No license information found** @@ -722,12 +722,12 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 19 11:08:42 WEST 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Sun Sep 24 16:41:14 WEST 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.gcloud:spine-pubsub:1.9.0` +# Dependencies of `io.spine.gcloud:spine-pubsub:1.9.1` ## Runtime 1. **Group:** com.google.android **Name:** annotations **Version:** 4.1.1.4 @@ -1149,12 +1149,12 @@ This report was generated on **Fri May 19 11:08:42 WEST 2023** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 19 11:08:54 WEST 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Sun Sep 24 16:41:22 WEST 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.gcloud:spine-stackdriver-trace:1.9.0` +# Dependencies of `io.spine.gcloud:spine-stackdriver-trace:1.9.1` ## Runtime 1. **Group:** com.google.android **Name:** annotations **Version:** 4.1.1.4 @@ -1784,12 +1784,12 @@ This report was generated on **Fri May 19 11:08:54 WEST 2023** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 19 11:09:10 WEST 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Sun Sep 24 16:41:35 WEST 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.gcloud:spine-testutil-gcloud:1.9.0` +# Dependencies of `io.spine.gcloud:spine-testutil-gcloud:1.9.1` ## Runtime 1. **Group:** com.fasterxml.jackson **Name:** jackson-bom **Version:** 2.14.2 **No license information found** @@ -2511,4 +2511,4 @@ This report was generated on **Fri May 19 11:09:10 WEST 2023** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri May 19 11:09:19 WEST 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Sun Sep 24 16:41:42 WEST 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/pom.xml b/pom.xml index 62d27698..ee410ae1 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ all modules and does not describe the project structure per-subproject. io.spine.gcloud spine-gcloud-java -1.9.0 +1.9.1 2015 diff --git a/testutil-gcloud/src/main/java/io/spine/testing/server/storage/datastore/SpyStorageFactory.java b/testutil-gcloud/src/main/java/io/spine/testing/server/storage/datastore/SpyStorageFactory.java index 4689fed8..1632e2b1 100644 --- a/testutil-gcloud/src/main/java/io/spine/testing/server/storage/datastore/SpyStorageFactory.java +++ b/testutil-gcloud/src/main/java/io/spine/testing/server/storage/datastore/SpyStorageFactory.java @@ -57,7 +57,7 @@ public SpyStorageFactory() { } @Override - protected DatastoreWrapper createDatastoreWrapper(boolean multitenant) { + public DatastoreWrapper createDatastoreWrapper(boolean multitenant) { return injectedWrapper; } diff --git a/testutil-gcloud/src/main/java/io/spine/testing/server/storage/datastore/TestDatastoreStorageFactory.java b/testutil-gcloud/src/main/java/io/spine/testing/server/storage/datastore/TestDatastoreStorageFactory.java index dd4faf99..9e6b6cec 100644 --- a/testutil-gcloud/src/main/java/io/spine/testing/server/storage/datastore/TestDatastoreStorageFactory.java +++ b/testutil-gcloud/src/main/java/io/spine/testing/server/storage/datastore/TestDatastoreStorageFactory.java @@ -27,9 +27,11 @@ package io.spine.testing.server.storage.datastore; import com.google.cloud.datastore.Datastore; +import com.google.cloud.datastore.Value; import com.google.common.collect.ImmutableSet; import com.google.common.flogger.FluentLogger; import io.spine.annotation.Internal; +import io.spine.server.entity.storage.ColumnMapping; import io.spine.server.storage.datastore.DatastoreStorageFactory; import io.spine.server.storage.datastore.DatastoreWrapper; import io.spine.server.storage.datastore.DsColumnMapping; @@ -52,10 +54,14 @@ public class TestDatastoreStorageFactory extends DatastoreStorageFactory { private final Collection allCreatedWrappers = new HashSet<>(); protected TestDatastoreStorageFactory(Datastore datastore) { + this(datastore, new DsColumnMapping()); + } + + protected TestDatastoreStorageFactory(Datastore datastore, ColumnMapping> mapping) { super(DatastoreStorageFactory .newBuilder() .setDatastore(datastore) - .setColumnMapping(new DsColumnMapping()) + .setColumnMapping(mapping) ); } @@ -68,6 +74,15 @@ public static TestDatastoreStorageFactory local() { return basedOn(TestDatastores.local()); } + /** + * Creates a new instance which works with a local Datastore emulator. + * + *

A shortcut for {@code basedOn(TestDatastores.local())}. + */ + public static TestDatastoreStorageFactory local(ColumnMapping> mapping) { + return basedOn(TestDatastores.local(), mapping); + } + /** * Creates a new factory instance which wraps the given Datastore. */ @@ -76,9 +91,18 @@ public static TestDatastoreStorageFactory basedOn(Datastore datastore) { return new TestDatastoreStorageFactory(datastore); } + /** + * Creates a new factory instance which wraps the given Datastore. + */ + private static TestDatastoreStorageFactory + basedOn(Datastore datastore, ColumnMapping> mapping) { + checkNotNull(datastore); + return new TestDatastoreStorageFactory(datastore, mapping); + } + @Internal @Override - protected DatastoreWrapper createDatastoreWrapper(boolean multitenant) { + public DatastoreWrapper createDatastoreWrapper(boolean multitenant) { TestDatastoreWrapper wrapper = TestDatastoreWrapper.wrap(datastore(), false); allCreatedWrappers.add(wrapper); return wrapper; diff --git a/version.gradle.kts b/version.gradle.kts index 9e19e396..c4de9fe4 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -37,4 +37,4 @@ val cloudTraceVersion: String by extra("2.14.0") val spineBaseVersion: String by extra("1.9.0") val spineCoreVersion: String by extra("1.9.0") -val versionToPublish: String by extra("1.9.0") +val versionToPublish: String by extra("1.9.1")