content: {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE GADTs #-}
  {-# LANGUAGE RankNTypes #-}
  
  -- | WARNING
  --
  -- This module is introduced in version @3.5.0.0@ to provide a smooth migration
  -- experience from this legacy syntax to the new and improved syntax. If you've
  -- imported this module, it means you've decided to use the old syntax for
  -- a little bit longer, rather than migrate to the new stuff. That's fine!
  --
  -- But you should know that this module, and all of the legacy syntax, will be
  -- completely removed from the library in version @4.0.0.0@.
  --
  -- The @esqueleto@ EDSL (embedded domain specific language).
  -- This module replaces @Database.Persist@, so instead of
  -- importing that module you should just import this one:
  --
  -- @
  -- -- For a module using just esqueleto.
  -- import Database.Esqueleto
  -- @
  --
  -- If you need to use @persistent@'s default support for queries
  -- as well, either import it qualified:
  --
  -- @
  -- -- For a module that mostly uses esqueleto.
  -- import Database.Esqueleto
  -- import qualified Database.Persist as P
  -- @
  --
  -- or import @esqueleto@ itself qualified:
  --
  -- @
  -- -- For a module that uses esqueleto just on some queries.
  -- import Database.Persist
  -- import qualified Database.Esqueleto as E
  -- @
  --
  -- Other than identifier name clashes, @esqueleto@ does not
  -- conflict with @persistent@ in any way.
  module Database.Esqueleto.Legacy
    ( -- * Setup
      -- $setup
  
      -- * Introduction
      -- $introduction
  
      -- * Getting started
      -- $gettingstarted
  
      -- * @esqueleto@'s Language
      where_, on, groupBy, orderBy, asc, desc, limit, offset
               , distinct, distinctOn, don, distinctOnOrderBy, having, locking
               , (^.), (?.)
               , val, isNothing, just, just', nothing, joinV, joinV', withNonNull
               , countRows, count, countDistinct
               , not_, (==.), (>=.), (>.), (<=.), (<.), (!=.), (&&.), (||.)
               , between, (+.), (-.), (/.), (*.)
               , round_, ceiling_, floor_
               , min_, max_, sum_, avg_, castNum, castNumM
               , coalesce, coalesceDefault
               , lower_, upper_, trim_, ltrim_, rtrim_, length_, left_, right_
               , like, ilike, (%), concat_, (++.), castString
               , subList_select, valList, justList
               , in_, notIn, exists, notExists
               , set, (=.), (+=.), (-=.), (*=.), (/=.)
               , case_, toBaseId, fromBaseId, fromBaseIdMaybe, toBaseIdMaybe
    , subSelect
    , subSelectMaybe
    , subSelectCount
    , subSelectForeign
    , subSelectList
    , subSelectUnsafe
    , ToBaseId(..)
    , when_
    , then_
    , else_
    , from
    , Value(..)
    , ValueList(..)
    , OrderBy
    , DistinctOn
    , LockingKind(..)
    , forUpdate
    , forUpdateSkipLocked
    , LockableEntity(..)
    , SqlString
      -- ** Joins
    , InnerJoin(..)
    , CrossJoin(..)
    , LeftOuterJoin(..)
    , RightOuterJoin(..)
    , FullOuterJoin(..)
    , JoinKind(..)
    , OnClauseWithoutMatchingJoinException(..)
      -- * SQL backend
    , SqlQuery
    , SqlExpr
    , SqlEntity
    , select
    , selectOne
    , selectSource
    , delete
    , deleteCount
    , update
    , updateCount
    , insertSelect
    , insertSelectCount
    , (<#)
    , (<&>)
    -- ** Rendering Queries
    , renderQueryToText
    , renderQuerySelect
    , renderQueryUpdate
    , renderQueryDelete
    , renderQueryInsertInto
      -- * Internal.Language
    , From
      -- * RDBMS-specific modules
      -- $rdbmsSpecificModules
  
      -- * Helpers
    , valkey
    , valJ
    , associateJoin
  
      -- * Re-exports
      -- $reexports
    , deleteKey
    , module Database.Esqueleto.Internal.PersistentImport
    ) where
  
  import Database.Esqueleto.Internal.Internal
  import Database.Esqueleto.Internal.PersistentImport
  
  
  -- $setup
  --
  -- If you're already using @persistent@, then you're ready to use
  -- @esqueleto@, no further setup is needed.  If you're just
  -- starting a new project and would like to use @esqueleto@, take
  -- a look at @persistent@'s book first
  -- (<http://www.yesodweb.com/book/persistent>) to learn how to
  -- define your schema.
  
  
  ----------------------------------------------------------------------
  
  
  -- $introduction
  --
  -- The main goals of @esqueleto@ are to:
  --
  --   * Be easily translatable to SQL.  When you take a look at a
  --   @esqueleto@ query, you should be able to know exactly how
  --   the SQL query will end up.  (As opposed to being a
  --   relational algebra EDSL such as HaskellDB, which is
  --   non-trivial to translate into SQL.)
  --
  --   * Support the most widely used SQL features.  We'd like you to be
  --   able to use @esqueleto@ for all of your queries, no
  --   exceptions.  Send a pull request or open an issue on our
  --   project page (<https://github.com/prowdsponsor/esqueleto>) if
  --   there's anything missing that you'd like to see.
  --
  --   * Be as type-safe as possible.  We strive to provide as many
  --   type checks as possible.  If you get bitten by some invalid
  --   code that type-checks, please open an issue on our project
  --   page so we can take a look.
  --
  -- However, it is /not/ a goal to be able to write portable SQL.
  -- We do not try to hide the differences between DBMSs from you,
  -- and @esqueleto@ code that works for one database may not work
  -- on another.  This is a compromise we have to make in order to
  -- give you as much control over the raw SQL as possible without
  -- losing too much convenience.  This also means that you may
  -- type-check a query that doesn't work on your DBMS.
  
  
  ----------------------------------------------------------------------
  
  
  -- $gettingstarted
  --
  -- We like clean, easy-to-read EDSLs.  However, in order to
  -- achieve this goal we've used a lot of type hackery, leading to
  -- some hard-to-read type signatures.  On this section, we'll try
  -- to build some intuition about the syntax.
  --
  -- For the following examples, we'll use this example schema:
  --
  -- @
  -- share [mkPersist sqlSettings, mkMigrate \"migrateAll\"] [persist|
  --   Person
  --     name String
  --     age Int Maybe
  --     deriving Eq Show
  --   BlogPost
  --     title String
  --     authorId PersonId
  --     deriving Eq Show
  --   Follow
  --     follower PersonId
  --     followed PersonId
  --     deriving Eq Show
  -- |]
  -- @
  --
  -- Most of @esqueleto@ was created with @SELECT@ statements in
  -- mind, not only because they're the most common but also
  -- because they're the most complex kind of statement.  The most
  -- simple kind of @SELECT@ would be:
  --
  -- @
  -- SELECT *
  -- FROM Person
  -- @
  --
  -- In @esqueleto@, we may write the same query above as:
  --
  -- @
  -- do people <- 'select' $
  --              'from' $ \\person -> do
  --              return person
  --    liftIO $ mapM_ (putStrLn . personName . entityVal) people
  -- @
  --
  -- The expression above has type @SqlPersist m ()@, while
  -- @people@ has type @[Entity Person]@.  The query above will be
  -- translated into exactly the same query we wrote manually, but
  -- instead of @SELECT *@ it will list all entity fields (using
  -- @*@ is not robust).  Note that @esqueleto@ knows that we want
  -- an @Entity Person@ just because of the @personName@ that we're
  -- printing later.
  --
  -- However, most of the time we need to filter our queries using
  -- @WHERE@.  For example:
  --
  -- @
  -- SELECT *
  -- FROM Person
  -- WHERE Person.name = \"John\"
  -- @
  --
  -- In @esqueleto@, we may write the same query above as:
  --
  -- @
  -- 'select' $
  -- 'from' $ \\p -> do
  -- 'where_' (p '^.' PersonName '==.' 'val' \"John\")
  -- return p
  -- @
  --
  -- Although @esqueleto@'s code is a bit more noisy, it's has
  -- almost the same structure (save from the @return@).  The
  -- @('^.')@ operator is used to project a field from an entity.
  -- The field name is the same one generated by @persistent@'s
  -- Template Haskell functions.  We use 'val' to lift a constant
  -- Haskell value into the SQL query.
  --
  -- Another example would be:
  --
  -- @
  -- SELECT *
  -- FROM Person
  -- WHERE Person.age >= 18
  -- @
  --
  -- In @esqueleto@, we may write the same query above as:
  --
  -- @
  -- 'select' $
  -- 'from' $ \\p -> do
  -- 'where_' (p '^.' PersonAge '>=.' 'just' ('val' 18))
  -- return p
  -- @
  --
  -- Since @age@ is an optional @Person@ field, we use 'just' to lift
  -- @'val' 18 :: SqlExpr (Value Int)@ into @just ('val' 18) ::
  -- SqlExpr (Value (Maybe Int))@.
  --
  -- Implicit joins are represented by tuples.  For example, to get
  -- the list of all blog posts and their authors, we could write:
  --
  -- @
  -- SELECT BlogPost.*, Person.*
  -- FROM BlogPost, Person
  -- WHERE BlogPost.authorId = Person.id
  -- ORDER BY BlogPost.title ASC
  -- @
  --
  -- In @esqueleto@, we may write the same query above as:
  --
  -- @
  -- 'select' $
  -- 'from' $ \\(b, p) -> do
  -- 'where_' (b '^.' BlogPostAuthorId '==.' p '^.' PersonId)
  -- 'orderBy' ['asc' (b '^.' BlogPostTitle)]
  -- return (b, p)
  -- @
  --
  -- However, you may want your results to include people who don't
  -- have any blog posts as well using a @LEFT OUTER JOIN@:
  --
  -- @
  -- SELECT Person.*, BlogPost.*
  -- FROM Person LEFT OUTER JOIN BlogPost
  -- ON Person.id = BlogPost.authorId
  -- ORDER BY Person.name ASC, BlogPost.title ASC
  -- @
  --
  -- In @esqueleto@, we may write the same query above as:
  --
  -- @
  -- 'select' $
  -- 'from' $ \\(p `'LeftOuterJoin`` mb) -> do
  -- 'on' ('just' (p '^.' PersonId) '==.' mb '?.' BlogPostAuthorId)
  -- 'orderBy' ['asc' (p '^.' PersonName), 'asc' (mb '?.' BlogPostTitle)]
  -- return (p, mb)
  -- @
  --
  -- On a @LEFT OUTER JOIN@ the entity on the right hand side may
  -- not exist (i.e. there may be a @Person@ without any
  -- @BlogPost@s), so while @p :: SqlExpr (Entity Person)@, we have
  -- @mb :: SqlExpr (Maybe (Entity BlogPost))@.  The whole
  -- expression above has type @SqlPersist m [(Entity Person, Maybe
  -- (Entity BlogPost))]@.  Instead of using @(^.)@, we used
  -- @('?.')@ to project a field from a @Maybe (Entity a)@.
  --
  -- We are by no means limited to joins of two tables, nor by
  -- joins of different tables.  For example, we may want a list
  -- of the @Follow@ entity:
  --
  -- @
  -- SELECT P1.*, Follow.*, P2.*
  -- FROM Person AS P1
  -- INNER JOIN Follow ON P1.id = Follow.follower
  -- INNER JOIN Person AS P2 ON P2.id = Follow.followed
  -- @
  --
  -- In @esqueleto@, we may write the same query above as:
  --
  -- @
  -- 'select' $
  -- 'from' $ \\(p1 `'InnerJoin`` f `'InnerJoin`` p2) -> do
  -- 'on' (p1 '^.' PersonId '==.' f '^.' FollowFollower)
  -- 'on' (p2 '^.' PersonId '==.' f '^.' FollowFollowed)
  -- return (p1, f, p2)
  -- @
  --
  -- We also currently support @UPDATE@ and @DELETE@ statements.
  -- For example:
  --
  -- @
  -- do 'update' $ \\p -> do
  --      'set' p [ PersonName '=.' 'val' \"João\" ]
  --      'where_' (p '^.' PersonName '==.' 'val' \"Joao\")
  --    'delete' $
  --      'from' $ \\p -> do
  --      'where_' (p '^.' PersonAge '<.' 'just' ('val' 14))
  -- @
  --
  -- The results of queries can also be used for insertions.
  -- In @SQL@, we might write the following, inserting a new blog
  -- post for every user:
  --
  -- @
  -- INSERT INTO BlogPost
  -- SELECT ('Group Blog Post', id)
  -- FROM Person
  -- @
  --
  -- In @esqueleto@, we may write the same query above as:
  --
  -- @
  --  'insertSelect' $ 'from' $ \\p->
  --  return $ BlogPost '<#' \"Group Blog Post\" '<&>' (p '^.' PersonId)
  -- @
  --
  -- Individual insertions can be performed through Persistent's
  -- 'insert' function, reexported for convenience.
  
  
  ----------------------------------------------------------------------
  
  
  -- $reexports
  --
  -- We re-export many symbols from @persistent@ for convenince:
  --
  --  * \"Store functions\" from "Database.Persist".
  --
  --  * Everything from "Database.Persist.Class" except for
  --    @PersistQuery@ and @delete@ (use 'deleteKey' instead).
  --
  --  * Everything from "Database.Persist.Types" except for
  --    @Update@, @SelectOpt@, @BackendSpecificFilter@ and @Filter@.
  --
  --  * Everything from "Database.Persist.Sql" except for
  --    @deleteWhereCount@ and @updateWhereCount@.
  
  
  ----------------------------------------------------------------------
  
  
  -- $rdbmsSpecificModules
  --
  -- There are many differences between SQL syntax and functions
  -- supported by different RDBMSs.  Since version 2.2.8,
  -- @esqueleto@ includes modules containing functions that are
  -- specific to a given RDBMS.
  --
  --  * PostgreSQL: "Database.Esqueleto.PostgreSQL".
  --
  -- In order to use these functions, you need to explicitly import
  -- their corresponding modules, they're not re-exported here.
  