Skip to content

Commit f5d0c20

Browse files
committed
Added support for GIN and GIST indexes
1 parent 3aa4ba1 commit f5d0c20

File tree

7 files changed

+104
-9
lines changed

7 files changed

+104
-9
lines changed

IHP/IDE/CodeGen/MigrationGenerator.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ normalizeStatement StatementCreateTable { unsafeGetCreateTable = table } = State
341341
normalizeStatement AddConstraint { tableName, constraint } = [ AddConstraint { tableName, constraint = normalizeConstraint constraint } ]
342342
normalizeStatement CreateEnumType { name, values } = [ CreateEnumType { name = Text.toLower name, values = map Text.toLower values } ]
343343
normalizeStatement CreatePolicy { name, action, tableName, using, check } = [ CreatePolicy { name, tableName, using = normalizeExpression <$> using, check = normalizeExpression <$> check, action = normalizePolicyAction action } ]
344-
normalizeStatement CreateIndex { expressions, .. } = [ CreateIndex { expressions = map normalizeExpression expressions, .. } ]
344+
normalizeStatement CreateIndex { expressions, indexType, .. } = [ CreateIndex { expressions = map normalizeExpression expressions, indexType = normalizeIndexType indexType, .. } ]
345345
normalizeStatement CreateFunction { .. } = [ CreateFunction { orReplace = False, .. } ]
346346
normalizeStatement otherwise = [otherwise]
347347

@@ -592,4 +592,8 @@ disableTransactionWhileAddingEnumValues statements =
592592
isAddEnumValueStatement otherwise = False
593593

594594
enableIfNotExists statement@(AddValueToEnumType { .. }) = statement { ifNotExists = True }
595-
enableIfNotExists otherwise = otherwise
595+
enableIfNotExists otherwise = otherwise
596+
597+
normalizeIndexType :: Maybe IndexType -> Maybe IndexType
598+
normalizeIndexType (Just Btree) = Nothing
599+
normalizeIndexType indexType = indexType

IHP/IDE/SchemaDesigner/Compiler.hs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ compileStatement DropColumn { tableName, columnName } = "ALTER TABLE " <> compil
3232
compileStatement RenameColumn { tableName, from, to } = "ALTER TABLE " <> compileIdentifier tableName <> " RENAME COLUMN " <> compileIdentifier from <> " TO " <> compileIdentifier to <> ";"
3333
compileStatement DropTable { tableName } = "DROP TABLE " <> compileIdentifier tableName <> ";"
3434
compileStatement Comment { content } = "--" <> content
35-
compileStatement CreateIndex { indexName, unique, tableName, expressions, whereClause } = "CREATE" <> (if unique then " UNIQUE " else " ") <> "INDEX " <> indexName <> " ON " <> tableName <> " (" <> (intercalate ", " (map compileExpression expressions)) <> ")" <> (case whereClause of Just expression -> " WHERE " <> compileExpression expression; Nothing -> "") <> ";"
35+
compileStatement CreateIndex { indexName, unique, tableName, expressions, whereClause, indexType } = "CREATE" <> (if unique then " UNIQUE " else " ") <> "INDEX " <> indexName <> " ON " <> tableName <> (maybe "" (\indexType -> " USING " <> compileIndexType indexType) indexType) <> " (" <> (intercalate ", " (map compileExpression expressions)) <> ")" <> (case whereClause of Just expression -> " WHERE " <> compileExpression expression; Nothing -> "") <> ";"
3636
compileStatement CreateFunction { functionName, functionBody, orReplace, returns, language } = "CREATE " <> (if orReplace then "OR REPLACE " else "") <> "FUNCTION " <> functionName <> "() RETURNS " <> compilePostgresType returns <> " AS $$" <> functionBody <> "$$ language " <> language <> ";"
3737
compileStatement EnableRowLevelSecurity { tableName } = "ALTER TABLE " <> tableName <> " ENABLE ROW LEVEL SECURITY;"
3838
compileStatement CreatePolicy { name, action, tableName, using, check } = "CREATE POLICY " <> compileIdentifier name <> " ON " <> compileIdentifier tableName <> maybe "" (\action -> " FOR " <> compilePolicyAction action) action <> maybe "" (\expr -> " USING (" <> compileExpression expr <> ")") using <> maybe "" (\expr -> " WITH CHECK (" <> compileExpression expr <> ")") check <> ";"
@@ -450,4 +450,9 @@ compileGenerator ColumnGenerator { generate, stored } =
450450
"GENERATED ALWAYS AS ("
451451
<> compileExpressionWithOptionalParenthese generate
452452
<> ")"
453-
<> (if stored then " STORED" else "")
453+
<> (if stored then " STORED" else "")
454+
455+
compileIndexType :: IndexType -> Text
456+
compileIndexType Gin = "GIN"
457+
compileIndexType Btree = "BTREE"
458+
compileIndexType Gist = "GIST"

