Skip to content

Commit

Permalink
Add tiledb_array_schema_get_enumeration API
Browse files Browse the repository at this point in the history
  • Loading branch information
rroelke committed Oct 23, 2024
1 parent 55c5d95 commit b484eb6
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 3 deletions.
73 changes: 73 additions & 0 deletions test/src/unit-cppapi-enumerations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@

using namespace tiledb;

static bool is_equivalent_enumeration(
const Enumeration& left, const Enumeration& right) {
return left.name() == right.name() && left.type() == right.type() &&
left.cell_val_num() == right.cell_val_num() &&
left.ordered() == right.ordered() &&
std::equal(
left.ptr()->data().begin(),
left.ptr()->data().end(),
right.ptr()->data().begin(),
right.ptr()->data().end());
}

struct CPPEnumerationFx {
CPPEnumerationFx();
~CPPEnumerationFx() = default;
Expand Down Expand Up @@ -313,6 +325,67 @@ TEST_CASE_METHOD(
REQUIRE(enmr_name2.has_value() == false);
}

TEST_CASE_METHOD(
CPPEnumerationFx,
"CPP: Enumerations From Disk - ArraySchema::get_enumeration",
"[enumeration][array-schema-get-enumeration]") {
create_array();

SECTION("default schema load does not populate enumeration") {
auto schema = Array::load_schema(ctx_, uri_);
auto enmr = ArraySchemaExperimental::get_enumeration(
ctx_, schema, "an_enumeration");
CHECK(!enmr.has_value());
}

SECTION("array get_enumeration loads enumeration and schema shares") {
auto array = tiledb::Array(ctx_, uri_, TILEDB_READ);
auto from_array =
ArrayExperimental::get_enumeration(ctx_, array, "an_enumeration");

auto schema = array.schema();
auto from_schema = ArraySchemaExperimental::get_enumeration(
ctx_, schema, "an_enumeration");
CHECK(is_equivalent_enumeration(from_array, *from_schema));
}

SECTION("array get_enumeration loads into user schema handle") {
auto array = tiledb::Array(ctx_, uri_, TILEDB_READ);
auto schema = array.schema();

// the enumeration is not populated yet
REQUIRE(!ArraySchemaExperimental::get_enumeration(
ctx_, schema, "an_enumeration")
.has_value());

// array method actually loads it
auto from_array =
ArrayExperimental::get_enumeration(ctx_, array, "an_enumeration");

// and once it is loaded, it is set on the schema
auto from_schema = ArraySchemaExperimental::get_enumeration(
ctx_, schema, "an_enumeration");
REQUIRE(from_schema.has_value());

CHECK(is_equivalent_enumeration(from_array, *from_schema));
}

SECTION("schema load with rest config does populate enumeration") {
Config config;
config["rest.load_enumerations_on_array_open"] = "true";

auto schema = Array::load_schema(ctx_, uri_, config);
auto enmr = ArraySchemaExperimental::get_enumeration(
ctx_, schema, "an_enumeration");
REQUIRE(enmr.has_value());
REQUIRE(enmr->ptr() != nullptr);
REQUIRE(enmr->name() == "an_enumeration");
REQUIRE(enmr->type() == TILEDB_STRING_ASCII);
REQUIRE(enmr->cell_val_num() == TILEDB_VAR_NUM);
REQUIRE(enmr->ordered() == false);
}
}

TEST_CASE_METHOD(
CPPEnumerationFx,
"CPP: Array::load_all_enumerations",
Expand Down
30 changes: 30 additions & 0 deletions tiledb/api/c_api/array_schema/array_schema_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,26 @@ capi_return_t tiledb_array_schema_timestamp_range(
return TILEDB_OK;
}

capi_return_t tiledb_array_schema_get_enumeration(
tiledb_array_schema_t* array_schema,
const char* enumeration_name,
tiledb_enumeration_t** enumeration) {
ensure_array_schema_is_valid(array_schema);
ensure_output_pointer_is_valid(enumeration);

if (enumeration_name == nullptr) {
throw CAPIException("'enumeration_name' must not be null");
}

auto ptr = array_schema->get_enumeration(enumeration_name);
if (ptr) {
*enumeration = tiledb_enumeration_handle_t::make_handle(ptr);
} else {
*enumeration = nullptr;
}
return TILEDB_OK;
}

capi_return_t tiledb_array_schema_add_enumeration(
tiledb_array_schema_t* array_schema, tiledb_enumeration_t* enumeration) {
ensure_array_schema_is_valid(array_schema);
Expand Down Expand Up @@ -540,6 +560,16 @@ CAPI_INTERFACE(
ctx, array_schema, lo, hi);
}

CAPI_INTERFACE(
array_schema_get_enumeration,
tiledb_ctx_t* ctx,
tiledb_array_schema_t* array_schema,
const char* enumeration_name,
tiledb_enumeration_t** enumeration) {
return api_entry_context<tiledb::api::tiledb_array_schema_get_enumeration>(
ctx, array_schema, enumeration_name, enumeration);
}

CAPI_INTERFACE(
array_schema_add_enumeration,
tiledb_ctx_t* ctx,
Expand Down
30 changes: 30 additions & 0 deletions tiledb/api/c_api/array_schema/array_schema_api_experimental.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,36 @@ TILEDB_EXPORT capi_return_t tiledb_array_schema_timestamp_range(
uint64_t* lo,
uint64_t* hi) TILEDB_NOEXCEPT;

/**
* Retrieves an already-loaded enumeration given its name.
*
* If the enumeration has already been loaded,
* such as via `tiledb_array_get_enumeration`,
* then this returns a pointer to the enumeration.
* Otherwise this returns `TILEDB_OK` and sets `enumeration` to NULL.
*
* **Example:**
*
* The following retrieves the enumeration named "states" in the schema.
*
* @code{.c}
* tiledb_enumeration_t* enmr;
* tiledb_array_schema_get_enumeration(ctx, array_schema, "states", &enmr);
* tiledb_attribute_free(&enmr);
* @endcode
*
* @param[in] ctx The TileDB context.
* @param[in] array_schema The array schema.
* @param[in] name The name of the enumeration to retrieve.
* @param[out] enmr The enumeration object to retrieve.
* @return `TILEDB_OK` for success and `TILEDB_ERR` for error.
*/
TILEDB_EXPORT capi_return_t tiledb_array_schema_get_enumeration(
tiledb_ctx_t* ctx,
tiledb_array_schema_t* array_schema,
const char* name,
tiledb_enumeration_t** enumeration) TILEDB_NOEXCEPT;

/**
* Adds an enumeration to an array schema.
*
Expand Down
5 changes: 5 additions & 0 deletions tiledb/api/c_api/array_schema/array_schema_api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ struct tiledb_array_schema_handle_t
dim_id, name, label_order, label_type, check_name);
}

shared_ptr<const tiledb::sm::Enumeration> get_enumeration(
const char* name) const {
return array_schema_->get_enumeration(name);
}

void add_enumeration(shared_ptr<const tiledb::sm::Enumeration> enmr) {
return array_schema_->add_enumeration(enmr);
}
Expand Down
62 changes: 62 additions & 0 deletions tiledb/api/c_api/array_schema/test/unit_capi_array_schema.cc
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,68 @@ TEST_CASE(
CHECK(enumeration == nullptr);
}

TEST_CASE(
"C API: tiledb_array_schema_get_enumeration argument validation",
"[capi][array_schema]") {
capi_return_t rc;
ordinary_array_schema x{};
tiledb_enumeration_t* enumeration;
SECTION("null context") {
rc = tiledb_array_schema_get_enumeration(
nullptr, x.schema, "primes", &enumeration);
REQUIRE(tiledb_status(rc) == TILEDB_INVALID_CONTEXT);
}
SECTION("null schema") {
rc = tiledb_array_schema_get_enumeration(
x.ctx(), nullptr, "primes", &enumeration);
REQUIRE(tiledb_status(rc) == TILEDB_ERR);
}
SECTION("null name") {
rc = tiledb_array_schema_get_enumeration(
x.ctx(), x.schema, nullptr, &enumeration);
REQUIRE(tiledb_status(rc) == TILEDB_ERR);
}
SECTION("null enumeration") {
rc = tiledb_array_schema_get_enumeration(
x.ctx(), x.schema, "primes", nullptr);
REQUIRE(tiledb_status(rc) == TILEDB_ERR);
}
SECTION("success") {
int32_t values[5] = {2, 3, 5, 7, 11};
rc = tiledb_enumeration_alloc(
x.ctx(),
"primes",
TILEDB_UINT32,
1,
0,
values,
sizeof(uint32_t) * 5,
nullptr,
0,
&enumeration);
REQUIRE(tiledb_status(rc) == TILEDB_OK);
tiledb_array_schema_add_enumeration(x.ctx(), x.schema, enumeration);
REQUIRE_NOTHROW(tiledb_enumeration_free(&enumeration));
CHECK(enumeration == nullptr);

rc = tiledb_array_schema_get_enumeration(
x.ctx(), x.schema, "primes", &enumeration);
REQUIRE(tiledb_status(rc) == TILEDB_OK);
REQUIRE(enumeration != nullptr);

tiledb_string_t* tiledb_name(nullptr);
rc = tiledb_enumeration_get_name(x.ctx(), enumeration, &tiledb_name);
REQUIRE(tiledb_status(rc) == TILEDB_OK);
REQUIRE(tiledb_name != nullptr);

const char* name;
size_t length;
rc = tiledb_string_view(tiledb_name, &name, &length);
REQUIRE(tiledb_status(rc) == TILEDB_OK);
CHECK(std::string(name, length) == "primes");
}
}

TEST_CASE(
"C API: tiledb_array_schema_set_coords_filter_list argument validation",
"[capi][array_schema]") {
Expand Down
12 changes: 9 additions & 3 deletions tiledb/sm/cpp_api/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,8 @@ class Array {

/**
* Loads the array schema from an array.
* Options to load additional features are read from the optionally-provided
* `config`. See `tiledb_array_schema_load_with_config`.
*
* **Example:**
* @code{.cpp}
Expand All @@ -708,12 +710,16 @@ class Array {
*
* @param ctx The TileDB context.
* @param uri The array URI.
* @param config The optional request for additional features.
* @return The loaded ArraySchema object.
*/
static ArraySchema load_schema(const Context& ctx, const std::string& uri) {
static ArraySchema load_schema(
const Context& ctx,
const std::string& uri,
const Config& config = Config()) {
tiledb_array_schema_t* schema;
ctx.handle_error(
tiledb_array_schema_load(ctx.ptr().get(), uri.c_str(), &schema));
ctx.handle_error(tiledb_array_schema_load_with_config(
ctx.ptr().get(), config.ptr().get(), uri.c_str(), &schema));
return ArraySchema(ctx, schema);
}

Expand Down
25 changes: 25 additions & 0 deletions tiledb/sm/cpp_api/array_schema_experimental.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,31 @@ class ArraySchemaExperimental {
ctx.ptr().get(), array_schema.ptr().get(), current_domain.ptr().get()));
}

/**
* Retrieve an enumeration from the array schema, if has already been loaded
* (such as via `ArrayExperimental::get_enumeration`).
*
* @param ctx TileDB context.
* @param array_schema Array schema.
* @param enumeration_name The name of the enumeration to retrieve.
*/
static std::optional<Enumeration> get_enumeration(
const Context& ctx,
const ArraySchema& array_schema,
const char* enumeration_name) {
tiledb_enumeration_t* enumeration;
ctx.handle_error(tiledb_array_schema_get_enumeration(
ctx.ptr().get(),
array_schema.ptr().get(),
enumeration_name,
&enumeration));
if (enumeration) {
return Enumeration(ctx, enumeration);
} else {
return std::nullopt;
}
}

/**
* Add an enumeration to the array schema.
*
Expand Down

0 comments on commit b484eb6

Please sign in to comment.