Skip to content

Latest commit

 

History

History
2183 lines (1653 loc) · 55.7 KB

File metadata and controls

2183 lines (1653 loc) · 55.7 KB

JSON Expressions Reference

This document provides comprehensive documentation for all expressions available in the JSON Expressions library. All examples show expressions operating on input data.

Looking for pack information? See the Pack Reference to understand which expressions are available in each pack.

Operand-Over-InputData Pattern

Many expressions in JSON Expressions follow the operand-over-inputData pattern, which allows them to operate on either:

  1. The operand (if provided and resolves to the correct type)
  2. The input data (if operand is null or wrong type)

This pattern makes expressions more composable and eliminates verbose $pipe chains.

Expressions using this pattern:

  • Transformations: $abs, $ceil, $floor, $sqrt, $lowercase, $uppercase, $trim, $reverse, $unique
  • Aggregations: $count, $sum, $min, $max, $mean
  • Accessors: $first, $last
// Traditional: operate on input data
apply({ $abs: null }, -5);  // Returns: 5

// Operand: operate on literal or expression result
apply({ $abs: -5 }, null);  // Returns: 5
apply({ $abs: { $get: "value" } }, { value: -10 });  // Returns: 10

// Composability: eliminates need for $pipe
// Before: apply({ $pipe: [{ $get: "temp" }, { $abs: null }] }, data)
// After:  apply({ $abs: { $get: "temp" } }, data)

Important Notes

Important note on equality: JavaScript has the notion of undefined being distinct from null. JSON Expressions is designed to be useful regardless of the implementing language, and most languages do not distinguish between the two. Therefore, undefined and null are considered to be equal throughout the library. Use $exists if you wish to determine if a key in an object is undefined.

const child = { name: "Zoë", age: null };

engine.apply({ $eq: [undefined, null] }, {}); // returns true
engine.apply({ $eq: null }, child.petName); // returns true
engine.apply({ $eq: [{ $get: "petName" }, { $get: "age" }] }, child); // returns true

engine.apply({ $exists: "age" }, child); // returns true
engine.apply({ $exists: "petName" }, child); // returns false

$abs

Returns the absolute value of a number. Can operate on either the operand (if provided and resolves to a number) or the input data.

// Operate on input data
apply({ $abs: null }, -2.5);
// Returns: 2.5

// Operate on operand
apply({ $abs: -2.5 }, null);
// Returns: 2.5

// Operate on expression result
apply({ $abs: { $get: "temperature" } }, { temperature: -15 });
// Returns: 15

$add

Performs addition of two numbers.

// Single operand: add to input data
apply({ $add: 5 }, 12);
// Returns: 17 (12 + 5)

// Array form: add two expressions
apply(
  { $add: [{ $get: "baseScore" }, { $get: "bonus" }] },
  { baseScore: 10, bonus: 3 },
);
// Returns: 13 (10 + 3)

// Mixed form: expression + literal (expression + expression is OK too)
apply({ $add: [{ $get: "age" }, 12] }, { age: 4 });
// Returns: 16 (4 + 12)

$addTime

Adds a duration to a date. Use negative values to subtract.

Supported units: years, months, weeks, days, hours, minutes, seconds, milliseconds

// Add single unit duration
apply({ $addTime: { days: 7 } }, "2025-10-05T00:00:00.000Z");
// Returns: "2025-10-12T00:00:00.000Z"

// Add multiple units
apply(
  { $addTime: { days: 7, hours: 2, minutes: 30 } },
  "2025-10-05T10:00:00.000Z"
);
// Returns: "2025-10-12T12:30:00.000Z"

// Subtract with negative values
apply({ $addTime: { days: -3 } }, "2025-10-05T00:00:00.000Z");
// Returns: "2025-10-02T00:00:00.000Z"

// Array form: explicit date
apply({ $addTime: ["2025-10-05T00:00:00.000Z", { days: 7 }] }, null);
// Returns: "2025-10-12T00:00:00.000Z"

$all

Tests if all elements in an array satisfy a predicate expression.

// Check if all children are ready for outdoor play
const children = [
  { name: "Aria", hasJacket: true },
  { name: "Kai", hasJacket: true },
  { name: "Zara", hasJacket: true },
];
apply({ $all: { $get: "hasJacket" } }, children);
// Returns: true

$and

Logical AND operation - returns true if all expressions are truthy.

// Check if child meets multiple criteria for field trip
const child = { age: 5, hasPermission: true, isHealthy: true };
apply(
  {
    $and: [
      { $pipe: [{ $get: "age" }, { $gte: 4 }] },
      { $get: "hasPermission" },
      { $get: "isHealthy" },
    ],
  },
  child,
);
// Returns: true

$any

Tests if any element in an array satisfies a predicate expression.

// Check if any child needs a nap
const children = [
  { name: "Chen", tired: false },
  { name: "Luna", tired: true },
  { name: "Diego", tired: false },
];
apply({ $any: { $get: "tired" } }, children);
// Returns: true

$between

Tests if a value is between two bounds (inclusive).

// Check if child's age is in preschool range
apply({ $between: { min: 3, max: 5 } }, 4);
// Returns: true

$case

Unified conditional expression supporting both literal comparisons and boolean predicates.

The $case expression automatically determines how to handle each when clause:

  • Boolean predicate expressions ($gt, $eq, $and, etc.) → Applied as predicates with the case value as input
  • All other values → Compared literally using deep equality
// Flexible activity assignment using both literal and predicate matching
const child = { age: 4, status: "active" };
apply(
  {
    $case: {
      value: { $get: "age" },
      cases: [
        { when: 2, then: "Sensory play and simple puzzles" }, // Literal comparison
        { when: 3, then: "Art activities and story time" }, // Literal comparison
        { when: { $eq: 4 }, then: "Pre-writing skills and group games" }, // Boolean predicate
        { when: { $gte: 5 }, then: "Early math and reading readiness" }, // Boolean predicate
      ],
      default: "Age-appropriate developmental activities",
    },
  },
  child,
);
// Returns: "Pre-writing skills and group games"
// Mix literal status checks with computed conditions
const child = { status: "active", energy: 8 };
apply(
  {
    $case: {
      value: { $get: "status" },
      cases: [
        { when: "napping", then: "Quiet time activities" }, // Literal comparison
        { when: "active", then: "High energy games" }, // Literal comparison
        { when: { $get: "fallbackStatus" }, then: "Custom activity" }, // Expression applied to literal
      ],
      default: "Free play",
    },
  },
  child,
);
// Returns: "High energy games"

$ceil

Returns the smallest integer greater than or equal to the input number (rounds up). Can operate on either the operand (if provided and resolves to a number) or the input data.

// Operate on input data
apply({ $ceil: null }, 4.1);
// Returns: 5

// Operate on operand
apply({ $ceil: 4.1 }, null);
// Returns: 5

// Operate on expression result
apply({ $ceil: { $get: "score" } }, { score: 92.3 });
// Returns: 93

$coalesce

Returns the first non-null value from an array.

// Get first available contact method
const parent = {
  phone: null,
  email: "parent@example.com",
  emergency: "555-1234",
};
apply(
  { $coalesce: [{ $get: "phone" }, { $get: "email" }, { $get: "emergency" }] },
  parent,
);
// Returns: "parent@example.com"

