executeComparisons function
List
executeComparisons(
- List results,
- ParserList before,
- ParserList after,
- Map<
String, dynamic> passed, - Comparator comparator, {
- bool where = false,
Implementation
@override
List executeComparisons(List results, ParserList before, ParserList after,
Map<String, dynamic> passed, Comparator comparator,
{bool where = false}) {
// TODO(Dokotela): Currently, this is going to assume that if a String is being compared
// with a Date, DateTime, or Time, and the String is a valid format of a Time
// or DateTime, then they should still be compared
// another type, for instance:
// Patient.birthDate = "1981-09-18"
// today() = Date("2022-04-15")
// this will throw an error, despite the fact that they should be comparable
// could consider testing it, e.g.
// if (param1 is! String || param2 is! String) {
// if(param)}
bool stringGt(String param1, String param2) {
final runes1 = param1.runes.toList();
final runes2 = param2.runes.toList();
if (runes1.length < runes2.length) {
return false;
}
for (var i = 0; i < runes1.length; i++) {
if (runes2[i] > runes1[i]) {
return false;
} else if (runes2[i] < runes1[i]) {
return true;
}
}
return false;
}
bool? makeComparison(Comparator comparator, dynamic param1, dynamic param2) {
try {
switch (comparator) {
case Comparator.gt:
return param1 > param2 as bool?;
case Comparator.gte:
return param1 >= param2 as bool?;
case Comparator.lt:
return param1 < param2 as bool?;
case Comparator.lte:
return param1 <= param2 as bool?;
}
} catch (e) {
if (e is UnequalPrecision) {
return null;
} else {
rethrow;
}
}
}
Exception cannotCompareException(dynamic param1, dynamic param2) =>
FhirPathEvaluationException(
'The comparator $comparator was not passed types that can be '
'compared.\n'
'Param1: $param1 - ${param1.runtimeType}\n'
'Param1: $param2 - ${param2.runtimeType}\n');
Exception invalidException(dynamic param1, dynamic param2) =>
FhirPathEvaluationException(
'The comparator $comparator was not passed two valid types.\n'
'Param1: $param1 - ${param1.runtimeType} - Valid? ${param1.isValid}\n'
'Param1: $param2 - ${param2.runtimeType} - Valid? ${param2.isValid}\n');
bool? compare(Comparator comparator, dynamic lhs, dynamic rhs) {
switch (lhs.runtimeType) {
case num:
return rhs is num
? makeComparison(comparator, lhs, rhs)
: rhs is FhirNumber && rhs.isValid
? makeComparison(comparator, lhs, rhs.valueNumber)
: rhs is String && num.tryParse(rhs) != null
? makeComparison(comparator, lhs, num.parse(rhs))
: throw cannotCompareException(lhs, rhs);
case int:
return rhs is num
? makeComparison(comparator, lhs, rhs)
: rhs is FhirNumber && rhs.isValid
? makeComparison(comparator, lhs, rhs.valueNumber)
: rhs is String && num.tryParse(rhs) != null
? makeComparison(comparator, lhs, num.parse(rhs))
: throw cannotCompareException(lhs, rhs);
case double:
return rhs is num
? makeComparison(comparator, lhs, rhs)
: rhs is FhirNumber && rhs.isValid
? makeComparison(comparator, lhs, rhs.valueNumber)
: rhs is String && num.tryParse(rhs) != null
? makeComparison(comparator, lhs, num.parse(rhs))
: throw cannotCompareException(lhs, rhs);
case FhirDate:
return rhs is FhirDateTimeBase
? (lhs as FhirDate).isValid && rhs.isValid
? makeComparison(comparator, lhs, rhs)
: throw invalidException(lhs, rhs)
: rhs is String && FhirDateTime(rhs).isValid
? makeComparison(comparator, lhs, rhs)
: throw cannotCompareException(lhs, rhs);
case DateTime:
return (rhs is FhirDateTimeBase && rhs.isValid)
? makeComparison(comparator, FhirDateTime(lhs), rhs)
: rhs is DateTime
? makeComparison(
comparator, FhirDateTime(lhs), FhirDateTime(rhs))
: rhs is String && FhirDateTime(rhs).isValid
? makeComparison(
comparator, FhirDateTime(lhs), FhirDateTime(rhs))
: throw cannotCompareException(lhs, rhs);
case FhirDateTime:
return rhs is FhirDateTimeBase
? (lhs as FhirDateTime).isValid && rhs.isValid
? makeComparison(comparator, lhs, rhs)
: throw invalidException(lhs, rhs)
: rhs is String && FhirDateTime(rhs).isValid
? makeComparison(comparator, lhs, FhirDateTime(rhs))
: throw cannotCompareException(lhs, rhs);
case FhirTime:
return rhs is FhirTime
? (lhs as FhirTime).isValid && rhs.isValid
? makeComparison(comparator, lhs, rhs)
: throw invalidException(lhs, rhs)
: rhs is String && FhirTime(rhs).isValid
? makeComparison(comparator, lhs, FhirTime(rhs))
: throw cannotCompareException(lhs, rhs);
case ValidatedQuantity:
return rhs is ValidatedQuantity
? makeComparison(comparator, lhs, rhs)
: rhs is String
? makeComparison(
comparator, lhs, ValidatedQuantity.fromString(rhs))
: throw cannotCompareException(lhs, rhs);
/// Default should be when lhs is a String
default:
{
if (lhs is String && rhs is String) {
return (comparator == Comparator.gt || comparator == Comparator.lt)
? lhs == rhs
? false
: comparator == Comparator.gt
? stringGt(lhs, rhs)
: !stringGt(lhs, rhs)
: lhs == rhs
? true
: comparator == Comparator.gte
? stringGt(lhs, rhs)
: !stringGt(lhs, rhs);
} else if (rhs is FhirTime && FhirTime(lhs).isValid) {
return makeComparison(comparator, FhirTime(lhs), rhs);
} else if ((rhs is FhirDate || rhs is FhirDateTime)) {
if (lhs is String && FhirDateTime(lhs).isValid) {
return makeComparison(comparator, FhirDateTime(lhs), rhs);
} else if (lhs is DateTime && FhirDateTime(lhs).isValid) {
return makeComparison(comparator, FhirDateTime(lhs), rhs);
} else if (lhs is FhirDateTimeBase && lhs.isValid) {
return makeComparison(comparator, lhs, rhs);
}
}
throw FhirPathEvaluationException(
'Can only compare Strings to other Strings',
operation: '$comparator',
arguments: [lhs, rhs],
);
}
}
}
final lhs = SingletonEvaluation.toSingleton(
before.execute(results.toList(), passed),
name: 'left-hand side',
operation: comparator.toString(),
collection: results);
final rhs = SingletonEvaluation.toSingleton(
after.execute(results.toList(), passed),
name: 'right-hand side',
operation: comparator.toString(),
collection: results);
if (lhs.isEmpty || rhs.isEmpty) {
return [];
} else if (lhs.length != 1 || rhs.length != 1) {
throw _wrongArgLength(
comparator.toString(),
['Left-hand side: $lhs', 'Right-hand side: $rhs'],
);
}
{
if (!_allowedTypes.contains(lhs.first.runtimeType) ||
!_allowedTypes.contains(rhs.first.runtimeType)) {
final functionName = comparator == Comparator.gt
? '>'
: comparator == Comparator.gte
? '>='
: comparator == Comparator.lt
? '<'
: '<=';
throw FhirPathEvaluationException(
'The comparator $functionName cannot work with the types '
'passed.\n'
'LHS: $lhs\n'
'RHS: $rhs',
operation: functionName,
arguments: [before, after]);
} else if (where) {
results.retainWhere((element) =>
compare(comparator, element[lhs.first], rhs.first) ?? false);
return results;
} else {
final newResult = compare(comparator, lhs.first, rhs.first);
return newResult == null ? [] : [newResult];
}
}
}