Skip to content

Commit

Permalink
Allow tuples in GIN, GIST and BRIN indexes (#8232)
Browse files Browse the repository at this point in the history
This is an oversight, as all those Postgres indexes support indexing
multiple columns.
  • Loading branch information
elprans authored Jan 17, 2025
1 parent 3086faa commit a9c3dd7
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 8 deletions.
23 changes: 18 additions & 5 deletions edb/schema/indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,19 @@ def is_index_valid_for_type(
schema: s_schema.Schema,
context: sd.CommandContext,
) -> bool:
index_name = str(index.get_name(schema))
index_allows_tuples = is_index_supporting_tuples(index, schema)

for index_match in schema.get_referrers(
index, scls_type=IndexMatch, field_name='index',
):
valid_type = index_match.get_valid_type(schema)
if index_name == 'std::fts::index':
# FTS index works not only on its valid type (document), but also
# on tuples comtaining document as an element.
if index_allows_tuples:
if is_subclass_or_tuple(expr_type, valid_type, schema):
return True
elif expr_type.issubclass(schema, valid_type):
return True

if context.testmode and index_name == 'default::test':
if context.testmode and str(index.get_name(schema)) == 'default::test':
# For functional tests of abstract indexes.
return expr_type.issubclass(
schema,
Expand All @@ -95,6 +93,21 @@ def is_index_valid_for_type(
return False


def is_index_supporting_tuples(
index: Index,
schema: s_schema.Schema,
) -> bool:
index_name = str(index.get_name(schema))
return index_name in {
"std::fts::index",
"ext::pg_trgm::gin",
"ext::pg_trgm::gist",
"pg::gist",
"pg::gin",
"pg::brin",
}


def is_subclass_or_tuple(
ty: s_types.Type, parent: s_types.Type, schema: s_schema.Schema
) -> bool:
Expand Down
10 changes: 10 additions & 0 deletions tests/schemas/pg_trgm.esdl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ type Gin extending Base {
index ext::pg_trgm::gin on (.p_str);
}

type Gin2 extending Base {
p_str_2: str;
index ext::pg_trgm::gist on ((.p_str, .p_str_2));
}

type Gist extending Base {
index ext::pg_trgm::gist on (.p_str);
}

type Gist2 extending Base {
p_str_2: str;
index ext::pg_trgm::gist on ((.p_str, .p_str_2));
}
18 changes: 15 additions & 3 deletions tests/schemas/pg_trgm_setup.edgeql
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@

for x in range_unpack(range(1, 1001)) union (
insert Gist {
p_str := "qwertyu" ++ str_pad_start(<str>x, 4, "0")
p_str := "qwertyu" ++ str_pad_start(<str>x, 4, "0"),
}
);

for x in range_unpack(range(1, 1001)) union (
insert Gist2 {
p_str := "qwertyu" ++ str_pad_start(<str>x, 4, "0"),
p_str_2 := "iopasdf" ++ str_pad_start(<str>x, 4, "0"),
}
);

Expand Down Expand Up @@ -531,7 +538,12 @@ for x in {
"Samarra School",
"Jangal-e Marakeh Sar",
} union (
insert Gist {
(insert Gist {
p_str := x
}
})
union
(insert Gist2 {
p_str := x,
p_str_2 := x,
})
);
78 changes: 78 additions & 0 deletions tests/test_edgeql_ext_pg_trgm.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,47 @@ async def test_edgeql_ext_pg_trgm_similarity(self):
index_type="ext::pg_trgm::gist",
)

qry = """
SELECT
Gist2 {
p_str,
sim_dist := ext::pg_trgm::similarity_dist(
.p_str, "q0987wertyu0988"
),
p_str_2,
sim_dist_2 := ext::pg_trgm::similarity_dist(
.p_str_2, "q0987opasdf0988"
),
}
ORDER BY
.sim_dist EMPTY LAST THEN .sim_dist_2 EMPTY LAST
LIMIT
2
"""

await self.assert_query_result(
qry,
[
{
"p_str": "qwertyu0988",
"sim_dist": 0.411765,
"p_str_2": "iopasdf0988",
"sim_dist_2": 0.5,
},
{
"p_str": "qwertyu0987",
"sim_dist": 0.5,
"p_str_2": "iopasdf0987",
"sim_dist_2": 0.57894737,
},
]
)

await self.assert_index_use(
qry,
index_type="ext::pg_trgm::gist",
)

async def test_edgeql_ext_pg_trgm_word_similarity(self):
await self.assert_query_result(
"""
Expand Down Expand Up @@ -216,6 +257,43 @@ async def test_edgeql_ext_pg_trgm_word_similarity(self):
index_type="ext::pg_trgm::gist",
)

qry = """
SELECT
Gist2 {
p_str,
word_sim_dist := ext::pg_trgm::word_similarity_dist(
"Kabankala", .p_str
),
p_str_2,
word_sim_dist_2 := ext::pg_trgm::word_similarity_dist(
"Pub", .p_str_2
)
}
ORDER BY
.word_sim_dist EMPTY LAST THEN .word_sim_dist_2 EMPTY LAST
LIMIT
2
"""

await self.assert_query_result(
qry,
[
{
"p_str": "Kabankala",
"word_sim_dist": 0.0,
},
{
"p_str": "Kabankalan City Public Plaza",
"word_sim_dist": 0.1,
},
]
)

await self.assert_index_use(
qry,
index_type="ext::pg_trgm::gist",
)

async def test_edgeql_ext_pg_trgm_strict_word_similarity(self):
await self.assert_query_result(
"""
Expand Down

0 comments on commit a9c3dd7

Please sign in to comment.