Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,18 @@ internal sealed class DataModelFieldCalculator

private readonly ILogger<DataModelFieldCalculator> _logger;
private readonly IAppResources _appResourceService;
private readonly ILayoutEvaluatorStateInitializer _layoutEvaluatorStateInitializer;
private readonly IDataElementAccessChecker _dataElementAccessChecker;
private readonly Telemetry? _telemetry;

public DataModelFieldCalculator(
ILogger<DataModelFieldCalculator> logger,
ILayoutEvaluatorStateInitializer layoutEvaluatorStateInitializer,
IAppResources appResourceService,
IDataElementAccessChecker dataElementAccessChecker,
Telemetry? telemetry = null
)
{
_logger = logger;
_appResourceService = appResourceService;
_layoutEvaluatorStateInitializer = layoutEvaluatorStateInitializer;
_dataElementAccessChecker = dataElementAccessChecker;
_telemetry = telemetry;
}
Expand All @@ -52,58 +49,44 @@ public async Task Calculate(IInstanceDataAccessor dataAccessor, string taskId)
var calculationConfig = _appResourceService.GetCalculationConfiguration(dataType.Id);
if (!string.IsNullOrEmpty(calculationConfig))
{
await CalculateFormData(dataAccessor, dataElement, taskId, calculationConfig);
await CalculateFormData(dataAccessor, dataElement, calculationConfig);
}
}
}

