Skip to content

Commit 090e68e

Browse files
Fix serialization for StoredProcedureDefinition inheritance (#3045)
## Why make this change? - To apply correct serialization and deserialization logic for stored procedures. With the previous changes, serialization was not working correctly for the StoredProcedureDefinition type, which extends SourceDefinition. When the value type was passed explicitly for serialization, the parent type was used instead, causing some child-type properties to be omitted. ## What is this change? Instead of manually specifying the value type during serialization, this change allows the library to infer the type automatically and perform the correct serialization. ## How was this tested? - [x] Unit Tests --------- Co-authored-by: Aniruddh Munde <[email protected]>
1 parent 725bf8c commit 090e68e

2 files changed

Lines changed: 30 additions & 14 deletions

File tree

src/Core/Services/MetadataProviders/Converters/DatabaseObjectConverter.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public override DatabaseObject Read(ref Utf8JsonReader reader, Type typeToConver
3434

3535
DatabaseObject objA = (DatabaseObject)JsonSerializer.Deserialize(document, concreteType, options)!;
3636

37-
foreach (PropertyInfo prop in objA.GetType().GetProperties().Where(IsSourceDefinitionProperty))
37+
foreach (PropertyInfo prop in objA.GetType().GetProperties().Where(IsSourceDefinitionOrDerivedClassProperty))
3838
{
3939
SourceDefinition? sourceDef = (SourceDefinition?)prop.GetValue(objA);
4040
if (sourceDef is not null)
@@ -73,25 +73,23 @@ public override void Write(Utf8JsonWriter writer, DatabaseObject value, JsonSeri
7373

7474
writer.WritePropertyName(prop.Name);
7575
object? propVal = prop.GetValue(value);
76-
Type propType = prop.PropertyType;
7776

78-
// Only escape columns for properties whose type is exactly SourceDefinition (not subclasses).
79-
// This is because, we do not want unnecessary mutation of subclasses of SourceDefinition unless needed.
80-
if (IsSourceDefinitionProperty(prop) && propVal is SourceDefinition sourceDef && propVal.GetType() == typeof(SourceDefinition))
77+
// Only escape columns for properties whose type(derived type) is SourceDefinition.
78+
if (IsSourceDefinitionOrDerivedClassProperty(prop) && propVal is SourceDefinition sourceDef)
8179
{
8280
EscapeDollaredColumns(sourceDef);
8381
}
8482

85-
JsonSerializer.Serialize(writer, propVal, propType, options);
83+
JsonSerializer.Serialize(writer, propVal, options);
8684
}
8785

8886
writer.WriteEndObject();
8987
}
9088

91-
private static bool IsSourceDefinitionProperty(PropertyInfo prop)
89+
private static bool IsSourceDefinitionOrDerivedClassProperty(PropertyInfo prop)
9290
{
93-
// Only return true for properties whose type is exactly SourceDefinition (not subclasses)
94-
return prop.PropertyType == typeof(SourceDefinition);
91+
// Return true for properties whose type is SourceDefinition or any class derived from SourceDefinition
92+
return typeof(SourceDefinition).IsAssignableFrom(prop.PropertyType);
9593
}
9694

9795
/// <summary>

src/Service.Tests/UnitTests/SerializationDeserializationTests.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,11 @@ public void TestDictionaryDatabaseObjectSerializationDeserialization_WithDollarC
299299
Dictionary<string, DatabaseObject> dict = new() { { "person", _databaseTable } };
300300

301301
string serializedDict = JsonSerializer.Serialize(dict, _options);
302-
Dictionary<string, DatabaseObject> deserializedDict = JsonSerializer.Deserialize<Dictionary<string, DatabaseObject>>(serializedDict, _options)!;
302+
// Assert that the serialized JSON contains the escaped dollar sign in column name
303+
Assert.IsTrue(serializedDict.Contains("DAB_ESCAPE$FirstName"),
304+
"Serialized JSON should contain the dollar-prefixed column name in SourceDefinition's Columns.");
303305

306+
Dictionary<string, DatabaseObject> deserializedDict = JsonSerializer.Deserialize<Dictionary<string, DatabaseObject>>(serializedDict, _options)!;
304307
DatabaseTable deserializedDatabaseTable = (DatabaseTable)deserializedDict["person"];
305308

306309
Assert.AreEqual(deserializedDatabaseTable.SourceType, _databaseTable.SourceType);
@@ -322,14 +325,22 @@ public void TestDatabaseViewSerializationDeserialization_WithDollarColumn()
322325

323326
TestTypeNameChanges(_databaseView, "DatabaseView");
324327

328+
Dictionary<string, DatabaseObject> dict = new();
329+
dict.Add("person", _databaseView);
330+
325331
// Test to catch if there is change in number of properties/fields
326332
// Note: On Addition of property make sure it is added in following object creation _databaseView and include in serialization
327333
// and deserialization test.
328334
int fields = typeof(DatabaseView).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Length;
329335
Assert.AreEqual(fields, 6);
330336

331-
string serializedDatabaseView = JsonSerializer.Serialize(_databaseView, _options);
332-
DatabaseView deserializedDatabaseView = JsonSerializer.Deserialize<DatabaseView>(serializedDatabaseView, _options)!;
337+
string serializedDatabaseView = JsonSerializer.Serialize(dict, _options);
338+
// Assert that the serialized JSON contains the escaped dollar sign in column name
339+
Assert.IsTrue(serializedDatabaseView.Contains("DAB_ESCAPE$FirstName"),
340+
"Serialized JSON should contain the dollar-prefixed column name in SourceDefinition's Columns.");
341+
Dictionary<string, DatabaseObject> deserializedDict = JsonSerializer.Deserialize<Dictionary<string, DatabaseObject>>(serializedDatabaseView, _options)!;
342+
343+
DatabaseView deserializedDatabaseView = (DatabaseView)deserializedDict["person"];
333344

334345
Assert.AreEqual(deserializedDatabaseView.SourceType, _databaseView.SourceType);
335346
deserializedDatabaseView.Equals(_databaseView);
@@ -349,14 +360,21 @@ public void TestDatabaseStoredProcedureSerializationDeserialization_WithDollarCo
349360

350361
TestTypeNameChanges(_databaseStoredProcedure, "DatabaseStoredProcedure");
351362

363+
Dictionary<string, DatabaseObject> dict = new();
364+
dict.Add("person", _databaseStoredProcedure);
365+
352366
// Test to catch if there is change in number of properties/fields
353367
// Note: On Addition of property make sure it is added in following object creation _databaseStoredProcedure and include in serialization
354368
// and deserialization test.
355369
int fields = typeof(DatabaseStoredProcedure).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Length;
356370
Assert.AreEqual(fields, 6);
357371

358-
string serializedDatabaseSP = JsonSerializer.Serialize(_databaseStoredProcedure, _options);
359-
DatabaseStoredProcedure deserializedDatabaseSP = JsonSerializer.Deserialize<DatabaseStoredProcedure>(serializedDatabaseSP, _options)!;
372+
string serializedDatabaseSP = JsonSerializer.Serialize(dict, _options);
373+
// Assert that the serialized JSON contains the escaped dollar sign in column name
374+
Assert.IsTrue(serializedDatabaseSP.Contains("DAB_ESCAPE$FirstName"),
375+
"Serialized JSON should contain the dollar-prefixed column name in SourceDefinition's Columns.");
376+
Dictionary<string, DatabaseObject> deserializedDict = JsonSerializer.Deserialize<Dictionary<string, DatabaseObject>>(serializedDatabaseSP, _options)!;
377+
DatabaseStoredProcedure deserializedDatabaseSP = (DatabaseStoredProcedure)deserializedDict["person"];
360378

361379
Assert.AreEqual(deserializedDatabaseSP.SourceType, _databaseStoredProcedure.SourceType);
362380
deserializedDatabaseSP.Equals(_databaseStoredProcedure);

0 commit comments

Comments
 (0)