Skip to content

Values & Types

FlyQL supports 10 value types: Integer, BigInt, Float, String, Boolean, Null, Array, Column, Function, and Parameter. Each value in the AST carries an explicit value_type field.

Whole numbers within the int64 range:

count = 42
status != 200
age >= 18

AST: value_type: "int"

Integers exceeding the int64 range (Go/Python) or MAX_SAFE_INTEGER (JavaScript):

id = 18446744073709551615

AST: value_type: "bigint"

Numbers with a decimal point:

price > 9.99
ratio = 3.14
temperature<=-0.5

AST: value_type: "float"

Text values must be quoted using single or double quotes. Unquoted values are interpreted as column references, not strings.

level = 'error'
user = "John Doe"
message = 'hello world'
count = '42'

AST: value_type: "string"

Escape quotes with backslash:

user = 'John\'s'
message = "said \"hello\""

The keywords true and false (lowercase, case-sensitive):

active = true
debug = false
active != true

AST: value_type: "bool", value is native boolean.

Capitalized variants (True, FALSE) are treated as column references, not booleans.

SQL generation:

DialectFlyQLGenerated SQL
ClickHousefield = truefield = true
ClickHousefield = falsefield = false
PostgreSQLfield = truefield = TRUE
PostgreSQLfield = falsefield = FALSE
StarRocksfield = truefield = true
StarRocksfield = falsefield = false

The keyword null (lowercase, case-sensitive):

field = null
field != null

AST: value_type: "null", value is native null.

Capitalized variants (Null, NULL) are treated as column references, not null.

Restrictions: Only = and != operators are valid with null. Using >, <, >=, <=, ~, or !~ with null produces a parse error.

SQL generation: field = null emits field IS NULL, field != null emits field IS NOT NULL (all dialects).

Any unquoted value that is not a number, boolean, null, or temporal function is treated as a column reference — a pointer to another column for column-to-column comparisons:

price > min_price
updated_at > created_at
field = otherfield

AST: value_type: "column"

If you intend to match a string value, you must use quotes:

level = 'error'

Without quotes, level = error treats error as a reference to a column named error.

Arrays are used with in and not in operators. Elements can be mixed types (heterogeneous):

status in [200, 201, 202]
name in ['alice', 'bob']
field in [1, "hello", true, null]

Each element carries its own type in the values_types array.

A standalone key without an operator checks if the field has a truthy value:

active
message and status

A value is considered falsy if it is:

  • null / None / missing
  • Empty string ""
  • Zero 0
  • Boolean false

Everything else is truthy.

Use not to check for falsy values:

not archived
active and not debug

Truthy/falsy checks are distinct from null comparisons: not field matches when the field is null, empty, or zero. field = null matches only when the field is specifically null.

FlyQL is whitespace-tolerant. Spaces around operators are optional:

status = 200
status =200

All of the above are equivalent.

Parsed expression values carry a LiteralKind tag. The constants are exported from the root package in every implementation.

Python:

from flyql import LiteralKind
# LiteralKind.INTEGER, LiteralKind.BIGINT, LiteralKind.FLOAT,
# LiteralKind.STRING, LiteralKind.BOOLEAN, LiteralKind.NULL, LiteralKind.ARRAY

Go:

import "github.com/iamtelescope/flyql/golang/literal"
// literal.Integer, literal.BigInt, literal.Float,
// literal.String, literal.Boolean, literal.Null, literal.Array

JavaScript:

import { LiteralKind } from 'flyql'
// LiteralKind.INTEGER, LiteralKind.BIGINT, LiteralKind.FLOAT,
// LiteralKind.STRING, LiteralKind.BOOLEAN, LiteralKind.NULL, LiteralKind.ARRAY

FlyQL supports temporal function calls as values on the right-hand side of comparison expressions. These enable time-relative filters without hardcoding timestamps.

AST: value_type: "function", value is a FunctionCall object.

Returns a timestamp relative to the current time. Supports compound durations.

timestamp > ago(1h)
created_at >= ago(7d)
updated_at > ago(1h30m)

Units (lowercase): s (seconds), m (minutes), h (hours), d (days), w (weeks).

Grammar. A duration is one or more <integer><unit> pairs. Units must appear in strictly descending order and at most once each: w > d > h > m > s. This matches the Prometheus / Grafana / Loki convention.

Valid:

ago(30s)
ago(2h15m)
ago(1w2d3h4m5s)
ago(1w30s)

Rejected at parse time:

  • ago(30m1h) — units out of order
  • ago(1h1h) — repeated unit
  • ago(3h1w) — larger unit after smaller
  • ago(1H) — unit letters must be lowercase

Returns the current timestamp.

expires_at < now()

Returns today’s date. Accepts an optional IANA timezone argument.

date = today()
date = today('Europe/Berlin')

Returns the start of the current day, week (Monday), or month. Accepts an optional timezone.

created_at > startOf('day')
created_at > startOf('week')
created_at > startOf('month', 'Asia/Tokyo')

Valid units: 'day', 'week', 'month'

Temporal functions can only be used with comparison operators: =, !=, >, >=, <, <=.

Using ~ or !~ with a temporal function produces a parse error. Operators like in, has, like, and ilike use separate parsing paths and are not compatible with function values.

Bare function names without parentheses are treated as column references, not function calls:

field = ago

This produces value_type: "column", not a function call.

Parameter placeholders ($name for named, $1 for positional) stand in for values to be resolved at runtime by bindParams(). They can appear anywhere a literal value is valid — including IN-lists, temporal function arguments, and transformer arguments.

status = $code
level in [$primary, 'warn']
created > ago($duration)

AST: value_type: "parameter", value is a Parameter object with name and positional fields.

See Parameters for the full reference.