moved string packing to parsers

This commit is contained in:
Ruslan Talpa
2015-09-28 10:11:59 +03:00
parent 380cab6ca3
commit db13724131
3 changed files with 41 additions and 35 deletions
+10 -10
View File
@@ -8,6 +8,7 @@ import Data.List (find)
import Data.Monoid import Data.Monoid
import Data.Text hiding (filter, find, foldr, head, last, map, import Data.Text hiding (filter, find, foldr, head, last, map,
null) null)
import Data.Tree import Data.Tree
import PostgREST.PgQuery (PStmt, QualifiedIdentifier (..), fromQi, import PostgREST.PgQuery (PStmt, QualifiedIdentifier (..), fromQi,
orderT, pgFmtIdent, pgFmtLit, pgFmtOperator, orderT, pgFmtIdent, pgFmtLit, pgFmtOperator,
@@ -35,17 +36,16 @@ findRelation allRelations s t1 t2 =
filterToCondition :: Text -> [Column] -> Text -> Filter -> Either Text Condition filterToCondition :: Text -> [Column] -> Text -> Filter -> Either Text Condition
filterToCondition schema allColumns table (Filter fld op val) = filterToCondition schema allColumns table (Filter fld op val) =
Condition <$> c <*> pure op <*> pure (VText (pack val)) Condition <$> c <*> pure op <*> pure (VText val)
where where
c = (,) <$> column <*> pure (snd fld) c = (,) <$> column <*> pure (snd fld)
column = findColumn allColumns schema table $ pack $ fst fld column = findColumn allColumns schema table $ fst fld
requestNodeToQuery ::Text -> [Table] -> [Column] -> RequestNode -> Either Text Query requestNodeToQuery ::Text -> [Table] -> [Column] -> RequestNode -> Either Text Query
requestNodeToQuery schema allTables allColumns (RequestNode tblNameS flds fltrs ord) = requestNodeToQuery schema allTables allColumns (RequestNode tblName flds fltrs ord) =
Select <$> mainTable <*> select <*> joinTables <*> qwhere <*> rel <*> pure ord Select <$> mainTable <*> select <*> joinTables <*> qwhere <*> rel <*> pure ord
where where
tblName = pack tblNameS
mainTable = findTable allTables schema tblName mainTable = findTable allTables schema tblName
select = mapM toDbSelectItem flds --besides specific columns, we allow * here also select = mapM toDbSelectItem flds --besides specific columns, we allow * here also
where where
@@ -54,7 +54,7 @@ requestNodeToQuery schema allTables allColumns (RequestNode tblNameS flds fltrs
toDbSelectItem (("*", Nothing), Nothing) = Right ((Star{colSchema = schema, colTable = tblName}, Nothing), Nothing) toDbSelectItem (("*", Nothing), Nothing) = Right ((Star{colSchema = schema, colTable = tblName}, Nothing), Nothing)
toDbSelectItem ((c,jp), cast) = (,) <$> dbFld <*> pure cast toDbSelectItem ((c,jp), cast) = (,) <$> dbFld <*> pure cast
where where
col = findColumn allColumns schema tblName $ pack c col = findColumn allColumns schema tblName c
dbFld = (,) <$> col <*> pure jp dbFld = (,) <$> col <*> pure jp
qwhere = mapM (filterToCondition schema allColumns tblName) fltrs qwhere = mapM (filterToCondition schema allColumns tblName) fltrs
@@ -166,7 +166,7 @@ pgFmtCondition (Condition (col,jp) ops val) =
notOp <> " " <> pgFmtColumn col <> pgFmtJsonPath jp <> " " <> pgFmtOperator opCode <> " " <> notOp <> " " <> pgFmtColumn col <> pgFmtJsonPath jp <> " " <> pgFmtOperator opCode <> " " <>
if opCode `elem` ["is","isnot"] then whiteList (getInner val) else sqlValue if opCode `elem` ["is","isnot"] then whiteList (getInner val) else sqlValue
where where
headPredicate:rest = split (=='.') $ pack ops headPredicate:rest = split (=='.') ops
hasNot caseTrue caseFalse = if headPredicate == "not" then caseTrue else caseFalse hasNot caseTrue caseFalse = if headPredicate == "not" then caseTrue else caseFalse
opCode = hasNot (head rest) headPredicate opCode = hasNot (head rest) headPredicate
notOp = hasNot headPredicate "" notOp = hasNot headPredicate ""
@@ -183,8 +183,8 @@ pgFmtColumn Column {colSchema=s, colTable=t, colName=c} = pgFmtIdent s <> "." <>
pgFmtColumn Star {colSchema=s, colTable=t} = pgFmtIdent s <> "." <> pgFmtIdent t <> ".*" pgFmtColumn Star {colSchema=s, colTable=t} = pgFmtIdent s <> "." <> pgFmtIdent t <> ".*"
pgFmtJsonPath :: Maybe JsonPath -> Text pgFmtJsonPath :: Maybe JsonPath -> Text
pgFmtJsonPath (Just [x]) = "->>" <> pgFmtLit (pack x) pgFmtJsonPath (Just [x]) = "->>" <> pgFmtLit x
pgFmtJsonPath (Just (x:xs)) = "->" <> pgFmtLit (pack x) <> pgFmtJsonPath ( Just xs ) pgFmtJsonPath (Just (x:xs)) = "->" <> pgFmtLit x <> pgFmtJsonPath ( Just xs )
pgFmtJsonPath _ = "" pgFmtJsonPath _ = ""
pgFmtTable :: Table -> Text pgFmtTable :: Table -> Text
@@ -192,8 +192,8 @@ pgFmtTable Table{tableSchema=s, tableName=n} = fromQi $ QualifiedIdentifier s n
selectItemToStr :: DbSelectItem -> Text selectItemToStr :: DbSelectItem -> Text
selectItemToStr ((c, jp), Nothing) = pgFmtColumn c <> pgFmtJsonPath jp <> asJsonPath jp selectItemToStr ((c, jp), Nothing) = pgFmtColumn c <> pgFmtJsonPath jp <> asJsonPath jp
selectItemToStr ((c, jp), Just cast ) = "CAST (" <> pgFmtColumn c <> pgFmtJsonPath jp <> " AS " <> pack cast <> " )" <> asJsonPath jp selectItemToStr ((c, jp), Just cast ) = "CAST (" <> pgFmtColumn c <> pgFmtJsonPath jp <> " AS " <> cast <> " )" <> asJsonPath jp
asJsonPath :: Maybe JsonPath -> Text asJsonPath :: Maybe JsonPath -> Text
asJsonPath Nothing = "" asJsonPath Nothing = ""
asJsonPath (Just xx) = " AS " <> pack (last xx) asJsonPath (Just xx) = " AS " <> last xx
+24 -18
View File
@@ -8,7 +8,9 @@ import Control.Applicative
import Control.Monad (join) import Control.Monad (join)
import Data.List (delete, find) import Data.List (delete, find)
import Data.Maybe import Data.Maybe
import Data.Monoid
import Data.String.Conversions (cs) import Data.String.Conversions (cs)
import Data.Text (Text)
import Data.Tree import Data.Tree
import Network.Wai (Request, pathInfo, queryString) import Network.Wai (Request, pathInfo, queryString)
import PostgREST.Types import PostgREST.Types
@@ -27,7 +29,7 @@ parseGetRequest httpRequest =
selectStr = fromMaybe "*" $ fromMaybe (Just "*") $ lookup "select" qString --in case the parametre is missing or empty we default to * selectStr = fromMaybe "*" $ fromMaybe (Just "*") $ lookup "select" qString --in case the parametre is missing or empty we default to *
whereFilters = [ (k, fromJust v) | (k,v) <- qString, k `notElem` ["select", "order"], isJust v ] whereFilters = [ (k, fromJust v) | (k,v) <- qString, k `notElem` ["select", "order"], isJust v ]
pRequestSelect :: String -> Parser ApiRequest pRequestSelect :: Text -> Parser ApiRequest
pRequestSelect rootNodeName = do pRequestSelect rootNodeName = do
fieldTree <- pFieldForest fieldTree <- pFieldForest
return $ foldr treeEntry (Node (RequestNode rootNodeName [] [] Nothing) []) fieldTree return $ foldr treeEntry (Node (RequestNode rootNodeName [] [] Nothing) []) fieldTree
@@ -41,8 +43,8 @@ pRequestSelect rootNodeName = do
pRequestFilter :: (String, String) -> Either ParseError (Path, Filter) pRequestFilter :: (String, String) -> Either ParseError (Path, Filter)
pRequestFilter (k, v) = (,) <$> path <*> (Filter <$> fld <*> op <*> val) pRequestFilter (k, v) = (,) <$> path <*> (Filter <$> fld <*> op <*> val)
where where
treePath = parse pTreePath ("failed to parser tree path ("++k++")") k treePath = parse pTreePath ("failed to parser tree path (" ++ k ++ ")") k
opVal = parse pOpValueExp ("failed to parse filter ("++v++")") v opVal = parse pOpValueExp ("failed to parse filter (" ++ v ++ ")") v
path = fst <$> treePath path = fst <$> treePath
fld = snd <$> treePath fld = snd <$> treePath
op = fst <$> opVal op = fst <$> opVal
@@ -63,8 +65,8 @@ addFilter (path, flt) (Node rn forest) =
Just node -> (Just node, delete node forest) Just node -> (Just node, delete node forest)
where maybeNode = find ((name==).nodeName.rootLabel) forst where maybeNode = find ((name==).nodeName.rootLabel) forst
ws :: Parser String ws :: Parser Text
ws = many (oneOf " \t") ws = cs <$> many (oneOf " \t")
lexeme :: Parser a -> Parser a lexeme :: Parser a -> Parser a
lexeme p = ws *> p <* ws lexeme p = ws *> p <* ws
@@ -73,7 +75,10 @@ pTreePath :: Parser (Path,Field)
pTreePath = do pTreePath = do
p <- pFieldName `sepBy1` pDelimiter p <- pFieldName `sepBy1` pDelimiter
jp <- optionMaybe ( string "->" >> pJsonPath) jp <- optionMaybe ( string "->" >> pJsonPath)
return (init p, (last p, jp)) let pp = map cs p
jpp = map cs <$> jp
return (init pp, (last pp, jpp))
where
pFieldForest :: Parser [Tree SelectItem] pFieldForest :: Parser [Tree SelectItem]
@@ -83,17 +88,17 @@ pFieldTree :: Parser (Tree SelectItem)
pFieldTree = try (Node <$> pSelect <*> ( char '(' *> pFieldForest <* char ')')) pFieldTree = try (Node <$> pSelect <*> ( char '(' *> pFieldForest <* char ')'))
<|> Node <$> pSelect <*> pure [] <|> Node <$> pSelect <*> pure []
pStar :: Parser String pStar :: Parser Text
pStar = string "*" *> pure "*" pStar = cs <$> (string "*" *> pure ("*"::String))
pFieldName :: Parser String pFieldName :: Parser Text
pFieldName = many1 (letter <|> digit <|> oneOf "_") pFieldName = cs <$> (many1 (letter <|> digit <|> oneOf "_")
<?> "field name (* or [a..z0..9_])" <?> "field name (* or [a..z0..9_])")
pJsonPathDelimiter :: Parser String pJsonPathDelimiter :: Parser Text
pJsonPathDelimiter = try (string "->>") <|> string "->" pJsonPathDelimiter = cs <$> (try (string "->>") <|> string "->")
pJsonPath :: Parser [String] pJsonPath :: Parser [Text]
pJsonPath = pFieldName `sepBy1` pJsonPathDelimiter pJsonPath = pFieldName `sepBy1` pJsonPathDelimiter
pField :: Parser Field pField :: Parser Field
@@ -101,13 +106,13 @@ pField = lexeme $ (,) <$> pFieldName <*> optionMaybe ( pJsonPathDelimiter *> pJ
pSelect :: Parser SelectItem pSelect :: Parser SelectItem
pSelect = lexeme $ pSelect = lexeme $
try ((,) <$> pField <*> optionMaybe (string "::" *> many letter)) try ((,) <$> pField <*>((cs <$>) <$> optionMaybe (string "::" *> many letter)) )
<|> do <|> do
s <- pStar s <- pStar
return ((s, Nothing), Nothing) return ((s, Nothing), Nothing)
pOperator :: Parser Operator pOperator :: Parser Operator
pOperator = try (string "lte") -- has to be before lt pOperator = cs <$> ( try (string "lte") -- has to be before lt
<|> try (string "lt") <|> try (string "lt")
<|> try (string "eq") <|> try (string "eq")
<|> try (string "gte") -- has to be before gh <|> try (string "gte") -- has to be before gh
@@ -122,6 +127,7 @@ pOperator = try (string "lte") -- has to be before lt
<|> try (string "isnot") <|> try (string "isnot")
<|> try (string "@@") <|> try (string "@@")
<?> "operator (eq, gt, ...)" <?> "operator (eq, gt, ...)"
)
-- pInt :: Parser Int -- pInt :: Parser Int
-- pInt = try (liftA read (many1 digit)) <?> "integer" -- pInt = try (liftA read (many1 digit)) <?> "integer"
@@ -130,13 +136,13 @@ pOperator = try (string "lte") -- has to be before lt
--pValue = (VInt <$> try (pInt <* eof)) --pValue = (VInt <$> try (pInt <* eof))
-- <|>(VString <$> many anyChar) -- <|>(VString <$> many anyChar)
pValue :: Parser FValue pValue :: Parser FValue
pValue = many anyChar pValue = cs <$> many anyChar
pDelimiter :: Parser Char pDelimiter :: Parser Char
pDelimiter = char '.' <?> "delimiter (.)" pDelimiter = char '.' <?> "delimiter (.)"
pOperatiorWithNegation :: Parser Operator pOperatiorWithNegation :: Parser Operator
pOperatiorWithNegation = try ( (++) <$> string "not." <*> pOperator) <|> pOperator pOperatiorWithNegation = try ( (<>) <$> ( cs <$> string "not." ) <*> pOperator) <|> pOperator
pOpValueExp :: Parser (Operator, FValue) pOpValueExp :: Parser (Operator, FValue)
pOpValueExp = (,) <$> pOperatiorWithNegation <*> (pDelimiter *> pValue) pOpValueExp = (,) <$> pOperatiorWithNegation <*> (pDelimiter *> pValue)
+7 -7
View File
@@ -63,17 +63,17 @@ data Relation = Relation {
-------- --------
-- Request Types -- Request Types
type Operator = String type Operator = Text
type FValue = String type FValue = Text
type ApiRequest = Tree RequestNode type ApiRequest = Tree RequestNode
type FieldName = String type FieldName = Text
type JsonPath = [String] type JsonPath = [Text]
type Field = (FieldName, Maybe JsonPath) type Field = (FieldName, Maybe JsonPath)
type Cast = String type Cast = Text
type SelectItem = (Field, Maybe Cast) type SelectItem = (Field, Maybe Cast)
type Path = [String] type Path = [Text]
data RequestNode = RequestNode { data RequestNode = RequestNode {
nodeName::String nodeName::Text
, fields::[SelectItem] , fields::[SelectItem]
, filters::[Filter] , filters::[Filter]
, order::Maybe [OrderTerm] , order::Maybe [OrderTerm]