validateFilter function
Implementation
String? validateFilter(FilterNode filter) {
if (filter.op != null) {
if (!<String>{'and', 'or', 'not'}.contains(filter.op)) {
return 'Invalid logical operator: ${filter.op}';
}
final nodes = filter.nodes;
if (nodes == null) {
return "Logical operation '${filter.op}' requires nodes array";
}
if (filter.op == 'not' && nodes.length != 1) {
return 'NOT operation requires exactly one child node, got ${nodes.length}';
}
if ((filter.op == 'and' || filter.op == 'or') && nodes.isEmpty) {
return '${filter.op!.toUpperCase()} operation requires at least one child node';
}
for (var index = 0; index < nodes.length; index += 1) {
final childError = validateFilter(nodes[index]);
if (childError != null) {
return 'Child node $index: $childError';
}
}
return null;
}
if (filter.key == null || filter.key!.isEmpty) {
return 'Leaf node requires a key';
}
if (filter.cmp == null || filter.cmp!.isEmpty) {
return 'Leaf node requires a comparison operator';
}
const validOps = <String>{
'eq',
'neq',
'in',
'nin',
'ex',
'nex',
'sw',
'ew',
'ct',
'gt',
'gte',
'lt',
'lte',
};
if (!validOps.contains(filter.cmp)) {
return 'Invalid comparison operator: ${filter.cmp}';
}
if (filter.cmp == 'in' || filter.cmp == 'nin') {
if (filter.vals == null || filter.vals!.isEmpty) {
return '${filter.cmp} operation requires non-empty vals array';
}
} else if (filter.cmp != 'ex' && filter.cmp != 'nex') {
if (filter.val == null || filter.val!.isEmpty) {
return '${filter.cmp} operation requires a val';
}
}
return null;
}