/* * This file is a part of the CaosDB Project. * * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> * Copyright (C) 2021 Daniel Hornung <d.hornung@indiscale.com> * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ #include "caosdb/connection.h" // for Connection, ConnectionManager #include "caosdb/data_type.h" // for AtomicDataType #include "caosdb/entity.h" // for Entity, Property, Role, Parent #include "caosdb/result_set.h" // for Entity, ResultSet, ResultSet::ite... #include "caosdb/result_table.h" // for ResultTable::HeaderIterator, Resu... #include "caosdb/transaction.h" // for Transaction, ResultTable #include "caosdb/value.h" // for Value #include <gtest/gtest-message.h> // for Message #include <gtest/gtest-spi.h> // for EXPECT_NONFATAL_FA... #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl #include <gtest/gtest_pred_impl.h> // for Test, TestInfo, EXPECT_EQ, TEST #include <iostream> // for operator<<, basic_ostream::operat... #include <memory> // for allocator, unique_ptr, __shared_p... #include <string> // for string namespace caosdb::transaction { using caosdb::entity::DataType; using caosdb::entity::AtomicDataType; using caosdb::entity::Entity; using caosdb::entity::Parent; using caosdb::entity::Property; using caosdb::entity::Role; using caosdb::entity::Value; class test_select : public ::testing::Test { public: static void InsertEntity(Entity *entity) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto insert_transaction(connection->CreateTransaction()); insert_transaction->InsertEntity(entity); insert_transaction->Execute(); } static void DeleteEntities() { // delete all entities const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("FIND Entity"); // query_transaction->Query("FIND Test*"); query_transaction->Execute(); if (query_transaction->GetResultSet().size() > 0) { std::cout << "Cleanup: Deleting " << query_transaction->GetResultSet().size() << " entities." << std::endl; auto delete_transaction(connection->CreateTransaction()); for (const Entity &entity : query_transaction->GetResultSet()) { delete_transaction->DeleteById(entity.GetId()); } delete_transaction->Execute(); } } static auto CreateTestProp(const std::string &name, AtomicDataType data_type) -> Entity { Entity entity; entity.SetRole(Role::PROPERTY); entity.SetName(name); entity.SetDescription("Prop Description " + name); entity.SetDataType(data_type); return entity; } static auto CreateTestRT() -> Entity { Entity entity; entity.SetRole(Role::RECORD_TYPE); entity.SetDescription("RT Description"); entity.SetName("TestRT"); return entity; } static auto CreateTestProp(const std::string &name, const std::string &data_type) -> Entity { Entity entity; entity.SetRole(Role::PROPERTY); entity.SetName(name); entity.SetDescription("Prop Description " + name); entity.SetDataType(data_type); return entity; } static auto CreateRecord(const std::string &property_name, const Value &value) -> Entity { Entity entity; entity.SetRole(Role::RECORD); Parent parent; parent.SetName("TestRT"); entity.AppendParent(parent); Property property; property.SetName(property_name); property.SetValue(value); entity.AppendProperty(property); Property dummyProperty; dummyProperty.SetName("TestProp2"); dummyProperty.SetValue("dummy value"); entity.AppendProperty(dummyProperty); return entity; } protected: // Fixture methods ////////////////////////////////////////////////////////// void SetUp() override { DeleteEntities(); const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto insert_transaction(connection->CreateTransaction()); auto rt = CreateTestRT(); auto rt2 = CreateTestRT(); rt2.SetName("TestRT2"); insert_transaction->InsertEntity(&rt); insert_transaction->InsertEntity(&rt2); auto p = CreateTestProp("TestProp", AtomicDataType::TEXT); insert_transaction->InsertEntity(&p); p = CreateTestProp("TestProp2", AtomicDataType::TEXT); insert_transaction->InsertEntity(&p); p = CreateTestProp("TestProp3", AtomicDataType::TEXT); insert_transaction->InsertEntity(&p); p = CreateTestProp("TestPropDouble", AtomicDataType::DOUBLE); p.SetUnit("m"); insert_transaction->InsertEntity(&p); p = CreateTestProp("TestPropInt", AtomicDataType::INTEGER); p.SetUnit("m"); insert_transaction->InsertEntity(&p); p = CreateTestProp("TestPropBool", AtomicDataType::BOOLEAN); insert_transaction->InsertEntity(&p); auto reference_entity = test_select::CreateRecord("TestProp3", Value("val3")); Property property; property.SetName("TestPropDouble"); property.SetUnit("km"); property.SetValue(231.012); reference_entity.AppendProperty(property); reference_entity.RemoveParent(0); Parent parent; parent.SetName("TestRT2"); reference_entity.AppendParent(parent); insert_transaction->InsertEntity(&reference_entity); insert_transaction->Execute(); } void TearDown() override { DeleteEntities(); } }; /* * Test select query on empty database. */ TEST_F(test_select, test_select_empty) { test_select::DeleteEntities(); const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT name FROM RecordType TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "name"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 0); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("name").GetAsString(), "bla"); // should never be executed } } /* * Test select name query on record type. */ TEST_F(test_select, test_select_name) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT name FROM RecordType TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "name"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("name").GetAsString(), "TestRT"); } } /* * Test select description query on record type. */ TEST_F(test_select, test_select_description) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT description FROM RecordType TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "description"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("description").GetAsString(), "RT Description"); } } /* * Test select TestProp query on record. */ TEST_F(test_select, test_select_testprop) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto entity = test_select::CreateRecord("TestProp", Value("val1")); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestProp FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestProp"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("TestProp").GetAsString(), "val1"); } } /* * Test select double value query on record. */ TEST_F(test_select, test_select_double) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto entity = test_select::CreateRecord("TestPropDouble", Value(2.123)); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestPropDouble FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestPropDouble"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_TRUE(row.GetValue("TestPropDouble").IsDouble()); EXPECT_EQ(row.GetValue("TestPropDouble").GetAsDouble(), 2.123); } } /* * Test select unit value query on record. */ TEST_F(test_select, test_select_unit) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto entity = test_select::CreateRecord("TestPropDouble", Value(2.123)); test_select::InsertEntity(&entity); auto check(connection->CreateTransaction()); check->Query("FIND Record TestRT"); check->Execute(); std::cout << check->GetResultSet().at(0).ToString() << std::endl; auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestPropDouble.unit FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestPropDouble.unit"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { // TODO(tf): create bug report: this is an insertion/update problem EXPECT_NONFATAL_FAILURE({ EXPECT_EQ(row.GetValue("TestPropDouble.unit").GetAsString(), "m"); }, "TestPropDouble.unit"); } } /* * Test select int value query on record. */ TEST_F(test_select, test_select_int) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto entity = test_select::CreateRecord("TestPropInt", Value(1234)); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestPropInt FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestPropInt"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_TRUE(row.GetValue("TestPropInt").IsInt64()); EXPECT_EQ(row.GetValue("TestPropInt").GetAsInt64(), 1234); } } /* Test select boolean value query on record. */ TEST_F(test_select, test_select_boolean) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto entity = test_select::CreateRecord("TestPropBool", Value(true)); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestPropBool FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestPropBool"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_TRUE(row.GetValue("TestPropBool").IsBool()); EXPECT_EQ(row.GetValue("TestPropBool").GetAsBool(), true); } } /* * Test select the referenced id. */ TEST_F(test_select, test_select_reference) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto get_id_of_ref_rec(connection->CreateTransaction()); get_id_of_ref_rec->Query("SELECT id FROM RECORD TestRT2"); get_id_of_ref_rec->Execute(); auto id = (* get_id_of_ref_rec->GetResultTable().GetRows().begin()).GetValue("id").GetAsString(); auto entity = test_select::CreateRecord("TestRT2", Value(id)); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestRT2 FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestRT2"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("TestRT2").GetAsString(), id); } } /* * Test select the referenced entity's property. */ TEST_F(test_select, test_select_reference_entitys_property) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto get_id_of_ref_rec(connection->CreateTransaction()); get_id_of_ref_rec->Query("SELECT id FROM RECORD TestRT2"); get_id_of_ref_rec->Execute(); auto id = (* get_id_of_ref_rec->GetResultTable().GetRows().begin()).GetValue("id").GetAsString(); auto entity = test_select::CreateRecord("TestRT2", Value(id)); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestRT2.TestProp3 FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestRT2.TestProp3"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("TestRT2.TestProp3").GetAsString(), "val3"); } } /* * Test select the referenced entity's property's unit. */ TEST_F(test_select, test_select_reference_entitys_propertys_unit) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto get_id_of_ref_rec(connection->CreateTransaction()); get_id_of_ref_rec->Query("SELECT id FROM RECORD TestRT2"); get_id_of_ref_rec->Execute(); auto id = (* get_id_of_ref_rec->GetResultTable().GetRows().begin()).GetValue("id").GetAsString(); auto entity = test_select::CreateRecord("TestRT2", Value(id)); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestRT2.TestPropDouble.unit FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestRT2.TestPropDouble.unit"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("TestRT2.TestPropDouble.unit").GetAsString(), "km"); } } /* * Test select the referenced entity's property's description. */ TEST_F(test_select, test_select_reference_entitys_propertys_description) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto get_id_of_ref_rec(connection->CreateTransaction()); get_id_of_ref_rec->Query("SELECT id FROM RECORD TestRT2"); get_id_of_ref_rec->Execute(); auto id = (* get_id_of_ref_rec->GetResultTable().GetRows().begin()).GetValue("id").GetAsString(); auto entity = test_select::CreateRecord("TestRT2", Value(id)); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestRT2.TestProp3.description FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestRT2.TestProp3.description"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("TestRT2.TestProp3.description").GetAsString(), "Prop Description TestProp3"); } } /* * Test select the referenced entity's property's name. */ TEST_F(test_select, test_select_reference_entitys_propertys_name) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto get_id_of_ref_rec(connection->CreateTransaction()); get_id_of_ref_rec->Query("SELECT id FROM RECORD TestRT2"); get_id_of_ref_rec->Execute(); auto id = (* get_id_of_ref_rec->GetResultTable().GetRows().begin()).GetValue("id").GetAsString(); auto entity = test_select::CreateRecord("TestRT2", Value(id)); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestRT2.TestProp3.name FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestRT2.TestProp3.name"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("TestRT2.TestProp3.name").GetAsString(), "TestProp3"); } } /* * Test select the referenced entity's property's id. */ TEST_F(test_select, test_select_reference_entitys_propertys_id) { const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); auto get_id_of_ref_rec(connection->CreateTransaction()); get_id_of_ref_rec->Query("SELECT id FROM RECORD TestRT2"); get_id_of_ref_rec->Execute(); auto id = (* get_id_of_ref_rec->GetResultTable().GetRows().begin()).GetValue("id").GetAsString(); auto get_id_of_prop(connection->CreateTransaction()); get_id_of_prop->Query("SELECT id FROM PROPERTY TestProp3"); get_id_of_prop->Execute(); auto pid = (* get_id_of_prop->GetResultTable().GetRows().begin()).GetValue("id").GetAsString(); auto entity = test_select::CreateRecord("TestRT2", Value(id)); test_select::InsertEntity(&entity); auto query_transaction(connection->CreateTransaction()); query_transaction->Query("SELECT TestRT2.TestProp3.id FROM Record TestRT"); query_transaction->Execute(); EXPECT_EQ(query_transaction->GetResultTable().GetHeader().size(), 1); for (const auto &column : query_transaction->GetResultTable().GetHeader()) { EXPECT_EQ(column.GetName(), "TestRT2.TestProp3.id"); } EXPECT_EQ(query_transaction->GetResultTable().size(), 1); for (const auto &row : query_transaction->GetResultTable().GetRows()) { EXPECT_EQ(row.GetValue("TestRT2.TestProp3.id").GetAsString(), pid); } } } // namespace caosdb::transaction