$concat

Concatenates multiple arrays together.

// Combine current children with new arrivals
const currentChildren = ["Aria", "Kai"];
apply({ $concat: [["Zara"], ["Luna", "Diego"]] }, currentChildren);
// Returns: ["Aria", "Kai", "Zara", "Luna", "Diego"]

$count

Returns the count of items in an array. Can operate on either the operand (if provided and resolves to an array) or the input data.

// Count items in input data array
const children = ["Amara", "Chen", "Fatima", "Kai"];
apply({ $count: null }, children);
// Returns: 4

// Count items in operand array
apply({ $count: [1, 2, 3, 4, 5] }, null);
// Returns: 5

// Count items from expression result
const data = { scores: [95, 87, 92, 88] };
apply({ $count: { $get: "scores" } }, data);
// Returns: 4

$debug

Pack: base

Logs the operand, input data, and result to console and returns the result unchanged. Useful for debugging expression pipelines during development.

⚠️ Development only: This expression should only be used during development, not in production. For production logging, telemetry, or observability, create a custom $log expression or similar instead.

// Debug intermediate value in pipeline
apply(
  {
    $pipe: [
      { $get: "children" },
      { $debug: { $filter: { $get: "enrolled" } } },
      { $map: { $get: "name" } },
    ],
  },
  daycareData,
);
// Logs: Debug: { operand: { $filter: { $get: "enrolled" } }, inputData: [...], result: [...] }
// Then continues processing

// Debug with simple pass-through
apply({ $debug: { $get: "name" } }, { name: "Amara" });
// Logs: Debug: { operand: { $get: "name" }, inputData: { name: "Amara" }, result: "Amara" }
// Returns: "Amara"

Custom debug implementations

You can override $debug with your own implementation to integrate with debuggers, logging frameworks, or custom tooling:

import { createEngine, packs } from "json-expressions";

const engine = createEngine({
  packs: [packs.base, packs.logic],
  custom: {
    // Override $debug with custom implementation
    $debug: (operand, inputData, { apply }) => {
      const result = apply(operand, inputData);

      // Integrate with your debugging tools
      debugger; // Trigger Node debugger
      // or: myLogger.debug({ operand, inputData, result });
      // or: writeToDebugFile({ operand, inputData, result });

      return result;
    },
  },
});

Note that you don't need to exclude the base pack's $debug—custom expressions automatically override pack expressions with the same name.

$diffDays

Calculates the difference in days between two dates.

// Array form: difference in days
apply(
  { $diffDays: ["2025-10-05T00:00:00.000Z", "2025-10-12T00:00:00.000Z"] },
  null,
);
// Returns: 7

// Input data form: difference from input date
apply({ $diffDays: "2025-10-12T00:00:00.000Z" }, "2025-10-05T00:00:00.000Z");
// Returns: 7

// Negative for earlier second date
apply(
  { $diffDays: ["2025-10-12T00:00:00.000Z", "2025-10-05T00:00:00.000Z"] },
  null,
);
// Returns: -7

$diffHours

Calculates the difference in hours between two dates.

// Array form: difference in hours
apply(
  { $diffHours: ["2025-10-05T10:00:00.000Z", "2025-10-05T15:00:00.000Z"] },
  null,
);
// Returns: 5

// Handles day boundaries
apply(
  { $diffHours: ["2025-10-05T22:00:00.000Z", "2025-10-06T01:00:00.000Z"] },
  null,
);
// Returns: 3

$diffMilliseconds

Calculates the difference in milliseconds between two dates.

// Array form: difference in milliseconds
apply(
  {
    $diffMilliseconds: ["2025-10-05T10:00:00.000Z", "2025-10-05T10:00:01.000Z"],
  },
  null,
);
// Returns: 1000

$diffMinutes

Calculates the difference in minutes between two dates.

// Array form: difference in minutes
apply(
  { $diffMinutes: ["2025-10-05T10:00:00.000Z", "2025-10-05T10:45:00.000Z"] },
  null,
);
// Returns: 45

$diffMonths

Calculates the difference in months between two dates.

// Array form: difference in months
apply(
  { $diffMonths: ["2025-10-05T00:00:00.000Z", "2026-01-05T00:00:00.000Z"] },
  null,
);
// Returns: 3

// Handles year boundaries
apply(
  { $diffMonths: ["2025-12-15T00:00:00.000Z", "2026-02-15T00:00:00.000Z"] },
  null,
);
// Returns: 2

$diffSeconds

Calculates the difference in seconds between two dates.

// Array form: difference in seconds
apply(
  { $diffSeconds: ["2025-10-05T10:00:00.000Z", "2025-10-05T10:01:00.000Z"] },
  null,
);
// Returns: 60

$diffYears

Calculates the difference in years between two dates.

// Array form: difference in years
apply(
  { $diffYears: ["2025-10-05T00:00:00.000Z", "2030-10-05T00:00:00.000Z"] },
  null,
);
// Returns: 5

$default

Returns a default value if the expression result is null (or undefined). Supports both object form and array form.

// Array form (concise): [expression, defaultValue]
const child = { name: "Amara", pickupTime: null };
apply(
  {
    $default: [{ $get: "pickupTime" }, "5:00 PM"],
  },
  child,
);
// Returns: "5:00 PM"

// Object form (legacy): { expression, default }
apply(
  {
    $default: {
      expression: { $get: "pickupTime" },
      default: "5:00 PM",
    },
  },
  child,
);
// Returns: "5:00 PM"

// Works with expression defaults
apply(
  {
    $default: [{ $get: "primaryContact" }, { $get: "secondaryContact" }],
  },
  { primaryContact: null, secondaryContact: "555-1234" },
);
// Returns: "555-1234"

// Preserves falsy non-null values
apply({ $default: [{ $get: "count" }, 10] }, { count: 0 });
// Returns: 0 (not 10, because 0 is not null/undefined)

$diffTime

Calculates the difference between two dates in a specific unit.

Supported units: years, months, weeks, days, hours, minutes, seconds, milliseconds

// Calculate difference in days
apply(
  { $diffTime: { date: "2025-12-25T00:00:00.000Z", unit: "days" } },
  "2025-10-05T00:00:00.000Z"
);
// Returns: 81 (days between Oct 5 and Dec 25)

// Calculate difference in hours
apply(
  { $diffTime: { date: "2025-10-05T15:00:00.000Z", unit: "hours" } },
  "2025-10-05T10:00:00.000Z"
);
// Returns: 5

// Array form: explicit dates
apply(
  { $diffTime: ["2025-10-05T00:00:00.000Z", "2025-12-25T00:00:00.000Z", "days"] },
  null
);
// Returns: 81

$divide

Performs division operation.

// Single operand: divide input data
apply({ $divide: 4 }, 20.0);
// Returns: 5.00 (20.0 / 4)

// Array form: divide two expressions
apply(
  { $divide: [{ $get: "total" }, { $get: "children" }] },
  { total: 24, children: 6 },
);
// Returns: 4 (24 / 6)

// Mixed form: expression / literal
apply({ $divide: [{ $get: "minutes" }, 60] }, { minutes: 150 });
// Returns: 2.5 (150 / 60)

$endOf

Gets the end of a time period (day, week, month, year).

Supported units: day, week, month, year

// Get end of day
apply({ $endOf: "day" }, "2025-10-05T10:00:00.000Z");
// Returns: "2025-10-05T23:59:59.999Z"

// Get end of month
apply({ $endOf: "month" }, "2025-10-15T10:00:00.000Z");
// Returns: "2025-10-31T23:59:59.999Z"

// Get end of year
apply({ $endOf: "year" }, "2025-10-15T10:00:00.000Z");
// Returns: "2025-12-31T23:59:59.999Z"

$eq

Tests equality using deep comparison. JSON has no notion of undefined, which means that undefined and null will be treated as equal when using $eq. If you wish to distinguish between the two, use $exists instead.

// Single operand: compare input data
apply({ $eq: "reading" }, "reading");
// Returns: true ("reading" === "reading")

// Array form: compare two expressions
apply(
  { $eq: [{ $get: "status" }, { $get: "expectedStatus" }] },
  { status: "active", expectedStatus: "active" },
);
// Returns: true ("active" === "active")

$endOfDay

Returns the end of day (23:59:59.999) for a given date.

// Get end of day
apply({ $endOfDay: "2025-10-05T15:23:45.234Z" }, null);
// Returns: "2025-10-05T23:59:59.999Z"

$endOfMonth

Returns the last moment of the month for a given date.

// End of 31-day month
apply({ $endOfMonth: "2025-10-15T15:23:45.234Z" }, null);
// Returns: "2025-10-31T23:59:59.999Z"

// End of 30-day month
apply({ $endOfMonth: "2025-11-15T15:23:45.234Z" }, null);
// Returns: "2025-11-30T23:59:59.999Z"

// End of February (non-leap year)
apply({ $endOfMonth: "2025-02-15T15:23:45.234Z" }, null);
// Returns: "2025-02-28T23:59:59.999Z"

$endOfYear

Returns the last moment of the year for a given date.

// Get end of year
apply({ $endOfYear: "2025-10-15T15:23:45.234Z" }, null);
// Returns: "2025-12-31T23:59:59.999Z"

$exists

Tests if a property or path exists in an object, regardless of its value. Different from $isPresent - this checks existence, not meaningfulness.

Type handling: Returns false when input data is not an object (null, undefined, arrays, or other primitive types).

Note: Wildcards ($) are not supported in paths. Use $all or $any to check existence across array elements.

// Check if child has allergies field (even if null)
const student = { name: "Zara", allergies: null, age: 4 };
apply({ $exists: "allergies" }, student);
// Returns: true (property exists, even though it's null)

apply({ $exists: "missing" }, student);
// Returns: false

// Works with nested paths
apply({ $exists: "parent.phone" }, { parent: { phone: "555-0123" } });
// Returns: true

$filter

Filters array items based on a condition.

// Find children who need extra help
const children = [
  { name: "Aria", needsHelp: true, age: 4 },
  { name: "Kai", needsHelp: false, age: 5 },
  { name: "Zara", needsHelp: true, age: 3 },
];
apply({ $filter: { $get: "needsHelp" } }, children);
// Returns: [{ name: "Aria", needsHelp: true, age: 4 }, { name: "Zara", needsHelp: true, age: 3 }]

$filterBy

Filters arrays by object property conditions (shorthand for $filter + $matchesAll).

Type handling: Returns an empty array [] when applied to non-array input (null, undefined, or other types).

Note: Wildcards ($) are not supported in property paths. Use nested $filter or $map for filtering based on nested array properties.

// Find active children ready for kindergarten
const children = [
  { name: "Aria", age: 4, active: true },
  { name: "Kai", age: 5, active: true },
  { name: "Zara", age: 5, active: false },
  { name: "Leo", age: 6, active: true },
];
apply({ $filterBy: { age: { $gte: 5 }, active: true } }, children);
// Returns: [{ name: "Kai", age: 5, active: true }, { name: "Leo", age: 6, active: true }]

$find

Returns the first element that satisfies a predicate.

// Find first child ready for kindergarten
const children = [
  { name: "Aria", age: 4 },
  { name: "Kai", age: 5 },
  { name: "Zara", age: 6 },
];
apply({ $find: { $matchesAll: { age: { $gte: 5 } } } }, children);
// Returns: { name: "Kai", age: 5 }

$first

Returns the first item in an array. Can operate on either the operand (if provided and resolves to an array) or the input data.

Type handling: Returns null when neither the operand nor input data is an array.

// Get first item from input data array
const lineup = ["Chen", "Fatima", "Diego", "Luna"];
apply({ $first: null }, lineup);
// Returns: "Chen"

// Get first item from operand array
apply({ $first: [10, 20, 30] }, null);
// Returns: 10

// Get first item from expression result
const data = { scores: [95, 87, 92] };
apply({ $first: { $get: "scores" } }, data);
// Returns: 95

// Common pattern: filter then get first
apply({ $first: { $filter: { $gt: 3 } } }, [1, 2, 3, 4, 5]);
// Returns: 4

$floor

Returns the largest integer less than or equal to the input number (rounds down). Can operate on either the operand (if provided and resolves to a number) or the input data.

// Operate on input data
apply({ $floor: null }, 4.9);
// Returns: 4

// Operate on operand
apply({ $floor: 4.9 }, null);
// Returns: 4

// Operate on expression result
apply({ $floor: { $get: "average" } }, { average: 87.6 });
// Returns: 87

$formatDate

Formats a date using date-fns format function. Format strings follow Unicode Technical Standard #35.

Common format tokens: yyyy (4-digit year), MM (2-digit month), dd (2-digit day), HH (2-digit hour), mm (minute), ss (second), EEEE (day of week), MMMM (month name)

// Format with pattern
apply({ $formatDate: "yyyy-MM-dd" }, "2025-10-05T14:30:00.000Z");
// Returns: "2025-10-05"

// Format with time
apply({ $formatDate: "yyyy-MM-dd HH:mm:ss" }, "2025-10-05T14:30:45.000Z");
// Returns: "2025-10-05 14:30:45" (time in local timezone)

// Array form: explicit date and format
apply({ $formatDate: ["2025-10-05T14:30:00.000Z", "yyyy-MM-dd"] }, null);
// Returns: "2025-10-05"

$fromPairs

Converts an array of [key, value] pairs into an object.

Type handling: Returns an empty object {} when applied to non-array input (null, undefined, or other types).

// Convert child data pairs to object
const childPairs = [
  ["name", "Zara"],
  ["age", 4],
  ["group", "Butterflies"],
];
apply({ $fromPairs: null }, childPairs);
// Returns: { name: "Zara", age: 4, group: "Butterflies" }

$flatMap

Maps and flattens array items.

// Get all toys from all children's belongings
const children = [
  { belongings: ["teddy", "book"] },
  { belongings: ["blocks", "puzzle", "crayons"] },
  { belongings: ["doll"] },
];
apply({ $flatMap: { $get: "belongings" } }, children);
// Returns: ["teddy", "book", "blocks", "puzzle", "crayons", "doll"]

$flatten

Flattens nested arrays by one level by default, with optional depth control.

// Flatten one level (default)
const nestedBelongings = [
  ["teddy", "book"],
  ["blocks", ["puzzle", "crayons"]],
  ["doll"],
];
apply({ $flatten: null }, nestedBelongings);
// Returns: ["teddy", "book", "blocks", ["puzzle", "crayons"], "doll"]

// Flatten multiple levels with depth
apply({ $flatten: { depth: 2 } }, nestedBelongings);
// Returns: ["teddy", "book", "blocks", "puzzle", "crayons", "doll"]

$get

Retrieves a value from data using dot notation, bracket notation, or array paths. Supports the $ wildcard for array element iteration and flattening. Returns null if the path does not exist. Combines well with $default.

Performance tip: For simple property access without path features, use $prop instead - it's 2.5x faster.

Property name edge case: If you need to access a property with brackets in its name (like "foo[0]"), use $prop instead of $get.

// Simple path access with dot notation
apply({ $get: "info.age" }, child);
// Returns: 4

// Bracket notation for array indices
const data = { users: [{ name: "Chen" }, { name: "Amira" }] };
apply({ $get: "users[0].name" }, data);
// Returns: "Chen"

// Mixed dot and bracket notation
apply({ $get: "users[1].name" }, data);
// Returns: "Amira"

// Path access with array notation
apply({ $get: ["info", "age"] }, child);
// Returns: 4

// Deep nesting with array path
const deepData = { child: { profile: { contact: { email: "test@example.com" } } } };
apply({ $get: ["child", "profile", "contact", "email"] }, deepData);
// Returns: "test@example.com"

// Array iteration with $ wildcard (dot notation)
const children = [
  { name: "Chen", age: 3 },
  { name: "Amira", age: 4 },
  { name: "Diego", age: 5 },
];
apply({ $get: "$.name" }, children);
// Returns: ["Chen", "Amira", "Diego"]

// Array iteration with $ wildcard (bracket notation)
apply({ $get: "[$].name" }, children);
// Returns: ["Chen", "Amira", "Diego"]

// Nested array iteration with mixed notation
const classrooms = {
  rooms: [
    { children: [{ name: "Sofia" }, { name: "Miguel" }] },
    { children: [{ name: "Zara" }, { name: "Omar" }] },
  ],
};
apply({ $get: "rooms[$].children[$].name" }, classrooms);
// Returns: ["Sofia", "Miguel", "Zara", "Omar"] (flattened)

$getTime

Extracts a component from a date.

Supported components: year, month (1-indexed), day, hour, minute, second, dayOfWeek (0=Sunday), dayOfYear

// Extract year
apply({ $getTime: "year" }, "2025-10-15T14:30:45.000Z");
// Returns: 2025

// Extract month (1-indexed)
apply({ $getTime: "month" }, "2025-10-15T14:30:45.000Z");
// Returns: 10

// Extract day of week (0=Sunday)
apply({ $getTime: "dayOfWeek" }, "2025-10-05T00:00:00.000Z");
// Returns: 0 (Sunday)

$groupBy

Groups array elements by a specified key or expression result.

Type handling: Returns an empty object {} when applied to non-array input (null, undefined, or other types).

// Group children by age
const children = [
  { name: "Aria", age: 4 },
  { name: "Kai", age: 5 },
  { name: "Zara", age: 4 },
  { name: "Chen", age: 5 },
];
apply({ $groupBy: { $get: "age" } }, children);
// Returns: {
//   "4": [{ name: "Aria", age: 4 }, { name: "Zara", age: 4 }],
//   "5": [{ name: "Kai", age: 5 }, { name: "Chen", age: 5 }]
// }

$gt

Tests if value is greater than operand.

// Single operand: compare input data
apply({ $gt: 4 }, 5);
// Returns: true (5 > 4)

// Array form: compare two expressions
apply({ $gt: [{ $get: "age" }, { $get: "minAge" }] }, { age: 6, minAge: 4 });
// Returns: true (6 > 4)

// Mixed form: expression > literal
apply({ $gt: [{ $get: "score" }, 80] }, { score: 85 });
// Returns: true (85 > 80)

$gte

Tests if value is greater than or equal to operand.

// Single operand: compare input data
apply({ $gte: 3 }, 3);
// Returns: true (3 >= 3)

// Array form: compare two expressions
apply(
  { $gte: [{ $get: "currentAge" }, { $get: "requiredAge" }] },
  { currentAge: 5, requiredAge: 4 },
);
// Returns: true (5 >= 4)

// Mixed form: expression >= literal
apply({ $gte: [{ $get: "attendance" }, 90] }, { attendance: 95 });
// Returns: true (95 >= 90)

$hour

Extracts the hour from a date (0-23).

// Extract hour from date
apply({ $hour: "2025-10-05T15:23:45.234Z" }, null);
// Returns: 15

// Midnight returns 0
apply({ $hour: "2025-10-05T00:23:45.234Z" }, null);
// Returns: 0

$if

Conditional expression that evaluates different branches based on a condition.

// Assign activity based on weather
const weather = { condition: "rainy", temperature: 65 };
apply(
  {
    $if: {
      if: { $pipe: [{ $get: "condition" }, { $eq: "sunny" }] },
      then: "Outdoor playground",
      else: "Indoor activities",
    },
  },
  weather,
);
// Returns: "Indoor activities"

$identity

Returns input data unchanged. This is useful as an identity function in pipelines or when you need to pass through values.

// Return child data unchanged (identity function)
const childData = { name: "Chen", age: 4 };
apply({ $identity: null }, childData);
// Returns: { name: "Chen", age: 4 }

// Operand is ignored (the convention is to use null here)
apply({ $identity: "ignored" }, "hello");
// Returns: "hello"

// Input data can be addressed with $identity
apply({ $if: { if: { $identity: null }, then: "yes", else: "no" } }, true);
// Returns: "yes"

$in

Tests if value exists in an array.

// Check if child's dietary need is in available options
const availableOptions = ["vegetarian", "gluten-free", "dairy-free"];
apply({ $in: availableOptions }, "vegetarian");
// Returns: true

$isAfter

Tests if first date is after second date.

// Compare input to threshold
apply({ $isAfter: "2025-10-05T00:00:00.000Z" }, "2025-10-15T00:00:00.000Z");
// Returns: true

// Array form: explicit dates
apply({ $isAfter: ["2025-10-15T00:00:00.000Z", "2025-10-05T00:00:00.000Z"] }, null);
// Returns: true

$isBefore

Tests if first date is before second date.

// Compare input to threshold
apply({ $isBefore: "2025-10-15T00:00:00.000Z" }, "2025-10-05T00:00:00.000Z");
// Returns: true

// Array form: explicit dates
apply({ $isBefore: ["2025-10-05T00:00:00.000Z", "2025-10-15T00:00:00.000Z"] }, null);
// Returns: true

$isDateValid

Checks if a date string is valid. Returns true if the date can be parsed, false otherwise.

// Validate with format pattern
apply({ $isDateValid: "MM/dd/yyyy" }, "10/05/2025");
// Returns: true

apply({ $isDateValid: "MM/dd/yyyy" }, "invalid");
// Returns: false

// Validate ISO string
apply({ $isDateValid: null }, "2025-10-05T00:00:00.000Z");
// Returns: true

$isEmpty

Tests if a value is empty or absent (null or undefined). The semantic inverse of $isPresent.

