tudor-sql 0.2.0

Does sql stuff to todo.txt files
Documentation
WHITESPACE = _{ " " | "\n" }
COMMENT = _{ "--" ~ ANY* ~ "\n"}

value = { null
        | boolean
        | text
        | set_of_texts
        }
    null = { "null" }
    boolean = { "true" | "false" }
    text = @{ "'" ~ (!"'" ~ ANY )* ~ "'" }
    set_of_texts = { "(" ~ (text ~ ",")* ~ text? ~ ")" }

// https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-PRECEDENCE
not = { "not" }
operand_0 = { identifier
            | nested
            | value
            }
        identifier = { todo_field }
        nested = { "(" ~ expression ~ ")" }
operand_1 = { function
            | operand_0
            }
        // for now ARGs are just [String]
        // TODO: size(identifier) / count(identifier)
        function = ${ function_name ~ function_argument_list }
            function_argument_list_empty = { "(" ~ ")"}
            // FIXME: why do i have to do this whitespace crap here?
            function_argument_list_nonempty = { "(" ~ WHITE_SPACE*
                                              ~ (value ~ WHITE_SPACE* ~ "," ~ WHITE_SPACE*)*
                                              ~ WHITE_SPACE* ~ value ~ WHITE_SPACE* ~ ")" }
            function_argument_list = { function_argument_list_empty | function_argument_list_nonempty }
            function_name = { ASCII_ALPHA+ }
operand_2 = { between
            | in_set
            | operand_1
            }
        between = {  operand_1 ~ not? ~ "between" ~ operand_1 ~ "and" ~ operand_1 }
        in_set = { operand_1 ~ not? ~ "in" ~ set_of_texts }
operand_3 = { comparison_op_
            | operand_2
            }
    comparison_operator = { eq
                          | not_eq
                          | gt_eq
                          | lt_eq
                          | contains
                          | is_contained_by
                          | overlap
                          | gt
                          | lt
                          }
        gt = { ">" }
        lt = { "<" }
        gt_eq = { ">=" }
        lt_eq = { "<=" }
        eq = { "==" | "=" }
        not_eq = { "<>" | "!="} // 🏴‍☠️
        // https://www.postgresql.org/docs/9.0/functions-array.html
        // set operations
        contains = {"@>"}
        is_contained_by = {"<@"}
        overlap = {"&&"}
    _comparison_operator_and_operand = { comparison_operator ~ operand_2 }
    comparison_op_ = { operand_2 ~ comparison_operator ~ operand_2 }
operand_4 = { is
            | operand_3
            }
        ntf = { "null" | "true" | "false" }
        is = { operand_3 ~ "is" ~ not? ~ ntf }
operand_5 = { negated
            | operand_4
            }
        negated = { not ~ operand_4 }

operand_6 = { and
            | operand_5
            }
    and = { operand_5 ~ ("and" ~ operand_5)+ }
operand_7 = { or
            | operand_6
            }
    or = { operand_6 ~ ("or" ~ operand_6)+ }
expression = { operand_7 }

todo_field = { "full_text"
             | "is_completed"
             | "id"
             | "is_blocking_for"
             | "is_blocked"
             | "blocked_by"
             | "creation_date"
             | "completion_date"
             | "priority"
             | "ccontext"
             | "contexts"
             | "cproject"
             | "projects"
             | "due_date"
             | "threshold_date"
             | "is_hidden"
             }
select = { "select" ~ select_fields_star
         ~ "from" ~ select_from
         ~ "where" ~ expression? }
    select_fields_star = { "*" }
    select_fields_list = { "(" ~ (todo_field ~ ",")* ~ todo_field ~ ")" }
    select_fields = { select_fields_star | select_fields_list }
    select_from = { "-"  // STDIN
                  | "todo_txt"
                  | "done_txt"
                  // TODO: other files in todo dir
                  }