@@ -56,64 +56,63 @@ data PGResult = PGSingle String
5656
5757-- | Takes PostgreSQL function signature and represent it as an algebraic data type.
5858parsePGFunction :: Text -> PGFunction
59- parsePGFunction s = either error id (parseOnly parseFunction s) where
59+ parsePGFunction s = either error id (parseOnly (ss *> function) s) where
6060 ss = skipSpace
6161
62- parseFunction = do
63- _ <- ss *> asciiCI " function"
64- schema <- ss *> ((parseIdentifier <* (char ' .' )) <|> (string " " ))
65- name <- ss *> parseIdentifier
66- args <- ss *> char ' (' *> (parseArgs `sepBy` (char ' ,' ))
67- ret <- ss *> char ' )' *> parseReturn
62+ function = do
63+ _ <- asciiCI " function"
64+ schema <- ss *> ((identifier <* (char ' .' )) <|> (string " " ))
65+ name <- ss *> identifier
66+ args <- ss *> char ' (' *> (arguments `sepBy` (char ' ,' ))
67+ ret <- ss *> char ' )' *> returnType
68+ _ <- ss
6869 return $ PGFunction (unpack schema) (unpack name) args ret
6970
70- parseArgs = do
71- name <- ss *> parseIdentifier
72- datatype <- ss *> parseType
71+ arguments = do
72+ name <- ss *> identifier
73+ datatype <- ss *> postgresType
7374 def <- ss *> ((asciiCI " default" <|> string " =" ) *> (takeTill (inClass " ,)" )) <|> (string " " ))
7475 -- WARNING: parsing default values requires ability to parse almost arbitraty expressions.
7576 -- Here is a quick and dirty implementation of the parser.
7677
7778 return $ PGArgument (unpack name) (unpack datatype) ((length def) > 0 )
7879
79- parseCols = do
80- name <- ss *> parseIdentifier
81- datatype <- ss *> parseType <* ss
80+ cols = do
81+ name <- ss *> identifier
82+ datatype <- ss *> postgresType <* ss
8283 return $ PGColumn (unpack name) (unpack datatype)
8384
84- parseReturn = do
85+ returnType = do
8586 ret <- ss *> asciiCI " returns" *> ss *> (
8687 asciiCI " setof"
8788 <|> asciiCI " table"
88- <|> parseType )
89+ <|> postgresType )
8990
9091 case toLower(ret) of
91- " setof" -> (PGSetOf . unpack) <$> (ss *> parseType )
92- " table" -> PGTable <$> (ss *> char ' (' *> parseCols `sepBy` (char ' ,' ) <* ss <* char ' )' )
92+ " setof" -> (PGSetOf . unpack) <$> (ss *> postgresType )
93+ " table" -> PGTable <$> (ss *> char ' (' *> cols `sepBy` (char ' ,' ) <* ss <* char ' )' )
9394 t -> return $ PGSingle (unpack t)
9495
95- parseIdentifier = do
96+ identifier = do
9697 s1 <- takeWhile1 (inClass " a-zA-Z_" )
9798 s2 <- takeWhile (inClass " a-zA-Z_0-9$" )
9899 return $ toLower $ s1 `append` s2
99100
100- parseType = toLower <$> (foldr1 (<|>) $
101+ postgresType = toLower <$> (foldr1 (<|>) $
101102 (map asciiCI [ " double precision" ])
102- ++ (map (\ t -> (asciiCI t <* ss <* (parseModifiers 1 ))) [" bit" , " character varying" ])
103- ++ (map (\ t -> (asciiCI t <* ss <* (parseModifiers 2 ))) [" numeric" , " decimal" ])
104- ++ (map parseTime [" timestamp" , " time" ])
105- ++ [parseInterval, parseIdentifier <* (parseModifiers 4 )])
106- -- WARNING: user defined types can have more complex modifiers.
107- -- The argument of parseModifiers might be a subject to change.
108-
109- parseTime t = do
110- base <- asciiCI t <* ss <* (parseModifiers 1 )
103+ ++ (map (\ t -> (asciiCI t <* ss <* (modifiers $ Just 1 ))) [" bit" , " character varying" ])
104+ ++ (map (\ t -> (asciiCI t <* ss <* (modifiers $ Just 2 ))) [" numeric" , " decimal" ])
105+ ++ (map timeType [" timestamp" , " time" ])
106+ ++ [intervalType, identifier <* (modifiers Nothing )])
107+
108+ timeType t = do
109+ base <- asciiCI t <* ss <* (modifiers $ Just 1 )
111110 tz <- ss *> ((asciiCI " with time zone" ) <|> (asciiCI " without time zone" ) <|> (string " " ))
112111 return $ case tz of
113112 " " -> base
114113 _ -> base `append` " " `append` tz
115114
116- parseInterval = do
115+ intervalType = do
117116 base <- (asciiCI " interval" ) <* ss
118117 fields <- foldr1 (<|>) $ map asciiCI [
119118 " year to month"
@@ -130,19 +129,22 @@ parsePGFunction s = either error id (parseOnly parseFunction s) where
130129 , " minute"
131130 , " second"
132131 , " " ]
133- _ <- ss *> (parseModifiers 1 )
132+ _ <- ss *> (modifiers $ Just 1 )
134133
135134 return $ case fields of
136135 " " -> base
137136 _ -> base `append` " " `append` fields
138137
139138
140- parseModifiers n = ((char ' (' ) *> (foldl (*>)
141- (ss *> (decimal :: Parser Int ) *> ss)
142- (replicate (n - 1 ) (char ' ,' *> ss *> (decimal :: Parser Int ) *> ss)))
143- *> (char ' )' ) *> (string " " ))
144- <|> (case n of
145- 1 -> (string " " )
146- _ -> (parseModifiers (n - 1 )))
139+ modifiers limit = (char ' (' ) *> exact <* (char ' )' ) <|> less where
140+ exact = ($ limit) $ maybe
141+ ((modifier `sepBy` (char ' ,' )) *> (string " " ))
142+ (\ n -> foldl1 ((*>) . (*> ((char ' ,' ) *> ss))) (replicate n modifier) *> string " " )
147143
144+ less = ($ limit) $ maybe
145+ (string " " )
146+ (\ n -> case n of
147+ 1 -> (string " " )
148+ _ -> (modifiers $ Just (n - 1 )))
148149
150+ modifier = (decimal :: Parser Int ) *> ss
0 commit comments