WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
COMMENT = _{ "//" ~ (!NEWLINE ~ ANY)* ~ NEWLINE }
comma = { "," }
identifier = @{ (LETTER | NUMBER | "_")+ }
namespace_entity = @{ (LETTER | NUMBER | "_" | ".")+ }
variable = @{ "$" ~ identifier }
query = { SOI ~ query_name ~ "{" ~ entity+ ~ "}" ~ EOI }
query_name = { "query" ~ (identifier)? }
entity = { entity_name ~ entity_param? ~ "{" ~ field+ ~ "}" }
entity_name = { namespace_entity ~ (":" ~ namespace_entity)? }
named_field = { identifier ~ (":" ~ identifier)? }
field = { entity | json_field | function | named_field }
entity_param = {
"(" ~ ")"
| "(" ~ param ~ (comma ~ param)* ~ comma? ~ ")"
}
param = { search | order_by | first | skip | before | after | nullable | json_filter | filter }
search = { "search" ~ "(" ~ search_value ~ ")" }
search_value = { variable | string }
order_by = { "order_by" ~ "(" ~ order_param ~ (comma ~ order_param)* ~ comma? ~ ")" }
order_param = { identifier ~ order_direction }
order_direction = { ^"asc" | ^"desc" }
first = { "first " ~ limit_value }
skip = { "skip " ~ limit_value }
limit_value = { unsigned_int | variable }
before = { "before" ~ "(" ~ before_value ~ ("," ~ before_value)* ~ ","? ~ ")" }
after = { "after" ~ "(" ~ before_value ~ ("," ~ before_value)* ~ ","? ~ ")" }
before_value = { variable | float | string | integer | boolean }
nullable = { "nullable" ~ "(" ~ identifier ~ ("," ~ identifier)* ~ ","? ~ ")" }
filter = {
identifier ~ (gt_eq | neq | lt_eq | eq | gt | lt) ~ filter_value
}
json_filter = { json_selector ~ (gt_eq | neq | lt_eq | eq | gt | lt) ~ filter_value }
filter_value = { variable | float | string | integer | boolean | null }
eq = { "=" }
neq = { "!=" }
gt = { ">" }
gt_eq = { ">=" }
lt = { "<" }
lt_eq = { "<=" }
string = ${ "\"" ~ inner ~ "\"" }
inner = @{ char* }
char = {
!("\"" | "\\") ~ ANY
| "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t")
| "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4})
}
float = @{
"-"? ~ ("0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) ~ ("." ~ ASCII_DIGIT*) ~ (^"e" ~ ("+" | "-")? ~ ASCII_DIGIT+)?
}
integer = @{
"-"? ~ ASCII_DIGIT+
}
boolean = { ^"true" | ^"false" }
unsigned_int = @{ ASCII_DIGIT+ }
null = { ^"null" }
function = { identifier ~ ":" ~ function_list }
function_list = { avg_fn | count_fn | max_fn | min_fn | sum_fn }
avg_fn = { "avg" ~ "(" ~ identifier ~ ")" }
count_fn = { "count" ~ "(" ~ ")" }
max_fn = { "max" ~ "(" ~ identifier ~ ")" }
min_fn = { "min" ~ "(" ~ identifier ~ ")" }
sum_fn = { "sum" ~ "(" ~ identifier ~ ")" }
json_field = { identifier ~ ":" ~ json_selector }
json_selector = ${ identifier ~ ("->") ~ (json_object_selector | json_array_selector) }
json_array_selector = @{ unsigned_int }
json_object_selector = @{ "$" ~ json_object_query* }
json_object_query = @{ "." ~ ((identifier ~ "[" ~ unsigned_int ~ "]") | identifier) }