// Check if pickup time is not set
apply({ $isEmpty: null }, null);
// Returns: true

apply({ $isEmpty: null }, undefined);
// Returns: true

apply({ $isEmpty: null }, "");
// Returns: false (empty string is not null/undefined)

apply({ $isEmpty: null }, 0);
// Returns: false (zero is not empty)

$isPresent

Tests if a value is meaningful (not null or undefined). Provides cross-language clarity about value presence.

// Check if emergency contact is provided
apply({ $isPresent: null }, "555-1234");
// Returns: true

// Check if child has meaningful data
apply({ $isPresent: null }, null);
// Returns: false

apply({ $isPresent: null }, undefined);
// Returns: false

apply({ $isPresent: null }, 0);
// Returns: true (zero is meaningful)

$isSameDay

Tests if two dates are on the same calendar day.

// Array form: compare two dates
apply(
  { $isSameDay: ["2025-10-05T10:00:00.000Z", "2025-10-05T15:00:00.000Z"] },
  null,
);
// Returns: true

// Different days return false
apply(
  { $isSameDay: ["2025-10-05T23:59:59.999Z", "2025-10-06T00:00:00.000Z"] },
  null,
);
// Returns: false

$isWeekday

Tests if a date falls on a weekday (Monday-Friday).

// Monday is a weekday
apply({ $isWeekday: "2025-10-06T00:00:00.000Z" }, null);
// Returns: true

// Friday is a weekday
apply({ $isWeekday: "2025-10-10T00:00:00.000Z" }, null);
// Returns: true

// Saturday is not a weekday
apply({ $isWeekday: "2025-10-04T00:00:00.000Z" }, null);
// Returns: false

$isWeekend

Tests if a date falls on a weekend (Saturday or Sunday).

// Saturday is a weekend
apply({ $isWeekend: "2025-10-04T00:00:00.000Z" }, null);
// Returns: true

// Sunday is a weekend
apply({ $isWeekend: "2025-10-05T00:00:00.000Z" }, null);
// Returns: true

// Monday is not a weekend
apply({ $isWeekend: "2025-10-06T00:00:00.000Z" }, null);
// Returns: false

$join

Joins array elements into a string with a separator. Note: This is intended to join arrays of string values. Attempting to join values of other types may behave differently across different runtimes. Consider overriding this expression if you have use cases more complex than joining arrays of strings.

// Create list of children's names
const names = ["Aria", "Chen", "Diego", "Luna"];
apply({ $join: ", " }, names);
// Returns: "Aria, Chen, Diego, Luna"

$keys

Returns an array of all property names from an object.

Type handling: Returns an empty array [] when applied to non-object input (null, undefined, arrays, or other types).

// Get all field names from child record
const child = { name: "Amara", age: 4, group: "Butterflies", present: true };
apply({ $keys: null }, child);
// Returns: ["name", "age", "group", "present"]

$last

Returns the last item in an array. Can operate on either the operand (if provided and resolves to an array) or the input data.

Type handling: Returns null when neither the operand nor input data is an array.

// Get last item from input data array
const pickupOrder = ["Kai", "Zara", "Amara", "Chen"];
apply({ $last: null }, pickupOrder);
// Returns: "Chen"

// Get last item from operand array
apply({ $last: [10, 20, 30] }, null);
// Returns: 30

// Get last item from expression result
const data = { scores: [95, 87, 92] };
apply({ $last: { $get: "scores" } }, data);
// Returns: 92

// Common pattern: filter then get last
apply({ $last: { $filter: { $gt: 3 } } }, [1, 2, 3, 4, 5]);
// Returns: 5

$literal

Returns a literal value (useful when you need to pass values that look like expressions). This expression cannot be excluded or overridden.

// Return exact object structure
apply({ $literal: { $special: "not an expression" } }, anyInput);
// Returns: { $special: "not an expression" }

$lowercase

Converts string to lowercase. Can operate on either the operand (if provided and resolves to a string) or the input data.

Type handling: Returns null when neither the operand nor input data is a string.

// Operate on input data
apply({ $lowercase: null }, "Amara Rodriguez");
// Returns: "amara rodriguez"

// Operate on operand
apply({ $lowercase: "Amara Rodriguez" }, null);
// Returns: "amara rodriguez"

// Operate on expression result
apply({ $lowercase: { $get: "name" } }, { name: "Amara Rodriguez" });
// Returns: "amara rodriguez"

$lt

Tests if value is less than operand.

// Single operand: compare input data
apply({ $lt: 4 }, 3);
// Returns: true (3 < 4)

// Array form: compare two expressions
apply({ $lt: [{ $get: "age" }, { $get: "maxAge" }] }, { age: 3, maxAge: 5 });
// Returns: true (3 < 5)

// Mixed form: expression < literal
apply({ $lt: [{ $get: "temperature" }, 75] }, { temperature: 68 });
// Returns: true (68 < 75)

$lte

Tests if value is less than or equal to operand.

// Single operand: compare input data
apply({ $lte: 6 }, 6);
// Returns: true (6 <= 6)

// Array form: compare two expressions
apply(
  { $lte: [{ $get: "groupSize" }, { $get: "maxCapacity" }] },
  { groupSize: 8, maxCapacity: 10 },
);
// Returns: true (8 <= 10)

// Mixed form: expression <= literal
apply({ $lte: [{ $get: "napTime" }, 120] }, { napTime: 90 });
// Returns: true (90 <= 120)

$map

Transforms each item in an array using an expression.

// Get all children's ages
const children = [
  { name: "Aria", age: 4 },
  { name: "Kai", age: 5 },
  { name: "Zara", age: 3 },
];
apply({ $map: { $get: "age" } }, children);
// Returns: [4, 5, 3]

// Transform to different output structure
apply({
  $map: {
    nombre: { $get: "name" },
    ageInMonths: { $multiply: [{ $get: "age" }, 12] },
  },
});

$matchesAll

Tests if an object matches all specified property conditions (AND logic). Supports literal values, expressions, and $literal-wrapped values for flexible matching.

Note: Wildcards ($) are not supported in property paths. To test all array elements, use $all with $matchesAll inside.

// Check if child meets multiple criteria
const child = {
  name: "Aria",
  age: 5,
  active: true,
  activity: { $get: "current" },
};
apply(
  {
    $matchesAll: {
      age: { $gte: 4 }, // match on an expression
      active: true, // match on a literal value
      activity: { $literal: { $get: "current" } }, // match the literal object (not as expression)
    },
  },
  child,
);
// Returns: true (all conditions match)

$matchesAny

Tests if an object matches at least one specified property condition (OR logic). Supports literal values, expressions, and $literal-wrapped values for flexible matching.

Note: Wildcards ($) are not supported in property paths. To test any array element, use $any with $matchesAll inside.

// Check if child meets any of the criteria for special activity
const child = {
  name: "Kai",
  age: 3,
  hasSpecialNeeds: false,
  isPremium: true,
};
apply(
  {
    $matchesAny: {
      age: { $gte: 5 }, // doesn't match (age is 3)
      hasSpecialNeeds: true, // doesn't match (false)
      isPremium: true, // matches!
    },
  },
  child,
);
// Returns: true (at least one condition matches)

