-
Daniel Hornung authoredDaniel Hornung authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
maoxdb.cpp 8.44 KiB
/*
* ** header v3.0
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2021 IndiScale GmbH <info@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/>.
*
* ** end header
*/
/**
* Mostly utility functions for MEX files interacting with libcaosdb.
*/
#include "maoxdb.hpp"
#include "mex.h"
#include "caosdb/status_code.h"
#include "caosdb/transaction.h"
#include "caosdb/transaction_status.h"
namespace maoxdb {
using std::string;
auto mxFromCaosDBParents(const caosdb::entity::Parents &parents) -> mxArray *;
auto mxFromCaosDBProperties(const caosdb::entity::Properties &properties) -> mxArray *;
auto mxFromCaosDBMessages(const caosdb::entity::Messages &messages) -> mxArray *;
// Exception and error handling ///////////////////////////////////////////////
/**
* Generate a mex error message from a TransactionStatus.
*/
auto transactionStatusToMessage(
const caosdb::transaction::Transaction *const trans)
-> std::pair<string, string> {
auto status = trans->GetStatus();
auto code = status.GetCode();
if (!status.IsError()) {
return std::pair<string, string>();
}
string id = std::to_string(code);
string text = status.GetDescription();
return std::pair<string, string>(id, text);
}
/**
* Throw an Octave error if the transaction did not finish properly.
*/
void throwOctExceptionIfError(
const caosdb::transaction::Transaction *const trans) {
auto msg = maoxdb::transactionStatusToMessage(trans);
if (msg.first != "") {
mexErrMsgIdAndTxt(msg.first.c_str(), msg.second.c_str());
}
}
/**
* Extract useful strings from an Exception: ID and description.
*/
auto exceptionToMessage(const caosdb::exceptions::Exception &exc)
-> std::pair<string, string> {
string id = std::to_string(exc.GetCode());
string text =
caosdb::get_status_description(exc.GetCode()) + "\n" + exc.what();
return std::pair<string, string>(id, text);
}
/**
* Just throw the error.
*/
void throwOctException(const caosdb::exceptions::Exception &exc) {
std::pair<string, string> excContent = exceptionToMessage(exc);
mexErrMsgIdAndTxt(excContent.first.c_str(), excContent.second.c_str());
}
// Entity handling ////////////////////////////////////////////////////////////
/**
* @brief Convert a ResultSet to a struct mexArray.
*/
auto mxFromResultSet(const caosdb::transaction::ResultSet &resultSet)
-> mxArray * {
auto resSize = resultSet.Size();
std::array<mwSize, 2> dims = {1, resSize};
std::vector<const mxArray *> entities;
// Obtain entities
for (auto entity : resultSet) {
entities.push_back(mxFromCaosDBEntity(entity));
}
auto * result = mxMergeScalarStructs(entities);
return result;
}
/**
* @brief Convert an Entity from libcaosdb to Octave struct mexArray.
*/
auto mxFromCaosDBEntity(const caosdb::entity::Entity &entity) -> mxArray * {
auto fields = std::vector<const char*>
{"role",
"id",
"versionId",
"name",
"description",
"datatype",
"unit",
"value",
"parents",
"properties",
"errors",
"warnings",
"infos"
};
std::array<mwSize, 2> dims = {1, (mwSize)fields.size()};
auto * result = mxCreateStructArray(2, dims.data(), fields.size(), fields.data());
// Fill with scalar values
mxSetField(result, 0, "role", mxCreateString(entity.GetRole().c_str()));
mxSetField(result, 0, "id", mxCreateString(entity.GetId().c_str()));
mxSetField(result, 0, "versionId", mxCreateString(entity.GetVersionId().c_str()));
mxSetField(result, 0, "name", mxCreateString(entity.GetName().c_str()));
mxSetField(result, 0, "description", mxCreateString(entity.GetDescription().c_str()));
mxSetField(result, 0, "datatype", mxCreateString(entity.GetDatatype().c_str()));
mxSetField(result, 0, "unit", mxCreateString(entity.GetUnit().c_str()));
// Parse value to proper type.
mxSetField(result, 0, "value", mxScalarFromStringValue(entity));
// Parents and Properties
mxSetField(result, 0, "parents", mxFromCaosDBParents(entity.GetParents()));
mxSetField(result, 0, "properties", mxFromCaosDBProperties(entity.GetProperties()));
// message type content
mxSetField(result, 0, "errors", mxFromCaosDBMessages(entity.GetErrors()));
mxSetField(result, 0, "warnings", mxFromCaosDBMessages(entity.GetWarnings()));
mxSetField(result, 0, "infos", mxFromCaosDBMessages(entity.GetInfos()));
return result;
}
// Parents to struct array
auto mxFromCaosDBParents(const caosdb::entity::Parents &parents) -> mxArray * {
std::vector<const char*> fields =
{"id",
"name",
"description"
};
std::array<mwSize, 2> fieldDims = {1, (mwSize)fields.size()};
std::array<mwSize, 2> dims = {1, (mwSize)parents.Size()};
auto * result = mxCreateStructArray (2, dims.data(), fields.size(), fields.data());
for (size_t i = 0; i < parents.Size(); ++i) {
auto parent = parents.At(i);
mxSetField(result, i, "id", mxCreateString(parent.GetId().c_str()));
mxSetField(result, i, "name", mxCreateString(parent.GetName().c_str()));
// FIXME Add again once upstream is ready.
// mxSetField(result, i, "description", mxCreateString(parent.GetDescription().c_str()));
}
return result;
}
// Properties to struct array
auto mxFromCaosDBProperties(const caosdb::entity::Properties &properties) -> mxArray * {
std::vector<const char*> fields =
{"id",
"name",
"description",
"importance",
"value",
"unit",
"datatype"
};
std::array<mwSize, 2> fieldDims = {1, (mwSize)fields.size()};
std::array<mwSize, 2> dims = {1, (mwSize)properties.Size()};
auto * result = mxCreateStructArray (2, dims.data(), fields.size(), fields.data());
for (mwIndex i = 0; i < properties.Size(); ++i) {
auto property = properties.At(i);
mxSetField(result, i, "id", mxCreateString(property.GetId().c_str()));
mxSetField(result, i, "name", mxCreateString(property.GetName().c_str()));
mxSetField(result, i, "description", mxCreateString(property.GetDescription().c_str()));
mxSetField(result, i, "importance", mxCreateString(property.GetImportance().c_str()));
mxSetField(result, i, "unit", mxCreateString(property.GetUnit().c_str()));
mxSetField(result, i, "datatype", mxCreateString(property.GetDatatype().c_str()));
// Parse value to proper type.
mxSetField(result, i, "value", mxScalarFromStringValue(property));
}
return result;
}
// Messages to struct array
auto mxFromCaosDBMessages(const caosdb::entity::Messages &messages) -> mxArray * {
std::vector<const char*> fields =
{"code",
"description"
};
std::array<mwSize, 2> fieldDims = {1, (mwSize)fields.size()};
std::array<mwSize, 2> dims = {1, (mwSize)messages.Size()};
auto * result = mxCreateStructArray (2, dims.data(), fields.size(), fields.data());
for (mwIndex i = 0; i < messages.Size(); ++i) {
auto message = messages.At(i);
mxSetField(result, i, "code", mxScalarINT64(message.GetCode()));
mxSetField(result, i, "description", mxCreateString(message.GetDescription().c_str()));
}
return result;
}
// Utility functions //////////////////////////////////////////////////////////
/**
* @brief Merges a number of scalar mex structs into a 1xN struct.
*/
auto mxMergeScalarStructs(const std::vector<const mxArray *> &structs) -> mxArray* {
// We need the field names first to create a new struct
auto nFields = (size_t)mxGetNumberOfFields(structs[0]);
auto fields = std::vector<const char*>(nFields);
for (mwIndex i = 0; i < nFields; ++i) {
fields[i] = mxGetFieldNameByNumber(structs[0], i);
}
auto dims = std::array<mwSize, 2>{1, (mwSize)structs.size()};
auto result = mxCreateStructArray(2, dims.data(), fields.size(), fields.data());
auto i = mwIndex(0) - 1;
for (auto scalarStruct: structs) {
++i;
for (auto field: fields) {
mxSetField(result, i, field, mxGetField(scalarStruct, 0, field));
}
}
return result;
}
} // namespace maoxdb