Skip to main content

Overview

Equality operators compare values for equality or inequality. Rule Engine JS provides two equality comparison operators:

eq

Tests if two values are equal

neq

Tests if two values are not equal

Architecture

Equality operators are implemented in the ComparisonOperators class which extends BaseOperator: Source Files:
  • Equality operators: src/operators/comparison.js
  • Base operator: src/operators/base/BaseOperator.js
  • Type utilities: src/utils/TypeUtils.js
  • Unit tests: tests/unit/operators/comparison.test.js

Key Features

  • Dynamic field comparison - Compare two fields or a field to a literal value
  • Strict/loose modes - Control type coercion behavior (== vs ===)
  • Type-safe equality - Handles primitives, objects, arrays, null, undefined
  • Comprehensive validation - Validates argument count and types

eq - Equals

Tests if two values are equal.

Syntax

{
  eq: [left, right];
}
{
  eq: [left, right, options];
}

Parameters

left
string | any
required
Left operand - field path or literal value
right
string | any
required
Right operand - field path or literal value
options
object
Configuration options

Returns

boolean - true if values are equal, false otherwise

Examples

  • Basic Equality
  • Dynamic Field Comparison
  • Strict vs Loose Mode
  • With Rule Helpers
import { createRuleEngine } from 'rule-engine-js';

const engine = createRuleEngine();
const data = {
  user: {
    name: 'John Doe',
    age: 28,
    active: true
  }
};

// String equality
engine.evaluateExpr({ eq: ['user.name', 'John Doe'] }, data);
// Result: { success: true, value: true }

// Numeric equality
engine.evaluateExpr({ eq: ['user.age', 28] }, data);
// Result: { success: true, value: true }

// Boolean equality
engine.evaluateExpr({ eq: ['user.active', true] }, data);
// Result: { success: true, value: true }

// Fails when not equal
engine.evaluateExpr({ eq: ['user.name', 'Jane Doe'] }, data);
// Result: { success: true, value: false }

Common Use Cases

const registration = {
  password: 'SecurePass123!',
  confirmPassword: 'SecurePass123!',
  email: 'user@example.com',
  confirmEmail: 'user@example.com'
};

const validation = {
  and: [
    { eq: ['password', 'confirmPassword'] },
    { eq: ['email', 'confirmEmail'] }
  ]
};

engine.evaluateExpr(validation, registration);
// Result: { success: true, value: true }
const user = {
  role: 'admin',
  status: 'active',
  department: 'engineering'
};

const canAccessAdminPanel = {
  and: [
    { eq: ['role', 'admin'] },
    { eq: ['status', 'active'] }
  ]
};

engine.evaluateExpr(canAccessAdminPanel, user);
// Result: { success: true, value: true }
const config = {
  environment: 'production',
  debugMode: false,
  maintenanceMode: false
};

const canServeTraffic = {
  and: [
    { eq: ['environment', 'production'] },
    { eq: ['debugMode', false] },
    { eq: ['maintenanceMode', false] }
  ]
};

engine.evaluateExpr(canServeTraffic, config);
// Result: { success: true, value: true }
const data = {
  user: {
    name: 'John',
    middleName: null
    // lastName is undefined
  }
};

// Check for null
engine.evaluateExpr({ eq: ['user.middleName', null] }, data);
// Result: { success: true, value: true }

// Undefined field
engine.evaluateExpr({ eq: ['user.lastName', undefined] }, data);
// Result: { success: true, value: true }

// Note: Consider using isNull/isNotNull operators instead
Type Coercion: By default, eq uses loose equality (==). Use { strict: true } or create a strict engine for type-safe comparisons.

neq - Not Equal

Tests if two values are not equal (inverse of eq).

Syntax

{
  neq: [left, right];
}
{
  neq: [left, right, options];
}

Parameters

left
string | any
required
Left operand - field path or literal value
right
string | any
required
Right operand - field path or literal value
options
object
Configuration options

Returns

boolean - true if values are not equal, false otherwise

Examples

  • Status Checks
  • Password Change Validation
  • Reserved Name Check
  • Change Detection
const data = {
  user: {
    status: 'active',
    role: 'editor'
  }
};

// Ensure not inactive
engine.evaluateExpr({ neq: ['user.status', 'inactive'] }, data);
// Result: { success: true, value: true }

// Fails when equal
engine.evaluateExpr({ neq: ['user.status', 'active'] }, data);
// Result: { success: true, value: false }

// Multiple exclusions
const notBannedOrSuspended = {
  and: [
    { neq: ['user.status', 'banned'] },
    { neq: ['user.status', 'suspended'] }
  ]
};
engine.evaluateExpr(notBannedOrSuspended, data);
// Result: { success: true, value: true }

Common Use Cases

const user = {
  role: 'editor',
  status: 'active',
  accountType: 'premium'
};

// Not a basic user
const hasAdvancedAccess = {
  and: [
    { neq: ['role', 'viewer'] },
    { neq: ['accountType', 'free'] },
    { eq: ['status', 'active'] }
  ]
};

engine.evaluateExpr(hasAdvancedAccess, user);
// Result: { success: true, value: true }
const form = {
  email: 'user@example.com',
  alternateEmail: 'alternate@example.com'
};

// Emails must be different
const uniqueEmails = { neq: ['email', 'alternateEmail'] };

engine.evaluateExpr(uniqueEmails, form);
// Result: { success: true, value: true }
const workflow = {
  currentState: 'pending',
  previousState: 'draft'
};

// Ensure state actually changed
const stateChanged = {
  neq: ['currentState', 'previousState']
};

engine.evaluateExpr(stateChanged, workflow);
// Result: { success: true, value: true }
For checking if a value is NOT in a list, prefer the notIn operator instead of multiple neq conditions.

Error Handling

Common Errors

// Missing second argument
const result = engine.evaluateExpr({ eq: ['user.name'] }, data);

// Returns:
// {
//   success: false,
//   error: "EQ operator requires 2-3 arguments, got 1"
// }
// Missing array brackets
const result = engine.evaluateExpr({ eq: 'user.name' }, data);

// Returns:
// {
//   success: false,
//   error: "EQ operator requires array arguments"
// }
const data = { user: { name: 'John' } };

// Field doesn't exist - not an error, returns false
const result = engine.evaluateExpr({ eq: ['user.age', 25] }, data);

// Returns:
// {
//   success: true,
//   value: false  // undefined !== 25
// }

Error Recovery

function safeEquals(engine, field, expected, data, fallback = false) {
  const result = engine.evaluateExpr({ eq: [field, expected] }, data);

  if (!result.success) {
    console.error('Evaluation failed:', result.error);
    return fallback;
  }

  return result.value;
}

// Usage
const isAdmin = safeEquals(engine, 'user.role', 'admin', userData, false);

Type Coercion

Equality operators support both strict and loose comparison modes:
ModeSymbolBehaviorExample
Loose (default)== / !=Type coercion enabled25 == '25'true
Strict=== / !==No type coercion25 === '25'false

Setting Strict Mode

// All rules use strict comparison
const engine = createRuleEngine({ strict: true });

engine.evaluateExpr({ eq: ['age', '25'] }, { age: 25 });
// Result: { success: true, value: false }

Use strict mode in production to prevent unexpected type coercion bugs.

API Reference

For complete API documentation: