Merge branch 'speed'

This commit is contained in:
Joe Nelson
2014-11-02 00:44:57 -07:00
2 changed files with 26 additions and 29 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
name: dbapi name: dbapi
version: 0.2.4.2 version: 0.2.4.3
synopsis: The database is your api synopsis: The database is your api
license: MIT license: MIT
license-file: LICENSE license-file: LICENSE
+25 -28
View File
@@ -16,20 +16,19 @@ module PgQuery (
, DbRole , DbRole
) where ) where
import Data.Text (Text) import Data.Text (Text, splitOn, intercalate)
import Data.String.Conversions (cs) import Data.String.Conversions (cs)
import Data.Functor ( (<$>) ) import Data.Functor ( (<$>) )
import Data.Maybe (fromMaybe, mapMaybe) import Data.Maybe (fromMaybe, mapMaybe)
import Data.List (intersperse, intercalate)
import Data.List.Split (splitOn)
import Data.Monoid ((<>), mconcat) import Data.Monoid ((<>), mconcat)
import qualified Data.Map as M import qualified Data.Map as M
import Control.Monad (join, void) import Control.Monad (join)
import qualified RangeQuery as R import qualified RangeQuery as R
import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy as BL
import qualified Data.List as L
import Database.HDBC hiding (colType, colNullable) import Database.HDBC hiding (colType, colNullable)
import Database.HDBC.PostgreSQL import Database.HDBC.PostgreSQL
@@ -48,7 +47,7 @@ data RangedResult = RangedResult {
, rrBody :: BL.ByteString , rrBody :: BL.ByteString
} deriving (Show) } deriving (Show)
type QuotedSql = (String, [SqlValue]) type QuotedSql = (Text, [SqlValue])
type Schema = String type Schema = String
type DbRole = BS.ByteString type DbRole = BS.ByteString
@@ -68,7 +67,7 @@ getRows schema table qq range conn = do
<> whereClause qq <> whereClause qq
<> orderClause qq <> orderClause qq
<> limitClause range) <> limitClause range)
r <- quickQuery conn query [] r <- quickQuery conn (cs query) []
return $ case r of return $ case r of
[[total, _, SqlNull]] -> RangedResult offset 0 (fromSql total) "[]" [[total, _, SqlNull]] -> RangedResult offset 0 (fromSql total) "[]"
@@ -87,21 +86,21 @@ whereClause qs =
where where
cols = [ col | col <- qs, fst col `notElem` ["order"] ] cols = [ col | col <- qs, fst col `notElem` ["order"] ]
conjunction = mconcat $ intersperse (" and ", []) (map wherePred cols) conjunction = mconcat $ L.intersperse (" and ", []) (map wherePred cols)
orderClause :: Net.Query -> QuotedSql orderClause :: Net.Query -> QuotedSql
orderClause qs = do orderClause qs = do
let order = fromMaybe "" $ join $ lookup "order" qs let order = fromMaybe "" $ join $ lookup "order" qs
terms = mapMaybe parseOrderTerm $ splitOn "," $ cs order terms = mapMaybe parseOrderTerm $ splitOn "," $ cs order
termPred = mconcat $ intersperse (", ", []) (map orderTermSql terms) termPred = mconcat $ L.intersperse (", ", []) (map orderTermSql terms)
if null terms if null terms
then ("", []) then ("", [])
else (" order by ", []) <> termPred else (" order by ", []) <> termPred
where where
parseOrderTerm :: String -> Maybe OrderTerm parseOrderTerm :: Text -> Maybe OrderTerm
parseOrderTerm s = parseOrderTerm s =
case splitOn "." s of case splitOn "." s of
[d,c] -> [d,c] ->
@@ -116,8 +115,8 @@ orderClause qs = do
data OrderTerm = OrderTerm { data OrderTerm = OrderTerm {
otDirection :: String otDirection :: Text
, otColumn :: String , otColumn :: Text
} }
@@ -163,7 +162,7 @@ jsonArrayRows q =
insert :: Schema -> Text -> SqlRow -> Connection -> IO (M.Map String SqlValue) insert :: Schema -> Text -> SqlRow -> Connection -> IO (M.Map String SqlValue)
insert schema table row conn = do insert schema table row conn = do
sql <- populateSql conn $ insertClause schema table row sql <- populateSql conn $ insertClause schema table row
stmt <- prepare conn sql stmt <- prepare conn $ cs sql
_ <- execute stmt $ sqlRowValues row _ <- execute stmt $ sqlRowValues row
Just m <- fetchRowMap stmt Just m <- fetchRowMap stmt
return m return m
@@ -192,34 +191,34 @@ checkPass = validatePassword
upsert :: Schema -> Text -> SqlRow -> Net.Query -> Connection -> IO (M.Map String SqlValue) upsert :: Schema -> Text -> SqlRow -> Net.Query -> Connection -> IO (M.Map String SqlValue)
upsert schema table row qq conn = do upsert schema table row qq conn = do
sql <- populateSql conn $ upsertClause schema table row qq sql <- populateSql conn $ upsertClause schema table row qq
stmt <- prepare conn sql stmt <- prepare conn $ cs sql
_ <- execute stmt $ join $ replicate 2 $ sqlRowValues row _ <- execute stmt $ join $ replicate 2 $ sqlRowValues row
Just m <- fetchRowMap stmt Just m <- fetchRowMap stmt
return m return m
placeholders :: String -> SqlRow -> String placeholders :: Text -> SqlRow -> Text
placeholders symbol = intercalate ", " . map (const symbol) . getRow placeholders symbol = intercalate ", " . map (const symbol) . getRow
insertClause :: Schema -> Text -> SqlRow -> QuotedSql insertClause :: Schema -> Text -> SqlRow -> QuotedSql
insertClause schema table (SqlRow []) = insertClause schema table (SqlRow []) =
("insert into %I.%I default values returning *", [toSql schema, toSql table]) ("insert into %I.%I default values returning *", [toSql schema, toSql table])
insertClause schema table row = insertClause schema table row =
("insert into %I.%I (" ++ placeholders "%I" row ++ ")", ("insert into %I.%I (" <> placeholders "%I" row <> ")",
map toSql $ cs schema : table : sqlRowColumns row) map toSql $ cs schema : table : sqlRowColumns row)
<> (" values (" ++ placeholders "?" row ++ ") returning *", sqlRowValues row) <> (" values (" <> placeholders "?" row <> ") returning *", sqlRowValues row)
insertClauseViaSelect :: Schema -> Text -> SqlRow -> QuotedSql insertClauseViaSelect :: Schema -> Text -> SqlRow -> QuotedSql
insertClauseViaSelect schema table row = insertClauseViaSelect schema table row =
("insert into %I.%I (" ++ placeholders "%I" row ++ ")", ("insert into %I.%I (" <> placeholders "%I" row <> ")",
map toSql $ cs schema : table : sqlRowColumns row) map toSql $ cs schema : table : sqlRowColumns row)
<> (" select " ++ placeholders "?" row, sqlRowValues row) <> (" select " <> placeholders "?" row, sqlRowValues row)
updateClause :: Schema -> Text -> SqlRow -> QuotedSql updateClause :: Schema -> Text -> SqlRow -> QuotedSql
updateClause schema table row = updateClause schema table row =
("update %I.%I set (" ++ placeholders "%I" row ++ ")", ("update %I.%I set (" <> placeholders "%I" row <> ")",
map toSql $ cs schema : table : sqlRowColumns row) map toSql $ cs schema : table : sqlRowColumns row)
<> (" = (" ++ placeholders "?" row ++ ")", []) <> (" = (" <> placeholders "?" row <> ")", [])
upsertClause :: Schema -> Text -> SqlRow -> Net.Query -> QuotedSql upsertClause :: Schema -> Text -> SqlRow -> Net.Query -> QuotedSql
upsertClause schema table row qq = upsertClause schema table row qq =
@@ -228,21 +227,19 @@ upsertClause schema table row qq =
<> (" returning *) ", []) <> insertClauseViaSelect schema table row <> (" returning *) ", []) <> insertClauseViaSelect schema table row
<> (" where not exists (select * from upsert) returning *", []) <> (" where not exists (select * from upsert) returning *", [])
populateSql :: Connection -> QuotedSql -> IO String populateSql :: Connection -> QuotedSql -> IO Text
populateSql conn sql = do populateSql conn sql = do
[[escaped]] <- quickQuery conn q (snd sql) [[escaped]] <- quickQuery conn (cs q) (snd sql)
return $ fromSql escaped return $ fromSql escaped
where where
q = concat [ "select format('", fst sql, "', ", ph (snd sql), ")" ] q = mconcat [ "select format('", fst sql, "', ", ph (snd sql), ")" ]
ph :: [a] -> String ph :: [a] -> Text
ph = intercalate ", " . map (const "?::varchar") ph = intercalate ", " . map (const "?::varchar")
setRole :: Connection -> DbRole -> IO () setRole :: Connection -> DbRole -> IO ()
setRole conn role = do setRole conn role = runRaw conn $ "set role " <> cs role
query <- populateSql conn ("set role %I", [toSql role])
void $ run conn query []
resetRole :: Connection -> IO () resetRole :: Connection -> IO ()
resetRole conn = void $ run conn "reset role" [] resetRole conn = runRaw conn "reset role"