IHP/IDE/SchemaDesigner/Parser.hs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,15 +507,20 @@ createIndex = do
507507
indexName <- identifier
508508
lexeme "ON"
509509
tableName <- qualifiedIdentifier
510-
optional do
510+
indexType <- optional do
511511
lexeme "USING"
512-
lexeme "btree"
512+
513+
let btree = do symbol' "btree"; pure Btree
514+
let gin = do symbol' "gin"; pure Gin
515+
let gist = do symbol' "gist"; pure Gist
516+
517+
btree <|> gin <|> gist
513518
expressions <- between (char '(' >> space) (char ')' >> space) (expression `sepBy1` (char ',' >> space))
514519
whereClause <- optional do
515520
lexeme "WHERE"
516521
expression
517522
char ';'
518-
pure CreateIndex { indexName, unique, tableName, expressions, whereClause }
523+
pure CreateIndex { indexName, unique, tableName, expressions, whereClause, indexType }
519524

520525
createFunction = do
521526
lexeme "CREATE"

IHP/IDE/SchemaDesigner/SchemaOperations.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ newForeignKeyIndex tableName columnName =
101101
, tableName
102102
, expressions = [VarExpression columnName]
103103
, whereClause = Nothing
104+
, indexType = Nothing
104105
}
105106

106107
appendStatement :: Statement -> [Statement] -> [Statement]
@@ -116,7 +117,7 @@ addForeignKeyConstraint :: Text -> Text -> Text -> Text -> OnDelete -> [Statemen
116117
addForeignKeyConstraint tableName columnName constraintName referenceTable onDelete list = list <> [AddConstraint { tableName = tableName, constraint = ForeignKeyConstraint { name = Just constraintName, columnName = columnName, referenceTable = referenceTable, referenceColumn = "id", onDelete = (Just onDelete) } }]
117118

118119
addTableIndex :: Text -> Bool -> Text -> [Text] -> [Statement] -> [Statement]
119-
addTableIndex indexName unique tableName columnNames list = list <> [CreateIndex { indexName, unique, tableName, expressions = map VarExpression columnNames, whereClause = Nothing }]
120+
addTableIndex indexName unique tableName columnNames list = list <> [CreateIndex { indexName, unique, tableName, expressions = map VarExpression columnNames, whereClause = Nothing, indexType = Nothing }]
120121

121122
-- | An enum is added after all existing enum statements, but right before @CREATE TABLE@ statements
122123
addEnum :: Text -> Schema -> Schema

IHP/IDE/SchemaDesigner/Types.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ data Statement
3131
| Comment { content :: Text }
3232
-- | CREATE INDEX indexName ON tableName (columnName); CREATE INDEX indexName ON tableName (LOWER(columnName));
3333
-- | CREATE UNIQUE INDEX name ON table (column [, ...]);
34-
| CreateIndex { indexName :: Text, unique :: Bool, tableName :: Text, expressions :: [Expression], whereClause :: Maybe Expression }
34+
| CreateIndex { indexName :: Text, unique :: Bool, tableName :: Text, expressions :: [Expression], whereClause :: Maybe Expression, indexType :: Maybe IndexType }
3535
-- | DROP INDEX indexName;
3636
| DropIndex { indexName :: Text }
3737
-- | CREATE OR REPLACE FUNCTION functionName() RETURNS TRIGGER AS $$functionBody$$ language plpgsql;
@@ -231,4 +231,7 @@ data PolicyAction
231231
| PolicyForInsert
232232
| PolicyForUpdate
233233
| PolicyForDelete
234+
deriving (Eq, Show)
235+
236+
data IndexType = Btree | Gin | Gist
234237
deriving (Eq, Show)

Test/IDE/SchemaDesigner/CompilerSpec.hs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,43 @@ tests = do
422422
, tableName = "users"
423423
, expressions = [VarExpression "user_name"]
424424
, whereClause = Nothing
425+
, indexType = Nothing
426+
}
427+
compileSql [statement] `shouldBe` sql
428+
429+
it "should compile a 'CREATE INDEX .. ON .. USING GIN' statement" do
430+
let sql = cs [plain|CREATE INDEX users_index ON users USING GIN (user_name);\n|]
431+
let statement = CreateIndex
432+
{ indexName = "users_index"
433+
, unique = False
434+
, tableName = "users"
435+
, expressions = [VarExpression "user_name"]
436+
, whereClause = Nothing
437+
, indexType = Just Gin
438+
}
439+
compileSql [statement] `shouldBe` sql
440+
441+
it "should compile a 'CREATE INDEX .. ON .. USING BTREE' statement" do
442+
let sql = cs [plain|CREATE INDEX users_index ON users USING BTREE (user_name);\n|]
443+
let statement = CreateIndex
444+
{ indexName = "users_index"
445+
, unique = False
446+
, tableName = "users"
447+
, expressions = [VarExpression "user_name"]
448+
, whereClause = Nothing
449+
, indexType = Just Btree
450+
}
451+
compileSql [statement] `shouldBe` sql
452+
453+
it "should compile a 'CREATE INDEX .. ON .. USING GIST' statement" do
454+
let sql = cs [plain|CREATE INDEX users_index ON users USING GIST (user_name);\n|]
455+
let statement = CreateIndex
456+
{ indexName = "users_index"
457+
, unique = False
458+
, tableName = "users"
459+
, expressions = [VarExpression "user_name"]
460+
, whereClause = Nothing
461+
, indexType = Just Gist
425462
}
426463
compileSql [statement] `shouldBe` sql
427464

