-
Notifications
You must be signed in to change notification settings - Fork 494
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PatchItemAsync is ignoring CosmosClientOptions.SerializerOptions.PropertyNamingPolicy when set to CamelCase #4733
Comments
@philipthomas-MSFT can you please look into it? |
NamingPolicy is a pure SDK concept not service concept. Patch API's all take string as path argument and application is expected to provide with the right cased value. |
I got this working by reading the Object in the patch and then reserializing back as a camelCase object. This works, but it would be great if the Cosmos DB SDK would do this using the same CosmosPropertyNamingPolicy which is what the Create and Upsert use. |
@calloncampbell Do you mind sharing your final solution. Also, agree with @kirankumarkolli on path being a string. We can consider a typed solution in the future. |
@calloncampbell it's an interesting idea to explore. Your solution will definitely help us learn and improve this API. The API can take Field/Property, but it will be scoped to a single name only, where the data model might be more nested. |
I think I am leaning toward a Current Container.PatchItemAsync
Future Container.PatchItemAsync overloaded with PatchOperationBuilder
Since all Container's operations have access to the CosmosSerializer, can use deferred execution to do the serialization after you create the builder and pass it into the overloaded Maybe implementation could look like this
Now the Also, I would obviously need to spend more on ensuring that all variations of the supported operations are supported and tested (Add, Replace, etc.). I think this would be a good addition to the SDK. |
Thanks for your investigation and efforts. |
Here is the solution I went with... I added this... public List<PatchOperationModel> CreatePatchOperation(string requestBody)
{
if (string.IsNullOrWhiteSpace(requestBody))
{
throw new Exception("RequestBody is null or empty");
}
// Use the Newtonsoft.Json.JsonConvert.DeserializeObject method to deserialize a JsonPatchDocument, and use
// System.Text.Json for all other JSON requests and responses.
JsonPatchDocument<CallLogModel> jsonPatchDocument = _serializationService.Deserialize<JsonPatchDocument<CallLogModel>>(requestBody);
if (jsonPatchDocument is null)
{
throw new Exception("Deserialization exception of request body into JsonPatchDocument.");
}
List<PatchOperationModel> patchOperations = new();
foreach (var operation in jsonPatchDocument.Operations)
{
if (operation.OperationType == OperationType.Add)
{
var camelCasePath = CamelCaseConverter.ToCamelCase(operation.path);
object camelCaseValue = _serializationService.CreateCamelCaseObject(operation.value);
patchOperations.Add(new()
{
OperationType = Domain.Enums.PatchOperationType.Add,
Path = camelCasePath,
Value = camelCaseValue
});
}
else if (operation.OperationType == OperationType.Replace)
{
var camelCasePath = CamelCaseConverter.ToCamelCase(operation.path);
object camelCaseValue = _serializationService.CreateCamelCaseObject(operation.value);
patchOperations.Add(new()
{
OperationType = Domain.Enums.PatchOperationType.Replace,
Path = camelCasePath,
Value = camelCaseValue
});
}
else
{
throw new Exception($"Unsupported operation type: {operation.OperationType}");
}
}
return patchOperations;
} In my serialization service, using the Newtonsoft JSON library, I used the public object CreateCamelCaseObject<T>(T objectToExpandoObject)
{
if (objectToExpandoObject is null)
{
return default;
}
try
{
if (objectToExpandoObject is string)
{
return objectToExpandoObject;
}
else if (objectToExpandoObject is int)
{
return objectToExpandoObject;
}
else if (objectToExpandoObject is long)
{
return objectToExpandoObject;
}
else if (objectToExpandoObject is decimal)
{
return objectToExpandoObject;
}
else if (objectToExpandoObject is bool)
{
return objectToExpandoObject;
}
else if (objectToExpandoObject is float)
{
return objectToExpandoObject;
}
else if (objectToExpandoObject is double)
{
return objectToExpandoObject;
}
else if (objectToExpandoObject is DateTime)
{
return objectToExpandoObject;
}
else if (objectToExpandoObject is DateTimeOffset)
{
return objectToExpandoObject;
}
else
{
var jObjectIn = JObject.FromObject(objectToExpandoObject, JsonSerializer.Create());
var jObjectOut = JObject.FromObject(jObjectIn.ToObject<ExpandoObject>(), JsonSerializer.Create(_readJsonSerializerOptions));
return jObjectOut;
}
}
catch
{
return default;
}
} Hope this helps. Callon |
Describe the bug
When using the PatchItem operation and I've configured the serialization to CamelCase, my results that show up in Cosmos DB for the patched item are in standard C# case (not CamelCase). When I use the CreateItem or UpsertItem, the data shows up in Cosmos DB using the desired serialization of CamelCase.
To Reproduce
Sample:
Expected behavior
When patching items, I expect it to work similarly to Create and Upsert where it uses the
PropertyNamingPolicy
which in my case has a value ofCamelCase
.Actual behavior
Data is patched in Cosmos container using the Default PropertyNamingPolicy.
Expected result in cosmos
Actual result in cosmos
Environment summary
Environment:
Azure Functions v4 - .NET 8 - Isolated worker
VS2022 17.11.4
Nuget Pakcges:
Additional context
Happy to provide additional code if needed.
The text was updated successfully, but these errors were encountered: