# Documents

> UStore for C++

A `docs_collection_t` hands out `docs_ref` proxies, which read and write JSON through `ustore_docs_read` and `ustore_docs_write`:

```cpp
auto [people, people_status] = db.create<docs_collection_t>("people");
status_t status = people[key_from_integer(1)].assign(R"({"person": "Alice", "age": 27, "height": 1})");
status = people[key_from_integer(2)].assign(R"({"person": "Bob", "age": "27", "weight": 2})");

expected<owned_value_t> document = people[key_from_integer(1)].value();
expected<owned_value_t> person = people[collection_key_field_t {key_from_integer(1), "/person"}].value(ustore_docs_field_type_string_k);

status = people[key_from_integer(1)].patch(R"([{"op": "replace", "path": "/age", "value": 28}])");
status = people[key_from_integer(2)].merge(R"({"weight": null})");
expected<values_view_t> documents = people[{key_from_integer(1), key_from_integer(2)}].value(arena);
expected<sz::strings_view_t> paths = people[{key_from_integer(1), key_from_integer(2)}].gist(arena);
```

Field access through a proxy is shorthand like any other read without an arena, while `gist` and `gather` export into the arena they are given.
Besides `assign`, a reference offers `insert`, `update` and `upsert`, and `as` switches the format every later call exchanges.

### Tables

`gather` reads fields of many documents into a `docs_table`, converting each field into its column type on a best-effort basis.
A header whose column types are known at compile time is built column by column:

```cpp
auto header = make_table_header() //
                  .with<std::int32_t>("age")
                  .with<std::string_view>("age")
                  .with<std::string_view>("person");

std::array<ustore_key_t, 3> keys {key_from_integer(1), key_from_integer(2), key_from_integer(3)};
auto table = people[keys].gather(header, arena);
auto ages = table->column<0>();
for (std::size_t row = 0; row != ages.size(); ++row)
    if (ages[row].valid)
        std::printf("%d\n", ages[row].value);
```

A header whose column types are known only at runtime views an array of `field_type_t`, and its columns are typed at the point of use:

```cpp
field_type_t const columns[] = {
    {"age", ustore_docs_field_type_i32_k},
    {"age", ustore_docs_field_type_string_k},
    {"person", ustore_docs_field_type_string_k},
};
auto dynamic = people[keys].gather(make_table_header(columns), arena);
auto names = dynamic->column(2).as<std::string_view>();
```

A table is a view: one `ustore_docs_column_view_t` per column lives in the arena, while its index and header view the keys and the header the gather was given.
Every cell carries `valid`, `converted` and `collides` flags beside its `value`, which is meaningful only when `valid`.

`#include <ustore/docs_collection.hpp>`

`#include <ustore/docs_ref.hpp>`

`#include <ustore/types.hpp>`

`#include <ustore/docs_table.hpp>`

## docs_read_collection_t

Map from keys to JSON documents that only reads, cheap to construct and to copy.

```cpp
class docs_read_collection_t
```

A handle addresses either the current state of a collection or its view inside a transaction or a snapshot, holds no state of its own, so any number of threads share it, and never outlives its database. The type of a handle shapes only how values cross it, since documents are stored as JSON whatever they arrive as.

- `modality_k` `ustore_modality_t`: What the collections this kind of handle addresses hold, which a creation records and a lookup checks.

## collection_key_field_t

A key inside a collection, optionally narrowed down to one field of its document.

```cpp
struct collection_key_field_t
```

- `collection` `ustore_collection_id_t`: Collection owning the key.
- `key` `ustore_key_t`: Key inside the collection.
- `field` `std::string_view`: Path of the document field, or an empty one for the whole value.

## cell

