-- | The AST for SQL.
{-# LANGUAGE DeriveDataTypeable #-}
module Language.SQL.SimpleSQL.Syntax
    (-- * Scalar expressions
     ScalarExpr(..)
    ,Name(..)
    ,TypeName(..)
    ,IntervalTypeField(..)
    ,Sign(..)
    ,PrecMultiplier(..)
    ,PrecUnits(..)
    ,SetQuantifier(..)
    ,SortSpec(..)
    ,Direction(..)
    ,NullsOrder(..)
    ,InPredValue(..)
    ,SubQueryExprType(..)
    ,CompPredQuantifier(..)
    ,Frame(..)
    ,FrameRows(..)
    ,FramePos(..)
    ,OdbcLiteralType(..)
     -- * Query expressions
    ,QueryExpr(..)
    ,SetOperatorName(..)
    ,Corresponding(..)
    ,Alias(..)
    ,GroupingExpr(..)
     -- ** From
    ,TableRef(..)
    ,JoinType(..)
    ,JoinCondition(..)
     -- * Statements
    ,Statement(..)
    ,DropBehaviour(..)
    ,IdentityRestart(..)
    ,InsertSource(..)
    ,SetClause(..)
    ,TableElement(..)
    ,ColumnDef(..)
    ,DefaultClause(..)
    ,IdentityWhen(..)
    ,SequenceGeneratorOption(..)
    ,ColConstraintDef(..)
    ,AutoincrementClause
    ,ColConstraint(..)
    ,TableConstraint(..)
    ,ReferenceMatch(..)
    ,ReferentialAction(..)
    ,AlterTableAction(..)
    ,CheckOption(..)
    ,AlterDomainAction(..)
    ,AdminOption(..)
    ,GrantOption(..)
    ,PrivilegeObject(..)
    ,PrivilegeAction(..)
    ,AdminOptionFor(..)
    ,GrantOptionFor(..)
     -- * Comment
    ,Comment(..)

    ,makeSelect
    ,toQueryExpr
    ,MakeSelect(..)
    ) where

import Data.Text (Text)

import Data.Data (Data, Typeable)

-- | Represents a value expression. This is used for the expressions
-- in select lists. It is also used for expressions in where, group
-- by, having, order by and so on.
data ScalarExpr
    = -- | a numeric literal optional decimal point, e+-
      -- integral exponent, e.g
      --
      -- * 10
      --
      -- * 10.
      --
      -- * .1
      --
      -- * 10.1
      --
      -- * 1e5
      --
      -- * 12.34e-6
      NumLit Text
      -- | string literal, with the start and end quote
      -- e.g. 'test' -> TextLit "'" "'" "test"
    | StringLit Text Text Text
      -- | text of interval literal, units of interval precision,
      -- e.g. interval 3 days (3)
    | IntervalLit
      {ilSign :: Maybe Sign -- ^ if + or - used
      ,ilLiteral :: Text -- ^ literal text
      ,ilFrom :: IntervalTypeField
      ,ilTo :: Maybe IntervalTypeField
      }

      -- | prefix 'typed literal', e.g. int '42'
    | TypedLit TypeName Text

      -- | identifier with parts separated by dots
    | Iden [Name]
      -- | star, as in select *, count(*)
    | Star
      -- | qualified star, as in a.*, b.c.*
    | QStar [Name]

    | Parameter -- ^ Represents a ? in a parameterized query
    | PositionalArg Int -- ^ Represents an e.g. $1 in a parameterized query
    | HostParameter Text (Maybe Text) -- ^ represents a host
                                          -- parameter, e.g. :a. The
                                          -- Maybe Text is for the
                                          -- indicator, e.g. :var
                                          -- indicator :nl


      -- | Infix binary operators. This is used for symbol operators
      -- (a + b), keyword operators (a and b) and multiple keyword
      -- operators (a is similar to b)
    | BinOp ScalarExpr [Name] ScalarExpr
      -- | Prefix unary operators. This is used for symbol
      -- operators, keyword operators and multiple keyword operators.
    | PrefixOp [Name] ScalarExpr
      -- | Postfix unary operators. This is used for symbol
      -- operators, keyword operators and multiple keyword operators.
    | PostfixOp [Name] ScalarExpr
      -- | Used for ternary, mixfix and other non orthodox
      -- operators. Currently used for row constructors, and for
      -- between.
    | SpecialOp [Name] [ScalarExpr]

      -- | function application (anything that looks like c style
      -- function application syntactically)
    | App [Name] [ScalarExpr]


      -- | aggregate application, which adds distinct or all, and
      -- order by, to regular function application
    | AggregateApp
      {aggName :: [Name] -- ^ aggregate function name
      ,aggDistinct :: SetQuantifier -- ^ distinct
      ,aggArgs :: [ScalarExpr]-- ^ args
      ,aggOrderBy :: [SortSpec] -- ^ order by
      ,aggFilter :: Maybe ScalarExpr -- ^ filter
      }
      -- | aggregates with within group
    | AggregateAppGroup
      {aggName :: [Name] -- ^ aggregate function name
      ,aggArgs :: [ScalarExpr] -- ^ args
      ,aggGroup :: [SortSpec] -- ^ within group
      }
      -- | window application, which adds over (partition by a order
      -- by b) to regular function application. Explicit frames are
      -- not currently supported
    | WindowApp
      {wnName :: [Name] -- ^ window function name
      ,wnArgs :: [ScalarExpr] -- ^ args
      ,wnPartition :: [ScalarExpr] -- ^ partition by
      ,wnOrderBy :: [SortSpec] -- ^ order by
      ,wnFrame :: Maybe Frame -- ^ frame clause
      }

      -- | Used for the operators which look like functions
      -- except the arguments are separated by keywords instead
      -- of commas. The maybe is for the first unnamed argument
      -- if it is present, and the list is for the keyword argument
      -- pairs.
    | SpecialOpK [Name] (Maybe ScalarExpr) [(Text,ScalarExpr)]

      -- | cast(a as typename)
    | Cast ScalarExpr TypeName

      -- | convert expression to given datatype @CONVERT(data_type(length), expression, style)@
    | Convert TypeName ScalarExpr (Maybe Integer)

      -- | case expression. both flavours supported
    | Case
      {caseTest :: Maybe ScalarExpr -- ^ test value
      ,caseWhens :: [([ScalarExpr],ScalarExpr)] -- ^ when branches
      ,caseElse :: Maybe ScalarExpr -- ^ else value
      }

    | Parens ScalarExpr

      -- | in list literal and in subquery, if the bool is false it
      -- means not in was used ('a not in (1,2)')
    | In Bool ScalarExpr InPredValue

      -- | exists, all, any, some subqueries
    | SubQueryExpr SubQueryExprType QueryExpr

    | QuantifiedComparison
            ScalarExpr
            [Name] -- operator
            CompPredQuantifier
            QueryExpr

    | Match ScalarExpr Bool -- true if unique
          QueryExpr
    | Array ScalarExpr [ScalarExpr] -- ^ represents an array
                                  -- access expression, or an array ctor
                                  -- e.g. a[3]. The first
                                  -- scalarExpr is the array, the
                                  -- second is the subscripts/ctor args
    | ArrayCtor QueryExpr -- ^ this is used for the query expression version of array constructors, e.g. array(select * from t)

{-
todo: special syntax for like, similar with escape - escape cannot go
in other places
-}

    --  | Escape ScalarExpr Char
    --  | UEscape ScalarExpr Char
    | Collate ScalarExpr [Name]
    | MultisetBinOp ScalarExpr SetOperatorName SetQuantifier ScalarExpr
    | MultisetCtor [ScalarExpr]
    | MultisetQueryCtor QueryExpr
    | NextValueFor [Name]
    | VEComment [Comment] ScalarExpr
    | OdbcLiteral OdbcLiteralType Text
      -- ^ an odbc literal e.g. {d '2000-01-01'}
    | OdbcFunc ScalarExpr
      -- ^ an odbc function call e.g. {fn CHARACTER_LENGTH('test')}
      deriving (Eq,Show,Read,Data,Typeable)

-- | Represents an identifier name, which can be quoted or unquoted.
-- examples:
--
-- * test -> Name Nothing "test"
-- * "test" -> Name (Just "\"","\"") "test"
-- * `something` -> Name (Just ("`","`") "something"
-- * [ms] -> Name (Just ("[","]") "ms"
data Name = Name (Maybe (Text,Text)) Text
            deriving (Eq,Show,Read,Data,Typeable)

-- | Represents a type name, used in casts.
data TypeName
    = TypeName [Name]
    | PrecTypeName [Name] Integer
    | PrecScaleTypeName [Name] Integer Integer
    | PrecLengthTypeName [Name] Integer (Maybe PrecMultiplier) (Maybe PrecUnits)
      -- precision, characterset, collate
    | CharTypeName [Name] (Maybe Integer) [Name] [Name]
    | TimeTypeName [Name] (Maybe Integer) Bool -- true == with time zone
    | RowTypeName [(Name,TypeName)]
    | IntervalTypeName IntervalTypeField (Maybe IntervalTypeField)
    | ArrayTypeName TypeName (Maybe Integer)
    | MultisetTypeName TypeName
      deriving (Eq,Show,Read,Data,Typeable)

data IntervalTypeField = Itf Text (Maybe (Integer, Maybe Integer))
                         deriving (Eq,Show,Read,Data,Typeable)

data Sign = Plus | Minus
            deriving (Eq,Show,Read,Data,Typeable)

data PrecMultiplier = PrecK | PrecM | PrecG | PrecT | PrecP
                      deriving (Eq,Show,Read,Data,Typeable)
data PrecUnits = PrecCharacters
               | PrecOctets
                deriving (Eq,Show,Read,Data,Typeable)

-- | Used for 'expr in (scalar expression list)', and 'expr in
-- (subquery)' syntax.
data InPredValue = InList [ScalarExpr]
                 | InQueryExpr QueryExpr
                   deriving (Eq,Show,Read,Data,Typeable)

-- not sure if scalar subquery, exists and unique should be represented like this

-- | A subquery in a scalar expression.
data SubQueryExprType
    = -- | exists (query expr)
      SqExists
      -- | unique (query expr)
    | SqUnique
      -- | a scalar subquery
    | SqSq
      deriving (Eq,Show,Read,Data,Typeable)

data CompPredQuantifier
    = CPAny
    | CPSome
    | CPAll
      deriving (Eq,Show,Read,Data,Typeable)

-- | Represents one field in an order by list.
data SortSpec = SortSpec ScalarExpr Direction NullsOrder
                deriving (Eq,Show,Read,Data,Typeable)

-- | Represents 'nulls first' or 'nulls last' in an order by clause.
data NullsOrder = NullsOrderDefault
                | NullsFirst
                | NullsLast
                  deriving (Eq,Show,Read,Data,Typeable)

-- | Represents the frame clause of a window
-- this can be [range | rows] frame_start
-- or [range | rows] between frame_start and frame_end
data Frame = FrameFrom FrameRows FramePos
           | FrameBetween FrameRows FramePos FramePos
             deriving (Eq,Show,Read,Data,Typeable)

-- | Represents whether a window frame clause is over rows or ranges.
data FrameRows = FrameRows | FrameRange
                 deriving (Eq,Show,Read,Data,Typeable)

-- | represents the start or end of a frame
data FramePos = UnboundedPreceding
              | Preceding ScalarExpr
              | Current
              | Following ScalarExpr
              | UnboundedFollowing
                deriving (Eq,Show,Read,Data,Typeable)


-- | the type of an odbc literal (e.g. {d '2000-01-01'}),
-- correpsonding to the letter after the opening {
data OdbcLiteralType = OLDate
                     | OLTime
                     | OLTimestamp
                       deriving (Eq,Show,Read,Data,Typeable)


-- | Represents a query expression, which can be:
--
-- * a regular select;
--
-- * a set operator (union, except, intersect);
--
-- * a common table expression (with);
--
-- * a table value constructor (values (1,2),(3,4)); or
--
-- * an explicit table (table t).
data QueryExpr
    = Select
      {qeSetQuantifier :: SetQuantifier
      ,qeSelectList :: [(ScalarExpr,Maybe Name)]
       -- ^ the expressions and the column aliases

{-
TODO: consider breaking this up. The SQL grammar has
queryexpr = select <select list> [<table expression>]
table expression = <from> [where] [groupby] [having] ...

This would make some things a bit cleaner?
-}

      ,qeFrom :: [TableRef]
      ,qeWhere :: Maybe ScalarExpr
      ,qeGroupBy :: [GroupingExpr]
      ,qeHaving :: Maybe ScalarExpr
      ,qeOrderBy :: [SortSpec]
      ,qeOffset :: Maybe ScalarExpr
      ,qeFetchFirst :: Maybe ScalarExpr
      }
    | QueryExprSetOp
      {qe0 :: QueryExpr
      ,qeCombOp :: SetOperatorName
      ,qeSetQuantifier :: SetQuantifier
      ,qeCorresponding :: Corresponding
      ,qe1 :: QueryExpr
      }
    | With
      {qeWithRecursive :: Bool
      ,qeViews :: [(Alias,QueryExpr)]
      ,qeQueryExpression :: QueryExpr}
    | Values [[ScalarExpr]]
    | Table [Name]
    | QueryExprParens QueryExpr
    | QEComment [Comment] QueryExpr
      deriving (Eq,Show,Read,Data,Typeable)

{-
TODO: add queryexpr parens to deal with e.g.
(select 1 union select 2) union select 3
I'm not sure if this is valid syntax or not.
-}

-- | Represents the Distinct or All keywords, which can be used
-- before a select list, in an aggregate/window function
-- application, or in a query expression set operator.
data SetQuantifier = SQDefault | Distinct | All deriving (Eq,Show,Read,Data,Typeable)

-- | The direction for a column in order by.
data Direction = DirDefault | Asc | Desc deriving (Eq,Show,Read,Data,Typeable)
-- | Query expression set operators.
data SetOperatorName = Union | Except | Intersect deriving (Eq,Show,Read,Data,Typeable)
-- | Corresponding, an option for the set operators.
data Corresponding = Corresponding | Respectively deriving (Eq,Show,Read,Data,Typeable)

-- | Represents an item in a group by clause.
data GroupingExpr
    = GroupingParens [GroupingExpr]
    | Cube [GroupingExpr]
    | Rollup [GroupingExpr]
    | GroupingSets [GroupingExpr]
    | SimpleGroup ScalarExpr
      deriving (Eq,Show,Read,Data,Typeable)

-- | Represents a entry in the csv of tables in the from clause.
data TableRef = -- | from t / from s.t
                TRSimple [Name]
                -- | from a join b, the bool is true if natural was used
              | TRJoin TableRef Bool JoinType TableRef (Maybe JoinCondition)
                -- | from (a)
              | TRParens TableRef
                -- | from a as b(c,d)
              | TRAlias TableRef Alias
                -- | from (query expr)
              | TRQueryExpr QueryExpr
                -- | from function(args)
              | TRFunction [Name] [ScalarExpr]
                -- | from lateral t
              | TRLateral TableRef
                -- | ODBC {oj t1 left outer join t2 on expr} syntax
              | TROdbc TableRef
                deriving (Eq,Show,Read,Data,Typeable)

-- | Represents an alias for a table valued expression, used in with
-- queries and in from alias, e.g. select a from t u, select a from t u(b),
-- with a(c) as select 1, select * from a.
data Alias = Alias Name (Maybe [Name])
             deriving (Eq,Show,Read,Data,Typeable)

-- | The type of a join.
data JoinType = JInner | JLeft | JRight | JFull | JCross
                deriving (Eq,Show,Read,Data,Typeable)

-- | The join condition.
data JoinCondition = JoinOn ScalarExpr -- ^ on expr
                   | JoinUsing [Name] -- ^ using (column list)
                     deriving (Eq,Show,Read,Data,Typeable)

-- ---------------------------

data Statement =
    -- ddl
    CreateSchema [Name]
  | DropSchema [Name] DropBehaviour
  | CreateTable [Name] [TableElement] Bool
  | AlterTable [Name] AlterTableAction
  | DropTable [Name] DropBehaviour
  | CreateIndex Bool [Name] [Name] [Name]
  | CreateView Bool [Name] (Maybe [Name])
        QueryExpr (Maybe CheckOption)
  | DropView [Name]  DropBehaviour
  | CreateDomain [Name] TypeName (Maybe ScalarExpr)
       [(Maybe [Name], ScalarExpr)]
  | AlterDomain [Name] AlterDomainAction
  | DropDomain [Name] DropBehaviour

    -- probably won't do character sets, collations
    -- and translations because I think they are too far from
    -- reality
  {-  | CreateCharacterSet
  | DropCharacterSet
  | CreateCollation
  | DropCollation
  | CreateTranslation
  | DropTranslation -}
  | CreateAssertion [Name] ScalarExpr
  | DropAssertion [Name] DropBehaviour
  {-   | CreateTrigger
  | DropTrigger
  | CreateType
  | AlterType
  | DropType
    -- routine stuff? TODO
  | CreateCast
  | DropCast
  | CreateOrdering
  | DropOrdering -}
    -- transforms
  | CreateSequence [Name] [SequenceGeneratorOption]
  | AlterSequence [Name] [SequenceGeneratorOption]
  | DropSequence [Name] DropBehaviour
    -- dml
  | SelectStatement QueryExpr
  {-    | DeclareCursor
  | OpenCursor
  | FetchCursor
  | CloseCursor
  | SelectInto -}
  --   | DeletePositioned
  | Delete [Name] (Maybe Name) (Maybe ScalarExpr)
  | Truncate [Name] IdentityRestart
  | Insert [Name] (Maybe [Name]) InsertSource
  --  | Merge
  | Update [Name] (Maybe Name) [SetClause] (Maybe ScalarExpr)
  {-  | TemporaryTable
  | FreeLocator
  | HoldLocator  -}
    -- access control
  | GrantPrivilege [PrivilegeAction] PrivilegeObject [Name] GrantOption
  | GrantRole [Name] [Name] AdminOption
  | CreateRole Name
  | DropRole Name
  | RevokePrivilege GrantOptionFor [PrivilegeAction] PrivilegeObject
            [Name] DropBehaviour
  | RevokeRole AdminOptionFor [Name] [Name] DropBehaviour
    -- transaction management
  | StartTransaction
  --  | SetTransaction
  --  | SetContraints
  | Savepoint Name
  | ReleaseSavepoint Name
  | Commit
  | Rollback (Maybe Name)
    -- session
  {-  | SetSessionCharacteristics
  | SetSessionAuthorization
  | SetRole
  | SetTimeZone
  | SetCatalog
  | SetSchema
  | SetNames
  | SetTransform
  | SetCollation -}
  | StatementComment [Comment]
  | EmptyStatement
    deriving (Eq,Show,Read,Data,Typeable)

data DropBehaviour =
    Restrict
  | Cascade
  | DefaultDropBehaviour
    deriving (Eq,Show,Read,Data,Typeable)

data IdentityRestart =
    ContinueIdentity
  | RestartIdentity
  | DefaultIdentityRestart
    deriving (Eq,Show,Read,Data,Typeable)

data InsertSource =
    InsertQuery QueryExpr
  | DefaultInsertValues
    deriving (Eq,Show,Read,Data,Typeable)

data SetClause =
    Set [Name] ScalarExpr
  | SetMultiple [[Name]] [ScalarExpr]
    deriving (Eq,Show,Read,Data,Typeable)

data TableElement =
    TableColumnDef ColumnDef
  | TableConstraintDef (Maybe [Name]) TableConstraint
    deriving (Eq,Show,Read,Data,Typeable)

data ColumnDef = ColumnDef Name (Maybe TypeName)
       [ColConstraintDef]
       -- (Maybe CollateClause)
    deriving (Eq,Show,Read,Data,Typeable)

data ColConstraintDef =
    ColConstraintDef (Maybe [Name]) ColConstraint
      -- (Maybe [ConstraintCharacteristics])
    deriving (Eq,Show,Read,Data,Typeable)

type AutoincrementClause = Bool

data ColConstraint =
    ColNullableConstraint
  | ColNotNullConstraint
  | ColUniqueConstraint
  | ColPrimaryKeyConstraint AutoincrementClause
  | ColReferencesConstraint [Name] (Maybe Name)
       ReferenceMatch
       ReferentialAction
       ReferentialAction
  | ColCheckConstraint ScalarExpr
  | ColDefaultClause DefaultClause
    deriving (Eq,Show,Read,Data,Typeable)

data TableConstraint =
    TableUniqueConstraint [Name]
  | TablePrimaryKeyConstraint [Name]
  | TableReferencesConstraint [Name] [Name] (Maybe [Name])
       ReferenceMatch
       ReferentialAction
       ReferentialAction
  | TableCheckConstraint ScalarExpr
    deriving (Eq,Show,Read,Data,Typeable)


data ReferenceMatch =
    DefaultReferenceMatch
  | MatchFull
  | MatchPartial
  | MatchSimple
    deriving (Eq,Show,Read,Data,Typeable)

data ReferentialAction =
    DefaultReferentialAction
  | RefCascade
  | RefSetNull
  | RefSetDefault
  | RefRestrict
  | RefNoAction
    deriving (Eq,Show,Read,Data,Typeable)

data AlterTableAction =
    AddColumnDef ColumnDef
  | AlterColumnSetDefault Name ScalarExpr
  | AlterColumnDropDefault Name
  | AlterColumnSetNotNull Name
  | AlterColumnDropNotNull Name
  | AlterColumnSetDataType Name TypeName
  {-  | AlterColumnAlterIdentity
  | AlterColumnDropIdentity
  | AlterColumnDropColumnGeneration-}
  | DropColumn Name DropBehaviour
  | AddTableConstraintDef (Maybe [Name]) TableConstraint
  --  | AlterTableConstraintDef
  | DropTableConstraintDef [Name] DropBehaviour
    deriving (Eq,Show,Read,Data,Typeable)

{-data ConstraintCharacteristics =
    ConstraintCharacteristics
        ConstraintCheckTime
        Deferrable
        ConstraintEnforcement
    deriving (Eq,Show,Read,Data,Typeable)

data ConstraintCheckTime =
    DefaultConstraintCheckTime
  | InitiallyDeferred
  | InitiallyImmeditate
    deriving (Eq,Show,Read,Data,Typeable)

data Deferrable =
    DefaultDefferable
  | Deferrable
  | NotDeferrable
    deriving (Eq,Show,Read,Data,Typeable)

data ConstraintEnforcement =
    DefaultConstraintEnforcement
  | Enforced
  | NotEnforced
    deriving (Eq,Show,Read,Data,Typeable) -}

{-data TableConstraintDef
    deriving (Eq,Show,Read,Data,Typeable) -}

data DefaultClause =
     DefaultClause ScalarExpr
   | IdentityColumnSpec IdentityWhen [SequenceGeneratorOption]
   | GenerationClause ScalarExpr
    deriving (Eq,Show,Read,Data,Typeable)

data IdentityWhen =
    GeneratedAlways
  | GeneratedByDefault
    deriving (Eq,Show,Read,Data,Typeable)

data SequenceGeneratorOption =
    SGODataType TypeName
  | SGOStartWith Integer
  | SGORestart (Maybe Integer)
  | SGOIncrementBy Integer
  | SGOMaxValue Integer
  | SGONoMaxValue
  | SGOMinValue Integer
  | SGONoMinValue
  | SGOCycle
  | SGONoCycle
    deriving (Eq,Show,Read,Data,Typeable)

data CheckOption =
    DefaultCheckOption
  | CascadedCheckOption
  | LocalCheckOption
    deriving (Eq,Show,Read,Data,Typeable)

data AlterDomainAction =
    ADSetDefault ScalarExpr
  | ADDropDefault
  | ADAddConstraint (Maybe [Name]) ScalarExpr
  | ADDropConstraint [Name]
    deriving (Eq,Show,Read,Data,Typeable)


data AdminOption = WithAdminOption | WithoutAdminOption
    deriving (Eq,Show,Read,Data,Typeable)

data GrantOption = WithGrantOption | WithoutGrantOption
    deriving (Eq,Show,Read,Data,Typeable)

data AdminOptionFor = AdminOptionFor | NoAdminOptionFor
    deriving (Eq,Show,Read,Data,Typeable)

data GrantOptionFor = GrantOptionFor | NoGrantOptionFor
    deriving (Eq,Show,Read,Data,Typeable)

data PrivilegeObject =
      PrivTable [Name]
    | PrivDomain [Name]
    | PrivType [Name]
    | PrivSequence [Name]
    | PrivFunction [Name]
    deriving (Eq,Show,Read,Data,Typeable)

data PrivilegeAction =
      PrivAll
    | PrivSelect [Name]
    | PrivDelete
    | PrivInsert [Name]
    | PrivUpdate [Name]
    | PrivReferences [Name]
    | PrivUsage
    | PrivTrigger
    | PrivExecute
    deriving (Eq,Show,Read,Data,Typeable)

-- | Comment. Useful when generating SQL code programmatically. The
-- parser doesn't produce these.
newtype Comment = BlockComment Text
               deriving (Eq,Show,Read,Data,Typeable)

data MakeSelect
    = MakeSelect
    {msSetQuantifier :: SetQuantifier
    ,msSelectList :: [(ScalarExpr,Maybe Name)]
    ,msFrom :: [TableRef]
    ,msWhere :: Maybe ScalarExpr
    ,msGroupBy :: [GroupingExpr]
    ,msHaving :: Maybe ScalarExpr
    ,msOrderBy :: [SortSpec]
    ,msOffset :: Maybe ScalarExpr
    ,msFetchFirst :: Maybe ScalarExpr
    }

-- | Helper/'default' value for query exprs to make creating query
-- expr values a little easier. It is defined like this:
--
-- > makeSelect :: MakeSelect
-- > makeSelect
-- >     = MakeSelect
-- >     {msSetQuantifier = SQDefault
-- >     ,msSelectList = []
-- >     ,msFrom = []
-- >     ,msWhere = Nothing
-- >     ,msGroupBy = []
-- >     ,msHaving = Nothing
-- >     ,msOrderBy = []
-- >     ,msOffset = Nothing
-- >     ,msFetchFirst = Nothing}
-- >
-- > Example, to create a select query expression with a select list 'sl':
-- >   toQueryExpr $ makeSelect {msSelectList = sl}

makeSelect :: MakeSelect
makeSelect
    = MakeSelect
    {msSetQuantifier = SQDefault
    ,msSelectList = []
    ,msFrom = []
    ,msWhere = Nothing
    ,msGroupBy = []
    ,msHaving = Nothing
    ,msOrderBy = []
    ,msOffset = Nothing
    ,msFetchFirst = Nothing}

toQueryExpr :: MakeSelect -> QueryExpr
toQueryExpr (MakeSelect q sl f w g h o ff fetch) = Select q sl f w g h o ff fetch