Skip to content

Commit f2982e1

Browse files
committed
parse EXCLUDE constraints
1 parent d7474a4 commit f2982e1

File tree

3 files changed

+82
-1
lines changed

3 files changed

+82
-1
lines changed

IHP/IDE/SchemaDesigner/Parser.hs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ parseTableConstraint = do
141141
lexeme "CONSTRAINT"
142142
identifier
143143
(Left <$> parsePrimaryKeyConstraint) <|>
144-
(Right <$> (parseForeignKeyConstraint name <|> parseUniqueConstraint name <|> parseCheckConstraint name))
144+
(Right <$> (parseForeignKeyConstraint name <|> parseUniqueConstraint name <|> parseCheckConstraint name <|> parseExcludeConstraint name))
145145

146146
parsePrimaryKeyConstraint = do
147147
lexeme "PRIMARY"
@@ -172,6 +172,34 @@ parseCheckConstraint name = do
172172
checkExpression <- between (char '(' >> space) (char ')' >> space) expression
173173
pure CheckConstraint { name, checkExpression }
174174

175+
parseExcludeConstraint name = do
176+
lexeme "EXCLUDE"
177+
excludeElements <- between (char '(' >> space) (char ')' >> space) $ excludeElement `sepBy` (char ',' >> space)
178+
predicate <- optional do
179+
lexeme "WHERE"
180+
between (char '(' >> space) (char ')' >> space) expression
181+
pure ExcludeConstraint { name, excludeElements, predicate }
182+
where
183+
excludeElement = do
184+
element <- identifier
185+
space
186+
lexeme "WITH"
187+
space
188+
operator <- parseOperator
189+
pure ExcludeConstraintElement { element, operator }
190+
191+
parseOperator = choice $ map lexeme
192+
[ "="
193+
, "<>"
194+
, "!="
195+
, "<="
196+
, "<"
197+
, ">="
198+
, ">"
199+
, "AND"
200+
, "OR"
201+
]
202+
175203
parseOnDelete = choice
176204
[ (lexeme "NO" >> lexeme "ACTION") >> pure NoAction
177205
, (lexeme "RESTRICT" >> pure Restrict)

IHP/IDE/SchemaDesigner/Types.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,20 @@ data Constraint
124124
{ name :: !(Maybe Text)
125125
, checkExpression :: !Expression
126126
}
127+
| ExcludeConstraint
128+
{ name :: !(Maybe Text)
129+
, excludeElements :: ![ExcludeConstraintElement]
130+
, predicate :: !(Maybe Expression)
131+
}
127132
| AlterTableAddPrimaryKey
128133
{ name :: !(Maybe Text)
129134
, primaryKeyConstraint :: !PrimaryKeyConstraint
130135
}
131136
deriving (Eq, Show)
132137

138+
data ExcludeConstraintElement = ExcludeConstraintElement { element :: !Text, operator :: !Text }
139+
deriving (Eq, Show)
140+
133141
data Expression =
134142
-- | Sql string like @'hello'@
135143
TextExpression Text

Test/IDE/SchemaDesigner/ParserSpec.hs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,51 @@ tests = do
310310
}
311311
}
312312

313+
it "should parse ALTER TABLE .. ADD CONSTRAINT .. EXCLUDE .." do
314+
parseSql "ALTER TABLE posts ADD CONSTRAINT unique_title_by_author EXCLUDE (title WITH =, author WITH =);" `shouldBe` AddConstraint
315+
{ tableName = "posts"
316+
, constraint = ExcludeConstraint
317+
{ name = "unique_title_by_author"
318+
, excludeElements =
319+
[ ExcludeConstraintElement { element = "title", operator = "=" }
320+
, ExcludeConstraintElement { element = "author", operator = "=" }
321+
]
322+
, predicate = Nothing
323+
}
324+
}
325+
326+
it "should parse ALTER TABLE .. ADD CONSTRAINT .. EXCLUDE .. WHERE .." do
327+
parseSql "ALTER TABLE posts ADD CONSTRAINT unique_title_by_author EXCLUDE (title WITH =, author WITH =) WHERE (title = 'why');" `shouldBe` AddConstraint
328+
{ tableName = "posts"
329+
, constraint = ExcludeConstraint
330+
{ name = "unique_title_by_author"
331+
, excludeElements =
332+
[ ExcludeConstraintElement { element = "title", operator = "=" }
333+
, ExcludeConstraintElement { element = "author", operator = "=" }
334+
]
335+
, predicate = Just $ EqExpression (VarExpression "title") (TextExpression "why")
336+
}
337+
}
338+
339+
it "should parse ALTER TABLE .. ADD CONSTRAINT .. EXCLUDE .. WHERE .. with various operators" do
340+
parseSql "ALTER TABLE posts ADD CONSTRAINT unique_title_by_author EXCLUDE (i1 WITH =, i2 WITH <>, i3 WITH !=, i4 WITH <, i5 WITH <=, i6 WITH >, i7 WITH >=, i8 WITH AND, i9 WITH OR) WHERE (title = 'why');" `shouldBe` AddConstraint
341+
{ tableName = "posts"
342+
, constraint = ExcludeConstraint
343+
{ name = "unique_title_by_author"
344+
, excludeElements =
345+
[ ExcludeConstraintElement { element = "i1", operator = "=" }
346+
, ExcludeConstraintElement { element = "i2", operator = "<>" }
347+
, ExcludeConstraintElement { element = "i3", operator = "!=" }
348+
, ExcludeConstraintElement { element = "i4", operator = "<" }
349+
, ExcludeConstraintElement { element = "i5", operator = "<=" }
350+
, ExcludeConstraintElement { element = "i6", operator = ">" }
351+
, ExcludeConstraintElement { element = "i7", operator = ">=" }
352+
, ExcludeConstraintElement { element = "i8", operator = "AND" }
353+
, ExcludeConstraintElement { element = "i9", operator = "OR" }
354+
]
355+
, predicate = Just $ EqExpression (VarExpression "title") (TextExpression "why")
356+
}
357+
}
313358

314359
it "should parse CREATE TYPE .. AS ENUM" do
315360
parseSql "CREATE TYPE colors AS ENUM ('yellow', 'red', 'green');" `shouldBe` CreateEnumType { name = "colors", values = ["yellow", "red", "green"] }

0 commit comments

Comments
 (0)