validateFilter function

String? validateFilter(
  1. FilterNode filter
)

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;
}