Repository: single-cell-data/TileDB-SOMA (language: python)

Issue:
[python/r/c++] Revisit `shape` for component arrays
## PRs

**Merged PRs:**

<details>

* #2909 `kerl/schevo-timestamp-methodize`
* #2913 `kerl/name-neaten`
* #2908 `kerl/ut-soma-exc-simplify`
* #2910 `kerl/test-common-parameterize`
* #2918 `kerl/cpp-test-deadstrip`
* #2919 `kerl/minor-unit-test-helper-mod`
* #2936 `kerl/cpp-ut-helper-neaten`
* #2938 `kerl/more-cur-dom-parameterize`
* #2915 `kerl/cpp-strict-int64-shape`
* #2911 `kerl/arrow-util-current-domain-optional`
* #2939 `kerl/step-two-temp`
* #2947 `kerl/cpp-ndarray-resize-testing`
* #2945 `kerl/dataframe-test-fixture`
* #2944 `kerl/cpp-variant-indexed-dataframes`
* #2916 `kerl/sdf-shape`
* #2917 `kerl/cpp-resizes`
* #2948 `kerl/upgrade-shape-int64`
* #2951 `kerl/sdf-test-accessors`
* #2953 `kerl/py-r-accessor-plumbing`
* #2957 `kerl/sdf-domain-accessors`
* #2960 `kerl/dense-link`
* #2963 `kerl/nightly-fix`
* #2970 `kerl/dense-writeable-after-create`
* #2968 `kerl/minor-trim`
* #2969 `kerl/more-py-domain-name-neaten`
* #2972 `kerl/libtiledbsoma-env-logging-level`
* #2962 `kerl/py-r-creation-paths`
* #2950 `kerl/py-r-test-2`
* #2994 `kerl/nanoarrow-helpers`
* #3011 `kerl/polydom3`
* #3017 `kerl/polydom5`
* #3018 `kerl/polydom6`
* #2990 `kerl/variant-nnz-bug`
* #3019 `kerl/index-swap`
* #3020 `kerl/ut-max-shape`
* #3012 `kerl/polydom4`
* #3025 `kerl/fix-3020-merge`
* #3026 `kerl/one-more-rename`
* #3028 `kerl/ff-not`
* #3029 `kerl/ut-vg`
* #3030 `kerl/table-utils-memory`
* #3067 `kerl/improve-sdf-test-field-names`
* #3068 `kerl/ut-generate`
* #3069 `kerl/cpp-sdf-domain-at-create`
* #3027 `kerl/hll-domainish`
* #3088 `kerl/max-domain-int64`
* #3090 `kerl/maybe-resize-soma-joinid-cpp-tweak`
* #3032 `kerl/sdf-domain-at-create` -- fixes #2967
* #3091 `kerl/maybe-resize-soma-joinid-py-r`
* #3095 `kerl/cpp-exp-resize-prep`
* #3089 `kerl/r-dataframe-shapeable`
* https://github.com/single-cell-data/SOMA/pull/233
* #3125 `kerl/cpp-ut-name-shortens`
* #3127 `kerl/helper-rename`
* #3130 `kerl/cpp-can-resizers-names`
* #3132 `kerl/cpp-dataframe-sizing-helpers`
* #3139 `kerl/cpp-dataframe-upgrade-test`
* #3140 `kerl/py-resizer-connects`
* #3151 `kerl/py-can-upgrade-shape`
* #3152 `kerl/registration-shape-acceessors`
* #3156 `kerl/py-exp-shaping`
* #3157 `kerl/py-exp-shaping2`
* #3148 `kerl/py-exp-resize`
* #3191 `kerl/py-domain-at-create-ut-1`
* #3190 `kerl/py-domain-at-create-ut-2`
* #3192 `kerl/py-domain-at-create-ut-3`
* #3193 `kerl/py-domain-at-create-ut-4`
* #3194 `kerl/py-domain-at-create-ut-5`
* #3203 `kerl/min-size-2`
* #3208 `kerl/r-min-sizing`
* #3211 `kerl/cpp-ugr-dom`
* #3232 `kerl/ff-interop`
* #3230 `kerl/ffon`
* #3234 `kerl/docstring-prune`
* #3236 `kerl/prefixing`
* #3241 `kerl/fix-bad-merge`
* #3235 `kerl/py-r-ugr-dom`
* #3237 `kerl/py-r-ugr-dom-2`
* #3238 `kerl/py-r-ugr-dom-3`
* #3253 `kerl/set-coords-rename`
* #3261 `kerl/pybind11-nda-sizing`
* #3265 `kerl/dense-227-a`
* #3263 `kerl/dense-range-trim`
* #3268 `kerl/dim-explosion`
* #3269 `kerl/python-227-dense-ned-read`
* #3270 `kerl/r-227-dense-fixes`
* #3280 `kerl/r-dense-227-more`
* #3286 `kerl/more-fn4m`
* #3283 `kerl/readthedocs-pre-1.15`
* #3288 `kerl/dense-ugrsh`
* #3289 `kerl/notebook-shape-upgrade`
* #3285 `kerl/new-shape-doc-updates`
* #3295 `kerl/notebook-data-refresh`
* #3290 `kerl/notebook-new-shape-refresh`
* #3301 `kerl/ffena`
* #3303 `kerl/r-data-refresh`
* #3300 `kerl/sdf-sjid-lower-zero`
* #3296 `kerl/dense-example-data-refresh`
* #3294 `kerl/new-shape-notebook-and-vignette`
* #3308 `kerl/upgrade-experiment-resources`
* #3309 `kerl/fix-notebook-merge`
* #3321 `kerl/more-use-shape`
* #3358 `kerl/revert-3300`
* #3368 `kerl/227a`
* #3369 `kerl/ucd1`
* #3370 `kerl/ucd2`
* #3371 `kerl/ucd3`
* #3372 `kerl/ucd4`
* #3396 `kerl/domain-at-create-docstrings`
* #3302 `kerl/new-shape-vignette`
* https://github.com/single-cell-data/SOMA/pull/250
* #3399 `kerl/new-shape-more-docstrings`
* #3400 `kerl/check-only-r`
* https://github.com/TileDB-Inc/somacore-feedstock/pull/27

</details>

**Closed/abandoned PRs:**

<details>

* #2785 -- This was only dogfooding for the core 2.25 release -- not to be merged
* #2952 `kerl/feature-flag-temp` -- folded into 2962
* #2995 `kerl/polydom`
* #2964 `kerl/tiledbsoma-io-test`
* #3189 `kerl/min-size`
* #3220 `kerl/cpp-ugr-dom-2`
* #3244 `kerl/dense-227-fixes`
* #3276 `kerl/dataframe-shape`

</details>

**Issues which are related but non-blocking:**

* https://github.com/single-cell-data/SOMA/pull/216
* https://github.com/TileDB-Inc/TileDB/pull/5303
* #2966
* #3081
* Note: R append mode does not exist yet -- see #1630 -- so an experiment-level resizer is not a priority in R
* #3271 
* #3272
* #3273

