Newer
Older
/*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2021 IndiScale GmbH <info@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/entity.h" // for Entity, Messages, Message
#include "caosdb/message_code.h" // for ENTITY_DOES_NOT_EXIST, Messag...
#include "caosdb/status_code.h" // for SUCCESS, StatusCode
#include "caosdb/transaction.h" // for Entity, Transaction, UniqueRe...
#include "caosdb/transaction_status.h" // for TransactionStatus, StatusCode
#include "gtest/gtest-message.h" // for Message
#include "gtest/gtest-test-part.h" // for TestPartResult, SuiteApiResolver
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, AssertionResult
#include <memory> // for unique_ptr, allocator, __shar...
using caosdb::entity::Property;
class test_transaction : public ::testing::Test {
protected:
const auto &connection =
caosdb::connection::ConnectionManager::GetDefaultConnection();
auto query_transaction(connection->CreateTransaction());
query_transaction->Query("FIND ENTITY WITH id > 99");
query_transaction->Execute();
if (query_transaction->GetResultSet().Size() > 0) {
for (const Entity &entity : query_transaction->GetResultSet()) {
auto delete_transaction(connection->CreateTransaction());
delete_transaction->DeleteById(entity.GetId());
delete_transaction->Execute();
}
}
TEST(test_transaction, DISABLED_retrieve_manufacturer_by_id) {
const auto &connection =
caosdb::connection::ConnectionManager::GetDefaultConnection();
const auto *id = "107";
const auto *role = "RecordType";
const auto *name = "Manufacturer";
const auto *description = "A generic manufacturer of all kinds of products";
const auto *version = "0bea8f7b17f0130fa5701a6c3849b9f8bfa0651b";
auto transaction(connection->CreateTransaction());
dynamic_cast<const UniqueResult &>(transaction->GetResultSet());
const auto &entity = result_set.GetEntity();
EXPECT_EQ(id, entity.GetId());
EXPECT_EQ(name, entity.GetName());
EXPECT_EQ(role, entity.GetRole());
EXPECT_EQ(description, entity.GetDescription());
const auto &connection =
caosdb::connection::ConnectionManager::GetDefaultConnection();
auto transaction(connection->CreateTransaction());
const auto *id = "non-existing-id";
transaction->RetrieveById(id);
EXPECT_EQ(status.GetCode(), TransactionStatus::TRANSACTION_ERROR().GetCode());
ASSERT_EQ(status.GetCode(), StatusCode::GENERIC_TRANSACTION_ERROR);
dynamic_cast<const UniqueResult &>(transaction->GetResultSet());
const auto &entity = result_set.GetEntity();
EXPECT_EQ(id, entity.GetId());
EXPECT_TRUE(entity.HasErrors());
ASSERT_EQ(entity.GetErrors().Size(), 1);
EXPECT_EQ(entity.GetErrors().At(0).GetCode(),
MessageCode::ENTITY_DOES_NOT_EXIST);
const auto &connection =
caosdb::connection::ConnectionManager::GetDefaultConnection();
auto insert_transaction(connection->CreateTransaction());
Entity entity;
entity.SetRole("RecordType");
entity.SetName("RT1");
insert_transaction->InsertEntity(&entity);
insert_transaction->ExecuteAsynchronously();
auto insert_status = insert_transaction->WaitForIt();
ASSERT_TRUE(insert_status.IsTerminated());
ASSERT_FALSE(insert_status.IsError());
dynamic_cast<const UniqueResult &>(insert_transaction->GetResultSet());
const auto &new_entity = insert_result_set.GetEntity();
EXPECT_FALSE(new_entity.GetId().empty());
EXPECT_FALSE(new_entity.HasErrors());
// Should have a warning since it has no properties
EXPECT_TRUE(new_entity.HasWarnings());
EXPECT_EQ(new_entity.GetWarnings().Size(), 1);
EXPECT_EQ(new_entity.GetWarnings().At(0).GetCode(),
MessageCode::ENTITY_HAS_NO_PROPERTIES);
auto delete_transaction(connection->CreateTransaction());
delete_transaction->DeleteById(new_entity.GetId());
delete_transaction->ExecuteAsynchronously();
auto delete_status = delete_transaction->WaitForIt();
ASSERT_TRUE(delete_status.IsTerminated());
ASSERT_FALSE(delete_status.IsError());
const auto &delete_result_set =
dynamic_cast<const UniqueResult &>(delete_transaction->GetResultSet());
const auto &deleted_entity = delete_result_set.GetEntity();
EXPECT_EQ(deleted_entity.GetId(), new_entity.GetId());
EXPECT_FALSE(deleted_entity.HasErrors());
const auto &connection =
caosdb::connection::ConnectionManager::GetDefaultConnection();
auto insert_transaction(connection->CreateTransaction());
Entity rt;
rt.SetRole("RecordType");
rt.SetName("TestRT");
insert_transaction->InsertEntity(&rt);
insert_transaction->ExecuteAsynchronously();
auto insert_status = insert_transaction->WaitForIt();
ASSERT_TRUE(insert_status.IsTerminated());
ASSERT_FALSE(insert_status.IsError());
const auto &insert_result_set =
dynamic_cast<const UniqueResult &>(insert_transaction->GetResultSet());
const auto &inserted_rt = insert_result_set.GetEntity();
Entity rec;
rec.SetRole("Record");
rec.SetName("TestRec");
Parent parent;
rec.AppendParent(parent);
auto rec_transaction(connection->CreateTransaction());
rec_transaction->InsertEntity(&rec);
rec_transaction->ExecuteAsynchronously();
auto rec_insert_status = rec_transaction->WaitForIt();
ASSERT_TRUE(rec_insert_status.IsTerminated());
ASSERT_FALSE(rec_insert_status.IsError());
const auto &rec_result_set =
dynamic_cast<const UniqueResult &>(rec_transaction->GetResultSet());
const auto &inserted_rec = rec_result_set.GetEntity();
EXPECT_FALSE(inserted_rec.GetId().empty());
auto retrieve_transaction(connection->CreateTransaction());
retrieve_transaction->RetrieveById(inserted_rec.GetId());
retrieve_transaction->ExecuteAsynchronously();
auto rec_retrieve_status = retrieve_transaction->WaitForIt();
ASSERT_TRUE(rec_retrieve_status.IsTerminated());
ASSERT_FALSE(rec_retrieve_status.IsError());
const auto &retrieve_result_set =
dynamic_cast<const UniqueResult &>(retrieve_transaction->GetResultSet());
const auto &retrieved_rec = retrieve_result_set.GetEntity();
EXPECT_EQ(retrieved_rec.GetName(), rec.GetName());
EXPECT_EQ(retrieved_rec.GetParents().Size(), 1);
EXPECT_EQ(retrieved_rec.GetParents().At(0).GetId(), inserted_rt.GetId());
EXPECT_EQ(retrieved_rec.GetParents().At(0).GetName(), rt.GetName());
auto rec_deletion(connection->CreateTransaction());
rec_deletion->DeleteById(retrieved_rec.GetId());
rec_deletion->ExecuteAsynchronously();
auto rec_delete_status = rec_deletion->WaitForIt();
ASSERT_TRUE(rec_delete_status.IsTerminated());
ASSERT_FALSE(rec_delete_status.IsError());
auto rt_deletion(connection->CreateTransaction());
rt_deletion->DeleteById(inserted_rt.GetId());
rt_deletion->ExecuteAsynchronously();
auto rt_delete_status = rt_deletion->WaitForIt();
ASSERT_TRUE(rt_delete_status.IsTerminated());
ASSERT_FALSE(rt_delete_status.IsError());
}
// TODO(fspreck) Insert a Record with a parent and a Property. Check
// for success and delete everything.
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
const auto &connection =
caosdb::connection::ConnectionManager::GetDefaultConnection();
// Create and insert property
Entity prop_ent;
prop_ent.SetRole("Property");
prop_ent.SetName("TestProperty");
prop_ent.SetDatatype("TEXT");
auto prop_insertion(connection->CreateTransaction());
prop_insertion->InsertEntity(&prop_ent);
prop_insertion->ExecuteAsynchronously();
auto prop_insert_status = prop_insertion->WaitForIt();
ASSERT_TRUE(prop_insert_status.IsTerminated());
ASSERT_FALSE(prop_insert_status.IsError());
const auto &prop_result_set =
dynamic_cast<const UniqueResult &>(prop_insertion->GetResultSet());
const auto &inserted_prop = prop_result_set.GetEntity();
EXPECT_FALSE(inserted_prop.GetId().empty());
// create and insert record type with the above property
Property prop_rt;
prop_rt.SetName(prop_ent.GetName());
prop_rt.SetId(inserted_prop.GetId());
prop_rt.SetImportance("SUGGESTED");
Entity rt;
rt.SetRole("RecordType");
rt.SetName("TestRT");
rt.AppendProperty(prop_rt);
auto rt_insertion(connection->CreateTransaction());
rt_insertion->InsertEntity(&rt);
rt_insertion->ExecuteAsynchronously();
auto rt_insert_status = rt_insertion->WaitForIt();
ASSERT_TRUE(rt_insert_status.IsTerminated());
ASSERT_FALSE(rt_insert_status.IsError());
const auto &rt_result_set =
dynamic_cast<const UniqueResult &>(rt_insertion->GetResultSet());
const auto &inserted_rt = rt_result_set.GetEntity();
EXPECT_FALSE(inserted_rt.GetId().empty());
// retrieve inserted rt for testing
auto rt_retrieval(connection->CreateTransaction());
rt_retrieval->RetrieveById(inserted_rt.GetId());
rt_retrieval->ExecuteAsynchronously();
auto rt_retrieve_status = rt_retrieval->WaitForIt();
ASSERT_TRUE(rt_retrieve_status.IsTerminated());
ASSERT_FALSE(rt_retrieve_status.IsError());
const auto &rt_retrieve_results =
dynamic_cast<const UniqueResult &>(rt_retrieval->GetResultSet());
const auto &retrieved_rt = rt_retrieve_results.GetEntity();
EXPECT_EQ(inserted_rt.GetId(), retrieved_rt.GetId());
EXPECT_EQ(rt.GetName(), retrieved_rt.GetName());
EXPECT_EQ(retrieved_rt.GetProperties().Size(), 1);
const auto &retrieved_prop_rt = retrieved_rt.GetProperties().At(0);
EXPECT_EQ(retrieved_prop_rt.GetName(), prop_ent.GetName());
EXPECT_EQ(retrieved_prop_rt.GetId(), inserted_prop.GetId());
EXPECT_EQ(retrieved_prop_rt.GetDatatype(), prop_ent.GetDatatype());
EXPECT_EQ(retrieved_prop_rt.GetImportance(), prop_rt.GetImportance());
// create and insert record of the above record type with a property
// with a value.
Parent parent;
parent.SetName(rt.GetName());
parent.SetId(inserted_rt.GetId());
Property prop_rec;
prop_rec.SetName(prop_ent.GetName());
prop_rec.SetId(inserted_prop.GetId());
prop_rec.SetValue("Test");
Entity rec;
rec.SetName("TestRec");
rec.SetRole("Record");
rec.AppendParent(parent);
rec.AppendProperty(prop_rec);
auto rec_insertion(connection->CreateTransaction());
rec_insertion->InsertEntity(&rec);
rec_insertion->ExecuteAsynchronously();
auto rec_insert_status = rec_insertion->WaitForIt();
ASSERT_TRUE(rec_insert_status.IsTerminated());
ASSERT_FALSE(rec_insert_status.IsError());
const auto &rec_result_set =
dynamic_cast<const UniqueResult &>(rec_insertion->GetResultSet());
const auto &inserted_rec = rec_result_set.GetEntity();
EXPECT_FALSE(inserted_rec.GetId().empty());
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
// Retrieve the record and verify paretn and property
auto rec_retrieval(connection->CreateTransaction());
rec_retrieval->RetrieveById(inserted_rec.GetId());
rec_retrieval->ExecuteAsynchronously();
auto rec_retrieve_status = rec_retrieval->WaitForIt();
ASSERT_TRUE(rec_retrieve_status.IsTerminated());
ASSERT_FALSE(rec_retrieve_status.IsError());
const auto &rec_retrieve_results =
dynamic_cast<const UniqueResult &>(rec_retrieval->GetResultSet());
const auto &retrieved_rec = rec_retrieve_results.GetEntity();
EXPECT_EQ(rec.GetName(), retrieved_rec.GetName());
EXPECT_EQ(inserted_rec.GetId(), retrieved_rec.GetId());
EXPECT_EQ(retrieved_rec.GetParents().Size(), 1);
EXPECT_EQ(retrieved_rec.GetProperties().Size(), 1);
const auto &retrieved_parent_rec = retrieved_rec.GetParents().At(0);
EXPECT_EQ(retrieved_parent_rec.GetName(), rt.GetName());
EXPECT_EQ(retrieved_parent_rec.GetId(), inserted_rt.GetId());
const auto &retrieved_prop_rec = retrieved_rec.GetProperties().At(0);
EXPECT_EQ(retrieved_prop_rec.GetName(), prop_ent.GetName());
EXPECT_EQ(retrieved_prop_rec.GetId(), inserted_prop.GetId());
EXPECT_EQ(retrieved_prop_rec.GetDatatype(), prop_ent.GetDatatype());
EXPECT_EQ(retrieved_prop_rec.GetValue(), prop_rec.GetValue());
// Delete eveything: First record ...
auto rec_deletion(connection->CreateTransaction());
rec_deletion->DeleteById(inserted_rec.GetId());
rec_deletion->ExecuteAsynchronously();
auto rec_delete_status = rec_deletion->WaitForIt();
ASSERT_TRUE(rec_delete_status.IsTerminated());
ASSERT_FALSE(rec_delete_status.IsError());
// ... then parent ...
auto rt_deletion(connection->CreateTransaction());
rt_deletion->DeleteById(inserted_rt.GetId());
rt_deletion->ExecuteAsynchronously();
auto rt_delete_status = rt_deletion->WaitForIt();
ASSERT_TRUE(rt_delete_status.IsTerminated());
ASSERT_FALSE(rt_delete_status.IsError());
// ... then property.
auto prop_deletion(connection->CreateTransaction());
prop_deletion->DeleteById(inserted_prop.GetId());
prop_deletion->ExecuteAsynchronously();
auto prop_delete_status = prop_deletion->WaitForIt();
ASSERT_TRUE(prop_delete_status.IsTerminated());
ASSERT_FALSE(prop_delete_status.IsError());
const auto &connection =
caosdb::connection::ConnectionManager::GetDefaultConnection();
auto transaction(connection->CreateTransaction());
const std::vector<std::string> ids = {"20", "21", "22"};
transaction->RetrieveById(ids.begin(), ids.end());
transaction->ExecuteAsynchronously();
auto status = transaction->WaitForIt();
ASSERT_TRUE(status.IsTerminated());
ASSERT_FALSE(status.IsError());
const auto &result_set = transaction->GetResultSet();
EXPECT_EQ(result_set.Size(), 3);
EXPECT_EQ(result_set.At(1).GetId(), "21");
EXPECT_EQ(result_set.At(1).GetName(), "unit");
EXPECT_FALSE(result_set.At(1).HasErrors());
EXPECT_EQ(result_set.At(2).GetId(), "22");
EXPECT_TRUE(result_set.At(2).HasErrors());
EXPECT_EQ(result_set.At(2).GetErrors().At(0).GetCode(),
MessageCode::ENTITY_DOES_NOT_EXIST);
const auto &connection =
caosdb::connection::ConnectionManager::GetDefaultConnection();
// INSERT
auto insert_transaction(connection->CreateTransaction());
Entity entity;
entity.SetRole("RecordType");
entity.SetName("RT1");
insert_transaction->InsertEntity(&entity);
insert_transaction->ExecuteAsynchronously();
auto insert_status = insert_transaction->WaitForIt();
ASSERT_TRUE(insert_status.IsTerminated());
ASSERT_FALSE(insert_status.IsError());
const auto &insert_result_set =
dynamic_cast<const UniqueResult &>(insert_transaction->GetResultSet());
const auto &new_entity = insert_result_set.GetEntity();
EXPECT_FALSE(new_entity.GetId().empty());
EXPECT_FALSE(new_entity.HasErrors());
// RETRIEVE
auto retrieve_transaction(connection->CreateTransaction());
retrieve_transaction->RetrieveById(new_entity.GetId());
retrieve_transaction->Execute();
// UPDATE
auto update_transaction(connection->CreateTransaction());
auto update_entity(retrieve_transaction->GetResultSet().At(0));
auto update_status = update_transaction->WaitForIt();
ASSERT_TRUE(update_status.IsTerminated());
ASSERT_FALSE(update_status.IsError());
EXPECT_EQ(update_transaction->GetResultSet().Size(), 1);
const auto &updated_entity = update_transaction->GetResultSet().At(0);
EXPECT_EQ(updated_entity.GetId(), new_entity.GetId());
EXPECT_FALSE(updated_entity.HasErrors());
// DELETE
auto delete_transaction(connection->CreateTransaction());
delete_transaction->DeleteById(new_entity.GetId());
delete_transaction->ExecuteAsynchronously();
auto delete_status = delete_transaction->WaitForIt();
ASSERT_TRUE(delete_status.IsTerminated());
ASSERT_FALSE(delete_status.IsError());
const auto &delete_result_set =
dynamic_cast<const UniqueResult &>(delete_transaction->GetResultSet());
const auto &deleted_entity = delete_result_set.GetEntity();
EXPECT_EQ(deleted_entity.GetId(), new_entity.GetId());
EXPECT_FALSE(deleted_entity.HasErrors());
}
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
TEST(test_transaction, test_query) {
const auto &connection =
caosdb::connection::ConnectionManager::GetDefaultConnection();
auto insert_transaction(connection->CreateTransaction());
Entity entity;
entity.SetRole("RecordType");
entity.SetName("RT1");
insert_transaction->InsertEntity(&entity);
insert_transaction->ExecuteAsynchronously();
auto insert_status = insert_transaction->WaitForIt();
ASSERT_TRUE(insert_status.IsTerminated());
ASSERT_FALSE(insert_status.IsError());
const auto &insert_result_set =
dynamic_cast<const UniqueResult &>(insert_transaction->GetResultSet());
const auto &new_entity = insert_result_set.GetEntity();
EXPECT_FALSE(new_entity.GetId().empty());
EXPECT_FALSE(new_entity.HasErrors());
auto query_transaction(connection->CreateTransaction());
query_transaction->Query("FIND ENTITY WITH id = " + new_entity.GetId());
query_transaction->Execute();
EXPECT_EQ(query_transaction->GetResultSet().Size(), 1);
EXPECT_EQ(query_transaction->GetResultSet().At(0).GetId(),
new_entity.GetId());
// No count query, so no count result should be present
EXPECT_TRUE((query_transaction->GetCountResult() < 0));
auto count_query_trans(connection->CreateTransaction());
count_query_trans->Query("COUNT ENTITY WITH id = " + new_entity.GetId());
count_query_trans->Execute();
// No result set in a count query
EXPECT_EQ(count_query_trans->GetResultSet().Size(), 0);
EXPECT_EQ(count_query_trans->GetCountResult(), 1);
// TODO(fspreck) Add tests for unique queries, count queries, and mixed
// transactions (FIND + RetrieveById, COUNT + RetrieveById).