diff --git a/IHP/IDE/SchemaDesigner/Compiler.hs b/IHP/IDE/SchemaDesigner/Compiler.hs index 0315d06eb..fd102f492 100644 --- a/IHP/IDE/SchemaDesigner/Compiler.hs +++ b/IHP/IDE/SchemaDesigner/Compiler.hs @@ -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) diff --git a/Test/IDE/SchemaDesigner/CompilerSpec.hs b/Test/IDE/SchemaDesigner/CompilerSpec.hs index f14b6d375..f7247c63b 100644 --- a/Test/IDE/SchemaDesigner/CompilerSpec.hs +++ b/Test/IDE/SchemaDesigner/CompilerSpec.hs @@ -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 @@ -508,4 +508,9 @@ tests = do (CallExpression "ihp_user_id" []) ) } - compileSql [policy] `shouldBe` sql \ No newline at end of file + 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 \ No newline at end of file