One entry of a column, with the flags [`ustore_docs_gather`](https://www.unum.cloud/docs/ustore/c/documents.md#ustore_docs_gather) reports for it.

```cpp
template <typename element_type_>
struct cell
```

- `valid` `bool`: Whether the value was found and converted.
- `converted` `bool`: Whether the conversion changed the semantics of the value.
- `collides` `bool`: Whether an inconvertible value sits under the field.
- `value` `element_type_`: The value, meaningful only when `valid`.

## scalar_column_view

Column of fixed-width scalars, viewing the arena of the gather.

```cpp
template <typename element_type_>
class scalar_column_view
```

## variable_length_column_view

Column of strings, a tape of either offset width inside the arena of the gather.

```cpp
template <typename element_type_>
class variable_length_column_view
```

## dynamic_column_view_t

Column whose type is known only at runtime, viewed as a typed column through `as`.

```cpp
class dynamic_column_view_t
```

## field_type_t

A column of a table header: the field to gather and the type to convert it into.

```cpp
struct field_type_t
```

- `field` `std::string_view`: Field inside every document.
- `type` `ustore_docs_field_type_t`: Type the field converts into.

## table_index_view_t

The first column of a table, naming the document of every row.

```cpp
struct table_index_view_t
```

- `collections_begin` `strided_iterator<ustore_collection_id_t const>`
- `keys_begin` `strided_iterator<ustore_key_t const>`
- `count` `std::size_t`

## table_header_view_t

The header row of a table, naming the field and type of every column.

```cpp
struct table_header_view_t
```

- `fields_begin` `strided_iterator<std::string_view const>`
- `types_begin` `strided_iterator<ustore_docs_field_type_t const>`
- `count` `std::size_t`

## table_header

Header of a table whose column types are known at compile time, built column by column through `with`.

```cpp
template <typename... column_types_>
struct table_header
```

- `columns` `std::array<field_type_t, sizeof...(column_types_)>`: Field and type of every column, in order.

## docs_table

Results of [`ustore_docs_gather`](https://www.unum.cloud/docs/ustore/c/documents.md#ustore_docs_gather), with documents as rows and fields as columns.

```cpp
template <typename... column_types_>
class docs_table
```

A view that copies cheaply: its columns live in the arena of the gather, while its index and header view the keys and fields the gather was asked for.

## docs_collection_t

Transactional map from keys to JSON documents, cheap to construct, which reads and writes the head or the view of a transaction.

```cpp
class docs_collection_t
```

## deferred_t

The twin a deferred receiver hands out, whose verbs answer deferred calls.

```cpp
using deferred_t = deferred_docs_collection_t;
```

## clear_values

Empties every document, keeping the keys.

```cpp
status_t clear_values() noexcept;
```

## clear

Removes every document, keeping the collection.

```cpp
status_t clear() noexcept;
```

## drop

Removes the collection with all its documents.

```cpp
status_t drop() noexcept;
```

## docs_read_ref

Proxy reading documents, or fields inside them, at a batch of locations, through a snapshot, a transaction or the head, which never writes them.

```cpp
template <typename locations_type_>
class docs_read_ref
```

A read given an arena answers views into it, valid until the next call given that arena. The same read without one is shorthand: it makes a one-off arena and answers a result owning it, or a scalar copied out of it, which is slower than reusing an arena and keeps no state anywhere. Copying is cheap and nothing throws.

## docs_read_ref

```cpp
docs_read_ref(
    receiver_t receiver,
    locations_type_ && locations,
    ustore_docs_field_type_t type = ustore_docs_field_type_json_k) noexcept;
```

## value

Reads the documents or fields into `arena`, in the format of the proxy.

```cpp
expected<value_t> value(
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

```cpp
expected<one_off_answer_of<value_t>> value(
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Reads the documents or fields into a one-off arena, which the answer owns, in the format of the proxy.

```cpp
expected<one_off_answer_of<value_t>> value(
    ustore_docs_field_type_t type,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Reads the documents or fields into a one-off arena, which the answer owns, in the format `type`.

## length

Reads the lengths of the documents or fields into `arena`.

```cpp
expected<length_t> length(
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

```cpp
expected<one_off_answer_of<length_t>> length(
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Reads the lengths of the documents or fields into a one-off arena.

## present

Checks which locations hold a value, which may be empty, into `arena`.

```cpp
expected<present_t> present(
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

```cpp
expected<one_off_answer_of<present_t>> present(
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Checks which locations hold a value, which may be empty, into a one-off arena.

## gist

Lists the unique paths to the leaves of the documents into `arena`.

```cpp
expected<sz::strings_view_t> gist(
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

## gather

Gathers every column of `header` from every document into `arena`, as a table typed at runtime.

```cpp
expected<docs_table_t> gather(
    table_header_view_t const & header,
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

```cpp
template <typename... column_types_>
expected<docs_table<column_types_...>> gather(
    table_header<column_types_...> const & header,
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Gathers every column of `header` from every document into `arena`, as a table typed at compile time.

## docs_ref

Proxy reading and writing documents, or fields inside them, at a batch of locations, at the head or through a transaction.

```cpp
template <typename locations_type_>
class docs_ref
```

A proxy assigns one value to one or many locations, or many values to as many locations.

## assign

Upserts `values` pair-wise into the locations, in the format of the proxy.

```cpp
template <typename values_argument_type_>
status_t assign(
    values_argument_type_ && values,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

```cpp
template <typename values_argument_type_>
status_t assign(
    values_argument_type_ && values,
    ustore_docs_field_type_t type,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

Upserts `values` pair-wise into the locations, in the format `type`.

## remove

Removes the documents whole, refusing locations that name a field, which a patch or a merge removes.

```cpp
status_t remove(
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

Statuses: - `status_code_t::invalid_argument_k` A location names a field.

## clear_values

Keeps the keys, but empties the associated values.

```cpp
status_t clear_values(
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

## patch

Patches the documents with RFC 6902 JSON Patches.

```cpp
template <typename values_argument_type_>
status_t patch(
    values_argument_type_ && values,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

## merge

Patches the documents with RFC 7386 JSON Merge Patches.

```cpp
template <typename values_argument_type_>
status_t merge(
    values_argument_type_ && values,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

## insert

Inserts `values`, failing where a document already exists.

```cpp
template <typename values_argument_type_>
status_t insert(
    values_argument_type_ && values,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

## upsert

Inserts `values`, replacing existing documents.

```cpp
template <typename values_argument_type_>
status_t upsert(
    values_argument_type_ && values,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

## update

Replaces existing documents or fields with `values`.

```cpp
template <typename values_argument_type_>
status_t update(
    values_argument_type_ && values,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

## docs_field_type

The document field type that stores `element_type_`.

```cpp
template <typename element_type_>
ustore_docs_field_type_t docs_field_type() noexcept;
```

## is_variable_length

Whether a gathered column of `type` holds strings, which offsets address, rather than scalars.

```cpp
bool is_variable_length(ustore_docs_field_type_t type) noexcept;
```

## make_table_header

Starts a header whose column types are known at compile time.

```cpp
table_header make_table_header() noexcept;
```

```cpp
table_header_view_t make_table_header(
    std::span<field_type_t const> columns) noexcept;
```

Views `columns`, whose types are known only at runtime, as a table header.

