diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp index 6612e3f57..e051c9fd1 100644 --- a/src/query/interpreter.cpp +++ b/src/query/interpreter.cpp @@ -2912,17 +2912,37 @@ PreparedQuery PrepareInfoQuery(ParsedQuery parsed_query, bool in_explicit_transa case InfoQuery::InfoType::INDEX: header = {"index type", "label", "property"}; handler = [interpreter_context] { + const std::string_view label_index_mark{"label"}; + const std::string_view label_property_index_mark{"label+property"}; auto *db = interpreter_context->db.get(); auto info = db->ListAllIndices(); std::vector> results; results.reserve(info.label.size() + info.label_property.size()); for (const auto &item : info.label) { - results.push_back({TypedValue("label"), TypedValue(db->LabelToName(item)), TypedValue()}); + results.push_back({TypedValue(label_index_mark), TypedValue(db->LabelToName(item)), TypedValue()}); } for (const auto &item : info.label_property) { - results.push_back({TypedValue("label+property"), TypedValue(db->LabelToName(item.first)), + results.push_back({TypedValue(label_property_index_mark), TypedValue(db->LabelToName(item.first)), TypedValue(db->PropertyToName(item.second))}); } + + std::sort(results.begin(), results.end(), [&label_index_mark](const auto &record_1, const auto &record_2) { + const auto type_1 = record_1[0].ValueString(); + const auto type_2 = record_2[0].ValueString(); + + if (type_1 != type_2) { + return type_1 < type_2; + } + + const auto label_1 = record_1[1].ValueString(); + const auto label_2 = record_2[1].ValueString(); + if (type_1 == label_index_mark || label_1 != label_2) { + return label_1 < label_2; + } + + return record_1[2].ValueString() < record_2[2].ValueString(); + }); + return std::pair{results, QueryHandlerResult::NOTHING}; }; break; diff --git a/tests/e2e/CMakeLists.txt b/tests/e2e/CMakeLists.txt index 7384fa7d7..8ebd66dda 100644 --- a/tests/e2e/CMakeLists.txt +++ b/tests/e2e/CMakeLists.txt @@ -63,6 +63,7 @@ add_subdirectory(analytical_mode) add_subdirectory(batched_procedures) add_subdirectory(import_mode) add_subdirectory(concurrent_query_modules) +add_subdirectory(show_index_info) add_subdirectory(set_properties) add_subdirectory(transaction_rollback) diff --git a/tests/e2e/show_index_info/CMakeLists.txt b/tests/e2e/show_index_info/CMakeLists.txt new file mode 100644 index 000000000..dd9bd28bb --- /dev/null +++ b/tests/e2e/show_index_info/CMakeLists.txt @@ -0,0 +1,6 @@ +function(copy_show_index_info_e2e_python_files FILE_NAME) + copy_e2e_python_files(show_index_info ${FILE_NAME}) +endfunction() + +copy_show_index_info_e2e_python_files(common.py) +copy_show_index_info_e2e_python_files(test_show_index_info.py) diff --git a/tests/e2e/show_index_info/common.py b/tests/e2e/show_index_info/common.py new file mode 100644 index 000000000..7ed62f885 --- /dev/null +++ b/tests/e2e/show_index_info/common.py @@ -0,0 +1,56 @@ +# Copyright 2023 Memgraph Ltd. +# +# Use of this software is governed by the Business Source License +# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +# License, and you may not use this file except in compliance with the Business Source License. +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0, included in the file +# licenses/APL.txt. + +import typing +from enum import IntEnum + +import mgclient +import pytest + + +class Row(IntEnum): + INDEX_TYPE = 0 + LABEL = 1 + PROPERTY = 2 + + +@pytest.fixture(scope="module") +def cursor(**kwargs) -> mgclient.Connection: + connection = mgclient.connect(host="localhost", port=7687, **kwargs) + connection.autocommit = True + cursor = connection.cursor() + + cursor.execute("CREATE INDEX ON :Gene;") + cursor.execute("CREATE INDEX ON :Gene(id);") + cursor.execute("CREATE INDEX ON :Gene(i5);") + cursor.execute("CREATE INDEX ON :Compound;") + cursor.execute("CREATE INDEX ON :Compound(id);") + cursor.execute("CREATE INDEX ON :Compound(mgid);") + cursor.execute("CREATE INDEX ON :Compound(inchikey);") + cursor.execute("CREATE INDEX ON :Anatomy;") + cursor.execute("CREATE INDEX ON :Disease;") + + yield cursor + + cursor.execute("DROP INDEX ON :Gene;") + cursor.execute("DROP INDEX ON :Gene(id);") + cursor.execute("DROP INDEX ON :Gene(i5);") + cursor.execute("DROP INDEX ON :Compound;") + cursor.execute("DROP INDEX ON :Compound(id);") + cursor.execute("DROP INDEX ON :Compound(mgid);") + cursor.execute("DROP INDEX ON :Compound(inchikey);") + cursor.execute("DROP INDEX ON :Anatomy;") + cursor.execute("DROP INDEX ON :Disease;") + + +def execute_and_fetch_all(cursor: mgclient.Cursor, query: str, params: dict = dict()) -> typing.List[tuple]: + cursor.execute(query, params) + return cursor.fetchall() diff --git a/tests/e2e/show_index_info/test_show_index_info.py b/tests/e2e/show_index_info/test_show_index_info.py new file mode 100644 index 000000000..8c2dc7cdd --- /dev/null +++ b/tests/e2e/show_index_info/test_show_index_info.py @@ -0,0 +1,47 @@ +# Copyright 2023 Memgraph Ltd. +# +# Use of this software is governed by the Business Source License +# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +# License, and you may not use this file except in compliance with the Business Source License. +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0, included in the file +# licenses/APL.txt. + +import sys + +import pytest +from common import Row, cursor, execute_and_fetch_all + + +def test_show_index_info(cursor): + index_info = execute_and_fetch_all(cursor, "SHOW INDEX INFO;") + expected_index_info = { + ("label", "Anatomy", None), + ("label", "Compound", None), + ("label", "Disease", None), + ("label", "Gene", None), + ("label+property", "Compound", "id"), + ("label+property", "Compound", "inchikey"), + ("label+property", "Compound", "mgid"), + ("label+property", "Gene", "i5"), + ("label+property", "Gene", "id"), + } + assert set(index_info) == expected_index_info + + +def test_index_info_sorted(cursor): + index_info = execute_and_fetch_all(cursor, "SHOW INDEX INFO;") + assert index_info == sorted( + index_info, + key=lambda index: ( + index[Row.INDEX_TYPE], + index[Row.LABEL], + index[Row.PROPERTY], + ), + ) + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__, "-rA"])) diff --git a/tests/e2e/show_index_info/workloads.yaml b/tests/e2e/show_index_info/workloads.yaml new file mode 100644 index 000000000..e79a74994 --- /dev/null +++ b/tests/e2e/show_index_info/workloads.yaml @@ -0,0 +1,13 @@ +show_index_info: &show_index_info + cluster: + main: + args: ["--bolt-port", "7687", "--log-level=TRACE", "--also-log-to-stderr"] + log_file: "test-show-index-info.log" + setup_queries: [] + validation_queries: [] + +workloads: + - name: "test-show-index-info" + binary: "tests/e2e/pytest_runner.sh" + args: ["show_index_info/test_show_index_info.py"] + <<: *show_index_info