Skip to content

Commit

Permalink
[Core] Add convenience signatures for entityExists
Browse files Browse the repository at this point in the history
Closes OpenAssetIO#1169. Add overloads for `entityExists`, similar to other API
methods. I.e. singular vs. batch, exception vs. result (variant).

Signed-off-by: David Feltell <david.feltell@foundry.com>
  • Loading branch information
feltech committed Jun 13, 2024
1 parent ae1de37 commit 982e02b
Show file tree
Hide file tree
Showing 9 changed files with 27,396 additions and 24,830 deletions.
10 changes: 5 additions & 5 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ v1.0.0-beta.x.y

### Improvements

- Added `getRelationship(s)` overloads for convenience, providing
alternatives to the core callback-based workflow. Includes a more
direct method for resolving relationships for single entity
references, or single relationships, as well exception vs. result
object workflows.
- Added `getRelationship(s)` and `entityExists` overloads for
convenience, providing alternatives to the core callback-based
workflow. Includes more direct methods for singular queries, as
well as exception vs. result object workflows.
[#973](https://github.com/OpenAssetIO/OpenAssetIO/issues/973)
[#1169](https://github.com/OpenAssetIO/OpenAssetIO/issues/1169)

- Added `.pyi` stub files to the Python package to aid IDE code
completion for Python bindings of C++ types.
Expand Down
51,850 changes: 27,048 additions & 24,802 deletions resources/abi/libopenassetio.so.1.0.0.xml

Large diffs are not rendered by default.

177 changes: 177 additions & 0 deletions src/openassetio-core/include/openassetio/hostApi/Manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,183 @@ class OPENASSETIO_CORE_EXPORT Manager final {
const ExistsSuccessCallback& successCallback,
const BatchElementErrorCallback& errorCallback);

/**
* Determines if the supplied @ref entity_reference points to an
* entity that exists in the @ref asset_management_system.
*
* See the documentation for the @ref
* entityExists(const EntityReferences&, <!--
* --> const ContextConstPtr&, const ExistsSuccessCallback&, <!--
* --> const BatchElementErrorCallback&) "callback overload" for more
* details.
*
* Errors that occur will be thrown as an exception, either from the
* @ref manager plugin (for errors not specific to the entity
* reference) or as a @fqref{errors.BatchElementException}
* "BatchElementException"-derived error.
*
* @param entityReference Entity reference to query.
*
* @param context The calling context.
*
* @param errorPolicyTag Parameter for selecting the appropriate
* overload (tagged dispatch idiom). See @ref
* BatchElementErrorPolicyTag::Exception.
*
* @return Boolean indicating existence of the entity.
*
* @throws errors.BatchElementException Converted exception thrown
* when the manager emits a @fqref{errors.BatchElementError}
* "BatchElementError".
*
* @throws errors.NotImplementedException Thrown when this method is
* not implemented by the manager. Check that this method is
* implemented before use by calling @ref hasCapability with @ref
* Capability.kExistenceQueries.
*
* @see @ref Capability.kExistenceQueries
*/
bool entityExists(const EntityReference& entityReference, const ContextConstPtr& context,
const BatchElementErrorPolicyTag::Exception& errorPolicyTag = {});

/**
* Determines if the supplied @ref entity_reference points to an
* entity that exists in the @ref asset_management_system.
*
* See the documentation for the @ref
* entityExists(const EntityReferences&, <!--
* --> const ContextConstPtr&, const ExistsSuccessCallback&, <!--
* --> const BatchElementErrorCallback&) "callback overload" for more
* details.
*
* If successful, the result is a boolean indicating the existence of
* the @ref entity.
*
* Otherwise, the result is populated with an error object detailing
* the reason for the failure to check the existence of this
* particular entity.
*
* Errors that are not specific to the entity being queried will be
* thrown as an exception.
*
* @param entityReference Entity reference to query.
*
* @param context The calling context.
*
* @param errorPolicyTag Parameter for selecting the appropriate
* overload (tagged dispatch idiom). See @ref
* BatchElementErrorPolicyTag::Variant.
*
* @return Object containing either a boolean indicating the existence
* of the entity or an error object.
*
* @throws errors.NotImplementedException Thrown when this method is
* not implemented by the manager. Check that this method is
* implemented before use by calling @ref hasCapability with @ref
* Capability.kExistenceQueries.
*
* @see @ref Capability.kExistenceQueries
*/
std::variant<errors::BatchElementError, bool> entityExists(
const EntityReference& entityReference, const ContextConstPtr& context,
const BatchElementErrorPolicyTag::Variant& errorPolicyTag);

/**
* Type to use in place of bool in `vector<bool>` so that the "dynamic
* bitset" specialisation of std::vector is not used.
*
* `std::vector<bool>` is a specialisation that uses a single bit per
* element, which is more memory efficient but limits the use of
* the vector for certain operations.
*
* As a workaround, we can use an integral type as the vector element,
* such that zero represents false and non-zero represents true.
*/
using BoolAsUint = std::uint_fast8_t;

/**
* Determines if each supplied @ref entity_reference points to an
* entity that exists in the @ref asset_management_system.
*
* See documentation for the <!--
* --> @ref entityExists(const EntityReferences&, <!--
* --> const ContextConstPtr&, const ExistsSuccessCallback&, <!--
* --> const BatchElementErrorCallback& errorCallback)
* "callback overload" for more details on existence check behaviour.
*
* Any errors that occur will be immediately thrown as an exception,
* either from the @ref manager plugin (for errors not specific to the
* entity reference) or as a @fqref{errors.BatchElementException}
* "BatchElementException"-derived error.
*
* @param entityReferences Entity references to query.
*
* @param context The calling context.
*
* @param errorPolicyTag Parameter for selecting the appropriate
* overload (tagged dispatch idiom). See @ref
* BatchElementErrorPolicyTag::Exception.
*
* @return List of boolean values indicating the existence of each
* entity.
*
* @throws errors.BatchElementException Converted exception thrown
* when the manager emits a @fqref{errors.BatchElementError}
* "BatchElementError".
*
* @throws errors.NotImplementedException Thrown when this method is
* not implemented by the manager. Check that this method is
* implemented before use by calling @ref hasCapability with @ref
* Capability.kExistenceQueries.
*
* @see @ref Capability.kExistenceQueries
*/
std::vector<BoolAsUint> entityExists(
const EntityReferences& entityReferences, const ContextConstPtr& context,
const BatchElementErrorPolicyTag::Exception& errorPolicyTag = {});

/**
* Determines if each supplied @ref entity_reference points to an
* entity that exists in the @ref asset_management_system.
*
* For successful references, the corresponding element of the result
* is populated with a boolean indicating the existence of the entity.
*
* Otherwise, the corresponding element of the result is populated
* with an error object detailing the reason for the failure to check
* the existence of that particular entity.
*
* Errors that are not specific to an entity will be thrown as an
* exception, failing the whole batch.
*
* See documentation for the <!--
* --> @ref entityExists(const EntityReferences&, <!--
* --> const ContextConstPtr&, const ExistsSuccessCallback&, <!--
* --> const BatchElementErrorCallback& errorCallback)
* "callback overload" for more details on existence check behaviour.
*
* @param entityReferences Entity references to query.
*
* @param context The calling context.
*
* @param errorPolicyTag Parameter for selecting the appropriate
* overload (tag dispatch idiom). See @ref
* BatchElementErrorPolicyTag::Variant.
*
* @return List of objects, each containing either a boolean indicating
* the existence of the entity or an error.
*
* @throws errors.NotImplementedException Thrown when this method is
* not implemented by the manager. Check that this method is
* implemented before use by calling @ref hasCapability with @ref
* Capability.kExistenceQueries.
*
* @see @ref Capability.kExistenceQueries
*/
std::vector<std::variant<errors::BatchElementError, bool>> entityExists(
const EntityReferences& entityReferences, const ContextConstPtr& context,
const BatchElementErrorPolicyTag::Variant& errorPolicyTag);

/**
* Callback signature used for a successful entity trait set query.
*/
Expand Down
30 changes: 19 additions & 11 deletions src/openassetio-core/src/errors/exceptionMessages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ Str errorCodeName(BatchElementError::ErrorCode code) {
return "Unknown ErrorCode";
}

std::string createBatchElementExceptionMessage(const BatchElementError& err, size_t index,
const EntityReference& entityReference,
internal::access::Access access) {
std::string createBatchElementExceptionMessage(
const BatchElementError& err, size_t index, const EntityReference& entityReference,
const std::optional<internal::access::Access> access) {
/*
* BatchElementException messages consist of five parts.
* 1. The name of the error code.
Expand All @@ -47,16 +47,24 @@ std::string createBatchElementExceptionMessage(const BatchElementError& err, siz
* Ends up looking something like : "entityAccessError: Could not
* access Entity [index=2] [access=read] [entity=bal:///entityRef]"
*/
const auto errorCodeStr = fmt::format("{}:", errorCodeName(err.code));
const auto errorMessageStr = err.message.empty() ? "" : fmt::format(" {}", err.message);
std::string result;

// Data elements
const auto indexStr = fmt::format(" [index={}]", index);
const auto accessStr = fmt::format(" [access={}]", access::kAccessNames[access]);
const auto entityReferenceStr = fmt::format(" [entity={}]", entityReference.toString());
result += fmt::format("{}:", errorCodeName(err.code));

return fmt::format("{}{}{}{}{}", errorCodeStr, errorMessageStr, indexStr, accessStr,
entityReferenceStr);
if (!err.message.empty()) {
result += " ";
result += err.message;
}

result += fmt::format(" [index={}]", index);

if (access) {
result += fmt::format(" [access={}]", access::kAccessNames[*access]);
}

result += fmt::format(" [entity={}]", entityReference.toString());

return result;
}
} // namespace errors
} // namespace OPENASSETIO_CORE_ABI_VERSION
Expand Down
2 changes: 1 addition & 1 deletion src/openassetio-core/src/errors/exceptionMessages.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Str errorCodeName(BatchElementError::ErrorCode code);
/**Construct a full message to place into a convenience exception.*/
std::string createBatchElementExceptionMessage(const BatchElementError& err, size_t index,
const EntityReference& entityReference,
internal::access::Access access);
std::optional<internal::access::Access> access);
} // namespace errors
} // namespace OPENASSETIO_CORE_ABI_VERSION
} // namespace openassetio
74 changes: 74 additions & 0 deletions src/openassetio-core/src/hostApi/ManagerConveniences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,84 @@
namespace openassetio {
inline namespace OPENASSETIO_CORE_ABI_VERSION {
namespace hostApi {

// The definitions below are the "convenience" method signatures -
// alternate, often friendlier signatures wrapping the core batch-first
// callback-based member functions found in `Manager.cpp`

/******************************************
* entityExists
******************************************/

// Singular Except
bool hostApi::Manager::entityExists(
const EntityReference &entityReference, const ContextConstPtr &context,
[[maybe_unused]] const BatchElementErrorPolicyTag::Exception &errorPolicyTag) {
bool result{};
entityExists(
{entityReference}, context,
[&result]([[maybe_unused]] std::size_t index, bool exists) { result = exists; },
[&entityReference](std::size_t index, errors::BatchElementError error) {
auto msg = errors::createBatchElementExceptionMessage(error, index, entityReference,
std::nullopt);
throw errors::BatchElementException(index, std::move(error), msg);
});

return result;
}

// Singular variant
std::variant<errors::BatchElementError, bool> hostApi::Manager::entityExists(
const EntityReference &entityReference, const ContextConstPtr &context,
[[maybe_unused]] const BatchElementErrorPolicyTag::Variant &errorPolicyTag) {
std::variant<errors::BatchElementError, bool> result;
entityExists(
{entityReference}, context,
[&result]([[maybe_unused]] std::size_t index, bool exists) { result = exists; },
[&result]([[maybe_unused]] std::size_t index, errors::BatchElementError error) {
result = std::move(error);
});

return result;
}

// Multi except
std::vector<hostApi::Manager::BoolAsUint> hostApi::Manager::entityExists(
const EntityReferences &entityReferences, const ContextConstPtr &context,
[[maybe_unused]] const BatchElementErrorPolicyTag::Exception &errorPolicyTag) {
std::vector<BoolAsUint> results;
results.resize(entityReferences.size());

entityExists(
entityReferences, context,
[&results](std::size_t index, bool exists) {
results[index] = static_cast<BoolAsUint>(exists);
},
[&entityReferences](std::size_t index, errors::BatchElementError error) {
auto msg = errors::createBatchElementExceptionMessage(
error, index, entityReferences[index], std::nullopt);
throw errors::BatchElementException(index, std::move(error), msg);
});

return results;
}

// Multi variant
std::vector<std::variant<errors::BatchElementError, bool>> hostApi::Manager::entityExists(
const EntityReferences &entityReferences, const ContextConstPtr &context,
[[maybe_unused]] const BatchElementErrorPolicyTag::Variant &errorPolicyTag) {
std::vector<std::variant<errors::BatchElementError, bool>> results;
results.resize(entityReferences.size());
entityExists(
entityReferences, context,
[&results](std::size_t index, bool exists) { results[index] = exists; },
[&results](std::size_t index, errors::BatchElementError error) {
results[index] = std::move(error);
});

return results;
}

/******************************************
* entityTraits
******************************************/
Expand Down
Loading

0 comments on commit 982e02b

Please sign in to comment.