type query = Query of select_stmt
and select_stmt = 
  | Select of column list * table list
and column = 
  | Asterisk
  | Column of string
and table = 
  | Table of string
  | Join of table * join_type * table * condition option
and join_type =
  | Inner
  | Left
  | Right
  | Full
  | Cross
  | Union
  | Natural
and condition = 
  | Condition of string * predicate
  | And of condition * condition
  | Or of condition * condition
  | Not of condition
and predicate = 
  | Comparison of operator * string
  | Between of string * string
  | NotBetween of string * string
  | In of string list
  | NotIn of string list
  | Like of string
and operator =
  | Equals
  | NotEquals
  | LessThan
  | GreaterThan
  | LessEquals
  | GreaterEquals
and filter = 
  | Filter of string
and search_condition =
  | Search of string


let rec pp_query ast = 
  match ast with
  | Query(s) ->  pp_select s

and pp_select s = 
  match s with
  | Select(cols, _) -> pp_columns cols

and pp_columns cols =
  match cols with
  | [] -> "" 
  | [col] -> pp_column col
  | col::l -> pp_column col ^ ";" ^ pp_columns l

and pp_column col = 
  match col with
  | Column(name) -> name
  | Asterisk -> "*"

and pp_tables tables =
  match tables with
  | [] -> ""
  | [table] -> pp_table table
  | table::l -> pp_table table ^ ";" ^ pp_tables l

and pp_table table =
  match table with
  | Table(table) -> table
  | Join(t1, j, t2, _) -> pp_table t1 ^ pp_join_type j ^ pp_table t2

and pp_join_type j =
  match j with
  | Inner -> "inner"
  | Left -> "left"
  | Right -> "right"
  | Full -> "full"
  | Cross -> "cross"
  | Union -> "union"
  | Natural -> "natural"