diff --git a/CHANGELOG.md b/CHANGELOG.md index 3785edbe3..46b8c3b8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +## [1.1.2] - 2024-03-26 + +### Changed + +- Fixes a bug in the InMemoryBackingStore that would not leave out properties in nested IBackedModel properties. + ## [1.1.1] - 2024-03-20 ### Changed diff --git a/components/abstractions/spotBugsExcludeFilter.xml b/components/abstractions/spotBugsExcludeFilter.xml index 23f22f549..4db33b49d 100644 --- a/components/abstractions/spotBugsExcludeFilter.xml +++ b/components/abstractions/spotBugsExcludeFilter.xml @@ -50,4 +50,12 @@ xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubu + + + + + + + + diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java b/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java index 50e22fae9..e8be53018 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java @@ -6,6 +6,7 @@ import jakarta.annotation.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -33,7 +34,7 @@ public A getValue0() { } public Pair setValue0(A value0) { - return new Pair(value0, value1); + return new Pair<>(value0, value1); } public B getValue1() { @@ -41,7 +42,7 @@ public B getValue1() { } public Pair setValue1(B value1) { - return new Pair(value0, value1); + return new Pair<>(value0, value1); } } @@ -55,7 +56,15 @@ public void setIsInitializationCompleted(final boolean value) { this.isInitializationCompleted = value; for (final Map.Entry> entry : this.store.entrySet()) { final Pair wrapper = entry.getValue(); - final Pair updatedValue = wrapper.setValue0(Boolean.valueOf(!value)); + if (wrapper.getValue1() instanceof BackedModel) { + BackedModel backedModel = (BackedModel) wrapper.getValue1(); + backedModel + .getBackingStore() + .setIsInitializationCompleted(value); // propagate initialization + } + ensureCollectionPropertyIsConsistent( + entry.getKey(), this.store.get(entry.getKey()).getValue1()); + final Pair updatedValue = wrapper.setValue0(!value); entry.setValue(updatedValue); } } @@ -80,10 +89,12 @@ public void clear() { final Map result = new HashMap<>(); for (final Map.Entry> entry : this.store.entrySet()) { final Pair wrapper = entry.getValue(); - final Object value = this.getValueFromWrapper(wrapper); + final Object value = this.getValueFromWrapper(entry.getKey(), wrapper); if (value != null) { result.put(entry.getKey(), wrapper.getValue1()); + } else if (Boolean.TRUE.equals(wrapper.getValue0())) { + result.put(entry.getKey(), null); } } return result; @@ -101,13 +112,15 @@ public void clear() { return result; } - private Object getValueFromWrapper(final Pair wrapper) { + private Object getValueFromWrapper(final String entryKey, final Pair wrapper) { if (wrapper != null) { final Boolean hasChanged = wrapper.getValue0(); - if (!this.returnOnlyChangedValues - || (this.returnOnlyChangedValues - && hasChanged != null - && hasChanged.booleanValue())) { + if (!this.returnOnlyChangedValues || Boolean.TRUE.equals(hasChanged)) { + ensureCollectionPropertyIsConsistent(entryKey, wrapper.getValue1()); + if (wrapper.getValue1() instanceof Pair) { + Pair collectionTuple = (Pair) wrapper.getValue1(); + return collectionTuple.getValue0(); + } return wrapper.getValue1(); } } @@ -118,7 +131,7 @@ private Object getValueFromWrapper(final Pair wrapper) { @Nullable public T get(@Nonnull final String key) { Objects.requireNonNull(key); final Pair wrapper = this.store.get(key); - final Object value = this.getValueFromWrapper(wrapper); + final Object value = this.getValueFromWrapper(key, wrapper); try { return (T) value; } catch (ClassCastException ex) { @@ -128,11 +141,39 @@ private Object getValueFromWrapper(final Pair wrapper) { public void set(@Nonnull final String key, @Nullable final T value) { Objects.requireNonNull(key); - final Pair valueToAdd = - new Pair(Boolean.valueOf(this.isInitializationCompleted), value); + Pair valueToAdd = new Pair<>(this.isInitializationCompleted, value); + if (value instanceof Collection) { + valueToAdd = valueToAdd.setValue1(new Pair<>(value, ((Collection) value).size())); + final Collection items = (Collection) value; + setupNestedSubscriptions(items, key, value); + } else if (value instanceof Map) { + valueToAdd = valueToAdd.setValue1(new Pair<>(value, ((Map) value).size())); + final Map items = (Map) value; + setupNestedSubscriptions(items.values(), key, value); + } else if (value instanceof BackedModel) { + final BackedModel backedModel = (BackedModel) value; + backedModel + .getBackingStore() + .subscribe( + key, + (keyString, oldObject, newObject) -> { + backedModel + .getBackingStore() + .setIsInitializationCompleted( + false); // All its properties are dirty as the model + // has been touched. + set(key, value); + }); // use property name(key) as subscriptionId to prevent excess + // subscription creation in the event this is called again + } + final Pair oldValue = this.store.put(key, valueToAdd); for (final TriConsumer callback : this.subscriptionStore.values()) { - callback.accept(key, oldValue.getValue1(), value); + if (oldValue != null) { + callback.accept(key, oldValue.getValue1(), value); + } else { + callback.accept(key, null, value); + } } } @@ -154,4 +195,53 @@ public void subscribe( Objects.requireNonNull(subscriptionId); this.subscriptionStore.put(subscriptionId, callback); } + + private void setupNestedSubscriptions( + final Collection items, final String key, final Object value) { + for (final Object item : items) { + if (item instanceof BackedModel) { + final BackedModel backedModel = (BackedModel) item; + backedModel.getBackingStore().setIsInitializationCompleted(false); + backedModel + .getBackingStore() + .subscribe(key, (keyString, oldObject, newObject) -> set(key, value)); + } + } + } + + private void ensureCollectionPropertyIsConsistent(final String key, final Object storeItem) { + if (storeItem instanceof Pair) { // check if we put in a collection annotated with the size + final Pair collectionTuple = (Pair) storeItem; + Object[] items; + if (collectionTuple.getValue0() instanceof Collection) { + items = ((Collection) collectionTuple.getValue0()).toArray(); + } else { // it is a map + items = ((Map) collectionTuple.getValue0()).values().toArray(); + } + + for (final Object item : items) { + touchNestedProperties(item); // call get on nested properties + } + + if (collectionTuple.getValue1() + != items.length) { // and the size has changed since we last updated + set( + key, + collectionTuple.getValue0()); // ensure the store is notified the collection + // property is "dirty" + } + } + touchNestedProperties(storeItem); // call get on nested properties + } + + private void touchNestedProperties(final Object nestedObject) { + if (nestedObject instanceof BackedModel) { + // Call Get<>() on nested properties so that this method may be called recursively to + // ensure collections are consistent + final BackedModel backedModel = (BackedModel) nestedObject; + for (final String itemKey : backedModel.getBackingStore().enumerate().keySet()) { + backedModel.getBackingStore().get(itemKey); + } + } + } } diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/TestEntity.java b/components/abstractions/src/test/java/com/microsoft/kiota/TestEntity.java index 511217a72..03d5111c1 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/TestEntity.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/TestEntity.java @@ -1,16 +1,101 @@ package com.microsoft.kiota; +import com.microsoft.kiota.serialization.AdditionalDataHolder; import com.microsoft.kiota.serialization.Parsable; import com.microsoft.kiota.serialization.ParseNode; import com.microsoft.kiota.serialization.SerializationWriter; +import com.microsoft.kiota.store.BackedModel; +import com.microsoft.kiota.store.BackingStore; +import com.microsoft.kiota.store.BackingStoreFactorySingleton; import jakarta.annotation.Nonnull; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Consumer; -public class TestEntity implements Parsable { +public class TestEntity implements Parsable, AdditionalDataHolder, BackedModel { + + protected BackingStore backingStore; + + /** + * Gets the backingStore property value. Stores model information. + * @return a {@link BackingStore} + */ + @jakarta.annotation.Nonnull public BackingStore getBackingStore() { + return this.backingStore; + } + + public String getOdataType() { + return this.backingStore.get("@odata.type"); + } + + public void setOdataType(String odataType) { + this.backingStore.set("@odata.type", odataType); + } + + public String getId() { + return this.backingStore.get("id"); + } + + public void setId(String _id) { + this.backingStore.set("id", _id); + } + + public List getBusinessPhones() { + return this.backingStore.get("businessPhones"); + } + + public void setBusinessPhones(List _businessPhones) { + this.backingStore.set("businessPhones", _businessPhones); + } + + public TestEntity getManager() { + return this.backingStore.get("manager"); + } + + public void setManager(TestEntity manager) { + this.backingStore.set("manager", manager); + } + + public List getColleagues() { + return this.backingStore.get("colleagues"); + } + + public void setColleagues(List colleagues) { + this.backingStore.set("colleagues", colleagues); + } + + /** + * Instantiates a new {@link TestEntity} and sets the default values. + */ + public TestEntity() { + this.backingStore = BackingStoreFactorySingleton.instance.createBackingStore(); + this.setAdditionalData(new HashMap<>()); + this.setOdataType("#microsoft.graph.testEntity"); + } + + /** + * Gets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + * @return a {@link Map} + */ + @jakarta.annotation.Nonnull public Map getAdditionalData() { + Map value = this.backingStore.get("additionalData"); + if (value == null) { + value = new HashMap<>(); + this.setAdditionalData(value); + } + return value; + } + + /** + * Sets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + * @param value Value to set for the AdditionalData property. + */ + public void setAdditionalData(@jakarta.annotation.Nullable final Map value) { + this.backingStore.set("additionalData", value); + } @Override @Nonnull public Map> getFieldDeserializers() { diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/store/InMemoryBackingStoreTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/store/InMemoryBackingStoreTest.java new file mode 100644 index 000000000..3fdee744f --- /dev/null +++ b/components/abstractions/src/test/java/com/microsoft/kiota/store/InMemoryBackingStoreTest.java @@ -0,0 +1,395 @@ +package com.microsoft.kiota.store; + +import static org.junit.jupiter.api.Assertions.*; + +import com.microsoft.kiota.TestEntity; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class InMemoryBackingStoreTest { + @Test + void SetsAndGetsValueFromStore() { + // Arrange + var testBackingStore = new InMemoryBackingStore(); + // Act + assertTrue(testBackingStore.enumerate().isEmpty()); + testBackingStore.set("name", "Peter"); + // Assert + assertFalse(testBackingStore.enumerate().isEmpty()); + assertEquals("Peter", testBackingStore.enumerate().values().toArray()[0]); + } + + @Test + void PreventsDuplicatesInStore() { + // Arrange + var testBackingStore = new InMemoryBackingStore(); + // Act + assertTrue(testBackingStore.enumerate().isEmpty()); + testBackingStore.set("name", "Peter"); + testBackingStore.set("name", "Peter Pan"); // modify a second time + // Assert + assertFalse(testBackingStore.enumerate().isEmpty()); + assertFalse(testBackingStore.enumerate().isEmpty()); + assertEquals("Peter Pan", testBackingStore.enumerate().values().toArray()[0]); + } + + @Test + void EnumeratesValuesChangedToNullInStore() { + // Arrange + var testBackingStore = new InMemoryBackingStore(); + // Act + assertTrue(testBackingStore.enumerate().isEmpty()); + testBackingStore.set("name", "Peter Pan"); + testBackingStore.set("email", "peterpan@neverland.com"); + testBackingStore.set("phone", null); // phone changes to null + // Assert + assertFalse(testBackingStore.enumerate().isEmpty()); + assertEquals( + 1, + testBackingStore + .enumerateKeysForValuesChangedToNull() + .spliterator() + .getExactSizeIfKnown()); + assertEquals(3, testBackingStore.enumerate().size()); // all values come back + assertEquals( + "phone", + testBackingStore + .enumerateKeysForValuesChangedToNull() + .iterator() + .next()); // first item + } + + @Test + void TestsBackingStoreEmbeddedInModel() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + testUser.getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change + testUser.setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + // Assert by retrieving only changed values + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals("businessPhones", changedValues.keySet().toArray()[0]); + } + + @Test + void TestsBackingStoreEmbeddedInModelWithAdditionDataValues() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + testUser.getAdditionalData().put("extensionData", null); + testUser.getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change to a property and additionalData + testUser.setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + testUser.getAdditionalData().put("anotherExtension", null); + // Assert by retrieving only changed values + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(2, changedValues.size()); + assertTrue(changedValues.containsKey("businessPhones")); + assertTrue(changedValues.containsKey("additionalData")); + } + + @Test + void TestsBackingStoreEmbeddedInModelWithCollectionPropertyReplacedWithNewCollection() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + testUser.getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change + testUser.setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + testUser.getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change + testUser.setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + // Assert by retrieving only changed values + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals("businessPhones", changedValues.keySet().toArray()[0]); + var businessPhones = testUser.getBackingStore().get("businessPhones"); + assertNotNull(businessPhones); + assertEquals(1, ((List) businessPhones).size()); + } + + @Test + void TestsBackingStoreEmbeddedInModelWithCollectionPropertyReplacedWithNull() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + testUser.getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change + testUser.setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + testUser.getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change + testUser.setBusinessPhones(null); + // Assert by retrieving only changed values + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals("businessPhones", changedValues.keySet().toArray()[0]); + var changedValuesToNull = testUser.getBackingStore().enumerateKeysForValuesChangedToNull(); + assertTrue(changedValuesToNull.iterator().hasNext()); + assertEquals("businessPhones", changedValues.keySet().toArray()[0]); + assertNull(changedValues.values().toArray()[0]); + } + + @Test + void TestsBackingStoreEmbeddedInModelWithCollectionPropertyModifiedByAdd() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + testUser.getAdditionalData().put("extensionData", null); + testUser.getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change to a property and additionalData + ArrayList phonesList = new ArrayList(); + phonesList.add("+1 234 567 891"); + testUser.setBusinessPhones(phonesList); + // Act on the data by making a change + testUser.getBusinessPhones().add("+1 234 567 891"); + // Assert by retrieving only changed values + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals("businessPhones", changedValues.keySet().toArray()[0]); + var businessPhones = testUser.getBackingStore().get("businessPhones"); + assertNotNull(businessPhones); + assertEquals(2, ((List) businessPhones).size()); + } + + @Test + void TestsBackingStoreEmbeddedInModelWithBySettingNestedIBackedModel() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + testUser.getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change + var manager = new TestEntity(); + manager.setId("2fe22fe5-1132-42cf-90f9-1dc17e325a74"); + testUser.setManager(manager); + // Assert by retrieving only changed values + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals("manager", changedValues.keySet().toArray()[0]); + var changedManager = (TestEntity) changedValues.values().toArray()[0]; + assertNotNull(changedManager); + assertEquals("2fe22fe5-1132-42cf-90f9-1dc17e325a74", changedManager.getId()); + } + + @Test + void TestsBackingStoreEmbeddedInModelWithByUpdatingNestedIBackedModel() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + var manager = new TestEntity(); + manager.setId("2fe22fe5-1132-42cf-90f9-1dc17e325a74"); + testUser.setManager(manager); + testUser.getBackingStore().setIsInitializationCompleted(true); + testUser.getManager().getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change in the nested Ibackedmodel + testUser.getManager().setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + // Assert by retrieving only changed values + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals( + "manager", + changedValues.keySet() + .toArray()[0]); // Backingstore should detect manager property changed + var changedManager = (TestEntity) changedValues.values().toArray()[0]; + assertNotNull(changedManager); + assertEquals("2fe22fe5-1132-42cf-90f9-1dc17e325a74", changedManager.getId()); + } + + @Test + void + TestsBackingStoreEmbeddedInModelWithByUpdatingNestedIBackedModelReturnsAllNestedProperties() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + var manager = new TestEntity(); + manager.setId("2fe22fe5-1132-42cf-90f9-1dc17e325a74"); + testUser.setManager(manager); + testUser.getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change in the nested Ibackedmodel + testUser.getManager().setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + // Assert by retrieving only changed values + testUser.getBackingStore().setReturnOnlyChangedValues(true); + testUser.getManager().getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals( + "manager", + changedValues.keySet() + .toArray()[0]); // Backingstore should detect manager property changed + var changedNestedValues = testUser.getManager().getBackingStore().enumerate(); + assertEquals(4, changedNestedValues.size()); + assertTrue(changedNestedValues.containsKey("id")); + assertTrue(changedNestedValues.containsKey("businessPhones")); + var changedManager = (TestEntity) changedValues.values().toArray()[0]; + assertNotNull(changedManager); + assertEquals("2fe22fe5-1132-42cf-90f9-1dc17e325a74", changedManager.getId()); + } + + @Test + void TestsBackingStoreEmbeddedInModelWithByUpdatingNestedIBackedModelCollectionProperty() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + var firstColleague = new TestEntity(); + firstColleague.setId("2fe22fe5-1132-42cf-90f9-1dc17e325a74"); + var colleagues = Arrays.asList(new TestEntity[] {firstColleague}); + testUser.setColleagues(colleagues); + testUser.getBackingStore().setIsInitializationCompleted(true); + testUser.getColleagues().get(0).getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change in the nested Ibackedmodel collection item + testUser.getColleagues() + .get(0) + .setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + // Assert by retrieving only changed values + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals( + "colleagues", + changedValues.keySet() + .toArray()[0]); // Backingstore should detect colleagues property changed + var changedColleagues = (List) (testUser.getBackingStore().get("colleagues")); + assertNotNull(changedColleagues); + assertEquals("2fe22fe5-1132-42cf-90f9-1dc17e325a74", changedColleagues.get(0).getId()); + } + + @Test + void + TestsBackingStoreEmbeddedInModelWithByUpdatingNestedIBackedModelCollectionPropertyReturnsAllNestedProperties() { + // Arrange dummy user with initialized backingstore + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + var firstColleague = new TestEntity(); + firstColleague.setId("2fe22fe5-1132-42cf-90f9-1dc17e325a74"); + var colleagues = Arrays.asList(new TestEntity[] {firstColleague}); + testUser.setColleagues(colleagues); + testUser.getBackingStore().setIsInitializationCompleted(true); + testUser.getColleagues().get(0).getBackingStore().setIsInitializationCompleted(true); + + testUser.getColleagues() + .get(0) + .setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + testUser.getBackingStore().setReturnOnlyChangedValues(true); + testUser.getColleagues() + .get(0) + .getBackingStore() + .setReturnOnlyChangedValues(true); // serializer will do this. + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertTrue( + changedValues.containsKey( + "colleagues")); // BackingStore should detect colleagues property changed + var changedNestedValues = testUser.getColleagues().get(0).getBackingStore().enumerate(); + assertEquals(4, changedNestedValues.size()); + assertTrue(changedNestedValues.containsKey("id")); + assertTrue(changedNestedValues.containsKey("businessPhones")); + } + + @Test + void + TestsBackingStoreEmbeddedInModelWithByUpdatingNestedIBackedModelCollectionPropertyWithExtraValueReturnsAllNestedProperties() { + // Arrange dummy user with initialized backing store + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + var firstColleague = new TestEntity(); + firstColleague.setId("2fe22fe5-1132-42cf-90f9-1dc17e325a74"); + List phonesList = new ArrayList<>(); + phonesList.add("+1 234 567 891"); + firstColleague.setBusinessPhones(phonesList); + var colleagues = Arrays.asList(new TestEntity[] {firstColleague}); + testUser.setColleagues(colleagues); + + testUser.getBackingStore().setIsInitializationCompleted(true); + testUser.getColleagues().get(0).getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change in the nested Ibackedmodel collection item + testUser.getColleagues().get(0).getBusinessPhones().add("+9 876 543 219"); + // Assert by retrieving only changed values + + testUser.getColleagues() + .get(0) + .getBackingStore() + .setReturnOnlyChangedValues(true); // serializer will do this. + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals( + "colleagues", + changedValues.keySet() + .toArray()[0]); // Backingstore should detect manager property changed + var changedNestedValues = testUser.getColleagues().get(0).getBackingStore().enumerate(); + assertEquals(4, changedNestedValues.size()); + assertTrue(changedNestedValues.containsKey("id")); + assertTrue(changedNestedValues.containsKey("businessPhones")); + var businessPhones = + (List) testUser.getColleagues().get(0).getBackingStore().get("businessPhones"); + assertEquals(2, businessPhones.size()); + } + + @Test + void + TestsBackingStoreEmbeddedInModelWithByUpdatingNestedIBackedModelCollectionPropertyWithExtraIBackedModelValueReturnsAllNestedProperties() { + // Arrange dummy user with initialized backing store + var testUser = new TestEntity(); + testUser.setId("84c747c1-d2c0-410d-ba50-fc23e0b4abbe"); + var firstColleague = new TestEntity(); + firstColleague.setId("2fe22fe5-1132-42cf-90f9-1dc17e325a74"); + firstColleague.setBusinessPhones(Arrays.asList(new String[] {"+1 234 567 891"})); + var colleagues = new ArrayList(); + colleagues.add(firstColleague); + testUser.setColleagues(colleagues); + testUser.getBackingStore().setIsInitializationCompleted(true); + testUser.getColleagues().get(0).getBackingStore().setIsInitializationCompleted(true); + // Act on the data by making a change in the nested Ibackedmodel collection item + var secondColleague = new TestEntity(); + secondColleague.setId("2fe22fe5-1132-42cf-90f9-1dc17e325a74"); + testUser.getColleagues().add(secondColleague); + // Assert by retrieving only changed values + + testUser.getColleagues() + .get(0) + .getBackingStore() + .setReturnOnlyChangedValues(true); // serializer will do this. + testUser.getBackingStore().setReturnOnlyChangedValues(true); + var changedValues = testUser.getBackingStore().enumerate(); + assertFalse(changedValues.isEmpty()); + assertEquals(1, changedValues.size()); + assertEquals( + "colleagues", + changedValues.keySet() + .toArray()[0]); // Backingstore should detect manager property changed + var colleaguesList = (List) testUser.getBackingStore().get("colleagues"); + assertEquals(2, colleaguesList.size()); + assertEquals("2fe22fe5-1132-42cf-90f9-1dc17e325a74", colleaguesList.get(0).getId()); + assertEquals("2fe22fe5-1132-42cf-90f9-1dc17e325a74", colleagues.get(0).getId()); + var changedNestedValues = colleaguesList.get(0).getBackingStore().enumerate(); + assertEquals(4, changedNestedValues.size()); + assertTrue(changedNestedValues.containsKey("id")); + assertTrue(changedNestedValues.containsKey("businessPhones")); + var businessPhones = + (List) colleaguesList.get(0).getBackingStore().get("businessPhones"); + assertEquals(1, businessPhones.size()); + } +} diff --git a/gradle.properties b/gradle.properties index ed1814fba..5be5fc750 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ org.gradle.caching=true mavenGroupId = com.microsoft.kiota mavenMajorVersion = 1 mavenMinorVersion = 1 -mavenPatchVersion = 1 +mavenPatchVersion = 2 mavenArtifactSuffix = #These values are used to run functional tests