// All conditions fail
apply(
  {
    $matchesAny: {
      age: { $gte: 5 }, // doesn't match
      hasSpecialNeeds: true, // doesn't match
    },
  },
  child,
);
// Returns: false (no conditions match)

$matchesRegex

Tests if string matches a regular expression with support for PCRE-style inline flags.

Type handling: Returns false when input data is not a string (null, undefined, numbers, or other types).

Supported flags:

  • i: Case insensitive matching
  • m: Multiline mode (^ and $ match line boundaries)
  • s: Single-line mode (. matches newlines)

Flag syntax: Use (?flags) at the beginning of your pattern to set flags.

// Basic pattern matching
apply({ $matchesRegex: "^\\d{3}-\\d{3}-\\d{4}$" }, "555-123-4567");
// Returns: true

// Case insensitive matching
apply({ $matchesRegex: "(?i)^hello" }, "HELLO world");
// Returns: true

// Multiple flags combined
apply({ $matchesRegex: "(?ims)test.*end" }, "TEST\nSOMETHING\nEND");
// Returns: true

// Multiline flag - match line boundaries
apply({ $matchesRegex: "(?m)^line" }, "first\nline two");
// Returns: true

$max

Returns the maximum value in an array. Can operate on either the operand (if provided and resolves to an array) or the input data.

// Find maximum in input data array
const ages = [3, 5, 4, 6, 2];
apply({ $max: null }, ages);
// Returns: 6

// Find maximum in operand array
apply({ $max: [10, 25, 15, 30] }, null);
// Returns: 30

// Find maximum from expression result
const data = { temperatures: [68, 72, 75, 73, 70] };
apply({ $max: { $get: "temperatures" } }, data);
// Returns: 75

$mean

Calculates the arithmetic mean (average) of array values. Can operate on either the operand (if provided and resolves to an array) or the input data.

// Calculate mean of input data array
const napTimes = [45, 60, 30, 75, 50]; // minutes
apply({ $mean: null }, napTimes);
// Returns: 52

// Calculate mean of operand array
apply({ $mean: [10, 20, 30] }, null);
// Returns: 20

// Calculate mean from expression result
const data = { scores: [88, 92, 95, 87] };
apply({ $mean: { $get: "scores" } }, data);
// Returns: 90.5

$merge

Merges an object into the input object, with the merge object properties overriding input object properties.

Type handling: When input is not an object (null, undefined, arrays, or other types), returns the operand object directly.

// Merge child info with updates
const child = { name: "Aria", age: 4, group: "Butterflies" };
apply({ $merge: { age: 5, present: true } }, child);
// Returns: { name: "Aria", age: 5, group: "Butterflies", present: true }

$min

Returns the minimum value in an array. Can operate on either the operand (if provided and resolves to an array) or the input data.

// Find minimum in input data array
const ages = [3, 5, 4, 6, 2];
apply({ $min: null }, ages);
// Returns: 2

// Find minimum in operand array
apply({ $min: [10, 25, 15, 30] }, null);
// Returns: 10

// Find minimum from expression result
const data = { temperatures: [68, 72, 75, 73, 70] };
apply({ $min: { $get: "temperatures" } }, data);
// Returns: 68

$minute

Extracts the minute from a date (0-59).

// Extract minute from date
apply({ $minute: "2025-10-05T15:23:45.234Z" }, null);
// Returns: 23

$month

Extracts the month from a date (1-12, 1-indexed).

// Extract month from date
apply({ $month: "2025-10-05T15:23:45.234Z" }, null);
// Returns: 10

// January returns 1
apply({ $month: "2025-01-05T15:23:45.234Z" }, null);
// Returns: 1

// December returns 12
apply({ $month: "2025-12-05T15:23:45.234Z" }, null);
// Returns: 12

$modulo

Performs modulo (remainder) operation.

// Single operand: modulo input data
apply({ $modulo: 2 }, 6);
// Returns: 0 (6 % 2, even number)

// Array form: modulo two expressions
apply(
  { $modulo: [{ $get: "total" }, { $get: "groups" }] },
  { total: 13, groups: 4 },
);
// Returns: 1 (13 % 4)

// Mixed form: expression % literal
apply({ $modulo: [{ $get: "childCount" }, 3] }, { childCount: 10 });
// Returns: 1 (10 % 3)

$multiply

Performs multiplication operation.

// Single operand: multiply input data
apply({ $multiply: 4 }, 3.5);
// Returns: 14.00 (3.5 * 4)

// Array form: multiply two expressions
apply(
  { $multiply: [{ $get: "price" }, { $get: "quantity" }] },
  { price: 2.5, quantity: 6 },
);
// Returns: 15.0 (2.5 * 6)

// Mixed form: expression * literal
apply({ $multiply: [{ $get: "hours" }, 8] }, { hours: 5 });
// Returns: 40 (5 * 8)

$ne

Tests inequality using deep comparison. JSON has no notion of undefined, which means that undefined and null will be treated as equal when using $ne.

// Single operand: compare input data
apply({ $ne: "reading" }, "playing");
// Returns: true ("playing" !== "reading")

// Array form: compare two expressions
apply(
  { $ne: [{ $get: "current" }, { $get: "previous" }] },
  { current: "art", previous: "music" },
);
// Returns: true ("art" !== "music")

// Mixed form: expression !== literal
apply({ $ne: [{ $get: "mood" }, "upset"] }, { mood: "happy" });
// Returns: true ("happy" !== "upset")

$nin

Tests if value does not exist in an array.

// Check if child doesn't have common allergies
const commonAllergies = ["nuts", "dairy", "eggs"];
apply({ $nin: commonAllergies }, "gluten");
// Returns: true

$not

Logical NOT - inverts the truthiness of an expression.

// Check if child is not sleeping
apply({ $not: { $get: "isNapping" } }, { isNapping: false });
// Returns: true

$or

Logical OR - returns true if at least one expression is truthy.

// Check if child can participate in activity
const child = { hasPermission: false, isEmergencyApproved: true };
apply(
  {
    $or: [{ $get: "hasPermission" }, { $get: "isEmergencyApproved" }],
  },
  child,
);
// Returns: true

$omit

Returns a new object excluding the specified properties.

Type handling: Returns an empty object {} when applied to non-object input (null, undefined, arrays, or other types).

// Remove sensitive data from child record
const child = {
  name: "Aria",
  age: 4,
  ssn: "123-45-6789",
  group: "Butterflies",
};
apply({ $omit: ["ssn"] }, child);
// Returns: { name: "Aria", age: 4, group: "Butterflies" }

$pairs

Converts an object into an array of [key, value] pairs.

Type handling: Returns an empty array [] when applied to non-object input (null, undefined, arrays, or other types).

// Convert child data to key-value pairs
const child = { name: "Zara", age: 4, group: "Butterflies" };
apply({ $pairs: null }, child);
// Returns: [["name", "Zara"], ["age", 4], ["group", "Butterflies"]]

$parseDate

Parses a date string using a format pattern and returns ISO 8601 string.

Common format tokens: yyyy (4-digit year), MM (2-digit month), dd (2-digit day), HH (2-digit hour), mm (minute), ss (second)

// Parse with format pattern
apply({ $parseDate: "MM/dd/yyyy" }, "10/05/2025");
// Returns: "2025-10-05T..." (ISO string)

// Validate ISO string
apply({ $parseDate: null }, "2025-10-05T00:00:00.000Z");
// Returns: "2025-10-05T00:00:00.000Z"

// Array form: explicit date and format
apply({ $parseDate: ["10/05/2025", "MM/dd/yyyy"] }, null);
// Returns: "2025-10-05T..." (ISO string)

$pick

Returns a new object containing only the specified properties by name.

Type handling: Returns an empty object {} when applied to non-object input (null, undefined, arrays, or other types).

// Extract only essential child info
const child = {
  name: "Aria",
  age: 4,
  ssn: "123-45-6789",
  group: "Butterflies",
  allergies: "none",
};
apply({ $pick: ["name", "age", "group"] }, child);
// Returns: { name: "Aria", age: 4, group: "Butterflies" }

// Works with nested property paths
const data = {
  child: { profile: { name: "Luna", age: 3 } },
  meta: { teacher: "Ms. Smith", room: "A" },
};
apply({ $pick: ["child.profile.name", "meta.teacher"] }, data);
// Returns: { "child.profile.name": "Luna", "meta.teacher": "Ms. Smith" }

Note: Use $pick to select properties by name. Use $select to transform and rename properties.

$pluck

Extracts a specific property from each object in an array (shorthand for $map + $get). Supports the $ wildcard for array iteration within each object.

Type handling: Returns an empty array [] when applied to non-array input (null, undefined, or other types).

// Get all children's names
const children = [
  { name: "Aria", age: 4 },
  { name: "Kai", age: 5 },
  { name: "Zara", age: 3 },
];
apply({ $pluck: "name" }, children);
// Returns: ["Aria", "Kai", "Zara"]

// Wildcard support for nested arrays
const teams = [
  { members: [{ name: "Chen" }, { name: "Amira" }] },
  { members: [{ name: "Diego" }, { name: "Sofia" }] },
];
apply({ $pluck: "members.$.name" }, teams);
// Returns: [["Chen", "Amira"], ["Diego", "Sofia"]]

$pipe

Pipes data through multiple expressions in sequence (left-to-right), starting with the input data then feeding the result of one expression to the next returning the result of the last expression.

// Process children data through multiple steps
const daycareData = {
  children: [
    { name: "Aria", age: 4, present: true },
    { name: "Kai", age: 5, present: true },
    { name: "Zara", age: 3, present: false },
  ],
};
apply(
  {
    $pipe: [
      { $get: "children" },
      { $filter: { $get: "present" } },
      { $map: { $get: "name" } },
      { $join: ", " },
    ],
  },
  daycareData,
);
// Returns: "Aria, Kai"

$pow

Performs power/exponentiation operation.

// Single operand: raise input data to power
apply({ $pow: 2 }, 8); // 8 squared
// Returns: 64 (8^2)

// Array form: power of two expressions
apply(
  { $pow: [{ $get: "base" }, { $get: "exponent" }] },
  { base: 3, exponent: 4 },
);
// Returns: 81 (3^4)

// Mixed form: expression ^ literal
apply({ $pow: [{ $get: "side" }, 2] }, { side: 5 });
// Returns: 25 (5^2)

$prop

Fast simple property access without path traversal. Performs direct property lookup (obj[key]) with no support for dot notation, wildcards, or array paths. Use $get when you need advanced path features; use $prop for better performance on simple property access.

Performance: ~2.5x faster than $get for simple property access.

// Simple property access
const child = { name: "Sofia", age: 4, toys: ["blocks", "dolls"] };
apply({ $prop: "name" }, child);
// Returns: "Sofia"

apply({ $prop: "age" }, child);
// Returns: 4

apply({ $prop: "toys" }, child);
// Returns: ["blocks", "dolls"]

// Returns null for missing properties
apply({ $prop: "missing" }, child);
// Returns: null

// Does NOT support dot notation (use $get instead)
const data = { user: { name: "Chen" } };
apply({ $prop: "user.name" }, data);
// Returns: null (treats "user.name" as literal key)

// For nested access, use $get instead
apply({ $get: "user.name" }, data);
// Returns: "Chen"

When to use:

  • Simple property access where performance matters
  • You know the property is at the root level
  • You don't need dot notation or wildcards

When to use $get instead:

  • Nested property access (user.profile.name)
  • Array wildcards ($.name)
  • Dynamic path construction
  • Path expressions

$replace

Replaces occurrences of a pattern in a string.

Type handling: Returns null when input data is not a string.

// Clean up child's name input
apply({ $replace: ["\\s+", " "] }, "Amara   Rodriguez");
// Returns: "Amara Rodriguez"

$reverse

Returns array with elements in reverse order. Can operate on either the operand (if provided and resolves to an array) or the input data.

// Operate on input data
const pickupOrder = ["Aria", "Chen", "Diego", "Luna"];
apply({ $reverse: null }, pickupOrder);
// Returns: ["Luna", "Diego", "Chen", "Aria"]

// Operate on operand
apply({ $reverse: ["Aria", "Chen", "Diego", "Luna"] }, null);
// Returns: ["Luna", "Diego", "Chen", "Aria"]

// Operate on expression result
apply({ $reverse: { $get: "lineup" } }, { lineup: ["Aria", "Chen", "Diego"] });
// Returns: ["Diego", "Chen", "Aria"]

$skip

Skips first N elements of an array.

// Skip first two children in line
const lineup = ["Aria", "Chen", "Diego", "Luna", "Kai"];
apply({ $skip: 2 }, lineup);
// Returns: ["Diego", "Luna", "Kai"]

$select

Creates a new object by selecting and transforming properties with custom key names.

// Select and transform child data
const child = {
  name: "Aria",
  age: 4,
  birthDate: "2020-03-15",
  group: "Butterflies",
};
apply(
  {
    $select: {
      childName: { $get: "name" },
      ageInMonths: { $pipe: [{ $get: "age" }, { $multiply: 12 }] },
      group: { $get: "group" },
    },
  },
  child,
);
// Returns: { childName: "Aria", ageInMonths: 48, group: "Butterflies" }

Note: To select properties by name without transformation, use $pick instead.

$second

Extracts the second from a date (0-59).

// Extract second from date
apply({ $second: "2025-10-05T15:23:45.234Z" }, null);
// Returns: 45

$sort

Sorts an array based on specified criteria.

Type handling: Returns an empty array [] when applied to non-array input (null, undefined, or other types).

Note: Wildcards ($) are not supported in sort paths. Sort operates on properties of array items, not nested arrays.

// Sort children by age
const children = [
  { name: "Zara", age: 3 },
  { name: "Aria", age: 4 },
  { name: "Kai", age: 5 },
];
apply({ $sort: { by: "age" } }, children);
// Returns: [{ name: "Zara", age: 3 }, { name: "Aria", age: 4 }, { name: "Kai", age: 5 }]

// Sort descending by name
apply({ $sort: { by: "name", desc: true } }, children);
// Returns: [{ name: "Zara", age: 3 }, { name: "Kai", age: 5 }, { name: "Aria", age: 4 }]

// Sort by expression - calculated age in months
apply({ $sort: { by: { $multiply: [{ $get: "age" }, 12] } } }, children);
// Returns: [{ name: "Zara", age: 3 }, { name: "Aria", age: 4 }, { name: "Kai", age: 5 }]

Note: The by field can be a property name (string) or an expression that computes the sort value.

$split

Splits a string into an array using a separator.

Type handling: Returns null when input data is not a string.

// Split child's full name
apply({ $split: " " }, "Amara Devika Rodriguez");
// Returns: ["Amara", "Devika", "Rodriguez"]

$startOfDay

Returns the start of day (00:00:00.000) for a given date.

// Get start of day
apply({ $startOfDay: "2025-10-05T15:23:45.234Z" }, null);
// Returns: "2025-10-05T00:00:00.000Z"

// Works with input data form
apply({ $startOfDay: null }, "2025-10-05T15:23:45.234Z");
// Returns: "2025-10-05T00:00:00.000Z"

$startOfMonth

Returns the first moment of the month for a given date.

// Get start of month
apply({ $startOfMonth: "2025-10-15T15:23:45.234Z" }, null);
// Returns: "2025-10-01T00:00:00.000Z"

$startOfYear

Returns the first moment of the year for a given date.

// Get start of year
apply({ $startOfYear: "2025-10-15T15:23:45.234Z" }, null);
// Returns: "2025-01-01T00:00:00.000Z"

$sqrt

Calculates the square root of a number. Can operate on either the operand (if provided and resolves to a number) or the input data.

// Operate on input data
apply({ $sqrt: null }, 64);
// Returns: 8

// Operate on operand
apply({ $sqrt: 64 }, null);
// Returns: 8

// Operate on expression result
apply({ $sqrt: { $get: "area" } }, { area: 64 });
// Returns: 8

$startOf

Gets the start of a time period (day, week, month, year).

Supported units: day, week, month, year

// Get start of day
apply({ $startOf: "day" }, "2025-10-05T15:23:45.123Z");
// Returns: "2025-10-05T00:00:00.000Z"

// Get start of month
apply({ $startOf: "month" }, "2025-10-15T15:23:45.123Z");
// Returns: "2025-10-01T00:00:00.000Z"

// Get start of year
apply({ $startOf: "year" }, "2025-10-15T15:23:45.123Z");
// Returns: "2025-01-01T00:00:00.000Z"

$substring

Extracts a portion of a string.

Type handling: Returns null when input data is not a string.

// Get child's initials from name
apply({ $substring: [0, 1] }, "Amara");
// Returns: "A"

$subtract

Performs subtraction operation.

// Single operand: subtract from input data
apply({ $subtract: 15.5 }, 25.0);
// Returns: 9.50 (25.0 - 15.5)

// Array form: subtract two expressions
apply(
  { $subtract: [{ $get: "total" }, { $get: "discount" }] },
  { total: 20, discount: 3 },
);
// Returns: 17 (20 - 3)

// Mixed form: expression - literal
apply({ $subtract: [{ $get: "age" }, 2] }, { age: 6 });
// Returns: 4 (6 - 2)

$subDays

Subtracts a specified number of days from a date.

// Array form: subtract days from date
apply({ $subDays: ["2025-10-12T00:00:00.000Z", 7] }, null);
// Returns: "2025-10-05T00:00:00.000Z"

// Input data form: subtract days from input date
apply({ $subDays: 7 }, "2025-10-12T00:00:00.000Z");
// Returns: "2025-10-05T00:00:00.000Z"

// Handles month boundaries
apply({ $subDays: ["2025-11-01T00:00:00.000Z", 1] }, null);
// Returns: "2025-10-31T00:00:00.000Z"

$subMonths

Subtracts a specified number of months from a date.

// Array form: subtract months from date
apply({ $subMonths: ["2026-01-05T00:00:00.000Z", 3] }, null);
// Returns: "2025-10-05T00:00:00.000Z"

// Handles year boundaries
apply({ $subMonths: ["2026-02-15T00:00:00.000Z", 2] }, null);
// Returns: "2025-12-15T00:00:00.000Z"

$subYears

Subtracts a specified number of years from a date.

// Array form: subtract years from date
apply({ $subYears: ["2030-10-05T00:00:00.000Z", 5] }, null);
// Returns: "2025-10-05T00:00:00.000Z"

$sum

Calculates the sum of array values. Can operate on either the operand (if provided and resolves to an array) or the input data.

// Calculate sum of input data array
const temperatures = [68, 72, 75, 73, 70];
apply({ $sum: null }, temperatures);
// Returns: 358

// Calculate sum of operand array
apply({ $sum: [10, 20, 30, 40] }, null);
// Returns: 100

// Calculate sum from expression result
const data = { dailySteps: [5000, 7500, 6000, 8000] };
apply({ $sum: { $get: "dailySteps" } }, data);
// Returns: 26500

$take

Takes first N elements of an array.

// Get first three children for small group activity
const allChildren = ["Aria", "Chen", "Diego", "Luna", "Kai"];
apply({ $take: 3 }, allChildren);
// Returns: ["Aria", "Chen", "Diego"]

$trim

Removes whitespace from beginning and end of string. Can operate on either the operand (if provided and resolves to a string) or the input data.

Type handling: Returns null when neither the operand nor input data is a string.

// Operate on input data
apply({ $trim: null }, "  Amara Rodriguez  ");
// Returns: "Amara Rodriguez"

// Operate on operand
apply({ $trim: "  Amara Rodriguez  " }, null);
// Returns: "Amara Rodriguez"

// Operate on expression result
apply({ $trim: { $get: "input" } }, { input: "  Amara Rodriguez  " });
// Returns: "Amara Rodriguez"

$uppercase

Converts string to uppercase. Can operate on either the operand (if provided and resolves to a string) or the input data.

Type handling: Returns null when neither the operand nor input data is a string.

// Operate on input data
apply({ $uppercase: null }, "Amara");
// Returns: "AMARA"

// Operate on operand
apply({ $uppercase: "Amara" }, null);
// Returns: "AMARA"

// Operate on expression result
apply({ $uppercase: { $get: "name" } }, { name: "Amara" });
// Returns: "AMARA"

$unique

Returns an array with duplicate values removed. Can operate on either the operand (if provided and resolves to an array) or the input data.

// Operate on input data
const restrictions = [
  "none",
  "nut allergy",
  "none",
  "vegetarian",
  "nut allergy",
];
apply({ $unique: null }, restrictions);
// Returns: ["none", "nut allergy", "vegetarian"]

// Operate on operand
apply({ $unique: ["none", "nut allergy", "none"] }, null);
// Returns: ["none", "nut allergy"]

// Operate on expression result
apply({ $unique: { $get: "tags" } }, { tags: ["red", "blue", "red", "green"] });
// Returns: ["red", "blue", "green"]

$values

Returns an array of all property values from an object.

Type handling: Returns an empty array [] when applied to non-object input (null, undefined, arrays, or other types).

// Get all values from child record
const child = { name: "Amara", age: 4, group: "Butterflies", present: true };
apply({ $values: null }, child);
// Returns: ["Amara", 4, "Butterflies", true]

$year

Extracts the year from a date.

// Extract year from date
apply({ $year: "2025-10-05T15:23:45.234Z" }, null);
// Returns: 2025

// Works with input data form
apply({ $year: null }, "2025-10-05T15:23:45.234Z");
// Returns: 2025