internal async Task CalculateFormData(
IInstanceDataAccessor dataAccessor,
DataElement dataElement,
string taskId,
string rawCalculationConfig
)
{
var evaluatorState = await _layoutEvaluatorStateInitializer.Init(dataAccessor, taskId);
var hiddenFields = await LayoutEvaluator.GetHiddenFieldsForRemoval(
evaluatorState,
evaluateRemoveWhenHidden: false
);
DataElementIdentifier dataElementIdentifier = dataElement;
var dataModelFieldCalculations = ParseDataModelFieldCalculationConfig(rawCalculationConfig);
var formDataWrapper = await dataAccessor.GetFormDataWrapper(dataElement);

foreach (var (baseField, calculation) in dataModelFieldCalculations)
{
var resolvedFields = await evaluatorState.GetResolvedKeys(
new DataReference() { Field = baseField, DataElementIdentifier = dataElementIdentifier },
true
);
var resolvedFields = formDataWrapper.GetResolvedKeys(baseField);
foreach (var resolvedField in resolvedFields)
{
if (
hiddenFields.Exists(d =>
d.DataElementIdentifier == resolvedField.DataElementIdentifier
&& IsSameOrDescendantField(resolvedField.Field, d.Field)
)
)
var resolvedFieldReference = new DataReference()
{
continue;
}

Field = resolvedField,
DataElementIdentifier = dataElementIdentifier,
};
var context = new ComponentContext(
evaluatorState,
dataAccessor,
component: null,
rowIndices: ExpressionHelper.GetRowIndices(resolvedField.Field),
dataElementIdentifier: resolvedField.DataElementIdentifier
rowIndices: ExpressionHelper.GetRowIndices(resolvedField),
dataElementIdentifier: dataElementIdentifier
);
var positionalArguments = new object[] { resolvedField.Field };
var positionalArguments = new ExpressionValue[] { resolvedField };

await RunCalculation(
formDataWrapper,
evaluatorState,
resolvedField,
dataAccessor,
context,
formDataWrapper,
resolvedFieldReference,
positionalArguments,
calculation
);
Expand All @@ -112,18 +95,18 @@ await RunCalculation(
}

private async Task RunCalculation(
IInstanceDataAccessor dataAccessor,
ComponentContext context,
IFormDataWrapper formDataWrapper,
LayoutEvaluatorState evaluatorState,
DataReference resolvedField,
ComponentContext context,
object[] positionalArguments,
ExpressionValue[] positionalArguments,
DataModelFieldCalculation calculation
)
{
try
{
var calculationResult = await ExpressionEvaluator.EvaluateExpressionToExpressionValue(
evaluatorState,
dataAccessor,
calculation.Expression,
context,
positionalArguments
Expand Down Expand Up @@ -212,16 +195,4 @@ out JsonElement calculationsObject

return dataModelFieldCalculation;
}

private static bool IsSameOrDescendantField(string candidate, string hiddenField)
{
if (candidate.Equals(hiddenField, StringComparison.Ordinal))
{
return true;
}

return candidate.StartsWith(hiddenField, StringComparison.Ordinal)
&& candidate.Length > hiddenField.Length
&& (candidate[hiddenField.Length] == '.' || candidate[hiddenField.Length] == '[');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ public class ExpressionValidator : IValidator

private readonly ILogger<ExpressionValidator> _logger;
private readonly IAppResources _appResourceService;
private readonly ILayoutEvaluatorStateInitializer _layoutEvaluatorStateInitializer;
private readonly IAppMetadata _appMetadata;
private readonly IDataElementAccessChecker _dataElementAccessChecker;

Expand All @@ -35,14 +34,12 @@ public class ExpressionValidator : IValidator
public ExpressionValidator(
ILogger<ExpressionValidator> logger,
IAppResources appResourceService,
ILayoutEvaluatorStateInitializer layoutEvaluatorStateInitializer,
IAppMetadata appMetadata,
IServiceProvider serviceProvider
)
{
_logger = logger;
_appResourceService = appResourceService;
_layoutEvaluatorStateInitializer = layoutEvaluatorStateInitializer;
_appMetadata = appMetadata;
_dataElementAccessChecker = serviceProvider.GetRequiredService<IDataElementAccessChecker>();
}
Expand Down Expand Up @@ -96,7 +93,7 @@ public async Task<List<ValidationIssue>> Validate(
var validationConfig = _appResourceService.GetValidationConfiguration(dataType.Id);
if (!string.IsNullOrEmpty(validationConfig))
{
var issues = await ValidateFormData(dataElement, dataAccessor, validationConfig, taskId, language);
var issues = await ValidateFormData(dataElement, dataAccessor, validationConfig);
validationIssues.AddRange(issues);
}
}
Expand All @@ -108,19 +105,12 @@ public async Task<List<ValidationIssue>> Validate(
internal async Task<List<ValidationIssue>> ValidateFormData(
DataElement dataElement,
IInstanceDataAccessor dataAccessor,
string rawValidationConfig,
string taskId,
string? language
string rawValidationConfig
)
{
var evaluatorState = await _layoutEvaluatorStateInitializer.Init(
dataAccessor,
taskId,
gatewayAction: null,
language
);
var formDataWrapper = await dataAccessor.GetFormDataWrapper(dataElement);
var hiddenFields = await LayoutEvaluator.GetHiddenFieldsForRemoval(
evaluatorState,
dataAccessor.GetLayoutEvaluatorState(),
evaluateRemoveWhenHidden: false
);

Expand All @@ -130,9 +120,11 @@ internal async Task<List<ValidationIssue>> ValidateFormData(

foreach (var (baseField, validations) in expressionValidations)
{
var resolvedFields = await evaluatorState.GetResolvedKeys(
new DataReference() { Field = baseField, DataElementIdentifier = dataElementIdentifier }
);
var resolvedFields = await dataAccessor
.GetLayoutEvaluatorState()
.GetResolvedKeys(
new DataReference() { Field = baseField, DataElementIdentifier = dataElementIdentifier }
);
foreach (var resolvedField in resolvedFields)
{
if (
Expand All @@ -150,13 +142,14 @@ internal async Task<List<ValidationIssue>> ValidateFormData(
rowIndices: ExpressionHelper.GetRowIndices(resolvedField.Field),
dataElementIdentifier: resolvedField.DataElementIdentifier
);
var positionalArguments = new object[] { resolvedField.Field };
var positionalArguments = new ExpressionValue[] { resolvedField.Field };
foreach (var validation in validations)
{
await RunValidation(
evaluatorState,
dataAccessor,
Comment thread
ivarne marked this conversation as resolved.
validationIssues,
resolvedField,
formDataWrapper,
context,
positionalArguments,
validation
Expand All @@ -169,27 +162,32 @@ await RunValidation(
}

private async Task RunValidation(
LayoutEvaluatorState evaluatorState,
IInstanceDataAccessor dataAccessor,
List<ValidationIssue> validationIssues,
DataReference resolvedField,
IFormDataWrapper formDataWrapper,
ComponentContext context,
object[] positionalArguments,
ExpressionValue[] positionalArguments,
ExpressionValidation validation
)
{
try
{
var validationResult = await ExpressionEvaluator.EvaluateExpression(
evaluatorState,
if (formDataWrapper.Get(resolvedField.Field) == null)
{
return; // Assume that the required validator will catch empty fields.
}
var validationResult = await ExpressionEvaluator.EvaluateExpressionToExpressionValue(
dataAccessor,
validation.Condition,
context,
positionalArguments
);
switch (validationResult)
switch (validationResult.ValueKind)
{
case true:
var message = await ExpressionEvaluator.EvaluateExpression(
evaluatorState,
case JsonValueKind.True:
var message = await ExpressionEvaluator.EvaluateExpressionToExpressionValue(
dataAccessor,
validation.Message,
context,
positionalArguments
Expand All @@ -200,13 +198,13 @@ ExpressionValidation validation
Field = resolvedField.Field,
DataElementId = resolvedField.DataElementIdentifier.Id,
Severity = validation.Severity ?? ValidationIssueSeverity.Error,
CustomTextKey = message as string ?? "",
Code = message as string ?? "",
Code = message.ToStringForText(),
CustomTextKey = message.ToStringForText(),
};
validationIssues.Add(validationIssue);

break;
case false:
case JsonValueKind.False:
break;
default:
throw new ArgumentException(
Expand Down
Loading
Loading