Skip to content

Commit 3aa4ba1

Browse files
committed
Fixed generated columns not normalized in migration generator causing bad migrations being generated
1 parent 2de4ac1 commit 3aa4ba1

File tree

6 files changed

+43
-4
lines changed

6 files changed

+43
-4
lines changed

IHP/IDE/CodeGen/MigrationGenerator.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ normalizeConstraint ForeignKeyConstraint { name, columnName, referenceTable, ref
395395
normalizeConstraint otherwise = otherwise
396396

397397
normalizeColumn :: CreateTable -> Column -> (Column, [Statement])
398-
normalizeColumn table Column { name, columnType, defaultValue, notNull, isUnique, generator } = (Column { name = normalizeName name, columnType = normalizeSqlType columnType, defaultValue = normalizedDefaultValue, notNull, isUnique = False, generator }, uniqueConstraint)
398+
normalizeColumn table Column { name, columnType, defaultValue, notNull, isUnique, generator } = (Column { name = normalizeName name, columnType = normalizeSqlType columnType, defaultValue = normalizedDefaultValue, notNull, isUnique = False, generator = normalizeColumnGenerator <$> generator }, uniqueConstraint)
399399
where
400400
uniqueConstraint =
401401
if isUnique
@@ -411,6 +411,9 @@ normalizeColumn table Column { name, columnType, defaultValue, notNull, isUnique
411411
then Nothing
412412
else Just (VarExpression "null") -- pg_dump columns don't have an explicit default null value
413413

414+
normalizeColumnGenerator :: ColumnGenerator -> ColumnGenerator
415+
normalizeColumnGenerator generator@(ColumnGenerator { generate }) = generator { generate = normalizeExpression generate }
416+
414417
normalizeExpression :: Expression -> Expression
415418
normalizeExpression e@(TextExpression {}) = e
416419
normalizeExpression (VarExpression var) = VarExpression (Text.toLower var)
@@ -427,6 +430,7 @@ normalizeExpression (GreaterThanExpression a b) = GreaterThanExpression (normali
427430
normalizeExpression (GreaterThanOrEqualToExpression a b) = GreaterThanOrEqualToExpression (normalizeExpression a) (normalizeExpression b)
428431
normalizeExpression e@(DoubleExpression {}) = e
429432
normalizeExpression e@(IntExpression {}) = e
433+
normalizeExpression (ConcatenationExpression a b) = ConcatenationExpression (normalizeExpression a) (normalizeExpression b)
430434
-- Enum default values from pg_dump always have an explicit type cast. Inside the Schema.sql they typically don't have those.
431435
-- Therefore we remove these typecasts here
432436
--

IHP/IDE/SchemaDesigner/Compiler.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ compilePostgresType (PNumeric Nothing _) = "NUMERIC"
161161
compilePostgresType (PVaryingN (Just limit)) = "CHARACTER VARYING(" <> show limit <> ")"
162162
compilePostgresType (PVaryingN Nothing) = "CHARACTER VARYING"
163163
compilePostgresType (PCharacterN length) = "CHARACTER(" <> show length <> ")"
164+
compilePostgresType PSingleChar = "\"char\""
164165
compilePostgresType PSerial = "SERIAL"
165166
compilePostgresType PBigserial = "BIGSERIAL"
166167
compilePostgresType PJSONB = "JSONB"

IHP/IDE/SchemaDesigner/Parser.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ sqlType = choice $ map optionalArray
228228
, inet
229229
, tsvector
230230
, trigger
231+
, singleChar
231232
, customType
232233
]
233234
where
@@ -347,6 +348,10 @@ sqlType = choice $ map optionalArray
347348
Just l -> pure (PCharacterN l)
348349
_ -> Prelude.fail "Failed to parse CHARACTER VARYING(..) expression"
349350

351+
singleChar = do
352+
try (symbol "\"char\"")
353+
pure PSingleChar
354+
350355
serial = do
351356
try (symbol' "SERIAL")
352357
pure PSerial

IHP/IDE/SchemaDesigner/Types.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ data PostgresType
196196
| PNumeric { precision :: Maybe Int, scale :: Maybe Int }
197197
| PVaryingN (Maybe Int)
198198
| PCharacterN Int
199+
| PSingleChar
199200
| PSerial
200201
| PBigserial
201202
| PJSONB

Test/IDE/CodeGeneration/MigrationGenerator.hs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -893,8 +893,36 @@ tests = do
893893

894894
diffSchemas targetSchema actualSchema `shouldBe` migration
895895

896+
it "should normalize generated columns" do
897+
let targetSchema = sql [i|
898+
CREATE TABLE products (
899+
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
900+
name TEXT NOT NULL,
901+
description TEXT NOT NULL,
902+
sku TEXT NOT NULL,
903+
text_search TSVECTOR GENERATED ALWAYS AS
904+
( setweight(to_tsvector('english', sku), 'A') ||
905+
setweight(to_tsvector('english', name), 'B') ||
906+
setweight(to_tsvector('english', description), 'C')
907+
) STORED
908+
);
909+
|]
910+
let actualSchema = sql [i|
911+
CREATE TABLE public.products (
912+
id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
913+
name text NOT NULL,
914+
description text NOT NULL,
915+
sku text NOT NULL,
916+
text_search tsvector GENERATED ALWAYS AS (((setweight(to_tsvector('english'::regconfig, sku), 'A'::"char") || setweight(to_tsvector('english'::regconfig, name), 'B'::"char")) || setweight(to_tsvector('english'::regconfig, description), 'C'::"char"))) STORED
917+
);
918+
|]
919+
let migration = sql [i|
920+
|]
921+
922+
diffSchemas targetSchema actualSchema `shouldBe` migration
923+
896924

897925
sql :: Text -> [Statement]
898926
sql code = case Megaparsec.runParser Parser.parseDDL "" code of
899-
Left parsingFailed -> error (tshow parsingFailed)
927+
Left parsingFailed -> error (cs $ Megaparsec.errorBundlePretty parsingFailed)
900928
Right r -> r

Test/IDE/SchemaDesigner/CompilerSpec.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ tests = do
677677
it "should compile 'GENERATED' columns" do
678678
let sql = [trimming|
679679
CREATE TABLE products (
680-
ts TSVECTOR GENERATED ALWAYS AS (setweight(to_tsvector('english', sku), 'A') || setweight(to_tsvector('english', name), 'B') || setweight(to_tsvector('english', description), 'C')) STORED
680+
ts TSVECTOR GENERATED ALWAYS AS (setweight(to_tsvector('english', sku), ('A'::"char")) || setweight(to_tsvector('english', name), 'B') || setweight(to_tsvector('english', description), 'C')) STORED
681681
);
682682
|] <> "\n"
683683
let statements = [
@@ -694,7 +694,7 @@ tests = do
694694
{ generate =
695695
ConcatenationExpression
696696
(ConcatenationExpression
697-
(CallExpression "setweight" [CallExpression "to_tsvector" [TextExpression "english",VarExpression "sku"],TextExpression "A"])
697+
(CallExpression "setweight" [CallExpression "to_tsvector" [TextExpression "english",VarExpression "sku"], TypeCastExpression (TextExpression "A") PSingleChar])
698698
(CallExpression "setweight" [CallExpression "to_tsvector" [TextExpression "english",VarExpression "name"],TextExpression "B"])
699699
)
700700
(CallExpression "setweight" [CallExpression "to_tsvector" [TextExpression "english",VarExpression "description"],TextExpression "C"])

0 commit comments

Comments
 (0)