ORDER BY support.

This commit is contained in:
Kei Hibino 2013-05-09 12:36:22 +09:00
parent 7824af3a78
commit c11310fc59
4 changed files with 43 additions and 15 deletions

View File

@ -21,4 +21,4 @@ import Database.Relational.Query.Projection
value, valueTrue, valueFalse, valueNull, placeholder) value, valueTrue, valueFalse, valueNull, placeholder)
import Database.Relational.Query.Relation (Relation) import Database.Relational.Query.Relation (Relation)
import Database.Relational.Query.Join import Database.Relational.Query.Join
import Database.Relational.Query.Type (Query, untypeQuery, toQuery) import Database.Relational.Query.Type (Query, untypeQuery, fromRelation)

View File

@ -2,7 +2,7 @@
module Database.Relational.Query.Join ( module Database.Relational.Query.Join (
QueryJoin, QueryJoin,
on, wheres, on, wheres, asc, desc,
table, table,
record, expr, compose, (>*<), (!), (!?), relation, record, expr, compose, (>*<), (!), (!?), relation,
@ -25,7 +25,7 @@ import qualified Database.Relational.Query.AliasId as AliasId
import Database.Relational.Query.Table (Table) import Database.Relational.Query.Table (Table)
import Database.Relational.Query.Sub (SubQuery) import Database.Relational.Query.Sub (SubQuery)
import Database.Relational.Query.Expr (Expr) import Database.Relational.Query.Expr (Expr, showExpr)
import qualified Database.Relational.Query.Expr as Expr import qualified Database.Relational.Query.Expr as Expr
import Database.Relational.Query.Product import Database.Relational.Query.Product
@ -37,17 +37,18 @@ import qualified Database.Relational.Query.Projection as Projection
import Database.Relational.Query.Pi (Pi) import Database.Relational.Query.Pi (Pi)
import Database.Relational.Query.Relation (Relation, finalizeRelation) import Database.Relational.Query.Relation (Relation, finalizeRelation, Order(Asc, Desc))
import qualified Database.Relational.Query.Relation as Relation import qualified Database.Relational.Query.Relation as Relation
data Context = Context data Context = Context
{ currentAliasId :: AliasId { currentAliasId :: AliasId
, product :: Maybe QueryProduct , product :: Maybe QueryProduct
, restriction :: Maybe (Expr Bool) , restriction :: Maybe (Expr Bool)
, orderByRev :: [(Order, String)]
} }
primContext :: Context primContext :: Context
primContext = Context primAlias Nothing Nothing primContext = Context primAlias Nothing Nothing []
nextAliasContext :: Context -> Context nextAliasContext :: Context -> Context
nextAliasContext s = s { currentAliasId = newAliasId (currentAliasId s) } nextAliasContext s = s { currentAliasId = newAliasId (currentAliasId s) }
@ -62,6 +63,10 @@ updateRestriction' e1 ctx =
where uf Nothing = e1 where uf Nothing = e1
uf (Just e0) = e0 `Expr.and` e1 uf (Just e0) = e0 `Expr.and` e1
updateOrderBy' :: Order -> Expr t -> Context -> Context
updateOrderBy' order e ctx =
ctx { orderByRev = ((order, showExpr e) :) . orderByRev $ ctx }
newtype QueryJoin a = newtype QueryJoin a =
QueryJoin { runQueryJoin :: Context -> (a, Context) } QueryJoin { runQueryJoin :: Context -> (a, Context) }
@ -89,6 +94,9 @@ updateJoinRestriction e = updateContext (updateProduct' d) where
updateRestriction :: Expr Bool -> QueryJoin () updateRestriction :: Expr Bool -> QueryJoin ()
updateRestriction e = updateContext (updateRestriction' e) updateRestriction e = updateContext (updateRestriction' e)
updateOrderBy :: Order -> Expr t -> QueryJoin ()
updateOrderBy order e = updateContext (updateOrderBy' order e)
on :: Expr Bool -> QueryJoin () on :: Expr Bool -> QueryJoin ()
on = updateJoinRestriction on = updateJoinRestriction
@ -96,6 +104,12 @@ on = updateJoinRestriction
wheres :: Expr Bool -> QueryJoin () wheres :: Expr Bool -> QueryJoin ()
wheres = updateRestriction wheres = updateRestriction
asc :: Expr t -> QueryJoin ()
asc = updateOrderBy Asc
desc :: Expr t -> QueryJoin ()
desc = updateOrderBy Desc
table :: Table r -> Relation r table :: Table r -> Relation r
table = Relation.fromTable table = Relation.fromTable
@ -157,7 +171,7 @@ from :: Table r -> QueryJoin (Projection r)
from = inner . table from = inner . table
relation :: QueryJoin (Projection r) -> Relation r relation :: QueryJoin (Projection r) -> Relation r
relation q = finalizeRelation projection product' (restriction st) where relation q = finalizeRelation projection product' (restriction st) (orderByRev st) where
(projection, st) = runQueryPrime q (projection, st) = runQueryPrime q
product' = maybe (error "relation: empty product!") Product.tree $ product st product' = maybe (error "relation: empty product!") Product.tree $ product st

View File

@ -1,6 +1,8 @@
{-# LANGUAGE OverloadedStrings #-}
module Database.Relational.Query.Relation ( module Database.Relational.Query.Relation (
Order (..),
Relation, Relation,
outer, outer,
@ -13,6 +15,7 @@ module Database.Relational.Query.Relation (
) where ) where
import Prelude hiding (product, and) import Prelude hiding (product, and)
import Data.List (foldl')
import Database.Relational.Query.AliasId (asColumnN) import Database.Relational.Query.AliasId (asColumnN)
@ -33,11 +36,14 @@ import Language.SQL.Keyword (Keyword(..), unwordsSQL)
import qualified Language.SQL.Keyword as SQL import qualified Language.SQL.Keyword as SQL
data Order = Asc | Desc
data Relation r = Table (Table r) data Relation r = Table (Table r)
| Relation | Relation
{ projection :: Projection r { projection :: Projection r
, product :: Product , product :: Product
, restriction :: Maybe (Expr Bool) , restriction :: Maybe (Expr Bool)
, orderByRev :: [(Order, String)]
} }
outer :: Relation r -> Relation (Maybe r) outer :: Relation r -> Relation (Maybe r)
@ -53,17 +59,23 @@ width = d where
fromTable :: Table r -> Relation r fromTable :: Table r -> Relation r
fromTable = Table fromTable = Table
composedSQL :: Projection r -> Product -> Maybe (Expr Bool) -> String composedSQL :: Projection r -> Product -> Maybe (Expr Bool) -> [(Order, String)] -> String
composedSQL pj pd re = composedSQL pj pd re odRev =
unwordsSQL unwordsSQL
$ [SELECT, columns' `SQL.sepBy` SQL.word ", ", $ [SELECT, columns' `SQL.sepBy` ", ",
FROM, SQL.word . productSQL $ pd ] FROM, SQL.word . productSQL $ pd]
++ wheres re ++ wheres re
++ orders
where columns' = zipWith where columns' = zipWith
(\f n -> SQL.word f `asColumnN` n) (\f n -> SQL.word f `asColumnN` n)
(Projection.columns pj) (Projection.columns pj)
[(0 :: Int)..] [(0 :: Int)..]
wheres = maybe [] (\e -> [WHERE, SQL.word . showExpr $ e]) wheres = maybe [] (\e -> [WHERE, SQL.word . showExpr $ e])
order Asc = ASC
order Desc = DESC
orderList = foldl' (\ r (o, e) -> [SQL.word e, order o] `SQL.sepBy` " " : r) [] odRev
orders | null odRev = []
| otherwise = [ORDER, BY, orderList `SQL.sepBy` ", "]
toSubQuery :: Relation r -> SubQuery toSubQuery :: Relation r -> SubQuery
toSubQuery = d where toSubQuery = d where
@ -72,10 +84,12 @@ toSubQuery = d where
(composedSQL (composedSQL
(projection rel) (projection rel)
(product rel) (product rel)
(restriction rel)) (restriction rel)
(orderByRev rel)
)
(width rel) (width rel)
finalizeRelation :: Projection r -> Product -> Maybe (Expr Bool) -> Relation r finalizeRelation :: Projection r -> Product -> Maybe (Expr Bool) -> [(Order, String)] -> Relation r
finalizeRelation = Relation finalizeRelation = Relation
toSQL :: Relation r -> String toSQL :: Relation r -> String

View File

@ -1,6 +1,6 @@
module Database.Relational.Query.Type ( module Database.Relational.Query.Type (
Query (untypeQuery), unsafeTypedQuery, toQuery Query (untypeQuery), unsafeTypedQuery, fromRelation
) where ) where
import Database.Relational.Query.Relation (Relation) import Database.Relational.Query.Relation (Relation)
@ -15,5 +15,5 @@ instance Show (Query p a) where
show = untypeQuery show = untypeQuery
toQuery :: Relation r -> Query p r fromRelation :: Relation r -> Query p r
toQuery = unsafeTypedQuery . Relation.toSQL fromRelation = unsafeTypedQuery . Relation.toSQL