Skip to content

[Feature] Add length conditional operator #1438

@Smirl

Description

@Smirl

What Would You Like to See with the Gateway?

Add new operator to be able to compare the length of an array to a number

This can either be a simple equals, or use nested queries to be able to use other operators (lt, gt, ne, etc).

Context for your Request

Location of Operator Handling

The comparison operators like $eq and $in are all handled in src/services/conditionalRouter.ts.

enum Operator {
  // Comparison Operators
  Equal = '$eq',
  NotEqual = '$ne',
  GreaterThan = '$gt',
  GreaterThanOrEqual = '$gte',
  LessThan = '$lt',
  LessThanOrEqual = '$lte',
  In = '$in',
  NotIn = '$nin',
  Regex = '$regex',

  // Logical Operators
  And = '$and',
  Or = '$or',
}

The actual comparison logic is in the evaluateOperator method (lines 92-135):

private evaluateOperator(operator: string, value: any): boolean {
  for (const [op, compareValue] of Object.entries(operator)) {
    switch (op) {
      case Operator.Equal:
        if (value !== compareValue) return false;
        break;
      case Operator.NotEqual:
        if (value === compareValue) return false;
        break;
      case Operator.GreaterThan:
        if (!(parseFloat(value) > parseFloat(compareValue))) return false;
        break;
      case Operator.GreaterThanOrEqual:
        if (!(parseFloat(value) >= parseFloat(compareValue))) return false;
        break;
      case Operator.LessThan:
        if (!(parseFloat(value) < parseFloat(compareValue))) return false;
        break;
      case Operator.LessThanOrEqual:
        if (!(parseFloat(value) <= parseFloat(compareValue))) return false;
        break;
      case Operator.In:
        if (!Array.isArray(compareValue) || !compareValue.includes(value))
          return false;
        break;
      case Operator.NotIn:
        if (!Array.isArray(compareValue) || compareValue.includes(value))
          return false;
        break;
      case Operator.Regex:
        try {
          const regex = new RegExp(compareValue);
          return regex.test(value);
        } catch (e) {
          return false;
        }
      default:
        throw new Error(
          `Unsupported operator used in the query router: ${op}`
        );
    }
  }
  return true;
}

Adding a $length Operator

Yes, you can easily add a $length operator! Here's how:

1. Add the operator to the enum (line 15-30):

enum Operator {
  // Comparison Operators
  Equal = '$eq',
  NotEqual = '$ne',
  GreaterThan = '$gt',
  GreaterThanOrEqual = '$gte',
  LessThan = '$lt',
  LessThanOrEqual = '$lte',
  In = '$in',
  NotIn = '$nin',
  Regex = '$regex',
  Length = '$length',  // ← Add this

  // Logical Operators
  And = '$and',
  Or = '$or',
}

2. Add the case to the switch statement (around line 121):

case Operator.Length:
  // For arrays, check length against compareValue
  if (!Array.isArray(value)) return false;
  if (value.length !== compareValue) return false;
  break;

Or if you want more flexibility with comparison operators on length:

case Operator.Length:
  if (!Array.isArray(value)) return false;
  // compareValue could be a number or an object like {$gt: 5}
  if (typeof compareValue === 'number') {
    if (value.length !== compareValue) return false;
  } else if (typeof compareValue === 'object') {
    // Recursively evaluate the length with other operators
    if (!this.evaluateOperator(compareValue, value.length)) return false;
  }
  break;

Example Usage

With the simple version:

{
  "query": { "params.messages": { "$length": 3 } },
  "then": "target-name"
}

With the advanced version (nested operators):

{
  "query": { "params.messages": { "$length": { "$gt": 5 } } },
  "then": "target-for-long-conversations"
}

The code is very clean and straightforward to extend - just add your operator to the enum and the switch statement!

Your Twitter/LinkedIn

alex-williams-5aa36761

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions