Language reference
This document describes the syntax and semantics of the custom language used in ransack.
Basic data types
Number
Numbers can be represented as integers, floating-point values, or in scientific notation.
Examples:
27, -15, 3.14, 2e25, 2.15e-17
String
A sequence of characters enclosed in single or double quotes.
Examples:
"hello", 'world'
Datetime
Combination of date and time, optionally joined by T.
Date:
YYYY-MM-DDTime:
HH:MM:SS[.fraction][Z|(+|-)HH:MM]
If the time component is omitted, it defaults to midnight.
Examples:
2025-04-11T14:30:00, 2025-04-11 14:30:00Z, 2025-04-11,
2025-04-11T14:30:00+07:00
Timedelta
Represents a time interval. An optional number of days (d or D) may precede the required
time component (HH:MM:SS).
Examples:
1D12:00:00, 23:59:59
IPv4 & IPv6
Supports individual addresses, ranges, and CIDR notation.
Examples:
192.168.1.1, 192.168.1.1-192.168.1.100, 192.168.1.0/24
2001:db8::1, 2001:db8::1-2001:db8::ff, 2001:db8::/64
Warning
IP addresses in quotation marks (e.g., "192.168.0.1") are recognized as strings.
That is, they are no longer recognized as IP addresses!
Variables
Alphanumeric with optional dots, underscores, or hyphens.
Examples:
Source.IP4, .Description
Context
The parser accepts an optional context dictionary at initialization, allowing users to define static variables that can be referenced in queries.
Context variables:
Are separate from input data.
Take precedence over similarly named data variables.
Allow for reusable query logic.
To resolve ambiguity, a prefixing convention is used:
Variables prefixed with a dot (e.g.,
.foo) are explicitly taken from the input data.Variables without a prefix (e.g.,
foo) are looked up in the context if available.
Example:
ctx = {"threshold": 100}
parser = Parser(context=ctx)
parser.parse("threshold > .load") # Context variable vs data variable
Functions
Functions use parentheses and comma-separated arguments.
For the full list and documentation of available functions, see ransack.function module.
Functions return either a basic data type or a collection.
Examples:
len(Source.IP4), now()
Collections
List
Comma-separated values in square brackets.
Examples:
[1, 2, 3.0], [192.168.0.1, 192.168.0.0/24]
Range
Defines an inclusive sequence of numbers, datetimes, or IP addresses.
Examples:
1..1024, 1.0 .. 0, 2025-01-01 .. 2025-12-31
Operators
Arithmetic operators
Operator |
Operand Types |
Result Type |
Description |
|---|---|---|---|
|
|
|
Standard numeric addition |
|
|
Adds duration to datetime |
|
|
|
Adds two time intervals |
|
|
|
|
Standard numeric subtraction |
|
|
Subtracts duration from datetime |
|
|
|
Subtracts two time intervals |
|
|
|
Time difference between two datetimes |
|
|
|
|
Scales a time interval |
|
|
Standard numeric multiplication |
|
|
|
|
Ratio of two time intervals |
|
|
Standard numeric division |
|
|
|
|
Remainder of timedelta division |
|
|
Standard numeric modulo |
Basic data type vs. collection: Operation is applied element-wise.
Collection vs. collection: Disallowed.
Comparison operators
=: Loose equality==: Strict equality>/>=: Greater than / Greater than or equal</<=: Less than / Less than or equal
Comparisons are valid for numbers, datetimes, timedeltas, and IP addresses.
Collections: True if any element satisfies the comparison.
Comparing two collections is treated as: “Does any element in the left collection match any element in the right collection?”
Warning
The == operator now represents strong equality, in contrast to the older behavior where it also matched elements within collections.
To support collection-aware comparisons, a new = operator has been introduced. This operator returns True if any element in the collection satisfies the comparison — mirroring the behavior of >, >=, <, and <=.
For example:
1 == [1, 2] # False
1 = [1, 2] # True
This change promotes consistency across all comparison operators, but be aware that it may lead to different results if you previously relied on == for implicit collection matching.
Special operators
in operator
Tests membership.
If the left-hand side (LHS) is a single value, it checks whether it exists in the right-hand side (RHS) collection.
If the LHS is itself a collection, then each element of the LHS is tested for membership in the RHS. The condition returns True as soon as any element is found (i.e. it checks for intersection, not subset).
If an element of the RHS is itself a collection, the membership check recurses into it. In other words, the condition x in right is evaluated for every element x of the LHS against each element of the RHS, and if an RHS element is a collection, the check is applied within that collection. This recursive behavior also applies to IP ranges and network types.
This means that:
[1, 2] in [2, 3, 4] → True (because 2 is present)
[1, 2] in [3, 4] → False (no element matches)
[1, 2] in [1, 2, 3] → True (1 is present; but note this is not a subset test)
1 in [[1, 2], [3, 4]] → True (1 is found inside the first nested list)
[2, 3] in [[1, 2], [3, 4]] → True (2 is inside the first nested list, 3 is inside the second; any match suffices)
5 in [[1, 2], [3, 4]] → False
contains operator
String containment check.
Example:
"abcdef" contains "abc" → True
Warning
"abc" in ["abcdef", "cccabcddd"] → False
?? operator
Existence/default fallback operator.
Unary:
var??— checks if a variable exists.Binary:
var ?? default— returnsdefaultifvaris not found.
Examples:
Description??, foo ?? "default", Source.Port??[]
. (Concatenation)
Used to concatenate strings or merge lists.
Examples:
'abc'.'def' , [1, 2, 3] . [4, 5, 6]
.. (Range)
Defines a range between two values (inclusive).
Examples:
1 .. 13, 1..Source.Port, 192.168.0.1..192.168.0.255
Logical operators
and/&&: Logical ANDor/||: Logical ORnot/!: Logical NOT
Return a boolean.
Evaluation order (precedence)
From highest to lowest:
Parentheses
()Unary minus
-Existence
??Multiplicative:
*,/,%Additive:
+,-Concatenation / Range:
.,..Comparison:
=,==,>,<,>=,<=,in,containsLogical NOT:
!,notLogical AND:
&&,andLogical OR:
||,or
Examples
(3 + 4) * 2
"tcp" in Source.Proto??[]
not (Format == "IDEA0")
Source.IP4 = 192.168.0.1 or Source.IP4 in 10.0.0.0/8