Skip to content

StarRocks

StarRocks SQL uses backtick-quoted identifiers, regexp() for regex, and -> with JSON-stringified keys for JSON access.

FlyQL Generated SQL
message = 'hello' `message` = 'hello'
message != 'hello' `message` != 'hello'
count > 10 `count` > 10
count <= 100 `count` <= 100
message ~ 'error.*' regexp(`message`, 'error.*')
message !~ 'test.*' NOT regexp(`message`, 'test.*')
host = 'prod' `host` = 'prod'
FlyQL Generated SQL
a = '1' and b > 10 `a` = '1' AND `b` > 10
a = '1' or b = '2' `a` = '1' OR `b` = '2'
not a = '1' NOT (`a` = '1')
FlyQL Generated SQL
status in [200, 201] `status` IN (200, 201)
env not in ['dev', 'test'] `env` NOT IN ('dev', 'test')
status in [] 0
status not in [] 1

A bare column reference (active, not active) generates type-aware SQL — there is no single “is truthy” expression, because what counts as falsy differs by column type.

Column Type FlyQL Generated SQL
String message (`message` IS NOT NULL AND `message` != '')
Int / Float count (`count` IS NOT NULL AND `count` != 0)
Bool active `active`
Date created_at (`created_at` IS NOT NULL)
Negated String not message (`message` IS NULL OR `message` = '')

The has operator generates different SQL depending on the column type:

Column Type FlyQL Generated SQL
String message has 'error' INSTR(`message`, 'error') > 0
String (negated) message not has 'error' (`message` IS NULL OR INSTR(`message`, 'error') = 0)
Array tags has 'web' array_contains(`tags`, 'web')
Array (negated) tags not has 'web' NOT array_contains(`tags`, 'web')
Map metadata has 'key' array_contains(map_keys(`metadata`), 'key')
Map (negated) metadata not has 'key' NOT array_contains(map_keys(`metadata`), 'key')
Native JSON data has 'key' json_exists(`data`, concat('$.', 'key'))

StarRocks supports two JSON column types with different SQL output.

Native JSON columns use the -> operator with JSON-stringified keys:

FlyQL Generated SQL
data.name = 'test' `data`->'"name"' = 'test'
data.user.name = 'john' `data`->'"user"'->'"name"' = 'john'

Columns storing JSON as a string (declared with the synthetic jsonstring raw type) require parse_json() before traversal:

FlyQL Generated SQL
log.name = 'test' parse_json(`log`)->'"name"' = 'test'
log.user.name = 'john' parse_json(`log`)->'"user"'->'"name"' = 'john'

The StarRocks generator treats a segmented path as belonging to a single container type — it does not currently descend through mixed nesting such as Map(K, Struct), Array(Map), or Struct fields that are themselves Map/Array. For such columns, flatten the path or expose the inner value as a separate column.

Map columns use bracket notation with direct comparison:

FlyQL Generated SQL
metadata.key1 = 'value1' `metadata`['key1'] = 'value1'
metadata.key1 != 'value1' `metadata`['key1'] != 'value1'
metadata.nested.key = 'value' `metadata`['nested']['key'] = 'value'
metadata.pattern ~ 'test.*' `metadata`['pattern'] regexp 'test.*'

FlyQL array indices are 0-based; the StarRocks generator adds 1 when emitting SQL because StarRocks arrays are 1-indexed at the SQL layer:

FlyQL Generated SQL
tags.0 = 'first' `tags`[1] = 'first'
tags.1 = 'second' `tags`[2] = 'second'

Text/varchar columns whose contents are valid JSON are declared with the synthetic jsonstring raw type (same as ClickHouse):

// Go
columns := map[string]*starrocks.Column{
"message": starrocks.NewColumn(starrocks.ColumnDef{Name: "message", Type: "VARCHAR(255)"}),
"data": starrocks.NewColumn(starrocks.ColumnDef{Name: "data", Type: "JSON"}), // native JSON
"log": starrocks.NewColumn(starrocks.ColumnDef{Name: "log", Type: "jsonstring"}), // JSON-in-text
}
// JavaScript
const columns = {
message: newColumn({ name: "message", type: "VARCHAR(255)" }),
data: newColumn({ name: "data", type: "JSON" }), // native JSON
log: newColumn({ name: "log", type: "jsonstring" }), // JSON-in-text
}

Transformers generate StarRocks-standard function calls with backtick-quoted column names:

FlyQL Generated SQL
status|upper = "ERROR" UPPER(`status`) = 'ERROR'
status|lower = "info" LOWER(`status`) = 'info'
message|len > 100 LENGTH(`message`) > 100
message|lower|len > 100 LENGTH(LOWER(`message`)) > 100
tags|split(",") has "urgent" array_contains(SPLIT(`tags`, ','), 'urgent')