**See also:** [[sc-51048]](https://app.shortcut.com/tiledb-inc/story/51048).

## Problem to be solved

Users want to know the `shape` of an array, in the SciPy sense:

* Reads and writes are bounds-checked against the shape
* This retains its value regardless of which values of a sparse array are or are not actually occupied
* Users can `resize`.
  * Some users need the ability to grow their datasets later, using either `tiledbsoma.io`'s append mode, or subsequent writes using the `tiledbsoma` API.
  * Note that the cellxgene census doesn't need this: eact week's published census has fixed shape, and any updates will happen in new storage, on a new week.

Using TileDB-SOMA up until the present:

* The TIleDB `domain` is immutable after array creation
  * This does bounds-checking for reads and writes, which is good
  * To leverage this to function as a `shape`, users would need to set the `domain` at array-creation time. However, users lose the ability to grow their datasets later.
* There is a `non_empty_domain` accessor
  * This only indicates min/max coordinates _at which data exists_. Consider an `X` array for 100 cells and 200 genes. If non-zero expression counts exist only for cell join IDs 2-17, then the `non_empty_domain` will indicate `(2,17)` along `soma_dim_0`.
  * Consider an `obms["X_pca"]` within the same experiment. This may be 100 cells by 50 PCA components: we need a placd to store the number 50.
  * Therefore users cannot leverage this to function as a `shape` accessor.
* We have offered a `used_shape` accessor since TileDB-SOMA 1.5.
  * This functions as a `shape` accessor, in the SciPy sense, but it is not multi-writer safe.

New feature for TileDB-SOMA 1.15:

* Arrays will have a  `shape`
* Reads and writes are bounds-checked against the shape
* This retains its value regardless of which values of a sparse array are or are not actually occupied
* Users can `resize`
* The `used_shape` accessor will be deprecated in TileDB-SOMA 1.13, and slated for removal in TileDB-SOMA 1.14.

Compatiblity:

This will now require users to do an explicit `resize` before appending/growing TileDB-SOMA Experiments. Guidance in the form of example notebooks will be provided.

##  Tracking

See also: [[sc-41074]](https://app.shortcut.com/tiledb-inc/story/41074) and [[sc-51048]](https://app.shortcut.com/tiledb-inc/story/51048).

## Scheduling

Support arrives in TileDB Core 2.25. Deprecations for TileDB-SOMA will be released with 1.13. Full support within TileDB-SOMA will be release in 1.14.

## Details

SOMA API mods as we've discussed in a Google doc are as follows.

### `SOMADataFrame`

* `create`: Retain the `domain` argument
  * Issue:
    * Core has a `(lo, hi)` tuple per dim, e.g. `(0,99)` or `(10,19)`
    * SOMA has count per dim, with 0 implicit: e.g. 100 or 20
    * For `SparseNDArray` and `DenseNDArray` core can have `(lo, hi)` and SOMA can have `count`
    * For `DataFrame` there can be multiple dims --- default is a single `soma_joinid`
    * That could be treated either in `(lo, hi)` fashion or `count` fashion
    * However additional dims (e.g. `cell_type`) can be on any type, including strings, floats, etc. where there is no implicit lo=0
    * Therefore we need to keep the current SOMA API wherein `DataFrame` takes a `domain` argument (in `(lo, hi)` fashion) and not a `shape` argument (in `count` fashion)

### `SparseNDArray and DenseNDArray`

* `create`
  * Have an optional shape argument which is of type `Tuple[Int,...]` where each element is the cell count of the corresponding dimension
    * If unsupplied, or if supplied but None in any slot: use the minimum 0 in each slot – nothing larger makes sense since we will not support downsize
  * User guidance should make clear that it will not be possible to create an ‘old’ style array with the ‘new style’ API. (See also the upgrade logic below.)

### All three of `SOMADataFrame`, `SparseNDArray`, `DenseNDArray`

* `write`
  * For new arrays, created with the new shape feature:
    * Core will bounds-check that coordinates provided at `write` time are within the current shape
    * Core will raise `tiledb.cc.TileDBError` to TileDB-SOMA, which will catch and raise `IndexError`, and R-standard behavior on the R side
  * For old arrays created before this feature:
    * Core will not bounds-check that coordinates provided at write time are within the current shape
* Existing `used_shape` accessor
  * TileDB-SOMA will deprecate this over a release cycle.
  * For new arrays: raise `NotImplementedError`
  * For old arrays: return what’s currently returned, with a deprecation warning.
  * Mechanism for determining old vs. new: `array.schema.version` (the core storage version).
* Existing `shape` accessor
  * For new arrays:
    * Have this return the new shape as proposed by core, no longer returning the TileDB domain.
  * For old arrays created before this feature:
    * Return the TileDB domain as now.
* Existing `non_empty_domain` accessor
  * Same behavior for old and new arrays (unaffected by this proposal).
  * Keep this accessor supported, but, with user notes that it’s generally non-useful
  * This should return None (or R equivalent) when there is a schema but no data have been written.
* New `maxshape` accessor
  * Maps the core-level `(lo, hi)` accessor for domain to count-style accessor hi+1. E.g. if the core domain is either `(0,99)` or `(50,99)` then TileDB-SOMA `maxshape` will say 100.
  * Same behavior for old and new arrays.
  * Let users query for what the TileDB domain is, with user notes that it’s the maximum that users can reshape to.
  * Issac suggests: maybe `domain` or `maxshape` (see h5py).
* New `resize` mutator
  * Note: `reshape` means something else in the community (numpy, zarr, h5py), e.g. a 5x20 (total 100 cells) being reinterpreted as 4x25 (still 100 cells). The standard name for changing cell-count is `resize`.
  * For old arrays created before this feature: raise `NotImplementedError`.
  * For new arrays:
    * Will raise `ValueError` if the new shape is smaller on any dim than currently in storage
    * Regardless of whether any data have been written whatsoever
    * Will raise `ValueError` if the new shape exceeds the TileDB domain from create time, which will serve TileDB-SOMA in a role of “max possible shape the user can reshape to”
    * Otherwise, any calls to write from this point will bounds-check writes within this new shape
    * **We don’t expect resize to be multi-writer safe with regard to write ; user notes must be clear on this point**
* New `tiledbsoma_upgrade_shape` method for SparseNDArray and DenseNDArray
  * This will leverage `array.schema.version` to see if an upgrade is needed
  * Leverage core support for storage-version updates
  * This will take a shape argument as in `create`
  * For arrays created with “just-right” size: this will succeed
  * For arrays created with “room-for-growth” / “two billion-ish” size: this will succeed
  * If the user passes a shape which exceeds the current TileDB domain: this will fail
* New `tiledbsoma_upgrade_domain method` for `DataFrame`
  * Same as for `SparseNDArray`/`DenseNDArray` except it will take a domain at the SOMA-API level just as `DataFrame`'s create method

### `tiledbsoma.io`

* The user-facing API has no shape arguments and thus won’t need changing.
* Internally to `tiledbsoma.io`, we’ll still ask the tiledbsoma API for the “big domain” (2 billionish)
* Append mode:
  * Will need a new `resize` method at the `Experiment` level
  * Users will need to:
    * Register as now
    * Call the experiment-level `resize`
      * Could be `exp.resize(...)`, or (better) this could be `tiledbsoma.io.reshape_experiment`
  * In either case: this method will take the new `obs` and `var` counts as inputs:
    * `exp.obs.reshape` to new `obs` count
    * `exp.ms[name].var.reshape` to new `var` count
    * `exp.ms[name].X[name].reshape` to new `obs` count x `var` count
    * `exp.ms[name].obsm[name].reshape` to new `obs` count x same width
    * `exp.ms[name].obsp[name].reshape` to new `obs` count x `obs` count
    * `exp.ms[name].varm[name].reshape` to new `var` count x same width
    * `exp.ms[name].varp[name].reshape` to new `var` count x `var` count
  * Do the individual append-mode writes as now



Discussion / hints:
#2785 is a quick-and-dirty concept-prover -- its sole function is to flush out any API misunderstandings we might have, in prep for 2.25.0 core release.

Fix patch:
diff --git a/libtiledbsoma/src/soma/soma_array.cc b/libtiledbsoma/src/soma/soma_array.cc
index e19aa4703d..c49c3a9167 100644
--- a/libtiledbsoma/src/soma/soma_array.cc
+++ b/libtiledbsoma/src/soma/soma_array.cc
@@ -1443,7 +1443,7 @@ std::vector<int64_t> SOMAArray::maxshape() {
 std::pair<bool, std::string> SOMAArray::_can_set_shape_helper(
     const std::vector<int64_t>& newshape,
     bool is_resize,
-    std::string method_name_for_messages) {
+    std::string function_name_for_messages) {
     // E.g. it's an error to try to upgrade_domain or resize specifying
     // a 3-D shape on a 2-D array.
     auto arg_ndim = newshape.size();
@@ -1453,7 +1453,7 @@ std::pair<bool, std::string> SOMAArray::_can_set_shape_helper(
             false,
             fmt::format(
                 "cannot {}: provided shape has ndim {}, while the array has {}",
-                method_name_for_messages,
+                function_name_for_messages,
                 arg_ndim,
                 array_ndim));
     }
@@ -1471,7 +1471,7 @@ std::pair<bool, std::string> SOMAArray::_can_set_shape_helper(
                 fmt::format(
                     "{}: array currently has no shape: please use "
                     "tiledbsoma_upgrade_shape.",
-                    method_name_for_messages));
+                    function_name_for_messages));
         }
     } else {
         // They're trying to do upgrade_shape on an array that already has a
@@ -1483,7 +1483,7 @@ std::pair<bool, std::string> SOMAArray::_can_set_shape_helper(
                     "{}: array already has a shape: please use resize rather "
                     "than "
                     "tiledbsoma_upgrade_shape.",
-                    method_name_for_messages));
+                    function_name_for_messages));
         }
     }
 
@@ -1498,7 +1498,7 @@ std::pair<bool, std::string> SOMAArray::_can_set_shape_helper(
     // if the requested shape fits in the array's core domain, it's good to go
     // as a new shape.
     auto domain_check = _can_set_shape_domainish_helper(
-        newshape, false, method_name_for_messages);
+        newshape, false, function_name_for_messages);
     if (!domain_check.first) {
         return domain_check;
     }
