{-# LANGUAGE FlexibleInstances #-} ----------------------------------------------------------- -- | -- Module : HaskellDB -- Copyright : Daan Leijen (c) 1999, daan@cs.uu.nl -- HWT Group (c) 2003, haskelldb-users@lists.sourceforge.net -- License : BSD-style -- -- Maintainer : "Justin Bailey" -- Stability : experimental -- Portability : non portable -- -- HaskellDB is a Haskell library for expressing database queries and -- operations in a type safe and declarative way. HaskellDB compiles a -- relational algebra-like syntax into SQL, submits the operations to the -- database for processing, and returns the results as ordinary Haskell -- values. -- -- This is the main module that the user should -- import. Beside this module, the user should import a -- particular database binding (ie. "Database.HaskellDB.HSQL.ODBC") -- and database definitions. -- -- HaskellDB was originally written by Daan Leijen and it's -- design is described in the paper Domain Specific Embedded -- Compilers, Daan Leijen and Erik Meijer. 2nd USENIX -- Conference on Domain-Specific Languages (DSL), Austin, -- USA, October 1999 (). -- -- This new version of HaskellDB was produced as a student project at -- Chalmers University of Technology in Gothenburg, Sweden. The aim of the -- project was to make HaskellDB a practically useful database library. -- That work is described in -- Student Paper: HaskellDB Improved, -- Björn Bringert, Anders Höckersten, Conny Andersson, Martin Andersson, -- Mary Bergman, Victor Blomqvist and Torbjörn Martin. -- In Proceedings of the ACM SIGPLAN 2004 Haskell Workshop, Snowbird, Utah, -- USA, September 22, 2004. -- () -- ----------------------------------------------------------- module Database.HaskellDB ( Rel, Attr, Expr, ExprAggr, Table, Query, OrderExpr -- * Records , HasField, Record, Select, ( # ), ( << ), (<<-), (!), (!.) -- * Relational operators , restrict, table, project, unique , union, intersect, divide, minus , copy, copyAll, subQuery -- * Query expressions , (.==.) , (.<>.), (.<.), (.<=.), (.>.), (.>=.) , (.&&.) , (.||.) , (.*.) , (./.), (.+.), (.-.), (.%.), (.++.) , _not, like, _in, cat, _length , isNull, notNull, fromNull, fromVal , constant, constVal, constNull, constExpr , param, namedParam, Args, func , queryParams, Param, cast, coerce , literal, toStr , count, _sum, _max, _min, avg , stddev, stddevP, variance, varianceP , asc, desc, order , top , _case , _default -- * Database operations , Database -- abstract , query, recCat , insert, delete, update, insertQuery , tables, describe, transaction -- * Debugging , showQuery, showQueryUnOpt, showSql, showSqlUnOpt ) where import Database.HaskellDB.HDBRec -- PrimQuery type is imported so that haddock can find it. import Database.HaskellDB.PrimQuery (PrimQuery) import Database.HaskellDB.Sql (SqlSelect(SqlSelect, SqlBin), SqlExpr(..), SqlName) import qualified Database.HaskellDB.Sql as S (SqlSelect(..), Mark(..)) import Database.HaskellDB.Sql.Generate (sqlQuery) import Database.HaskellDB.Sql.Default (defaultSqlGenerator) import Database.HaskellDB.Sql.Print (ppSql) import Database.HaskellDB.Optimize (optimize) import Database.HaskellDB.Query import Database.HaskellDB.Database import Text.PrettyPrint.HughesPJ (Doc) import Data.Foldable (foldr') -- | Represents a query parameter. Left parameters are indexed -- by position, while right parameters are named. type Param = Either Int String -- | Shows the optimized SQL for the query. instance Show (Query (Rel r)) where showsPrec _ query = shows (showSql query) -- | Shows the optimized 'PrimQuery'. showQuery :: Query (Rel r) -> String showQuery = show . optimize . runQuery -- | Shows the unoptimized 'PrimQuery'. showQueryUnOpt :: Query (Rel r) -> String showQueryUnOpt = show . runQuery -- | Shows the optimized SQL query. showSql :: Query (Rel r) -> String showSql = show . ppSql . sqlQuery defaultSqlGenerator . optimize . runQuery -- | Shows the unoptimized SQL query. showSqlUnOpt :: Query (Rel r) -> String showSqlUnOpt = show . ppSql . sqlQuery defaultSqlGenerator . runQuery -- | Get paramaters from a query in order. queryParams :: Query (Rel r) -> [Param] queryParams q = snd . indexParams . selectParams . toSelect $ q where -- Use foldr so we don't have to reverse parameter list built. indexParams = foldr' renumber (1, []) renumber (Just n) (idx, ps) = (idx, Right n : ps) renumber Nothing (idx, ps) = (idx + 1, Left idx : ps) toSelect = sqlQuery defaultSqlGenerator . optimize . runQuery -- | All parameters that are in the select, in the textual order -- they will appear. selectParams :: SqlSelect -> [Maybe SqlName] selectParams select@(SqlSelect { S.attrs = a, S.tables = t, S.criteria = c, S.groupby = g, S.orderby = o}) = (attrParams a ++) . (tableParams t ++) . (criteriaParams c ++) . (groupByParams g ++) . orderByParams $ o where attrParams = getParams (exprParams . snd) tableParams = getParams (selectParams . snd) criteriaParams = getParams exprParams groupByParams Nothing = [] groupByParams (Just S.All) = [] groupByParams (Just (S.Columns cols)) = getParams (exprParams . snd) cols orderByParams = getParams (exprParams . fst) getParams :: (a -> [Maybe SqlName]) -> [a] -> [Maybe SqlName] getParams f = concatMap f -- | All parameters in the expression, in the textual order -- in which they will appear. exprParams :: SqlExpr -> [Maybe SqlName] exprParams (ColumnSqlExpr _) = [] exprParams (ConstSqlExpr _) = [] exprParams (ParamSqlExpr p _) = [p] exprParams (BinSqlExpr _ l r) = exprParams l ++ exprParams r exprParams (PrefixSqlExpr _ e) = exprParams e exprParams (PostfixSqlExpr _ e) = exprParams e exprParams (FunSqlExpr _ es) = (concatMap exprParams es) exprParams (AggrFunSqlExpr _ es) = (concatMap exprParams es) exprParams (CaseSqlExpr es e) = let caseExprs = concatMap (\(l, r) -> exprParams l ++ exprParams r) es in caseExprs ++ exprParams e exprParams (ListSqlExpr es) = concatMap exprParams es exprParams (ExistsSqlExpr select) = selectParams select exprParams PlaceHolderSqlExpr = [] exprParams (ParensSqlExpr e) = exprParams e exprParams (CastSqlExpr _ e) = exprParams e selectParams (SqlBin _ l r) = selectParams l ++ selectParams r selectParams _ = []