Skip to content

Commit 9c04f98

Browse files
authored
Merge pull request #230 from AzureCosmosDB/copilot/fix-cosmos-getpropertyvalue-error
Fix GetPropertyValue to support nested partition key paths
2 parents dd51ed3 + e3bb40f commit 9c04f98

File tree

2 files changed

+140
-1
lines changed

2 files changed

+140
-1
lines changed

Extensions/Cosmos/Cosmos.DataTransfer.CosmosExtension.UnitTests/CosmosDataSinkExtensionTests.cs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,5 +366,120 @@ public static bool HasProperty(object obj, string name)
366366
var values = (IDictionary<string, object>)obj;
367367
return values.ContainsKey(name);
368368
}
369+
370+
private static string? InvokeGetPropertyValue(ExpandoObject item, string propertyName)
371+
{
372+
var method = typeof(CosmosDataSinkExtension).GetMethod("GetPropertyValue",
373+
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
374+
return method?.Invoke(null, new object[] { item, propertyName }) as string;
375+
}
376+
377+
[TestMethod]
378+
public void GetPropertyValue_WithSimpleProperty_ReturnsValue()
379+
{
380+
// Arrange
381+
var expando = new ExpandoObject();
382+
var dict = (IDictionary<string, object?>)expando;
383+
dict["id"] = "test-id-123";
384+
dict["name"] = "test-name";
385+
386+
// Act
387+
var result = InvokeGetPropertyValue(expando, "id");
388+
389+
// Assert
390+
Assert.IsNotNull(result);
391+
Assert.AreEqual("test-id-123", result);
392+
}
393+
394+
[TestMethod]
395+
public void GetPropertyValue_WithNestedProperty_ReturnsValue()
396+
{
397+
// Arrange - Create nested structure matching the issue example
398+
var expando = new ExpandoObject();
399+
var dict = (IDictionary<string, object?>)expando;
400+
dict["id"] = "test-id";
401+
402+
var nestedExpando = new ExpandoObject();
403+
var nestedDict = (IDictionary<string, object?>)nestedExpando;
404+
nestedDict["partitionkeyvalue2"] = "guid-value-123";
405+
nestedDict["somevalue4"] = "other-guid";
406+
nestedDict["UserName"] = "testuser";
407+
408+
dict["partitionkeyvalue1"] = nestedExpando;
409+
410+
// Act
411+
var result = InvokeGetPropertyValue(expando, "partitionkeyvalue1/partitionkeyvalue2");
412+
413+
// Assert
414+
Assert.IsNotNull(result);
415+
Assert.AreEqual("guid-value-123", result);
416+
}
417+
418+
[TestMethod]
419+
public void GetPropertyValue_WithDeeplyNestedProperty_ReturnsValue()
420+
{
421+
// Arrange - Create deeply nested structure
422+
var expando = new ExpandoObject();
423+
var dict = (IDictionary<string, object?>)expando;
424+
dict["id"] = "test-id";
425+
426+
var level1 = new ExpandoObject();
427+
var level1Dict = (IDictionary<string, object?>)level1;
428+
429+
var level2 = new ExpandoObject();
430+
var level2Dict = (IDictionary<string, object?>)level2;
431+
432+
var level3 = new ExpandoObject();
433+
var level3Dict = (IDictionary<string, object?>)level3;
434+
level3Dict["finalValue"] = "deeply-nested-value";
435+
436+
level2Dict["level3"] = level3;
437+
level1Dict["level2"] = level2;
438+
dict["level1"] = level1;
439+
440+
// Act
441+
var result = InvokeGetPropertyValue(expando, "level1/level2/level3/finalValue");
442+
443+
// Assert
444+
Assert.IsNotNull(result);
445+
Assert.AreEqual("deeply-nested-value", result);
446+
}
447+
448+
[TestMethod]
449+
public void GetPropertyValue_WithMissingNestedProperty_ReturnsNull()
450+
{
451+
// Arrange
452+
var expando = new ExpandoObject();
453+
var dict = (IDictionary<string, object?>)expando;
454+
dict["id"] = "test-id";
455+
456+
var nestedExpando = new ExpandoObject();
457+
var nestedDict = (IDictionary<string, object?>)nestedExpando;
458+
nestedDict["existingKey"] = "value";
459+
460+
dict["parent"] = nestedExpando;
461+
462+
// Act
463+
var result = InvokeGetPropertyValue(expando, "parent/nonExistentKey");
464+
465+
// Assert
466+
Assert.IsNull(result);
467+
}
468+
469+
[TestMethod]
470+
public void GetPropertyValue_WithNullIntermediateValue_ReturnsNull()
471+
{
472+
// Arrange
473+
var expando = new ExpandoObject();
474+
var dict = (IDictionary<string, object?>)expando;
475+
dict["id"] = "test-id";
476+
dict["parent"] = null;
477+
478+
// Act
479+
var result = InvokeGetPropertyValue(expando, "parent/child");
480+
481+
// Assert
482+
Assert.IsNull(result);
483+
}
369484
}
370485
}

Extensions/Cosmos/Cosmos.DataTransfer.CosmosExtension/CosmosDataSinkExtension.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,31 @@ private static MemoryStream CreateItemStream(ExpandoObject item)
286286

287287
private static string? GetPropertyValue(ExpandoObject item, string propertyName)
288288
{
289-
return ((IDictionary<string, object?>)item)[propertyName]?.ToString();
289+
// Handle nested property paths (e.g., "property1/property2/property3")
290+
// Note: Calling code uses TrimStart('/') to remove leading slash before calling this method
291+
var pathSegments = propertyName.Split('/');
292+
object? current = item;
293+
294+
foreach (var segment in pathSegments)
295+
{
296+
if (current == null)
297+
{
298+
return null;
299+
}
300+
301+
if (current is not ExpandoObject expandoObj)
302+
{
303+
return null;
304+
}
305+
306+
var dict = (IDictionary<string, object?>)expandoObj;
307+
if (!dict.TryGetValue(segment, out current))
308+
{
309+
return null;
310+
}
311+
}
312+
313+
return current?.ToString();
290314
}
291315

292316
public IEnumerable<IDataExtensionSettings> GetSettings()

0 commit comments

Comments
 (0)