diff --git a/README.md b/README.md index 6d851760..bfeb0762 100644 --- a/README.md +++ b/README.md @@ -28,16 +28,16 @@ Gradle: dependencies { // Datastore Storage support library. - implementation("io.spine.gcloud:spine-datastore:1.9.0") + implementation("io.spine.gcloud:spine-datastore:1.9.1") // Pub/Sub messaging support library. - implementation("io.spine.gcloud:spine-pubsub:1.9.0") + implementation("io.spine.gcloud:spine-pubsub:1.9.1") // Stackdriver Trace support library. - implementation("io.spine.gcloud:spine-stackdriver-trace:1.9.0") + implementation("io.spine.gcloud:spine-stackdriver-trace:1.9.1") // Datastore-related test utilities (if needed). - testImplementation("io.spine.gcloud:testutil-gcloud:1.9.0") + testImplementation("io.spine.gcloud:testutil-gcloud:1.9.1") } ``` diff --git a/datastore/src/main/java/io/spine/server/storage/datastore/config/DsColumnMapping.java b/datastore/src/main/java/io/spine/server/storage/datastore/config/DsColumnMapping.java index 812276ce..ec4ae21a 100644 --- a/datastore/src/main/java/io/spine/server/storage/datastore/config/DsColumnMapping.java +++ b/datastore/src/main/java/io/spine/server/storage/datastore/config/DsColumnMapping.java @@ -39,11 +39,15 @@ 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.storage.AbstractColumnMapping; import io.spine.server.storage.ColumnTypeMapping; import io.spine.string.Stringifiers; +import java.util.HashMap; +import java.util.Map; + import static com.google.cloud.Timestamp.ofTimeSecondsAndNanos; /** @@ -56,12 +60,51 @@ */ 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<>(); + var 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 +163,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/tenant/given/CollegeProjection.java b/datastore/src/test/java/io/spine/server/storage/datastore/given/CollegeProjection.java similarity index 96% rename from datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/CollegeProjection.java rename to datastore/src/test/java/io/spine/server/storage/datastore/given/CollegeProjection.java index fbbe42ef..495cead7 100644 --- a/datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/CollegeProjection.java +++ b/datastore/src/test/java/io/spine/server/storage/datastore/given/CollegeProjection.java @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.server.storage.datastore.tenant.given; +package io.spine.server.storage.datastore.given; import io.spine.server.projection.Projection; import io.spine.test.datastore.College; diff --git a/datastore/src/test/java/io/spine/server/storage/datastore/record/DsEntityColumnsTest.java b/datastore/src/test/java/io/spine/server/storage/datastore/record/DsEntityColumnsTest.java new file mode 100644 index 00000000..69ae4b50 --- /dev/null +++ b/datastore/src/test/java/io/spine/server/storage/datastore/record/DsEntityColumnsTest.java @@ -0,0 +1,77 @@ +/* + * 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.record; + +import io.spine.server.storage.datastore.record.given.DsEntityColumnsTestEnv.CustomMapping; +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.given.TestEnvironment.singleTenantSpec; +import static io.spine.server.storage.datastore.record.RecordId.ofEntityId; +import static io.spine.server.storage.datastore.record.given.DsEntityColumnsTestEnv.COLLEGE_CLS; +import static io.spine.server.storage.datastore.record.given.DsEntityColumnsTestEnv.COLLEGE_KIND; +import static io.spine.server.storage.datastore.record.given.DsEntityColumnsTestEnv.clearAdmission; +import static io.spine.server.storage.datastore.record.given.DsEntityColumnsTestEnv.futureFromNow; +import static io.spine.server.storage.datastore.record.given.DsEntityColumnsTestEnv.newCollege; +import static io.spine.server.storage.datastore.record.given.DsEntityColumnsTestEnv.newId; +import static io.spine.server.storage.datastore.record.given.DsEntityColumnsTestEnv.someVersion; +import static io.spine.server.storage.datastore.record.given.DsEntityColumnsTestEnv.writeAndReadDeadline; +import static io.spine.testing.server.storage.datastore.TestDatastoreStorageFactory.local; + +@DisplayName("When dealing with `Entity` columns, `DsEntityRecordStorage` should") +final class DsEntityColumnsTest { + + 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() { + var spec = singleTenantSpec(); + var storage = datastoreFactory.createEntityRecordStorage(spec, COLLEGE_CLS); + var datastore = datastoreFactory.newDatastoreWrapper(false); + + var id = newId(); + var key = datastore.keyFor(COLLEGE_KIND, ofEntityId(id)); + var version = someVersion(); + + var admissionDeadline = futureFromNow(); + var college = newCollege(id, admissionDeadline); + + var storedDeadline = writeAndReadDeadline(college, version, storage, datastore, key); + assertThat(storedDeadline).isNotNull(); + + var collegeNoAdmission = clearAdmission(college); + var presumablyEmptyDeadline = + writeAndReadDeadline(collegeNoAdmission, version, storage, datastore, key); + assertThat(presumablyEmptyDeadline) + .isNull(); + } +} diff --git a/datastore/src/test/java/io/spine/server/storage/datastore/record/given/DsEntityColumnsTestEnv.java b/datastore/src/test/java/io/spine/server/storage/datastore/record/given/DsEntityColumnsTestEnv.java new file mode 100644 index 00000000..4303b34f --- /dev/null +++ b/datastore/src/test/java/io/spine/server/storage/datastore/record/given/DsEntityColumnsTestEnv.java @@ -0,0 +1,169 @@ +/* + * 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.record.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.Any; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; +import io.spine.base.Identifier; +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.storage.EntityRecordStorage; +import io.spine.server.entity.storage.EntityRecordWithColumns; +import io.spine.server.storage.ColumnTypeMapping; +import io.spine.server.storage.datastore.DatastoreWrapper; +import io.spine.server.storage.datastore.Kind; +import io.spine.server.storage.datastore.config.DsColumnMapping; +import io.spine.server.storage.datastore.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 com.google.common.base.Preconditions.checkArgument; +import static io.spine.base.Identifier.newUuid; +import static io.spine.protobuf.AnyPacker.pack; + +/** + * Test environment + * for {@link io.spine.server.storage.datastore.record.DsEntityColumnsTest DsEntityColumnsTest}. + */ +public final class DsEntityColumnsTestEnv { + + 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 DsEntityColumnsTestEnv() { + } + + public static com.google.cloud.Timestamp + writeAndReadDeadline(College college, + Version version, + EntityRecordStorage storage, + DatastoreWrapper datastore, + Key key) { + var record = toEntityRecord(college, version); + var recordWithCols = EntityRecordWithColumns.create(record, COLLEGE_CLS); + storage.write(recordWithCols); + var response = datastore.read(key); + checkArgument(response.isPresent()); + var storedDeadline = readAdmissionDeadline(response.get()); + return storedDeadline; + } + + public static College newCollege(CollegeId id, Timestamp admissionDeadline) { + var 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")) + .build(); + return college; + } + + private static EntityRecord toEntityRecord(College college, Version version) { + var packedId = Identifier.pack(college.getId()); + var recordNoAdmission = EntityRecord + .newBuilder() + .setEntityId(packedId) + .setState(pack(college)) + .setVersion(version) + .build(); + return recordNoAdmission; + } + + public static College clearAdmission(College college) { + return college.toBuilder() + .clearAdmissionDeadline() + .build(); + } + + 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()) + .build(); + } + + private static com.google.cloud.Timestamp readAdmissionDeadline(Entity response) { + var 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/given/package-info.java b/datastore/src/test/java/io/spine/server/storage/datastore/record/given/package-info.java similarity index 79% rename from datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/package-info.java rename to datastore/src/test/java/io/spine/server/storage/datastore/record/given/package-info.java index 6b0de382..2f12bfde 100644 --- a/datastore/src/test/java/io/spine/server/storage/datastore/tenant/given/package-info.java +++ b/datastore/src/test/java/io/spine/server/storage/datastore/record/given/package-info.java @@ -24,10 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -@CheckReturnValue +/** + * Describes the test environment for tests against + * {@link io.spine.server.storage.datastore.record.DsRecordStorage DsRecordStorage} + * and those storage types which delegate their operations to {@code DsRecordStorage}. + */ @ParametersAreNonnullByDefault -package io.spine.server.storage.datastore.tenant.given; +@CheckReturnValue +package io.spine.server.storage.datastore.record.given; import com.google.errorprone.annotations.CheckReturnValue; -import javax.annotation.ParametersAreNonnullByDefault; +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file 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 e73bb2f2..c4d8a46d 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 @@ -39,7 +39,7 @@ import io.spine.server.entity.EntityRecord; import io.spine.server.entity.storage.EntityRecordSpec; import io.spine.server.storage.datastore.DatastoreStorageFactory; -import io.spine.server.storage.datastore.tenant.given.CollegeProjection; +import io.spine.server.storage.datastore.given.CollegeProjection; import io.spine.test.datastore.College; import io.spine.test.datastore.CollegeId; import io.spine.testing.TestValues; @@ -53,7 +53,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.Map; import static com.google.common.base.Throwables.getStackTraceAsString; import static com.google.common.truth.Truth.assertThat; diff --git a/license-report.md b/license-report.md index aa517d36..53382396 100644 --- a/license-report.md +++ b/license-report.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine.gcloud:spine-datastore:2.0.0-SNAPSHOT.157` +# Dependencies of `io.spine.gcloud:spine-datastore:2.0.0-SNAPSHOT.158` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.15.2.**No license information found** @@ -910,12 +910,12 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Sun Aug 27 17:21:18 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 **Wed Sep 27 15:51:07 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:2.0.0-SNAPSHOT.157` +# Dependencies of `io.spine.gcloud:spine-pubsub:2.0.0-SNAPSHOT.158` ## Runtime 1. **Group** : com.google.android. **Name** : annotations. **Version** : 4.1.1.4. @@ -1608,12 +1608,12 @@ This report was generated on **Sun Aug 27 17:21:18 WEST 2023** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Sun Aug 27 17:21: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). +This report was generated on **Wed Sep 27 15:51:09 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:2.0.0-SNAPSHOT.157` +# Dependencies of `io.spine.gcloud:spine-stackdriver-trace:2.0.0-SNAPSHOT.158` ## Runtime 1. **Group** : com.google.android. **Name** : annotations. **Version** : 4.1.1.4. @@ -2504,12 +2504,12 @@ This report was generated on **Sun Aug 27 17:21:19 WEST 2023** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Sun Aug 27 17:21:20 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 **Wed Sep 27 15:51: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). -# Dependencies of `io.spine.gcloud:spine-testutil-gcloud:2.0.0-SNAPSHOT.157` +# Dependencies of `io.spine.gcloud:spine-testutil-gcloud:2.0.0-SNAPSHOT.158` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.15.2.**No license information found** @@ -3493,4 +3493,4 @@ This report was generated on **Sun Aug 27 17:21:20 WEST 2023** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Sun Aug 27 17:21:21 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 **Wed Sep 27 15:51:12 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 dcec3cae..8ec8c643 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ all modules and does not describe the project structure per-subproject. --> io.spine.gcloud spine-gcloud-java -2.0.0-SNAPSHOT.157 +2.0.0-SNAPSHOT.158 2015 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 289f7140..f6b128ed 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,8 +27,10 @@ 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 io.spine.annotation.Internal; +import io.spine.server.storage.ColumnMapping; import io.spine.server.storage.datastore.DatastoreStorageFactory; import io.spine.server.storage.datastore.DatastoreWrapper; @@ -56,6 +58,14 @@ protected TestDatastoreStorageFactory(DatastoreStorageFactory.Builder builder) { super(builder); } + protected TestDatastoreStorageFactory(Datastore datastore, ColumnMapping> mapping) { + super(DatastoreStorageFactory + .newBuilder() + .setDatastore(datastore) + .setColumnMapping(mapping) + ); + } + /** * Creates a new instance which works with a local Datastore emulator. * @@ -65,14 +75,34 @@ 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. */ + @SuppressWarnings("WeakerAccess" /* Open for Spine users. */) public static TestDatastoreStorageFactory basedOn(Datastore datastore) { checkNotNull(datastore); return new TestDatastoreStorageFactory(datastore); } + /** + * Creates a new factory instance which wraps the given Datastore, + * and uses the given column mapping. + */ + private static TestDatastoreStorageFactory + basedOn(Datastore datastore, ColumnMapping> mapping) { + checkNotNull(datastore); + return new TestDatastoreStorageFactory(datastore, mapping); + } + /** * Creates a new factory instance based * on the pre-configured builder of a {@code DatastoreStorageFactory}. diff --git a/version.gradle.kts b/version.gradle.kts index 381eec66..b1841635 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -24,4 +24,4 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -val versionToPublish: String by extra("2.0.0-SNAPSHOT.157") +val versionToPublish: String by extra("2.0.0-SNAPSHOT.158")