Skip to content

Commit

Permalink
Fixed parenthese not correctly applied in SQL Compiler. Fixes #1087
Browse files Browse the repository at this point in the history
  • Loading branch information
mpscholten committed Oct 7, 2021
1 parent f01ec32 commit 124defa
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 12 deletions.
34 changes: 24 additions & 10 deletions IHP/IDE/SchemaDesigner/Compiler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,35 @@ compileDefaultValue value = "DEFAULT " <> compileExpression value
compileExpression :: Expression -> Text
compileExpression (TextExpression value) = "'" <> value <> "'"
compileExpression (VarExpression name) = name
compileExpression (CallExpression func args) = func <> "(" <> intercalate ", " (map compileExpression args) <> ")"
compileExpression (CallExpression func args) = func <> "(" <> intercalate ", " (map compileExpressionWithOptionalParenthese args) <> ")"
compileExpression (NotEqExpression a b) = compileExpression a <> " <> " <> compileExpression b
compileExpression (EqExpression a b) = compileExpression a <> " = " <> compileExpression b
compileExpression (IsExpression a b) = compileExpression a <> " IS " <> compileExpression b
compileExpression (NotExpression a) = "NOT " <> compileExpression a
compileExpression (AndExpression a b) = compileExpression a <> " AND " <> compileExpression b
compileExpression (OrExpression a b) = "(" <> compileExpression a <> ") OR (" <> compileExpression b <> ")"
compileExpression (LessThanExpression a b) = compileExpression a <> " < " <> compileExpression b
compileExpression (LessThanOrEqualToExpression a b) = compileExpression a <> " <= " <> compileExpression b
compileExpression (GreaterThanExpression a b) = compileExpression a <> " > " <> compileExpression b
compileExpression (GreaterThanOrEqualToExpression a b) = compileExpression a <> " >= " <> compileExpression b
compileExpression (EqExpression a b) = compileExpressionWithOptionalParenthese a <> " = " <> compileExpressionWithOptionalParenthese b
compileExpression (IsExpression a b) = compileExpressionWithOptionalParenthese a <> " IS " <> compileExpressionWithOptionalParenthese b
compileExpression (NotExpression a) = "NOT " <> compileExpressionWithOptionalParenthese a
compileExpression (AndExpression a b) = compileExpressionWithOptionalParenthese a <> " AND " <> compileExpressionWithOptionalParenthese b
compileExpression (OrExpression a b) = compileExpressionWithOptionalParenthese a <> " OR " <> compileExpressionWithOptionalParenthese b
compileExpression (LessThanExpression a b) = compileExpressionWithOptionalParenthese a <> " < " <> compileExpressionWithOptionalParenthese b
compileExpression (LessThanOrEqualToExpression a b) = compileExpressionWithOptionalParenthese a <> " <= " <> compileExpressionWithOptionalParenthese b
compileExpression (GreaterThanExpression a b) = compileExpressionWithOptionalParenthese a <> " > " <> compileExpressionWithOptionalParenthese b
compileExpression (GreaterThanOrEqualToExpression a b) = compileExpressionWithOptionalParenthese a <> " >= " <> compileExpressionWithOptionalParenthese b
compileExpression (DoubleExpression double) = tshow double
compileExpression (IntExpression integer) = tshow integer
compileExpression (TypeCastExpression value type_) = compileExpression value <> "::" <> compilePostgresType type_

compileExpressionWithOptionalParenthese :: Expression -> Text
compileExpressionWithOptionalParenthese expr@(VarExpression {}) = compileExpression expr
compileExpressionWithOptionalParenthese expr@(IsExpression a (NotExpression b)) = compileExpression a <> " IS " <> compileExpression (NotExpression b) -- 'IS (NOT NULL)' => 'IS NOT NULL'
compileExpressionWithOptionalParenthese expr@(IsExpression {}) = compileExpression expr
compileExpressionWithOptionalParenthese expr@(EqExpression {}) = compileExpression expr
compileExpressionWithOptionalParenthese expr@(AndExpression a@(AndExpression {}) b ) = "(" <> compileExpression a <> " AND " <> compileExpressionWithOptionalParenthese b <> ")" -- '(a AND b) AND c' => 'a AND b AND C'
compileExpressionWithOptionalParenthese expr@(AndExpression a b@(AndExpression {}) ) = "(" <> compileExpressionWithOptionalParenthese a <> " AND " <> compileExpression b <> ")" -- 'a AND (b AND c)' => 'a AND b AND C'
--compileExpressionWithOptionalParenthese expr@(OrExpression a@(IsExpression {}) b ) = compileExpressionWithOptionalParenthese a <> " OR " <> compileExpressionWithOptionalParenthese b -- '(a IS NULL) OR b' => 'A IS NULL OR b'
compileExpressionWithOptionalParenthese expr@(CallExpression {}) = compileExpression expr
compileExpressionWithOptionalParenthese expr@(TextExpression {}) = compileExpression expr
compileExpressionWithOptionalParenthese expr@(IntExpression {}) = compileExpression expr
compileExpressionWithOptionalParenthese expr@(DoubleExpression {}) = compileExpression expr
compileExpressionWithOptionalParenthese expression = "(" <> compileExpression expression <> ")"

compareStatement (CreateEnumType {}) _ = LT
compareStatement (StatementCreateTable CreateTable {}) (AddConstraint {}) = LT
compareStatement (a@AddConstraint {}) (b@AddConstraint {}) = compare (get #constraintName a) (get #constraintName b)
Expand Down
9 changes: 7 additions & 2 deletions Test/IDE/SchemaDesigner/CompilerSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import IHP.IDE.SchemaDesigner.Compiler (compileSql)
import IHP.IDE.SchemaDesigner.Types
import IHP.ViewPrelude (cs, plain)
import qualified Text.Megaparsec as Megaparsec
import Test.IDE.SchemaDesigner.ParserSpec (col)
import Test.IDE.SchemaDesigner.ParserSpec (col, parseSql)

tests = do
describe "The Schema.sql Compiler" do
Expand Down Expand Up @@ -508,4 +508,9 @@ tests = do
(CallExpression "ihp_user_id" [])
)
}
compileSql [policy] `shouldBe` sql
compileSql [policy] `shouldBe` sql

it "should use parentheses where needed" do
-- https://github.com/digitallyinduced/ihp/issues/1087
let inputSql = cs [plain|ALTER TABLE listings ADD CONSTRAINT source CHECK ((NOT (user_id IS NOT NULL AND agent_id IS NOT NULL)) AND (user_id IS NOT NULL OR agent_id IS NOT NULL));\n|]
compileSql [parseSql inputSql] `shouldBe` inputSql

0 comments on commit 124defa

Please sign in to comment.