26#include <morph/core/callback_scope.hpp>
32#include <unordered_map>
33#include <unordered_set>
37namespace morph::table {
79 : _patcher{&patcher}, _commit{std::move(
commit)}, _engine{engine} {}
90 if (_engine ==
nullptr) {
93 std::vector<RowId> rows{_ending.begin(), _ending.end()};
94 for (
auto const& [row, queue] : _queues) {
99 for (
auto const& row : rows) {
100 _engine->endEdit(row);
107 auto& queue = _queues[request.row];
108 queue.push_back(std::move(request));
109 if (queue.size() == 1) {
110 start(queue.front().row);
118 [[nodiscard]]
bool stale(
RowId const& row, std::string_view column)
const {
119 auto const found = _queues.find(row);
120 if (found == _queues.end()) {
123 return std::ranges::any_of(found->second,
124 [&](
EditRequest const& request) { return request.column == column; });
131 [[nodiscard]] std::optional<std::string>
error(
RowId const& row, std::string_view column)
const {
132 auto const found = _errors.find(row);
133 if (found == _errors.end()) {
136 auto const cell = found->second.find(column);
137 return cell == found->second.end() ? std::nullopt : std::optional{cell->second};
144 for (
auto const& [row, queue] : _queues) {
151 void start(
RowId const& row) {
152 if (_engine !=
nullptr) {
157 auto const request = _queues.at(row).front();
159 _commit(request, _alive.
guard([
this, row](std::expected<std::vector<Cell>, FieldError> outcome) {
160 settle(row, std::move(outcome));
167 void settle(RowId
const& row, std::expected<std::vector<Cell>, FieldError> outcome) {
168 auto const found = _queues.find(row);
169 if (found == _queues.end() || found->second.empty()) {
172 auto const request = std::move(found->second.front());
173 found->second.pop_front();
174 bool const more = !found->second.empty();
176 _queues.erase(found);
180 if (
auto const errors = _errors.find(row); errors != _errors.end()) {
181 errors->second.erase(
request.column);
183 auto const alive = _alive.token();
184 _patcher->patchRow(row, std::move(*outcome));
185 if (alive.expired()) {
189 auto const column = outcome.error().column.empty() ?
request.column : outcome.error().column;
190 _errors[
row].insert_or_assign(column, std::move(outcome.error().message));
197 if (_queues.contains(row)) {
201 if (_engine !=
nullptr) {
202 _engine->endEdit(row);
206 RowPatcher* _patcher;
209 std::unordered_map<RowId, std::deque<EditRequest>> _queues;
210 std::unordered_set<RowId> _ending;
211 std::unordered_map<RowId, std::map<std::string, std::string, std::less<>>> _errors;
212 async::CallbackScope _alive;
Node column(Nodes const &children, ContainerOptions const &options={})
A column node.
Handle< T > row()
The innermost row, {"row": ""}.
auto guard(F &&fn) const
Wraps fn so it runs only while this scope is alive and un-stopped.
Commits cell edits row by row, in order.
~CellEdits()
Ends the engine edit of every row with an edit in flight or settling: its completion will be ignored,...
std::optional< std::string > error(RowId const &row, std::string_view column) const
The error a cell shows, until its next edit succeeds.
std::size_t unsettled() const
Edits committed and not yet settled, across rows.
CellEdits(RowPatcher &patcher, EditCommit commit, Engine *engine=nullptr)
Builds the committer.
void commit(EditRequest request)
Commits an edit: now, or after the row's earlier edits settle.
bool stale(RowId const &row, std::string_view column) const
Whether a cell has an edit committed and not yet settled.
Sorts, filters and maps the view of one table.
void beginEdit(RowId const &key)
Marks a row as being edited: with Deferred reorder it keeps its place through updates until endEdit.
Replaces a row by key; what a committed cell edit patches.
The rows a table engine reads, and the services it is given.
std::variant< std::monostate, std::int64_t, math::Rational, double, std::string, bool, QuantityCell > Cell
One cell as a data source hands it out.
std::variant< std::int64_t, std::string > RowId
A row's identity: the table's key, stable across reloads.
std::function< void(std::expected< std::vector< Cell >, FieldError >)> EditDone
Settles one commit, on the owner thread: the row as the server returned it, or the field error.
std::function< void(EditRequest const &request, EditDone done)> EditCommit
Runs a commit: the table's mutation for request, calling done once with its outcome.
The table engine: sort, filter and view mapping, on and off the owner.
void request(Store< ViewState, Msg > &store, bridge::BridgeHandler< Model, Sharing > &handler, async::CallbackScope const &scope, Action action, ToMsg toMsg, ToFailMsg toFailMsg)
Executes action and sends its result, or its failure, to store as one message.
One edited cell to commit.
Cell value
The value the user entered.
std::string column
The column's id.
A server's refusal of an edit, attached to the cell.
std::string column
The column the error is about.
std::string message
The message the cell shows.