@@ -1507,7 +1507,7 @@ std::pair<bool, std::string> SOMAArray::_can_set_shape_helper(
     // shape (core current domain) isn't a downsize of the current one.
     if (has_shape) {
         auto current_domain_check = _can_set_shape_domainish_helper(
-            newshape, true, method_name_for_messages);
+            newshape, true, function_name_for_messages);
         if (!current_domain_check.first) {
             return current_domain_check;
         }
@@ -1522,7 +1522,7 @@ std::pair<bool, std::string> SOMAArray::_can_set_shape_helper(
 std::pair<bool, std::string> SOMAArray::_can_set_shape_domainish_helper(
     const std::vector<int64_t>& newshape,
     bool check_current_domain,
-    std::string method_name_for_messages) {
+    std::string function_name_for_messages) {
     Domain domain = arr_->schema().domain();
 
     for (unsigned i = 0; i < domain.ndim(); i++) {
@@ -1538,7 +1538,7 @@ std::pair<bool, std::string> SOMAArray::_can_set_shape_domainish_helper(
             throw TileDBSOMAError(fmt::format(
                 "{}: internal error: expected {} dim to "
                 "be {}; got {}",
-                method_name_for_messages,
+                function_name_for_messages,
                 dim_name,
                 tiledb::impl::type_to_str(TILEDB_INT64),
                 tiledb::impl::type_to_str(dim.type())));
@@ -1554,7 +1554,7 @@ std::pair<bool, std::string> SOMAArray::_can_set_shape_domainish_helper(
                     false,
                     fmt::format(
                         "cannot {} for {}: new {} < existing shape {}",
-                        method_name_for_messages,
+                        function_name_for_messages,
                         dim_name,
                         newshape[i],
                         old_dim_shape));
@@ -1570,7 +1570,7 @@ std::pair<bool, std::string> SOMAArray::_can_set_shape_domainish_helper(
                     false,
                     fmt::format(
                         "cannot {} for {}: new {} < maxshape {}",
-                        method_name_for_messages,
+                        function_name_for_messages,
                         dim_name,
                         newshape[i],
                         old_dim_shape));
diff --git a/libtiledbsoma/src/soma/soma_array.h b/libtiledbsoma/src/soma/soma_array.h
index 22617948ae..1619936ac6 100644
--- a/libtiledbsoma/src/soma/soma_array.h
+++ b/libtiledbsoma/src/soma/soma_array.h
@@ -1193,7 +1193,7 @@ class SOMAArray : public SOMAObject {
     std::pair<bool, std::string> _can_set_shape_helper(
         const std::vector<int64_t>& newshape,
         bool is_resize,
-        std::string method_name_for_messages);
+        std::string function_name_for_messages);
 
     /**
      * This is a second-level code-dedupe helper for _can_set_shape_helper.
@@ -1201,7 +1201,7 @@ class SOMAArray : public SOMAObject {
     std::pair<bool, std::string> _can_set_shape_domainish_helper(
         const std::vector<int64_t>& newshape,
         bool check_current_domain,
-        std::string method_name_for_messages);
+        std::string function_name_for_messages);
 
     /**
      * This is a code-dedupe helper method for resize and upgrade_shape.


Test patch:
diff --git a/libtiledbsoma/test/unit_soma_dataframe.cc b/libtiledbsoma/test/unit_soma_dataframe.cc
index eb298e51be..1f9b4aeeb7 100644
--- a/libtiledbsoma/test/unit_soma_dataframe.cc
+++ b/libtiledbsoma/test/unit_soma_dataframe.cc
@@ -1,5 +1,5 @@
 /**
- * @file   unit_soma_dataframe.cc
+ * @file   unit_sdf.cc
  *
  * @section LICENSE
  *
@@ -167,7 +167,7 @@ struct VariouslyIndexedDataFrameFixture {
     }
 
     void write_sjid_u32_str_data_from(int64_t sjid_base) {
-        auto soma_dataframe = SOMADataFrame::open(uri_, OpenMode::write, ctx_);
+        auto sdf = SOMADataFrame::open(uri_, OpenMode::write, ctx_);
 
         auto i64_data = std::vector<int64_t>({sjid_base + 1, sjid_base + 2});
 
@@ -190,15 +190,13 @@ struct VariouslyIndexedDataFrameFixture {
         }
         char_offsets.push_back(offset);
 
-        soma_dataframe->set_column_data(
-            i64_name, i64_data.size(), i64_data.data());
-        soma_dataframe->set_column_data(
+        sdf->set_column_data(i64_name, i64_data.size(), i64_data.data());
+        sdf->set_column_data(
             str_name, strings.size(), char_data.data(), char_offsets.data());
-        soma_dataframe->set_column_data(
-            u32_name, u32_data.size(), u32_data.data());
-        soma_dataframe->write();
+        sdf->set_column_data(u32_name, u32_data.size(), u32_data.data());
+        sdf->write();
 
-        soma_dataframe->close();
+        sdf->close();
     }
 };
 
@@ -228,40 +226,36 @@ TEST_CASE_METHOD(
         REQUIRE(!SOMASparseNDArray::exists(uri_, ctx_));
         REQUIRE(!SOMADenseNDArray::exists(uri_, ctx_));
 
-        auto soma_dataframe = open(OpenMode::read);
-        REQUIRE(soma_dataframe->uri() == uri_);
-        REQUIRE(soma_dataframe->ctx() == ctx_);
-        REQUIRE(soma_dataframe->type() == "SOMADataFrame");
+        auto sdf = open(OpenMode::read);
+        REQUIRE(sdf->uri() == uri_);
+        REQUIRE(sdf->ctx() == ctx_);
+        REQUIRE(sdf->type() == "SOMADataFrame");
         std::vector<std::string> expected_index_column_names = {
             dim_infos[0].name};
-        REQUIRE(
-            soma_dataframe->index_column_names() ==
-            expected_index_column_names);
-        REQUIRE(soma_dataframe->nnz() == 0);
-        soma_dataframe->close();
+        REQUIRE(sdf->index_column_names() == expected_index_column_names);
+        REQUIRE(sdf->nnz() == 0);
+        sdf->close();
 
         std::vector<int64_t> d0(10);
         for (int j = 0; j < 10; j++)
             d0[j] = j;
         std::vector<uint32_t> a0(10, 1);
 
-        soma_dataframe = open(OpenMode::write);
-        soma_dataframe->set_column_data(
-            dim_infos[0].name, d0.size(), d0.data());
-        soma_dataframe->set_column_data(
-            attr_infos[0].name, a0.size(), a0.data());
-        soma_dataframe->write();
-        soma_dataframe->close();
+        sdf = open(OpenMode::write);
+        sdf->set_column_data(dim_infos[0].name, d0.size(), d0.data());
+        sdf->set_column_data(attr_infos[0].name, a0.size(), a0.data());
+        sdf->write();
+        sdf->close();
 
-        soma_dataframe = open(OpenMode::read);
-        while (auto batch = soma_dataframe->read_next()) {
+        sdf = open(OpenMode::read);
+        while (auto batch = sdf->read_next()) {
             auto arrbuf = batch.value();
             auto d0span = arrbuf->at(dim_infos[0].name)->data<int64_t>();
             auto a0span = arrbuf->at(attr_infos[0].name)->data<uint32_t>();
             REQUIRE(d0 == std::vector<int64_t>(d0span.begin(), d0span.end()));
             REQUIRE(a0 == std::vector<uint32_t>(a0span.begin(), a0span.end()));
         }
-        soma_dataframe->close();
+        sdf->close();
 
         auto soma_object = SOMAObject::open(uri_, OpenMode::read, ctx_);
         REQUIRE(soma_object->uri() == uri_);
@@ -347,8 +341,8 @@ TEST_CASE_METHOD(
 
             create(dim_infos, attr_infos, platform_config);
 
-            auto soma_dataframe = open(OpenMode::read);
-            auto sch = soma_dataframe->tiledb_schema();
+            auto sdf = open(OpenMode::read);
+            auto sch = sdf->tiledb_schema();
             REQUIRE(
                 sch->offsets_filter_list().filter(0).filter_type() ==
                 filter.second);
@@ -372,7 +366,7 @@ TEST_CASE_METHOD(
                         .filter(0)
                         .filter_type() == filter.second);
             }
-            soma_dataframe->close();
+            sdf->close();
         }
     }
 }
@@ -398,55 +392,55 @@ TEST_CASE_METHOD(
 
         create(dim_infos, attr_infos, PlatformConfig(), TimestampRange(0, 2));
 
-        auto soma_dataframe = open(
+        auto sdf = open(
             OpenMode::write, ResultOrder::automatic, TimestampRange(1, 1));
 
         int32_t val = 100;
-        soma_dataframe->set_metadata("md", TILEDB_INT32, 1, &val);
-        soma_dataframe->close();
+        sdf->set_metadata("md", TILEDB_INT32, 1, &val);
+        sdf->close();
 
         // Read metadata
-        soma_dataframe->open(OpenMode::read, TimestampRange(0, 2));
-        REQUIRE(soma_dataframe->metadata_num() == 3);
-        REQUIRE(soma_dataframe->has_metadata("soma_object_type"));
-        REQUIRE(soma_dataframe->has_metadata("soma_encoding_version"));
-        REQUIRE(soma_dataframe->has_metadata("md"));
-        auto mdval = soma_dataframe->get_metadata("md");
+        sdf->open(OpenMode::read, TimestampRange(0, 2));
+        REQUIRE(sdf->metadata_num() == 3);
+        REQUIRE(sdf->has_metadata("soma_object_type"));
+        REQUIRE(sdf->has_metadata("soma_encoding_version"));
+        REQUIRE(sdf->has_metadata("md"));
+        auto mdval = sdf->get_metadata("md");
         REQUIRE(std::get<MetadataInfo::dtype>(*mdval) == TILEDB_INT32);
         REQUIRE(std::get<MetadataInfo::num>(*mdval) == 1);
         REQUIRE(
             *((const int32_t*)std::get<MetadataInfo::value>(*mdval)) == 100);
-        soma_dataframe->close();
+        sdf->close();
 
         // md should not be available at (2, 2)
-        soma_dataframe->open(OpenMode::read, TimestampRange(2, 2));
-        REQUIRE(soma_dataframe->metadata_num() == 2);
-        REQUIRE(soma_dataframe->has_metadata("soma_object_type"));
-        REQUIRE(soma_dataframe->has_metadata("soma_encoding_version"));
-        REQUIRE(!soma_dataframe->has_metadata("md"));
-        soma_dataframe->close();
+        sdf->open(OpenMode::read, TimestampRange(2, 2));
+        REQUIRE(sdf->metadata_num() == 2);
+        REQUIRE(sdf->has_metadata("soma_object_type"));
+        REQUIRE(sdf->has_metadata("soma_encoding_version"));
+        REQUIRE(!sdf->has_metadata("md"));
+        sdf->close();
 
         // Metadata should also be retrievable in write mode
-        soma_dataframe->open(OpenMode::write, TimestampRange(0, 2));
-        REQUIRE(soma_dataframe->metadata_num() == 3);
-        REQUIRE(soma_dataframe->has_metadata("soma_object_type"));
-        REQUIRE(soma_dataframe->has_metadata("soma_encoding_version"));
-        REQUIRE(soma_dataframe->has_metadata("md"));
-        mdval = soma_dataframe->get_metadata("md");
+        sdf->open(OpenMode::write, TimestampRange(0, 2));
+        REQUIRE(sdf->metadata_num() == 3);
+        REQUIRE(sdf->has_metadata("soma_object_type"));
+        REQUIRE(sdf->has_metadata("soma_encoding_version"));
+        REQUIRE(sdf->has_metadata("md"));
+        mdval = sdf->get_metadata("md");
         REQUIRE(
             *((const int32_t*)std::get<MetadataInfo::value>(*mdval)) == 100);
 
         // Delete and have it reflected when reading metadata while in write
         // mode
-        soma_dataframe->delete_metadata("md");
-        mdval = soma_dataframe->get_metadata("md");
+        sdf->delete_metadata("md");
+        mdval = sdf->get_metadata("md");
         REQUIRE(!mdval.has_value());
-        soma_dataframe->close();
+        sdf->close();
 
         // Confirm delete in read mode
-        soma_dataframe->open(OpenMode::read, TimestampRange(0, 2));
-        REQUIRE(!soma_dataframe->has_metadata("md"));
-        REQUIRE(soma_dataframe->metadata_num() == 2);
+        sdf->open(OpenMode::read, TimestampRange(0, 2));
+        REQUIRE(!sdf->has_metadata("md"));
+        REQUIRE(sdf->metadata_num() == 2);
     }
 }
 
@@ -467,27 +461,27 @@ TEST_CASE_METHOD(
 
     create(dim_infos, attr_infos);
 
-    auto soma_dataframe = open(OpenMode::write);
+    auto sdf = open(OpenMode::write);
 
     std::vector<int64_t> d0({old_max + 1, old_max + 2});
     std::vector<double> a0({1.5, 2.5});
-    soma_dataframe->set_column_data(dim_infos[0].name, d0.size(), d0.data());
-    soma_dataframe->set_column_data(attr_infos[0].name, a0.size(), a0.data());
+    sdf->set_column_data(dim_infos[0].name, d0.size(), d0.data());
+    sdf->set_column_data(attr_infos[0].name, a0.size(), a0.data());
     // Writing outside the current domain should fail
-    REQUIRE_THROWS(soma_dataframe->write());
-    soma_dataframe->close();
+    REQUIRE_THROWS(sdf->write());
+    sdf->close();
 
-    soma_dataframe = open(OpenMode::write);
-    soma_dataframe->resize_soma_joinid(int64_t{new_max});
-    soma_dataframe->close();
+    sdf = open(OpenMode::write);
+    sdf->resize_soma_joinid(int64_t{new_max});
+    sdf->close();
 
-    soma_dataframe = open(OpenMode::write);
-    soma_dataframe->set_column_data(dim_infos[0].name, d0.size(), d0.data());
-    soma_dataframe->set_column_data(attr_infos[0].name, a0.size(), a0.data());
+    sdf = open(OpenMode::write);
+    sdf->set_column_data(dim_infos[0].name, d0.size(), d0.data());
+    sdf->set_column_data(attr_infos[0].name, a0.size(), a0.data());
     // Writing after resize should succeed
-    soma_dataframe->write();
+    sdf->write();
 
-    soma_dataframe->close();
+    sdf->close();
 }
 
 TEST_CASE_METHOD(
@@ -512,10 +506,9 @@ TEST_CASE_METHOD(
         create(dim_infos, attr_infos);
 
         // Check current domain
-        auto soma_dataframe = open(OpenMode::read);
+        auto sdf = open(OpenMode::read);
 
-        CurrentDomain current_domain = soma_dataframe
-                                           ->get_current_domain_for_test();
+        CurrentDomain current_domain = sdf->get_current_domain_for_test();
         if (!use_current_domain) {
             REQUIRE(current_domain.is_empty());
         } else {
@@ -531,40 +524,39 @@ TEST_CASE_METHOD(
 
         // Check shape before resize
         int64_t expect = dim_infos[0].dim_max + 1;
-        std::optional<int64_t> actual = soma_dataframe
-                                            ->maybe_soma_joinid_shape();
+        std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
         REQUIRE(actual.has_value());
         REQUIRE(actual.value() == expect);
 
-        REQUIRE(soma_dataframe->nnz() == 0);
+        REQUIRE(sdf->nnz() == 0);
 
-        soma_dataframe->close();
+        sdf->close();
 
         // Write data
         write_sjid_u32_str_data_from(0);
 
         // Check shape after write
-        soma_dataframe->open(OpenMode::read);
+        sdf->open(OpenMode::read);
 
-        REQUIRE(soma_dataframe->nnz() == 2);
+        REQUIRE(sdf->nnz() == 2);
 
         expect = dim_infos[0].dim_max + 1;
-        actual = soma_dataframe->maybe_soma_joinid_shape();
+        actual = sdf->maybe_soma_joinid_shape();
         REQUIRE(actual.has_value());
         REQUIRE(actual.value() == expect);
 
         // Check domainish accessors before resize
-        ArrowTable non_empty_domain = soma_dataframe->get_non_empty_domain();
+        ArrowTable non_empty_domain = sdf->get_non_empty_domain();
         std::vector<int64_t> ned_sjid =
             ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
                 non_empty_domain, "soma_joinid");
 
-        ArrowTable soma_domain = soma_dataframe->get_soma_domain();
+        ArrowTable soma_domain = sdf->get_soma_domain();
         std::vector<int64_t> dom_sjid =
             ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
                 soma_domain, "soma_joinid");
 
-        ArrowTable soma_maxdomain = soma_dataframe->get_soma_maxdomain();
+        ArrowTable soma_maxdomain = sdf->get_soma_maxdomain();
         std::vector<int64_t> maxdom_sjid =
             ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
                 soma_maxdomain, "soma_joinid");
@@ -581,11 +573,11 @@ TEST_CASE_METHOD(
             REQUIRE(maxdom_sjid[1] > 2000000000);
         }
 
-        soma_dataframe->close();
+        sdf->close();
 
-        REQUIRE(soma_dataframe->nnz() == 2);
+        REQUIRE(sdf->nnz() == 2);
         write_sjid_u32_str_data_from(8);
-        REQUIRE(soma_dataframe->nnz() == 4);
+        REQUIRE(sdf->nnz() == 4);
 
         // Resize
         auto new_shape = int64_t{SOMA_JOINID_RESIZE_DIM_MAX + 1};
@@ -597,58 +589,57 @@ TEST_CASE_METHOD(
             // * throw on an attempt to resize.
             REQUIRE_THROWS(write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
 
-            soma_dataframe = open(OpenMode::write);
+            sdf = open(OpenMode::write);
             // Array not resizeable if it has not already been sized
-            REQUIRE_THROWS(soma_dataframe->resize_soma_joinid(new_shape));
-            soma_dataframe->close();
+            REQUIRE_THROWS(sdf->resize_soma_joinid(new_shape));
+            sdf->close();
 
         } else {
             // Expect throw on write beyond current domain before resize
             REQUIRE_THROWS(write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
 
             // Check shape after write
-            soma_dataframe = open(OpenMode::read);
+            sdf = open(OpenMode::read);
             expect = dim_infos[0].dim_max + 1;
 
-            std::optional<int64_t> actual = soma_dataframe
-                                                ->maybe_soma_joinid_shape();
+            std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
             REQUIRE(actual.has_value());
             REQUIRE(actual.value() == expect);
-            soma_dataframe->close();
+            sdf->close();
 
-            soma_dataframe = open(OpenMode::read);
-            REQUIRE_THROWS(soma_dataframe->resize_soma_joinid(new_shape));
-            soma_dataframe->close();
+            sdf = open(OpenMode::read);
+            REQUIRE_THROWS(sdf->resize_soma_joinid(new_shape));
+            sdf->close();
 
-            soma_dataframe = open(OpenMode::write);
-            soma_dataframe->resize_soma_joinid(new_shape);
-            soma_dataframe->close();
+            sdf = open(OpenMode::write);
+            sdf->resize_soma_joinid(new_shape);
+            sdf->close();
 
             // Check shape after resize
-            soma_dataframe = open(OpenMode::read);
+            sdf = open(OpenMode::read);
             expect = SOMA_JOINID_RESIZE_DIM_MAX + 1;
-            actual = soma_dataframe->maybe_soma_joinid_shape();
+            actual = sdf->maybe_soma_joinid_shape();
             REQUIRE(actual.has_value());
             REQUIRE(actual.value() == expect);
 
-            soma_dataframe->close();
+            sdf->close();
 
             // Implicitly we expect no throw
             write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
         }
 
         // Check domainish accessors after resize
-        soma_dataframe->open(OpenMode::read);
+        sdf->open(OpenMode::read);
 
-        non_empty_domain = soma_dataframe->get_non_empty_domain();
+        non_empty_domain = sdf->get_non_empty_domain();
         ned_sjid = ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
             non_empty_domain, "soma_joinid");
 
-        soma_domain = soma_dataframe->get_soma_domain();
+        soma_domain = sdf->get_soma_domain();
         dom_sjid = ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
             soma_domain, "soma_joinid");
 
-        soma_maxdomain = soma_dataframe->get_soma_maxdomain();
+        soma_maxdomain = sdf->get_soma_maxdomain();
         maxdom_sjid = ArrowAdapter::get_table_non_string_column_by_name<
             int64_t>(soma_maxdomain, "soma_joinid");
 
@@ -665,8 +656,7 @@ TEST_CASE_METHOD(
         }
 
         // Check can_resize_soma_joinid
-        std::pair<bool, std::string> check = soma_dataframe
-                                                 ->can_resize_soma_joinid(1);
+        std::pair<bool, std::string> check = sdf->can_resize_soma_joinid(1);
         if (!use_current_domain) {
             REQUIRE(check.first == false);
             REQUIRE(
@@ -680,13 +670,12 @@ TEST_CASE_METHOD(
                 check.second ==
                 "cannot resize_soma_joinid: new soma_joinid shape 1 < existing "
                 "shape 199");
-            check = soma_dataframe->can_resize_soma_joinid(
-                SOMA_JOINID_RESIZE_DIM_MAX + 1);
+            check = sdf->can_resize_soma_joinid(SOMA_JOINID_RESIZE_DIM_MAX + 1);
             REQUIRE(check.first == true);
             REQUIRE(check.second == "");
         }
 
-        soma_dataframe->close();
+        sdf->close();
     }
 }
 
@@ -712,10 +701,9 @@ TEST_CASE_METHOD(
         create(dim_infos, attr_infos);
 
         // Check current domain
-        auto soma_dataframe = open(OpenMode::read);
+        auto sdf = open(OpenMode::read);
 
-        CurrentDomain current_domain = soma_dataframe
-                                           ->get_current_domain_for_test();
+        CurrentDomain current_domain = sdf->get_current_domain_for_test();
         if (!use_current_domain) {
             REQUIRE(current_domain.is_empty());
         } else {
@@ -736,26 +724,25 @@ TEST_CASE_METHOD(
 
         // Check shape before write
         int64_t expect = dim_infos[1].dim_max + 1;
-        std::optional<int64_t> actual = soma_dataframe
-                                            ->maybe_soma_joinid_shape();
+        std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
         REQUIRE(actual.has_value());
         REQUIRE(actual.value() == expect);
 
-        soma_dataframe->close();
+        sdf->close();
 
-        REQUIRE(soma_dataframe->nnz() == 0);
+        REQUIRE(sdf->nnz() == 0);
 
         // Write
         write_sjid_u32_str_data_from(0);
 
-        REQUIRE(soma_dataframe->nnz() == 2);
+        REQUIRE(sdf->nnz() == 2);
         write_sjid_u32_str_data_from(8);
-        REQUIRE(soma_dataframe->nnz() == 4);
+        REQUIRE(sdf->nnz() == 4);
 
         // Check domainish accessors before resize
-        soma_dataframe->open(OpenMode::read);
+        sdf->open(OpenMode::read);
 
-        ArrowTable non_empty_domain = soma_dataframe->get_non_empty_domain();
+        ArrowTable non_empty_domain = sdf->get_non_empty_domain();
         std::vector<int64_t> ned_sjid =
             ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
                 non_empty_domain, "soma_joinid");
@@ -763,7 +750,7 @@ TEST_CASE_METHOD(
             ArrowAdapter::get_table_non_string_column_by_name<uint32_t>(
                 non_empty_domain, "myuint32");
 
-        ArrowTable soma_domain = soma_dataframe->get_soma_domain();
+        ArrowTable soma_domain = sdf->get_soma_domain();
         std::vector<int64_t> dom_sjid =
             ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
                 soma_domain, "soma_joinid");
@@ -771,7 +758,7 @@ TEST_CASE_METHOD(
             ArrowAdapter::get_table_non_string_column_by_name<uint32_t>(
                 soma_domain, "myuint32");
 
-        ArrowTable soma_maxdomain = soma_dataframe->get_soma_maxdomain();
+        ArrowTable soma_maxdomain = sdf->get_soma_maxdomain();
         std::vector<int64_t> maxdom_sjid =
             ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
                 soma_maxdomain, "soma_joinid");
@@ -795,15 +782,15 @@ TEST_CASE_METHOD(
             REQUIRE(maxdom_u32[1] > 2000000000);
         }
 
-        soma_dataframe->close();
+        sdf->close();
 
         // Check shape after write
-        soma_dataframe = open(OpenMode::read);
+        sdf = open(OpenMode::read);
         expect = dim_infos[1].dim_max + 1;
-        actual = soma_dataframe->maybe_soma_joinid_shape();
+        actual = sdf->maybe_soma_joinid_shape();
         REQUIRE(actual.has_value());
         REQUIRE(actual.value() == expect);
-        soma_dataframe->close();
+        sdf->close();
 
         // Resize
         auto new_shape = int64_t{SOMA_JOINID_RESIZE_DIM_MAX + 1};
@@ -815,60 +802,59 @@ TEST_CASE_METHOD(
             // * throw on an attempt to resize.
             REQUIRE_THROWS(write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
 
-            soma_dataframe = open(OpenMode::write);
+            sdf = open(OpenMode::write);
             // Array not resizeable if it has not already been sized
-            REQUIRE_THROWS(soma_dataframe->resize_soma_joinid(new_shape));
-            soma_dataframe->close();
+            REQUIRE_THROWS(sdf->resize_soma_joinid(new_shape));
+            sdf->close();
 
         } else {
             // Expect throw on write beyond current domain before resize
             REQUIRE_THROWS(write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
 
             // Check shape after write
-            soma_dataframe = open(OpenMode::read);
+            sdf = open(OpenMode::read);
             expect = dim_infos[1].dim_max + 1;
-            std::optional<int64_t> actual = soma_dataframe
-                                                ->maybe_soma_joinid_shape();
+            std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
             REQUIRE(actual.has_value());
             REQUIRE(actual.value() == expect);
-            soma_dataframe->close();
+            sdf->close();
 
-            soma_dataframe = open(OpenMode::read);
-            REQUIRE_THROWS(soma_dataframe->resize_soma_joinid(new_shape));
-            soma_dataframe->close();
+            sdf = open(OpenMode::read);
+            REQUIRE_THROWS(sdf->resize_soma_joinid(new_shape));
+            sdf->close();
 
-            soma_dataframe = open(OpenMode::write);
-            soma_dataframe->resize_soma_joinid(new_shape);
-            soma_dataframe->close();
+            sdf = open(OpenMode::write);
+            sdf->resize_soma_joinid(new_shape);
+            sdf->close();
 
             // Check shape after resize
-            soma_dataframe = open(OpenMode::read);
+            sdf = open(OpenMode::read);
             expect = SOMA_JOINID_RESIZE_DIM_MAX + 1;
-            actual = soma_dataframe->maybe_soma_joinid_shape();
+            actual = sdf->maybe_soma_joinid_shape();
             REQUIRE(actual.has_value());
             REQUIRE(actual.value() == expect);
-            soma_dataframe->close();
+            sdf->close();
 
             // Implicitly we expect no throw
             write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
         }
 
         // Check domainish accessors after resize
-        soma_dataframe->open(OpenMode::read);
+        sdf->open(OpenMode::read);
 
-        non_empty_domain = soma_dataframe->get_non_empty_domain();
+        non_empty_domain = sdf->get_non_empty_domain();
         ned_sjid = ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
             non_empty_domain, "soma_joinid");
         ned_u32 = ArrowAdapter::get_table_non_string_column_by_name<uint32_t>(
             non_empty_domain, "myuint32");
 
-        soma_domain = soma_dataframe->get_soma_domain();
+        soma_domain = sdf->get_soma_domain();
         dom_sjid = ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
             soma_domain, "soma_joinid");
         dom_u32 = ArrowAdapter::get_table_non_string_column_by_name<uint32_t>(
             soma_domain, "myuint32");
 
-        soma_maxdomain = soma_dataframe->get_soma_maxdomain();
+        soma_maxdomain = sdf->get_soma_maxdomain();
         maxdom_sjid = ArrowAdapter::get_table_non_string_column_by_name<
             int64_t>(soma_maxdomain, "soma_joinid");
         maxdom_u32 = ArrowAdapter::get_table_non_string_column_by_name<
@@ -901,8 +887,7 @@ TEST_CASE_METHOD(
         }
 
         // Check can_resize_soma_joinid
-        std::pair<bool, std::string> check = soma_dataframe
-                                                 ->can_resize_soma_joinid(1);
+        std::pair<bool, std::string> check = sdf->can_resize_soma_joinid(1);
         if (!use_current_domain) {
             REQUIRE(check.first == false);
             REQUIRE(
@@ -916,13 +901,12 @@ TEST_CASE_METHOD(
                 check.second ==
                 "cannot resize_soma_joinid: new soma_joinid shape 1 < existing "
                 "shape 199");
-            check = soma_dataframe->can_resize_soma_joinid(
-                SOMA_JOINID_RESIZE_DIM_MAX + 1);
+            check = sdf->can_resize_soma_joinid(SOMA_JOINID_RESIZE_DIM_MAX + 1);
             REQUIRE(check.first == true);
             REQUIRE(check.second == "");
         }
 
-        soma_dataframe->close();
+        sdf->close();
     }
 }
 
@@ -956,10 +940,9 @@ TEST_CASE_METHOD(
         create(dim_infos, attr_infos);
 
         // Check current domain
-        auto soma_dataframe = open(OpenMode::read);
+        auto sdf = open(OpenMode::read);
 
-        CurrentDomain current_domain = soma_dataframe
-                                           ->get_current_domain_for_test();
+        CurrentDomain current_domain = sdf->get_current_domain_for_test();
         if (!use_current_domain) {
             REQUIRE(current_domain.is_empty());
         } else {
@@ -989,30 +972,29 @@ TEST_CASE_METHOD(
 
         // Check shape before write
         int64_t expect = dim_infos[0].dim_max + 1;
-        std::optional<int64_t> actual = soma_dataframe
-                                            ->maybe_soma_joinid_shape();
+        std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
         REQUIRE(actual.has_value());
         REQUIRE(actual.value() == expect);
-        soma_dataframe->close();
+        sdf->close();
 
-        REQUIRE(soma_dataframe->nnz() == 0);
+        REQUIRE(sdf->nnz() == 0);
 
         // Write
         write_sjid_u32_str_data_from(0);
 
-        REQUIRE(soma_dataframe->nnz() == 2);
+        REQUIRE(sdf->nnz() == 2);
         write_sjid_u32_str_data_from(8);
-        REQUIRE(soma_dataframe->nnz() == 4);
+        REQUIRE(sdf->nnz() == 4);
 
         // Check shape after write
-        soma_dataframe = open(OpenMode::read);
+        sdf = open(OpenMode::read);
         expect = dim_infos[0].dim_max + 1;
-        actual = soma_dataframe->maybe_soma_joinid_shape();
+        actual = sdf->maybe_soma_joinid_shape();
         REQUIRE(actual.has_value());
         REQUIRE(actual.value() == expect);
 
         // Check domainish accessors before resize
-        ArrowTable non_empty_domain = soma_dataframe->get_non_empty_domain();
+        ArrowTable non_empty_domain = sdf->get_non_empty_domain();
         std::vector<int64_t> ned_sjid =
             ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
                 non_empty_domain, "soma_joinid");
@@ -1020,7 +1002,7 @@ TEST_CASE_METHOD(
             ned_str = ArrowAdapter::get_table_string_column_by_name(
                 non_empty_domain, "mystring");
 
-        ArrowTable soma_domain = soma_dataframe->get_soma_domain();
+        ArrowTable soma_domain = sdf->get_soma_domain();
         std::vector<int64_t> dom_sjid =
             ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
                 soma_domain, "soma_joinid");
@@ -1028,7 +1010,7 @@ TEST_CASE_METHOD(
             dom_str = ArrowAdapter::get_table_string_column_by_name(
                 soma_domain, "mystring");
 
-        ArrowTable soma_maxdomain = soma_dataframe->get_soma_maxdomain();
+        ArrowTable soma_maxdomain = sdf->get_soma_maxdomain();
         std::vector<int64_t> maxdom_sjid =
             ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
                 soma_maxdomain, "soma_joinid");
@@ -1057,7 +1039,7 @@ TEST_CASE_METHOD(
         }
         REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
 
-        soma_dataframe->close();
+        sdf->close();
 
         // Resize
         auto new_shape = int64_t{SOMA_JOINID_RESIZE_DIM_MAX + 1};
@@ -1069,60 +1051,59 @@ TEST_CASE_METHOD(
             // * throw on an attempt to resize.
             REQUIRE_THROWS(write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
 
-            soma_dataframe = open(OpenMode::write);
+            sdf = open(OpenMode::write);
             // Array not resizeable if it has not already been sized
-            REQUIRE_THROWS(soma_dataframe->resize_soma_joinid(new_shape));
-            soma_dataframe->close();
+            REQUIRE_THROWS(sdf->resize_soma_joinid(new_shape));
+            sdf->close();
 
         } else {
             // Expect throw on write beyond current domain before resize
             REQUIRE_THROWS(write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
 
             // Check shape after write
-            soma_dataframe = open(OpenMode::read);
+            sdf = open(OpenMode::read);
             expect = dim_infos[0].dim_max + 1;
-            std::optional<int64_t> actual = soma_dataframe
-                                                ->maybe_soma_joinid_shape();
+            std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
             REQUIRE(actual.has_value());
             REQUIRE(actual.value() == expect);
-            soma_dataframe->close();
+            sdf->close();
 
-            soma_dataframe = open(OpenMode::read);
-            REQUIRE_THROWS(soma_dataframe->resize_soma_joinid(new_shape));
-            soma_dataframe->close();
+            sdf = open(OpenMode::read);
+            REQUIRE_THROWS(sdf->resize_soma_joinid(new_shape));
+            sdf->close();
 
-            soma_dataframe = open(OpenMode::write);
-            soma_dataframe->resize_soma_joinid(new_shape);
-            soma_dataframe->close();
+            sdf = open(OpenMode::write);
+            sdf->resize_soma_joinid(new_shape);
+            sdf->close();
 
             // Check shape after resize
-            soma_dataframe = open(OpenMode::read);
+            sdf = open(OpenMode::read);
             expect = SOMA_JOINID_RESIZE_DIM_MAX + 1;
-            actual = soma_dataframe->maybe_soma_joinid_shape();
+            actual = sdf->maybe_soma_joinid_shape();
             REQUIRE(actual.has_value());
             REQUIRE(actual.value() == expect);
-            soma_dataframe->close();
+            sdf->close();
 
             // Implicitly we expect no throw
             write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
         }
 
         // Check domainish accessors after resize
-        soma_dataframe->open(OpenMode::read, TimestampRange(0, 2));
+        sdf->open(OpenMode::read, TimestampRange(0, 2));
 
-        non_empty_domain = soma_dataframe->get_non_empty_domain();
+        non_empty_domain = sdf->get_non_empty_domain();
         ned_sjid = ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
             non_empty_domain, "soma_joinid");
         ned_str = ArrowAdapter::get_table_string_column_by_name(
             non_empty_domain, "mystring");
 
-        soma_domain = soma_dataframe->get_soma_domain();
+        soma_domain = sdf->get_soma_domain();
         dom_sjid = ArrowAdapter::get_table_non_string_column_by_name<int64_t>(
             soma_domain, "soma_joinid");
         dom_str = ArrowAdapter::get_table_string_column_by_name(
             soma_domain, "mystring");
 
-        soma_maxdomain = soma_dataframe->get_soma_maxdomain();
+        soma_maxdomain = sdf->get_soma_maxdomain();
         maxdom_sjid = ArrowAdapter::get_table_non_string_column_by_name<
             int64_t>(soma_maxdomain, "soma_joinid");
         maxdom_str = ArrowAdapter::get_table_string_column_by_name(
@@ -1153,8 +1134,7 @@ TEST_CASE_METHOD(
         REQUIRE(ned_str == std::vector<std::string>({"", ""}));
 
         // Check can_resize_soma_joinid
-        std::pair<bool, std::string> check = soma_dataframe
-                                                 ->can_resize_soma_joinid(1);
+        std::pair<bool, std::string> check = sdf->can_resize_soma_joinid(1);
         if (!use_current_domain) {
             REQUIRE(check.first == false);
             REQUIRE(
@@ -1168,13 +1148,12 @@ TEST_CASE_METHOD(
                 check.second ==
                 "cannot resize_soma_joinid: new soma_joinid shape 1 < existing "
                 "shape 99");
-            check = soma_dataframe->can_resize_soma_joinid(
-                SOMA_JOINID_RESIZE_DIM_MAX + 1);
+            check = sdf->can_resize_soma_joinid(SOMA_JOINID_RESIZE_DIM_MAX + 1);
             REQUIRE(check.first == true);
             REQUIRE(check.second == "");
         }
 
-        soma_dataframe->close();
+        sdf->close();
     }
 }
 
@@ -1208,10 +1187,9 @@ TEST_CASE_METHOD(
         create(dim_infos, attr_infos);
 
         // Check current domain
-        auto soma_dataframe = open(OpenMode::read);
+        auto sdf = open(OpenMode::read);
 
-        CurrentDomain current_domain = soma_dataframe
-                                           ->get_current_domain_for_test();
+        CurrentDomain current_domain = sdf->get_current_domain_for_test();
         if (!use_current_domain) {
             REQUIRE(current_domain.is_empty());
         } else {
@@ -1240,22 +1218,21 @@ TEST_CASE_METHOD(
         }
 
         // Check shape before write
-        std::optional<int64_t> actual = soma_dataframe
-                                            ->maybe_soma_joinid_shape();
+        std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
         REQUIRE(!actual.has_value());
 
         // Check domainish accessors before resize
-        ArrowTable non_empty_domain = soma_dataframe->get_non_empty_domain();
+        ArrowTable non_empty_domain = sdf->get_non_empty_domain();
         std::vector<std::string>
             ned_str = ArrowAdapter::get_table_string_column_by_name(
                 non_empty_domain, "mystring");
 
-        ArrowTable soma_domain = soma_dataframe->get_soma_domain();
+        ArrowTable soma_domain = sdf->get_soma_domain();
         std::vector<std::string>
             dom_str = ArrowAdapter::get_table_string_column_by_name(
                 soma_domain, "mystring");
 
-        ArrowTable soma_maxdomain = soma_dataframe->get_soma_maxdomain();
+        ArrowTable soma_maxdomain = sdf->get_soma_maxdomain();
         std::vector<std::string>
             maxdom_str = ArrowAdapter::get_table_string_column_by_name(
                 soma_maxdomain, "mystring");
@@ -1275,24 +1252,24 @@ TEST_CASE_METHOD(
             REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
         }
 
-        soma_dataframe->close();
+        sdf->close();
 
-        REQUIRE(soma_dataframe->nnz() == 0);
+        REQUIRE(sdf->nnz() == 0);
 
         // Write
         write_sjid_u32_str_data_from(0);
 
-        REQUIRE(soma_dataframe->nnz() == 2);
+        REQUIRE(sdf->nnz() == 2);
         write_sjid_u32_str_data_from(8);
         // soma_joinid is not a dim here and so the second write is an overwrite
         // of the first here
-        REQUIRE(soma_dataframe->nnz() == 2);
+        REQUIRE(sdf->nnz() == 2);
 
         // Check shape after write
-        soma_dataframe = open(OpenMode::read);
-        actual = soma_dataframe->maybe_soma_joinid_shape();
+        sdf = open(OpenMode::read);
+        actual = sdf->maybe_soma_joinid_shape();
         REQUIRE(!actual.has_value());
-        soma_dataframe->close();
+        sdf->close();
 
         // Resize
         auto new_shape = int64_t{SOMA_JOINID_RESIZE_DIM_MAX + 1};
@@ -1304,49 +1281,48 @@ TEST_CASE_METHOD(
             //   a dim, so no throw
             // * throw on an attempt to resize.
 
-            soma_dataframe = open(OpenMode::write);
+            sdf = open(OpenMode::write);
             // Array not resizeable if it has not already been sized
-            REQUIRE_THROWS(soma_dataframe->resize_soma_joinid(new_shape));
-            soma_dataframe->close();
+            REQUIRE_THROWS(sdf->resize_soma_joinid(new_shape));
+            sdf->close();
 
         } else {
             // Check shape after write
-            soma_dataframe = open(OpenMode::read);
-            std::optional<int64_t> actual = soma_dataframe
-                                                ->maybe_soma_joinid_shape();
+            sdf = open(OpenMode::read);
+            std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
             REQUIRE(!actual.has_value());
-            soma_dataframe->close();
+            sdf->close();
 
-            soma_dataframe = open(OpenMode::read);
-            REQUIRE_THROWS(soma_dataframe->resize_soma_joinid(new_shape));
-            soma_dataframe->close();
+            sdf = open(OpenMode::read);
+            REQUIRE_THROWS(sdf->resize_soma_joinid(new_shape));
+            sdf->close();
 
-            soma_dataframe = open(OpenMode::write);
-            soma_dataframe->resize_soma_joinid(new_shape);
-            soma_dataframe->close();
+            sdf = open(OpenMode::write);
+            sdf->resize_soma_joinid(new_shape);
+            sdf->close();
 
             // Check shape after resize -- noting soma_joinid is not a dim here
-            soma_dataframe = open(OpenMode::read);
-            actual = soma_dataframe->maybe_soma_joinid_shape();
+            sdf = open(OpenMode::read);
+            actual = sdf->maybe_soma_joinid_shape();
             REQUIRE(!actual.has_value());
-            soma_dataframe->close();
+            sdf->close();
 
             // Implicitly we expect no throw
             write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
         }
 
         // Check domainish accessors after resize
-        soma_dataframe->open(OpenMode::read, TimestampRange(0, 2));
+        sdf->open(OpenMode::read, TimestampRange(0, 2));
 
-        non_empty_domain = soma_dataframe->get_non_empty_domain();
+        non_empty_domain = sdf->get_non_empty_domain();
         ned_str = ArrowAdapter::get_table_string_column_by_name(
             non_empty_domain, "mystring");
 
-        soma_domain = soma_dataframe->get_soma_domain();
+        soma_domain = sdf->get_soma_domain();
         dom_str = ArrowAdapter::get_table_string_column_by_name(
             soma_domain, "mystring");
 
-        soma_maxdomain = soma_dataframe->get_soma_maxdomain();
+        soma_maxdomain = sdf->get_soma_maxdomain();
         maxdom_str = ArrowAdapter::get_table_string_column_by_name(
             soma_maxdomain, "mystring");
 
@@ -1366,8 +1342,7 @@ TEST_CASE_METHOD(
         }
 
         // Check can_resize_soma_joinid
-        std::pair<bool, std::string> check = soma_dataframe
-                                                 ->can_resize_soma_joinid(0);
+        std::pair<bool, std::string> check = sdf->can_resize_soma_joinid(0);
         if (!use_current_domain) {
             REQUIRE(check.first == false);
             REQUIRE(
@@ -1380,6 +1355,6 @@ TEST_CASE_METHOD(
             REQUIRE(check.second == "");
         }
 
-        soma_dataframe->close();
+        sdf->close();
     }
 }
diff --git a/libtiledbsoma/test/unit_soma_dense_ndarray.cc b/libtiledbsoma/test/unit_soma_dense_ndarray.cc
index d9aaca6790..c55a04ce3c 100644
--- a/libtiledbsoma/test/unit_soma_dense_ndarray.cc
+++ b/libtiledbsoma/test/unit_soma_dense_ndarray.cc
@@ -96,59 +96,59 @@ TEST_CASE("SOMADenseNDArray: basic", "[SOMADenseNDArray]") {
             REQUIRE(!SOMADataFrame::exists(uri, ctx));
             REQUIRE(!SOMASparseNDArray::exists(uri, ctx));
 
-            auto soma_dense = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
-            REQUIRE(soma_dense->uri() == uri);
-            REQUIRE(soma_dense->ctx() == ctx);
-            REQUIRE(soma_dense->type() == "SOMADenseNDArray");
-            REQUIRE(soma_dense->is_sparse() == false);
-            REQUIRE(soma_dense->soma_data_type() == attr_arrow_format);
-            auto schema = soma_dense->tiledb_schema();
+            auto dnda = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
+            REQUIRE(dnda->uri() == uri);
+            REQUIRE(dnda->ctx() == ctx);
+            REQUIRE(dnda->type() == "SOMADenseNDArray");
+            REQUIRE(dnda->is_sparse() == false);
+            REQUIRE(dnda->soma_data_type() == attr_arrow_format);
+            auto schema = dnda->tiledb_schema();
             REQUIRE(schema->has_attribute("soma_data"));
             REQUIRE(schema->array_type() == TILEDB_DENSE);
             REQUIRE(schema->domain().has_dimension(dim_name));
-            REQUIRE(soma_dense->ndim() == 1);
+            REQUIRE(dnda->ndim() == 1);
 
             // TODO: Once we have support for current domain in dense arrays
             // https://github.com/single-cell-data/TileDB-SOMA/issues/2955
             // if (use_current_domain) {
-            //    REQUIRE(soma_dense->shape() == std::vector<int64_t>{dim_max +
+            //    REQUIRE(dnda->shape() == std::vector<int64_t>{dim_max +
             //    1});
             //} else {
             //    REQUIRE(
-            //        soma_dense->maxshape() == std::vector<int64_t>{dim_max +
+            //        dnda->maxshape() == std::vector<int64_t>{dim_max +
             //        1});
             //}
 
-            REQUIRE(soma_dense->maxshape() == std::vector<int64_t>{shape});
+            REQUIRE(dnda->maxshape() == std::vector<int64_t>{shape});
 
-            soma_dense->close();
+            dnda->close();
 
             std::vector<int64_t> d0{1, 10};
             std::vector<int32_t> a0(10, 1);
 
-            soma_dense->open(OpenMode::write);
-            soma_dense->set_column_data("soma_data", a0.size(), a0.data());
-            soma_dense->set_column_data(dim_name, d0.size(), d0.data());
-            soma_dense->write();
-            soma_dense->close();
+            dnda->open(OpenMode::write);
+            dnda->set_column_data("soma_data", a0.size(), a0.data());
+            dnda->set_column_data(dim_name, d0.size(), d0.data());
+            dnda->write();
+            dnda->close();
 
-            soma_dense->open(OpenMode::read);
-            while (auto batch = soma_dense->read_next()) {
+            dnda->open(OpenMode::read);
+            while (auto batch = dnda->read_next()) {
                 auto arrbuf = batch.value();
                 auto a0span = arrbuf->at("soma_data")->data<int32_t>();
                 REQUIRE(
                     a0 == std::vector<int32_t>(a0span.begin(), a0span.end()));
             }
-            soma_dense->close();
+            dnda->close();
 
-            soma_dense = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
+            dnda = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
             auto new_shape = std::vector<int64_t>({shape * 2});
             // * When use_current_domain is false: can't resize what has not
             //   been sized.
             // * When use_current_domain is true: TODO: current domain not
             //   supported for dense arrays yet (see above).
-            REQUIRE_THROWS(soma_dense->resize(new_shape));
-            soma_dense->close();
+            REQUIRE_THROWS(dnda->resize(new_shape));
+            dnda->close();
         }
     }
 }
@@ -205,8 +205,8 @@ TEST_CASE("SOMADenseNDArray: platform_config", "[SOMADenseNDArray]") {
                 ctx,
                 platform_config);
 
-            auto soma_dense = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
-            auto dim_filter = soma_dense->tiledb_schema()
+            auto dnda = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
+            auto dim_filter = dnda->tiledb_schema()
                                   ->domain()
                                   .dimension(dim_name)
                                   .filter_list()
@@ -215,7 +215,7 @@ TEST_CASE("SOMADenseNDArray: platform_config", "[SOMADenseNDArray]") {
             REQUIRE(
                 dim_filter.get_option<int32_t>(TILEDB_COMPRESSION_LEVEL) == 6);
 
-            soma_dense->close();
+            dnda->close();
         }
     }
 }
@@ -256,7 +256,7 @@ TEST_CASE("SOMADenseNDArray: metadata", "[SOMADenseNDArray]") {
             PlatformConfig(),
             TimestampRange(0, 2));
 
-        auto soma_dense = SOMADenseNDArray::open(
+        auto dnda = SOMADenseNDArray::open(
             uri,
             OpenMode::write,
             ctx,
@@ -265,50 +265,50 @@ TEST_CASE("SOMADenseNDArray: metadata", "[SOMADenseNDArray]") {
             std::pair<uint64_t, uint64_t>(1, 1));
 
         int32_t val = 100;
-        soma_dense->set_metadata("md", TILEDB_INT32, 1, &val);
-        soma_dense->close();
+        dnda->set_metadata("md", TILEDB_INT32, 1, &val);
+        dnda->close();
 
         // Read metadata
-        soma_dense->open(OpenMode::read, TimestampRange(0, 2));
-        REQUIRE(soma_dense->metadata_num() == 3);
-        REQUIRE(soma_dense->has_metadata("soma_object_type"));
-        REQUIRE(soma_dense->has_metadata("soma_encoding_version"));
-        REQUIRE(soma_dense->has_metadata("md"));
-        auto mdval = soma_dense->get_metadata("md");
+        dnda->open(OpenMode::read, TimestampRange(0, 2));
+        REQUIRE(dnda->metadata_num() == 3);
+        REQUIRE(dnda->has_metadata("soma_object_type"));
+        REQUIRE(dnda->has_metadata("soma_encoding_version"));
+        REQUIRE(dnda->has_metadata("md"));
+        auto mdval = dnda->get_metadata("md");
         REQUIRE(std::get<MetadataInfo::dtype>(*mdval) == TILEDB_INT32);
         REQUIRE(std::get<MetadataInfo::num>(*mdval) == 1);
         REQUIRE(
             *((const int32_t*)std::get<MetadataInfo::value>(*mdval)) == 100);
-        soma_dense->close();
+        dnda->close();
 
         // md should not be available at (2, 2)
-        soma_dense->open(OpenMode::read, TimestampRange(2, 2));
-        REQUIRE(soma_dense->metadata_num() == 2);
-        REQUIRE(soma_dense->has_metadata("soma_object_type"));
-        REQUIRE(soma_dense->has_metadata("soma_encoding_version"));
-        REQUIRE(!soma_dense->has_metadata("md"));
-        soma_dense->close();
+        dnda->open(OpenMode::read, TimestampRange(2, 2));
+        REQUIRE(dnda->metadata_num() == 2);
+        REQUIRE(dnda->has_metadata("soma_object_type"));
+        REQUIRE(dnda->has_metadata("soma_encoding_version"));
+        REQUIRE(!dnda->has_metadata("md"));
+        dnda->close();
 
         // Metadata should also be retrievable in write mode
-        soma_dense->open(OpenMode::write, TimestampRange(0, 2));
-        REQUIRE(soma_dense->metadata_num() == 3);
-        REQUIRE(soma_dense->has_metadata("soma_object_type"));
-        REQUIRE(soma_dense->has_metadata("soma_encoding_version"));
-        REQUIRE(soma_dense->has_metadata("md"));
-        mdval = soma_dense->get_metadata("md");
+        dnda->open(OpenMode::write, TimestampRange(0, 2));
+        REQUIRE(dnda->metadata_num() == 3);
+        REQUIRE(dnda->has_metadata("soma_object_type"));
+        REQUIRE(dnda->has_metadata("soma_encoding_version"));
+        REQUIRE(dnda->has_metadata("md"));
+        mdval = dnda->get_metadata("md");
         REQUIRE(
             *((const int32_t*)std::get<MetadataInfo::value>(*mdval)) == 100);
 
         // Delete and have it reflected when reading metadata while in write
         // mode
-        soma_dense->delete_metadata("md");
-        mdval = soma_dense->get_metadata("md");
+        dnda->delete_metadata("md");
+        mdval = dnda->get_metadata("md");
         REQUIRE(!mdval.has_value());
-        soma_dense->close();
+        dnda->close();
 
         // Confirm delete in read mode
-        soma_dense->open(OpenMode::read, TimestampRange(0, 2));
-        REQUIRE(!soma_dense->has_metadata("md"));
-        REQUIRE(soma_dense->metadata_num() == 2);
+        dnda->open(OpenMode::read, TimestampRange(0, 2));
+        REQUIRE(!dnda->has_metadata("md"));
+        REQUIRE(dnda->metadata_num() == 2);
     }
 }
diff --git a/libtiledbsoma/test/unit_soma_sparse_ndarray.cc b/libtiledbsoma/test/unit_soma_sparse_ndarray.cc
index 9315a8724b..fa66faf96e 100644
--- a/libtiledbsoma/test/unit_soma_sparse_ndarray.cc
+++ b/libtiledbsoma/test/unit_soma_sparse_ndarray.cc
@@ -83,47 +83,47 @@ TEST_CASE("SOMASparseNDArray: basic", "[SOMASparseNDArray]") {
         REQUIRE(!SOMADataFrame::exists(uri, ctx));
         REQUIRE(!SOMADenseNDArray::exists(uri, ctx));
 
-        auto soma_sparse = SOMASparseNDArray::open(uri, OpenMode::read, ctx);
-        REQUIRE(soma_sparse->uri() == uri);
-        REQUIRE(soma_sparse->ctx() == ctx);
-        REQUIRE(soma_sparse->type() == "SOMASparseNDArray");
-        REQUIRE(soma_sparse->is_sparse() == true);
-        REQUIRE(soma_sparse->soma_data_type() == attr_arrow_format);
-        auto schema = soma_sparse->tiledb_schema();
+        auto snda = SOMASparseNDArray::open(uri, OpenMode::read, ctx);
+        REQUIRE(snda->uri() == uri);
+        REQUIRE(snda->ctx() == ctx);
+        REQUIRE(snda->type() == "SOMASparseNDArray");
+        REQUIRE(snda->is_sparse() == true);
+        REQUIRE(snda->soma_data_type() == attr_arrow_format);
+        auto schema = snda->tiledb_schema();
         REQUIRE(schema->has_attribute(attr_name));
         REQUIRE(schema->array_type() == TILEDB_SPARSE);
         REQUIRE(schema->domain().has_dimension(dim_name));
-        REQUIRE(soma_sparse->ndim() == 1);
-        REQUIRE(soma_sparse->nnz() == 0);
+        REQUIRE(snda->ndim() == 1);
+        REQUIRE(snda->nnz() == 0);
 
         auto expect = std::vector<int64_t>({shape});
-        REQUIRE(soma_sparse->shape() == expect);
+        REQUIRE(snda->shape() == expect);
         if (!use_current_domain) {
-            REQUIRE(soma_sparse->maxshape() == expect);
+            REQUIRE(snda->maxshape() == expect);
         }
 
-        soma_sparse->close();
+        snda->close();
 
         std::vector<int64_t> d0(10);
         for (int j = 0; j < 10; j++)
             d0[j] = j;
         std::vector<int32_t> a0(10, 1);
 
-        soma_sparse->open(OpenMode::write);
-        soma_sparse->set_column_data(dim_name, d0.size(), d0.data());
-        soma_sparse->set_column_data(attr_name, a0.size(), a0.data());
-        soma_sparse->write();
-        soma_sparse->close();
+        snda->open(OpenMode::write);
+        snda->set_column_data(dim_name, d0.size(), d0.data());
+        snda->set_column_data(attr_name, a0.size(), a0.data());
+        snda->write();
+        snda->close();
 
-        soma_sparse->open(OpenMode::read);
-        while (auto batch = soma_sparse->read_next()) {
+        snda->open(OpenMode::read);
+        while (auto batch = snda->read_next()) {
             auto arrbuf = batch.value();
             auto d0span = arrbuf->at(dim_name)->data<int64_t>();
             auto a0span = arrbuf->at(attr_name)->data<int32_t>();
             REQUIRE(d0 == std::vector<int64_t>(d0span.begin(), d0span.end()));
             REQUIRE(a0 == std::vector<int32_t>(a0span.begin(), a0span.end()));
         }
-        soma_sparse->close();
+        snda->close();
 
         std::vector<int64_t> d0b({dim_max, dim_max + 1});
         std::vector<int64_t> a0b({30, 40});
@@ -133,59 +133,59 @@ TEST_CASE("SOMASparseNDArray: basic", "[SOMASparseNDArray]") {
         //   outside the (immutable) doqain.
         // * With current domain support: this should throw since it's outside
         // the (mutable) current domain.
-        soma_sparse = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
-        soma_sparse->set_column_data(dim_name, d0b.size(), d0b.data());
-        soma_sparse->set_column_data(attr_name, a0b.size(), a0b.data());
-        REQUIRE_THROWS(soma_sparse->write());
-        soma_sparse->close();
+        snda = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
+        snda->set_column_data(dim_name, d0b.size(), d0b.data());
+        snda->set_column_data(attr_name, a0b.size(), a0b.data());
+        REQUIRE_THROWS(snda->write());
+        snda->close();
 
         if (!use_current_domain) {
             auto new_shape = std::vector<int64_t>({shape});
 
-            soma_sparse = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
+            snda = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
             // Without current-domain support: this should throw since
             // one cannot resize what has not been sized.
-            REQUIRE(!soma_sparse->has_current_domain());
-            REQUIRE_THROWS(soma_sparse->resize(new_shape));
+            REQUIRE(!snda->has_current_domain());
+            REQUIRE_THROWS(snda->resize(new_shape));
             // Now set the shape
-            soma_sparse->upgrade_shape(new_shape);
-            soma_sparse->close();
+            snda->upgrade_shape(new_shape);
+            snda->close();
 
-            soma_sparse->open(OpenMode::read);
-            REQUIRE(soma_sparse->has_current_domain());
-            soma_sparse->close();
+            snda->open(OpenMode::read);
+            REQUIRE(snda->has_current_domain());
+            snda->close();
 
-            soma_sparse->open(OpenMode::write);
-            REQUIRE(soma_sparse->has_current_domain());
+            snda->open(OpenMode::write);
+            REQUIRE(snda->has_current_domain());
             // Should not fail since we're setting it to what it already is.
-            soma_sparse->resize(new_shape);
-            soma_sparse->close();
+            snda->resize(new_shape);
+            snda->close();
 
-            soma_sparse = SOMASparseNDArray::open(uri, OpenMode::read, ctx);
-            REQUIRE(soma_sparse->shape() == new_shape);
-            soma_sparse->close();
+            snda = SOMASparseNDArray::open(uri, OpenMode::read, ctx);
+            REQUIRE(snda->shape() == new_shape);
+            snda->close();
 
         } else {
             auto new_shape = std::vector<int64_t>({shape * 2});
 
-            soma_sparse = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
+            snda = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
             // Should throw since this already has a shape (core current
             // domain).
-            REQUIRE_THROWS(soma_sparse->upgrade_shape(new_shape));
-            soma_sparse->resize(new_shape);
-            soma_sparse->close();
+            REQUIRE_THROWS(snda->upgrade_shape(new_shape));
+            snda->resize(new_shape);
+            snda->close();
 
             // Try out-of-bounds write after resize.
-            soma_sparse = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
-            soma_sparse->set_column_data(dim_name, d0b.size(), d0b.data());
-            soma_sparse->set_column_data(attr_name, a0b.size(), a0b.data());
+            snda = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
+            snda->set_column_data(dim_name, d0b.size(), d0b.data());
+            snda->set_column_data(attr_name, a0b.size(), a0b.data());
             // Implicitly checking for no throw
-            soma_sparse->write();
-            soma_sparse->close();
+            snda->write();
+            snda->close();
 
-            soma_sparse->open(OpenMode::read);
-            REQUIRE(soma_sparse->shape() == new_shape);
-            soma_sparse->close();
+            snda->open(OpenMode::read);
+            REQUIRE(snda->shape() == new_shape);
+            snda->close();
         }
     }
 }
@@ -284,7 +284,7 @@ TEST_CASE("SOMASparseNDArray: metadata", "[SOMASparseNDArray]") {
             PlatformConfig(),
             TimestampRange(0, 2));
 
-        auto soma_sparse = SOMASparseNDArray::open(
+        auto snda = SOMASparseNDArray::open(
             uri,
             OpenMode::write,
             ctx,
@@ -293,51 +293,51 @@ TEST_CASE("SOMASparseNDArray: metadata", "[SOMASparseNDArray]") {
             std::pair<uint64_t, uint64_t>(1, 1));
 
         int32_t val = 100;
-        soma_sparse->set_metadata("md", TILEDB_INT32, 1, &val);
-        soma_sparse->close();
+        snda->set_metadata("md", TILEDB_INT32, 1, &val);
+        snda->close();
 
         // Read metadata
-        soma_sparse->open(OpenMode::read, TimestampRange(0, 2));
-        REQUIRE(soma_sparse->metadata_num() == 3);
-        REQUIRE(soma_sparse->has_metadata("soma_object_type"));
-        REQUIRE(soma_sparse->has_metadata("soma_encoding_version"));
-        REQUIRE(soma_sparse->has_metadata("md"));
-        auto mdval = soma_sparse->get_metadata("md");
+        snda->open(OpenMode::read, TimestampRange(0, 2));
+        REQUIRE(snda->metadata_num() == 3);
+        REQUIRE(snda->has_metadata("soma_object_type"));
+        REQUIRE(snda->has_metadata("soma_encoding_version"));
+        REQUIRE(snda->has_metadata("md"));
+        auto mdval = snda->get_metadata("md");
         REQUIRE(std::get<MetadataInfo::dtype>(*mdval) == TILEDB_INT32);
         REQUIRE(std::get<MetadataInfo::num>(*mdval) == 1);
         REQUIRE(
             *((const int32_t*)std::get<MetadataInfo::value>(*mdval)) == 100);
-        soma_sparse->close();
+        snda->close();
 
         // md should not be available at (2, 2)
-        soma_sparse->open(OpenMode::read, TimestampRange(2, 2));
-        REQUIRE(soma_sparse->metadata_num() == 2);
-        REQUIRE(soma_sparse->has_metadata("soma_object_type"));
-        REQUIRE(soma_sparse->has_metadata("soma_encoding_version"));
-        REQUIRE(!soma_sparse->has_metadata("md"));
-        soma_sparse->close();
+        snda->open(OpenMode::read, TimestampRange(2, 2));
+        REQUIRE(snda->metadata_num() == 2);
+        REQUIRE(snda->has_metadata("soma_object_type"));
+        REQUIRE(snda->has_metadata("soma_encoding_version"));
+        REQUIRE(!snda->has_metadata("md"));
+        snda->close();
 
         // Metadata should also be retrievable in write mode
-        soma_sparse->open(OpenMode::write, TimestampRange(0, 2));
-        REQUIRE(soma_sparse->metadata_num() == 3);
-        REQUIRE(soma_sparse->has_metadata("soma_object_type"));
-        REQUIRE(soma_sparse->has_metadata("soma_encoding_version"));
-        REQUIRE(soma_sparse->has_metadata("md"));
-        mdval = soma_sparse->get_metadata("md");
+        snda->open(OpenMode::write, TimestampRange(0, 2));
+        REQUIRE(snda->metadata_num() == 3);
+        REQUIRE(snda->has_metadata("soma_object_type"));
+        REQUIRE(snda->has_metadata("soma_encoding_version"));
+        REQUIRE(snda->has_metadata("md"));
+        mdval = snda->get_metadata("md");
         REQUIRE(
             *((const int32_t*)std::get<MetadataInfo::value>(*mdval)) == 100);
 
         // Delete and have it reflected when reading metadata while in write
         // mode
-        soma_sparse->delete_metadata("md");
-        mdval = soma_sparse->get_metadata("md");
+        snda->delete_metadata("md");
+        mdval = snda->get_metadata("md");
         REQUIRE(!mdval.has_value());
-        soma_sparse->close();
+        snda->close();
 
         // Confirm delete in read mode
-        soma_sparse->open(OpenMode::read, TimestampRange(0, 2));
-        REQUIRE(!soma_sparse->has_metadata("md"));
-        REQUIRE(soma_sparse->metadata_num() == 2);
+        snda->open(OpenMode::read, TimestampRange(0, 2));
+        REQUIRE(!snda->has_metadata("md"));
+        REQUIRE(snda->metadata_num() == 2);
     }
 }
 void breakme() {
@@ -375,16 +375,16 @@ TEST_CASE(
             std::move(index_columns.first), std::move(index_columns.second)),
         ctx);
 
-    auto soma_sparse = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
-    REQUIRE(soma_sparse->has_current_domain() == false);
+    auto snda = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
+    REQUIRE(snda->has_current_domain() == false);
 
     // For old-style arrays, from before the current-domain feature:
     // * The shape specified at create becomes the core (max) domain
     //   o Recall that the core domain is immutable
     // * There is no current domain set
     //   o A current domain can be applied to it, up to <= (max) domain
-    auto dom = soma_sparse->soma_domain_slot<int64_t>(dim_name);
-    auto mxd = soma_sparse->soma_maxdomain_slot<int64_t>(dim_name);
+    auto dom = snda->soma_domain_slot<int64_t>(dim_name);
+    auto mxd = snda->soma_maxdomain_slot<int64_t>(dim_name);
     REQUIRE(dom == mxd);
     REQUIRE(dom.first == 0);
     REQUIRE(dom.second == dim_max);
@@ -394,21 +394,21 @@ TEST_CASE(
     std::vector<int64_t> newshape_too_big({dim_max + 10});
     std::vector<int64_t> newshape_good({40});
 
-    auto check = soma_sparse->can_upgrade_shape(newshape_wrong_dims);
+    auto check = snda->can_upgrade_shape(newshape_wrong_dims);
     REQUIRE(check.first == false);
     REQUIRE(
         check.second ==
         "cannot tiledbsoma_upgrade_shape: provided shape has ndim 2, while the "
         "array has 1");
 
-    check = soma_sparse->can_upgrade_shape(newshape_too_big);
+    check = snda->can_upgrade_shape(newshape_too_big);
     REQUIRE(check.first == false);
     REQUIRE(
         check.second ==
         "cannot tiledbsoma_upgrade_shape for soma_dim_0: new 1009 < maxshape "
         "1000");
 
-    check = soma_sparse->can_upgrade_shape(newshape_good);
+    check = snda->can_upgrade_shape(newshape_good);
     REQUIRE(check.first == true);
     REQUIRE(check.second == "");
 }
@@ -444,16 +444,16 @@ TEST_CASE("SOMASparseNDArray: can_resize", "[SOMASparseNDArray]") {
             std::move(index_columns.first), std::move(index_columns.second)),
         ctx);
 
-    auto soma_sparse = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
-    REQUIRE(soma_sparse->has_current_domain() == true);
+    auto snda = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
+    REQUIRE(snda->has_current_domain() == true);
 
     // For new-style arrays, with the current-domain feature:
     // * The shape specified at create becomes the core current domain
     //   o Recall that the core current domain is mutable, up tp <= (max) domain
     // * The core (max) domain is huge
     //   o Recall that the core max domain is immutable
-    auto dom = soma_sparse->soma_domain_slot<int64_t>(dim_name);
-    auto mxd = soma_sparse->soma_maxdomain_slot<int64_t>(dim_name);
+    auto dom = snda->soma_domain_slot<int64_t>(dim_name);
+    auto mxd = snda->soma_maxdomain_slot<int64_t>(dim_name);
     REQUIRE(dom != mxd);
     REQUIRE(dom.first == 0);
     REQUIRE(dom.second == dim_max);
@@ -462,19 +462,19 @@ TEST_CASE("SOMASparseNDArray: can_resize", "[SOMASparseNDArray]") {
     std::vector<int64_t> newshape_too_small({40});
     std::vector<int64_t> newshape_good({2000});
 
-    auto check = soma_sparse->can_resize(newshape_wrong_dims);
+    auto check = snda->can_resize(newshape_wrong_dims);
     REQUIRE(check.first == false);
     REQUIRE(
         check.second ==
         "cannot resize: provided shape has ndim 2, while the array has 1");
 
-    check = soma_sparse->can_resize(newshape_too_small);
+    check = snda->can_resize(newshape_too_small);
     REQUIRE(check.first == false);
     REQUIRE(
         check.second ==
         "cannot resize for soma_dim_0: new 40 < existing shape 1000");
 
-    check = soma_sparse->can_resize(newshape_good);
+    check = snda->can_resize(newshape_good);
     REQUIRE(check.first == true);
     REQUIRE(check.second == "");
 }