Skip to content

Instantly share code, notes, and snippets.

@CraftyFella
Created October 19, 2020 16:52
Show Gist options
  • Save CraftyFella/d6ee592a650dcd0fd42ce9b6cd2dd035 to your computer and use it in GitHub Desktop.
Save CraftyFella/d6ee592a650dcd0fd42ce9b6cd2dd035 to your computer and use it in GitHub Desktop.
open FParsec
[<RequireQualifiedAccess>]
type QueryComparison =
| Equal
| NotEqual
[<RequireQualifiedAccess>]
type TableOperators =
| And
| Or
[<RequireQualifiedAccess>]
type Filter =
| Property of name: string * QueryComparison * value: string
| Combined of Filter * TableOperators * Filter
let letterOrNumber = asciiLetter <|> digit
let manyLettersOrNumbers = many1Chars letterOrNumber
let manyCharsNotSingleQuote = (many1Chars (noneOf [ '\'' ]))
let stringParser =
let quote = pchar '\''
between quote quote manyCharsNotSingleQuote |>> (string)
let fieldValueParser = stringParser
let queryComparisonParser =
[ ("eq", QueryComparison.Equal); ("ne", QueryComparison.NotEqual) ]
|> List.map (fun (toMatch, qc) -> stringReturn toMatch qc <?> (sprintf "%O" qc))
|> choice
let propertyParser =
let name = manyLettersOrNumbers .>> spaces <?> "Name"
let queryComparison = queryComparisonParser .>> spaces <?> "QueryComparison"
let filterValue = fieldValueParser <?> "FilterValue"
name .>>. queryComparison .>>. filterValue |>> (fun ((n, qc), fv) -> Filter.Property(n, qc, fv))
let opp = new OperatorPrecedenceParser<Filter, unit, unit>()
let expr = opp.ExpressionParser
opp.AddOperator(InfixOperator("and", spaces, 1, Associativity.Left, fun left right -> Filter.Combined(left, TableOperators.And, right)))
opp.AddOperator(InfixOperator("or", spaces, 2, Associativity.Left, fun left right -> Filter.Combined(left, TableOperators.Or, right)))
opp.TermParser <- choice [propertyParser; expr]
let filter = spaces >>. expr .>> spaces .>> eof
let parse query = run filter query
[<EntryPoint>]
let main argv =
parse "Name eq 'Dave' and Colour ne 'red'" |> printfn "%A"
(*
Failure:
Error in Ln: 1 Col: 16
Name eq 'Dave' and Colour ne 'red'
^
Expecting: end of input
*)
0 // return an integer exit code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment