Implement ResultSourceMapping
This commit is contained in:
parent
21e8616ead
commit
35eac713ff
5 changed files with 371 additions and 0 deletions
168
tests/pglabtests/ResultSourceMappingTest.cpp
Normal file
168
tests/pglabtests/ResultSourceMappingTest.cpp
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock-matchers.h>
|
||||
|
||||
#include "ResultSourceMapping.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr Oid tableA = 1001;
|
||||
constexpr Oid tableB = 1002;
|
||||
|
||||
ResultColumnSource src(Oid table, int attnum)
|
||||
{
|
||||
ResultColumnSource s;
|
||||
s.tableOid = table;
|
||||
s.attnum = attnum;
|
||||
return s;
|
||||
}
|
||||
|
||||
ResultColumnSource expression()
|
||||
{
|
||||
return ResultColumnSource{};
|
||||
}
|
||||
|
||||
TablePrimaryKey pk(Oid table, std::vector<int> attnums)
|
||||
{
|
||||
TablePrimaryKey key;
|
||||
key.tableOid = table;
|
||||
key.attnums = std::move(attnums);
|
||||
return key;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
TEST(ResultSourceMappingTest, single_table_with_pk_all_columns_editable)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), src(tableA, 2), src(tableA, 3)}, {pk(tableA, {1})});
|
||||
|
||||
EXPECT_EQ(m.columnCount(), 3);
|
||||
EXPECT_TRUE(m.isEditable(0));
|
||||
EXPECT_TRUE(m.isEditable(1));
|
||||
EXPECT_TRUE(m.isEditable(2));
|
||||
EXPECT_EQ(m.tableOid(1), tableA);
|
||||
EXPECT_EQ(m.attnum(2), 3);
|
||||
EXPECT_THAT(m.primaryKeyColumns(tableA), ::testing::ElementsAre(0));
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, composite_pk_maps_key_columns_in_key_order)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 3), src(tableA, 1), src(tableA, 2)}, {pk(tableA, {1, 2})});
|
||||
|
||||
EXPECT_TRUE(m.isEditable(0));
|
||||
EXPECT_THAT(m.primaryKeyColumns(tableA), ::testing::ElementsAre(1, 2));
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, join_with_both_pks_both_tables_editable)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), src(tableA, 2), src(tableB, 1), src(tableB, 2)},
|
||||
{pk(tableA, {1}), pk(tableB, {1})});
|
||||
|
||||
for (int col = 0; col < m.columnCount(); ++col) {
|
||||
EXPECT_TRUE(m.isEditable(col)) << "column " << col;
|
||||
}
|
||||
EXPECT_THAT(m.primaryKeyColumns(tableA), ::testing::ElementsAre(0));
|
||||
EXPECT_THAT(m.primaryKeyColumns(tableB), ::testing::ElementsAre(2));
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, join_where_only_one_table_has_pk_in_result)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), src(tableA, 2), src(tableB, 2)},
|
||||
{pk(tableA, {1}), pk(tableB, {1})});
|
||||
|
||||
EXPECT_TRUE(m.isEditable(0));
|
||||
EXPECT_TRUE(m.isEditable(1));
|
||||
EXPECT_FALSE(m.isEditable(2));
|
||||
EXPECT_TRUE(m.primaryKeyColumns(tableB).empty());
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, pk_missing_from_result_is_read_only)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 2), src(tableA, 3)}, {pk(tableA, {1})});
|
||||
|
||||
EXPECT_FALSE(m.isEditable(0));
|
||||
EXPECT_FALSE(m.isEditable(1));
|
||||
EXPECT_TRUE(m.primaryKeyColumns(tableA).empty());
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, composite_pk_partially_present_is_read_only)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), src(tableA, 3)}, {pk(tableA, {1, 2})});
|
||||
|
||||
EXPECT_FALSE(m.isEditable(0));
|
||||
EXPECT_FALSE(m.isEditable(1));
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, table_without_pk_is_read_only)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), src(tableA, 2)}, {});
|
||||
|
||||
EXPECT_FALSE(m.isEditable(0));
|
||||
EXPECT_FALSE(m.isEditable(1));
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, expression_column_is_read_only)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), expression(), src(tableA, 2)}, {pk(tableA, {1})});
|
||||
|
||||
EXPECT_TRUE(m.isEditable(0));
|
||||
EXPECT_FALSE(m.isEditable(1));
|
||||
EXPECT_EQ(m.tableOid(1), InvalidOid);
|
||||
EXPECT_EQ(m.attnum(1), 0);
|
||||
EXPECT_TRUE(m.isEditable(2));
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, system_column_is_read_only)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), src(tableA, -2)}, {pk(tableA, {1})});
|
||||
|
||||
EXPECT_TRUE(m.isEditable(0));
|
||||
EXPECT_FALSE(m.isEditable(1));
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, duplicate_pk_column_still_editable)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), src(tableA, 1), src(tableA, 2)}, {pk(tableA, {1})});
|
||||
|
||||
EXPECT_TRUE(m.isEditable(0));
|
||||
EXPECT_TRUE(m.isEditable(1));
|
||||
EXPECT_TRUE(m.isEditable(2));
|
||||
EXPECT_THAT(m.primaryKeyColumns(tableA), ::testing::ElementsAre(0));
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, same_non_pk_column_twice_makes_table_read_only)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), src(tableA, 2), src(tableA, 2)}, {pk(tableA, {1})});
|
||||
|
||||
EXPECT_FALSE(m.isEditable(0));
|
||||
EXPECT_FALSE(m.isEditable(1));
|
||||
EXPECT_FALSE(m.isEditable(2));
|
||||
EXPECT_TRUE(m.primaryKeyColumns(tableA).empty());
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, self_join_with_aliased_non_pk_columns_is_read_only)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1), src(tableA, 1), src(tableA, 2), src(tableA, 2)}, {pk(tableA, {1})});
|
||||
|
||||
EXPECT_FALSE(m.isEditable(0));
|
||||
EXPECT_FALSE(m.isEditable(2));
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, out_of_range_column_throws)
|
||||
{
|
||||
ResultSourceMapping m({src(tableA, 1)}, {pk(tableA, {1})});
|
||||
|
||||
EXPECT_THROW(m.isEditable(1), std::range_error);
|
||||
EXPECT_THROW(m.isEditable(-1), std::range_error);
|
||||
EXPECT_THROW(m.tableOid(1), std::range_error);
|
||||
EXPECT_THROW(m.attnum(-1), std::range_error);
|
||||
}
|
||||
|
||||
TEST(ResultSourceMappingTest, empty_result_has_no_columns)
|
||||
{
|
||||
ResultSourceMapping m({}, {});
|
||||
|
||||
EXPECT_EQ(m.columnCount(), 0);
|
||||
EXPECT_TRUE(m.primaryKeyColumns(tableA).empty());
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue