diff --git a/src/Config/Entity.cs b/src/Config/Entity.cs
index ce6b2b1c1e..dbcd069764 100644
--- a/src/Config/Entity.cs
+++ b/src/Config/Entity.cs
@@ -154,7 +154,7 @@ public void TryPopulateSourceFields()
}
else
{
- ObjectType = ConvertSourceType(objectSource.Type);
+ ObjectType = objectSource.Type;
SourceName = objectSource.Name;
Parameters = objectSource.Parameters;
KeyFields = objectSource.KeyFields;
@@ -165,23 +165,6 @@ public void TryPopulateSourceFields()
throw new JsonException(message: $"Source not one of string or object");
}
}
-
- ///
- /// Tries to convert the given string sourceType into one of the supported SourceType enums
- /// Throws an exception if not a case-insensitive match
- ///
- private static SourceType ConvertSourceType(string? sourceType)
- {
- // If sourceType is not explicitly specified, we assume it is a Table
- return sourceType is null ? SourceType.Table
- : sourceType.ToLowerInvariant() switch
- {
- "table" => SourceType.Table,
- "view" => SourceType.View,
- "stored-procedure" => SourceType.StoredProcedure,
- _ => throw new JsonException(message: "Source type must be one of: [table, view, stored-procedure]")
- };
- }
}
///
@@ -196,13 +179,52 @@ private static SourceType ConvertSourceType(string? sourceType)
/// The field(s) to be used as primary keys.
/// Support tracked in #547
public record DatabaseObjectSource(
- string Type,
+ [property: JsonConverter(typeof(SourceTypeEnumJsonConverter))]
+ SourceType Type,
[property: JsonPropertyName("object")]
string Name,
Dictionary? Parameters,
[property: JsonPropertyName("key-fields")]
Array KeyFields);
+ ///
+ /// Class to specify custom converter used while deserialising json config
+ /// to SourceType and serializing from SourceType to string.
+ /// Tries to convert the given string sourceType into one of the supported SourceType enums
+ /// Throws an exception if not a case-insensitive match
+ ///
+ public class SourceTypeEnumJsonConverter : JsonConverter
+ {
+ public const string STORED_PROCEDURE = "stored-procedure";
+
+ ///
+ public override SourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ string? type = reader.GetString();
+ if (STORED_PROCEDURE.Equals(type))
+ {
+ return SourceType.StoredProcedure;
+ }
+
+ if (Enum.TryParse(type, ignoreCase: true, out SourceType sourceType))
+ {
+ return sourceType;
+ }
+ else
+ {
+ throw new JsonException($"Invalid Source Type: {type}." +
+ $" Valid values are {STORED_PROCEDURE}, {SourceType.Table}, and {SourceType.View}.");
+ }
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, SourceType value, JsonSerializerOptions options)
+ {
+ string valueToWrite = value is SourceType.StoredProcedure ? STORED_PROCEDURE : value.ToString().ToLower();
+ writer.WriteStringValue(valueToWrite);
+ }
+ }
+
///
/// Supported source types as defined by json schema
///
diff --git a/src/Service.Tests/Authorization/AuthorizationHelpers.cs b/src/Service.Tests/Authorization/AuthorizationHelpers.cs
index 8951848d5f..50d4c6533d 100644
--- a/src/Service.Tests/Authorization/AuthorizationHelpers.cs
+++ b/src/Service.Tests/Authorization/AuthorizationHelpers.cs
@@ -58,7 +58,7 @@ public static AuthorizationResolver InitAuthorizationResolver(RuntimeConfig runt
///
public static RuntimeConfig InitRuntimeConfig(
string entityName = TEST_ENTITY,
- string entitySource = TEST_ENTITY,
+ object? entitySource = null,
string roleName = "Reader",
Operation operation = Operation.Create,
HashSet? includedCols = null,
@@ -69,6 +69,11 @@ public static RuntimeConfig InitRuntimeConfig(
{
Field? fieldsForRole = null;
+ if (entitySource is null)
+ {
+ entitySource = TEST_ENTITY;
+ }
+
if (includedCols is not null || excludedCols is not null)
{
// Only create object for Fields if inc/exc cols is not null.
diff --git a/src/Service.Tests/Configuration/ConfigurationTests.cs b/src/Service.Tests/Configuration/ConfigurationTests.cs
index 6b349ea336..edea620cd0 100644
--- a/src/Service.Tests/Configuration/ConfigurationTests.cs
+++ b/src/Service.Tests/Configuration/ConfigurationTests.cs
@@ -99,6 +99,76 @@ public async Task TestNoConfigReturnsServiceUnavailable(string[] args)
Assert.AreEqual(HttpStatusCode.ServiceUnavailable, result.StatusCode);
}
+ ///
+ /// Checks correct serialization and deserialization of Source Type from
+ /// Enum to String and vice-versa.
+ /// Consider both cases for source as an object and as a string
+ ///
+ [DataTestMethod]
+ [DataRow(true, SourceType.StoredProcedure, "stored-procedure", DisplayName = "source is a stored-procedure")]
+ [DataRow(true, SourceType.Table, "table", DisplayName = "source is a table")]
+ [DataRow(true, SourceType.View, "view", DisplayName = "source is a view")]
+ [DataRow(false, null, null, DisplayName = "source is just string")]
+ public void TestCorrectSerializationOfSourceObject(
+ bool isDatabaseObjectSource,
+ SourceType sourceObjectType,
+ string sourceTypeName)
+ {
+ object entitySource;
+ if (isDatabaseObjectSource)
+ {
+ entitySource = new DatabaseObjectSource(
+ Type: sourceObjectType,
+ Name: "sourceName",
+ Parameters: null,
+ KeyFields: null
+ );
+ }
+ else
+ {
+ entitySource = "sourceName";
+ }
+
+ RuntimeConfig runtimeConfig = AuthorizationHelpers.InitRuntimeConfig(
+ entityName: "MyEntity",
+ entitySource: entitySource,
+ roleName: "Anonymous",
+ operation: Operation.All,
+ includedCols: null,
+ excludedCols: null,
+ databasePolicy: null
+ );
+
+ string runtimeConfigJson = JsonSerializer.Serialize(runtimeConfig);
+
+ if (isDatabaseObjectSource)
+ {
+ Assert.IsTrue(runtimeConfigJson.Contains(sourceTypeName));
+ }
+
+ Mock logger = new();
+ Assert.IsTrue(RuntimeConfig.TryGetDeserializedConfig(
+ runtimeConfigJson,
+ out RuntimeConfig deserializedRuntimeConfig,
+ logger.Object));
+
+ Assert.IsTrue(deserializedRuntimeConfig.Entities.ContainsKey("MyEntity"));
+ deserializedRuntimeConfig.Entities["MyEntity"].TryPopulateSourceFields();
+ Assert.AreEqual("sourceName", deserializedRuntimeConfig.Entities["MyEntity"].SourceName);
+
+ JsonElement sourceJson = (JsonElement)deserializedRuntimeConfig.Entities["MyEntity"].Source;
+ if (isDatabaseObjectSource)
+ {
+ Assert.AreEqual(JsonValueKind.Object, sourceJson.ValueKind);
+ Assert.AreEqual(sourceObjectType, deserializedRuntimeConfig.Entities["MyEntity"].ObjectType);
+ }
+ else
+ {
+ Assert.AreEqual(JsonValueKind.String, sourceJson.ValueKind);
+ Assert.AreEqual("sourceName", deserializedRuntimeConfig.Entities["MyEntity"].Source.ToString());
+ }
+ }
+
[TestMethod("Validates that once the configuration is set, the config controller isn't reachable.")]
public async Task TestConflictAlreadySetConfiguration()
{