{- |
   Module     : Database.HDBI
   Copyright  : Copyright (C) 2005-2011 John Goerzen
   License    : BSD3

   Maintainer : Aleksey Uymanov <s9gf4ult@gmail.com>
   Stability  : experimental
   Portability: portable
 -}

module Database.HDBI
       (

-- | Welcome to HDBI, the Haskell Database Independed interface.  Written by
-- John Goerzen, jgoerzen\@complete.org, rewritten by Aleksey Uymanov
-- <s9gf4ult@gmail.com>

-- * Introduction

-- |HDBI provides an abstraction layer between Haskell programs and SQL
-- relational databases.  This lets you write database code once, in Haskell,
-- and have it work with any number of backend SQL databases (MySQL, Oracle,
-- PostgreSQL, ODBC-compliant databases, etc.)

-- * Design notes

-- | There is two typeclasses 'Connection' and 'Statement'. Each database driver
-- must provide it's own types (e.g. PostgreConnection and PostgreStatement in
-- HDBI-postgresql driver) and instances for them. Driver can provide additional
-- low-level functions not covered by these typeclasses.
--
-- There is also database-independent wrappers 'StmtWrapper' and 'ConnWrapper'
-- which are instances of 'Statement' and 'Connection' respectively. These
-- wrappers can hold database-specific type and call it's instance methods to
-- interact with database. You can still use low-level functions provided for
-- wrapped type by casting the wrapper back to the specific type by functions
-- 'castStatement' and 'castConnection'. Here is how it's look like:
--
-- @
--genericStmtLen :: StmtWrapper -> IO Int
--genericStmtLen stmt = do
--   executeRaw stmt
--   case castStatement stmt of
--     Nothing -> wrapperLen stmt
--     Just pgstmt -> pgLen pgstmt
--
--wrapperLen :: StmtWrapper -> IO Int
--wrapperLen stmt = length \<$\> fetchAllRows stmt
--
--pgLen :: PostgreStatement -> IO Int
--pgLen = undefined -- assume implementation is provided by driver, the fast
--                  -- PostgreSQL-specific way by ''ntuples'' low-level function. This
--                  -- feature is not included to 'Statement' typeclass because some
--                  -- databases have no such posibility.
-- @
--
-- You can see, that 'StmtWrapper' is still can be converted safely to
-- PostgreStatement, and if you pass PostgreStatement wrapped in StmtWrapper
-- function ''genericStmtLen'' will automatically use fast PostgreSQL
-- implementation. If it could not cast statement to specific type it will use
-- slow implementation based on 'Statement' methods.
--
-- There is also 'SqlValue' representing value from database's columns. This
-- type has a set of constructors each of them holds value of some type. There
-- is 'SqlUTCTime' for saving and fetching 'UTCTime' value from the database,
-- and 'SqlText' to save and get the text from database fields. You can execute
-- queries like this:
--
-- @
-- {-# LANGUAGE
--   OverloadedStrings
--  #-}
--
--module Main where
--
--import Database.HDBI
--import Database.HDBI.PostgreSQL
--import Control.Applicative
--import Data.Time
--import qualified Data.ByteString as B
--import qualified Data.Text.Lazy as TL
--
--insertTuples :: (Connection conn) => [(Int, TL.Text, UTCTime, B.ByteString)] -> conn -> IO ()
--insertTuples x conn = runMany conn
--                      \"insert into tupletbl (ifield, tfield, dtfield, bsfield) values (?,?,?,?)\"
--                      $ map (\(a, b, c, d) -> [ toSql a , toSql b , toSql c , toSql d]) x
-- @
--
-- Note, that you can still safely use ''?'' parameter placeholders inside the
-- query even with PostgreSQL, which use ''$1'' like placeholders.
--
-- There is also 'Query' type which is type-safe newtype wrapper around simple
-- lazy Text. You can write it literal, using ''-XOverloadedStrings'' extension.
--
-- We do not use String except inside 'SqlError', not 'Query' nor 'SqlText' does
-- not use String inside.

-- * Some kind of roadmap

-- |* Finish other hdbi drivers, like mysql and sqlite
--
-- * Unify the testing and benchmarking with one package.
--
-- * Create package hdbi-introspect with common interface to introspect and
-- change the schema. Also it will be necessary to create packages
-- hdbi-introspect-postgresql, hdbi-introspect-mysql and so on for each database
-- using specific methods to introspect and change the schema. This is the base
-- package for doing migrations like in Ruby on Rails.
--
-- * Create hdbi-resourcet and hdbi-conduit to provide convenient and reliable
-- way for finalizing statements and streaming processing the query results.
--
-- * Port other high-level database interfaces, like ''persistent'' and
-- ''haskelldb''. This will posibly lead to need to patch ''persistent'' and/or
-- ''haskelldb'' to support Decimal for example, or not. This is too earnly to
-- plan this in detail.

-- * Project scope

-- |* Provide common interface to execute queries and send/fetch data to/from
-- the database.
--
--  * Provide the type (''SqlValue'') to represent data which can be sent or fetched
--    from the database.
--
--  * Provide convenient way to convert Haskell-side data to database-side data
--  and vice versa. This is done with 'FromSql' and 'ToSql' instances.
--
--  * Give the most wide set of supported types, such as Decimal (arbitrary
--    precision values), Integer, Date and Time
--
--  * Safe interface with protection from re-release of resources. There must
--  not be errors, the more segafults, if you try to finish the statement when
--  the connection is already closed.
--
--  * Thread-safety.
--
--  * Concurrency. If database's low level client library provides concurrent
--  acces to one connection and/or statement then driver must support it. As
--  well as protect connection/statement from concurrent access if database does
--  not support it.
--
--  * To be clean, minimalistic, well-tested and correct base for other
--  higher-level packages.

-- * Out of scope

-- | * Database introspection: HDBI must not know how to introspect the
--    database. This problem must be solved with separate package
--    e.g. hdbi-introspect providing the common interface to introspect the
--    schema and drivers hdbi-introspect-postgresql, hdbi-introspect-mysql and
--    so on to provide database-specific implementation of this
--    interface. Current HDBI architecture allows to acces to low-levl
--    connection and statement functions. The mandatory Typeable instance for
--    any Connection and Statement instance allows to downcast any polymorphic
--    type to specific type and do whatever you need.
--
--  * Implicit transactions: if you want to work in transaction you must use
--    withTransaction function which correctly rollback the transaction on
--    exceptions.
--
--  * Lazy IO and resource management: to be short Conduit and ResourceT
--
--  * Any other things not related to query execution.

-- * Difference between HDBC and HDBI

-- |This is the rewritten HDBC with new features and better design. Here is the
-- difference between HDBC and HDBI:
--
--  * typeclass IConnection renamed to 'Connection' to be more Haskell-specific
--
--  * removed methods getTables and describeTable because they are not
--    compatible with project's goals.
--
--  * 'Statement' is not data but typeclass for now
--
--  * 'Connection' and 'Statement' instances must be 'Typeable' instances as
--    well. 'Typeable' let you to write database-independent code with
--    'ConnWrapper' and 'StmtWrapper' wrappers.
--
--  * 'ConnWrapper' and 'StmtWrapper' wrappers which can be downcasted to
--    specific 'Connection' or 'Statement' instance or used
--    directly. 'ConnWrapper' and 'StmtWrapper' are 'Connection' and 'Statement'
--    instances too
--
--  * 'SqlValue' constructors set is reduced.
--
--  * Removed any lazy IO operations.
--
--  * Fast parsers for date, time, timestamp and numbers. Written using 'attoparsec'.         

-- ** Differences in SqlValue

-- |New 'SqlValue' has just the munimum set of posible types which can be stored
-- on database side or fetched from the database.
--
--  * SqlString is replaced with SqlText which stores lazy text instead of
--    String. String is ineffective in memory and speed.
--
--  * SqlByteString is renamed to SqlBlob to be more verbal.
--
--  * SqlWord32, SqlWord64, SqlInt32, SqlInt64 are removed and replaced with one
--    SqlInteger.
--
--  * SqlChar is removed because this is the same as Text with one character,
--    and there is no special ''one char'' type.
--
--  * SqlRational is replaced with SqlDecimal because there is no one database
--    which has native Rational support. You can not to save any Rational value
--    to database and get back just the same. Decimal is more proper type to
--    represent database-level arbitrary precision value.
--
--  * SqlZonedLocalTimeOfDay is removed because there is no native support of
--    this type on database-level except the PostgreSQL. But the documentation
--    says, that this type is deprecated, difficult to use and must not be used
--    in new applications.
--
--  * SqlZonedTime, SqlPOSIXTime and SqlEpochTime are removed. They has
--    absolutely the same type on database side as SqlUTCTime. You can convert
--    PosixTime to UTCTime and vice versa explicitly, so there is no need in
--    this consturctors. No one database has native type storing ZoneInfo
--    directly, every database convert zoned datetime to utc format and apply
--    local server's timezone to convert utc back to zoned datetime when you
--    select this value. So SqlZonedTime is just the same as SqlUTCTime on
--    database side.
--
--  * SqlZonedTime and SqlDiffTime removed because no wide support of this types on
--    database level. In fact just PostgreSql. But maybe I am wrong.
--
--  * 'SqlUUID' is added because there is many databases supporting UUID
--  natively.

-- * Drivers

-- |Drivers must be implemented using clean and safe bindings. You must not use
-- C-hacks to interact with database client library, this is the binding's goal.
--
--  * HDBI-postgresql: use postgresql-libpq and postgresql-simple
--    bindings. PostgreSQL use ''$n'' (where ''n'' is parameter index)
--    placeholder for query parameters, but you can safely use ''?'' placeholder
--    like in other databases. HDBI-postgresql replaces ''?'' with sequential
--    ''$n'' placeholders before passing the query to database. You can also use
--    ''$n'' directly but will break portablility.

-- * Thread-safety

-- | All HDBI drivers must use thread safe MVars to store data, which can be
-- shared between threads.

-- * Reimported modules
         module Database.HDBI.SqlValue
       , module Database.HDBI.Types
       ) where


import Database.HDBI.SqlValue
import Database.HDBI.Types