@@ -433,6 +470,7 @@ tests = do
433470
, tableName = "users"
434471
, expressions = [VarExpression "user_name", VarExpression "project_id"]
435472
, whereClause = Nothing
473+
, indexType = Nothing
436474
}
437475
compileSql [statement] `shouldBe` sql
438476

@@ -444,6 +482,7 @@ tests = do
444482
, tableName = "users"
445483
, expressions = [CallExpression "LOWER" [VarExpression "email"]]
446484
, whereClause = Nothing
485+
, indexType = Nothing
447486
}
448487
compileSql [statement] `shouldBe` sql
449488

@@ -455,6 +494,7 @@ tests = do
455494
, tableName = "users"
456495
, expressions = [VarExpression "user_name"]
457496
, whereClause = Nothing
497+
, indexType = Nothing
458498
}
459499
compileSql [statement] `shouldBe` sql
460500

@@ -510,6 +550,7 @@ tests = do
510550
AndExpression
511551
(IsExpression (VarExpression "source") (NotExpression (VarExpression "NULL")))
512552
(IsExpression (VarExpression "source_id") (NotExpression (VarExpression "NULL"))))
553+
, indexType = Nothing
513554
}
514555
compileSql [index] `shouldBe` sql
515556

Test/IDE/SchemaDesigner/ParserSpec.hs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,14 +476,47 @@ tests = do
476476
, tableName = "users"
477477
, expressions = [VarExpression "user_name"]
478478
, whereClause = Nothing
479+
, indexType = Nothing
479480
}
481+
482+
it "should parse a 'CREATE INDEX .. ON .. USING GIN' statement" do
483+
parseSql "CREATE INDEX users_index ON users USING GIN (user_name);\n" `shouldBe` CreateIndex
484+
{ indexName = "users_index"
485+
, unique = False
486+
, tableName = "users"
487+
, expressions = [VarExpression "user_name"]
488+
, whereClause = Nothing
489+
, indexType = Just Gin
490+
}
491+
492+
it "should parse a 'CREATE INDEX .. ON .. USING btree' statement" do
493+
parseSql "CREATE INDEX users_index ON users USING btree (user_name);\n" `shouldBe` CreateIndex
494+
{ indexName = "users_index"
495+
, unique = False
496+
, tableName = "users"
497+
, expressions = [VarExpression "user_name"]
498+
, whereClause = Nothing
499+
, indexType = Just Btree
500+
}
501+
502+
it "should parse a 'CREATE INDEX .. ON .. USING GIST' statement" do
503+
parseSql "CREATE INDEX users_index ON users USING GIST (user_name);\n" `shouldBe` CreateIndex
504+
{ indexName = "users_index"
505+
, unique = False
506+
, tableName = "users"
507+
, expressions = [VarExpression "user_name"]
508+
, whereClause = Nothing
509+
, indexType = Just Gist
510+
}
511+
480512
it "should parse a CREATE INDEX statement with multiple columns" do
481513
parseSql "CREATE INDEX users_index ON users (user_name, project_id);\n" `shouldBe` CreateIndex
482514
{ indexName = "users_index"
483515
, unique = False
484516
, tableName = "users"
485517
, expressions = [VarExpression "user_name", VarExpression "project_id"]
486518
, whereClause = Nothing
519+
, indexType = Nothing
487520
}
488521
it "should parse a CREATE INDEX statement with a LOWER call" do
489522
parseSql "CREATE INDEX users_email_index ON users (LOWER(email));\n" `shouldBe` CreateIndex
@@ -492,6 +525,7 @@ tests = do
492525
, tableName = "users"
493526
, expressions = [CallExpression "LOWER" [VarExpression "email"]]
494527
, whereClause = Nothing
528+
, indexType = Nothing
495529
}
496530
it "should parse a CREATE UNIQUE INDEX statement" do
497531
parseSql "CREATE UNIQUE INDEX users_index ON users (user_name);\n" `shouldBe` CreateIndex
@@ -500,6 +534,7 @@ tests = do
500534
, tableName = "users"
501535
, expressions = [VarExpression "user_name"]
502536
, whereClause = Nothing
537+
, indexType = Nothing
503538
}
504539

505540
it "should parse a CREATE OR REPLACE FUNCTION ..() RETURNS TRIGGER .." do
@@ -560,6 +595,7 @@ $$;
560595
AndExpression
561596
(IsExpression (VarExpression "source") (NotExpression (VarExpression "NULL")))
562597
(IsExpression (VarExpression "source_id") (NotExpression (VarExpression "NULL"))))
598+
, indexType = Nothing
563599
}
564600

565601
it "should parse 'ENABLE ROW LEVEL SECURITY' statements" do

0 commit comments

Comments
 (0)