discret 0.6.2

A backend to create peer to peer (P2P) applications, using a GraphQL inspired syntax
Documentation
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) }