What Masu does not do yet, or does with a cost to know.
Browsers
The grid needs a browser with ResizeObserver, Intl.NumberFormat and
Intl.DateTimeFormat: every browser of the last few years. Decimals keep
every digit where the browser formats a decimal string exactly
(Intl.NumberFormat v3: Chrome 106, Firefox 116, Safari 15.4); an older
browser rounds a decimal of more than fifteen digits as it shows it. The
copy is exact in every browser.
Rows of one height
Every row has the height of row_height. A cell does not wrap, and
clips what does not fit.
Groups in a database
An Ecto source keeps the groups that show (their values, counts and
totals) in the LiveView: grouping by a column of a hundred thousand
values holds a hundred thousand groups. SQLite sums decimals as floating
point numbers; PostgreSQL and MySQL sum them exactly. A database orders
NULL groups by its own rule, a list puts them last. Following a person
(Masu.Presence) does not find their row in a grouped Ecto grid, and a
detail does not show there.
A tree in a database
An Ecto tree keeps the ids of the rows that show, and reads a block's
rows with WHERE id IN (...). A filter keeps its matches and their
ancestors the same way, so a filter that keeps hundreds of thousands of
rows of a tree runs into the database's limit of query parameters
(65,535 in PostgreSQL). A tree deeper than a hundred levels shows its
deeper rows as roots while a filter applies.
Details
A detail is as tall as its content, and the rows are one height: a detail of a grid in a detail is measured as it changes. Fifty details are open at most.
A deep OFFSET
An Ecto source reads the block after a block it read by key (see
Export, selection and large tables), but a jump into the
middle of a table of millions of rows (the scrollbar dragged) is an
OFFSET, which the database counts row by row. A grouped Ecto grid
reads an open group's rows by OFFSET. Paging by key is tested on
SQLite; the order of NULLs it assumes for PostgreSQL is PostgreSQL's
default.
Export
An export downloads from the app's export route (Masu.Router), not
over the LiveView's socket, as its rows are read: a block of 500 rows at
a time, from an Ecto source by key. Its link is good once, for five
minutes, and from the LiveView that made it while it runs. On several
nodes, the download must reach a node connected to the LiveView's
(distributed Erlang). An XLSX file is zipped as it is written, with no
ZIP64: its sheet stays under 4 GB, and it has Excel's 1,048,576 rows at
most (a CSV export has every row). An XLSX file's dates before 1900 are
numbers Excel does not show as dates.
Empty values in a database
A list puts empty values (nil) last in both directions. A database puts
them where it does: PostgreSQL last when ascending and first when
descending, MySQL and SQLite first when ascending.
Sorting a list
A list sorts in the LiveView's process: about a fifth of a second for a hundred thousand rows by one column. A larger list belongs in a database.
Datetime filters
The menu takes a date and a time in the browser's time zone, and gives
the server the instant. A list compares it with a NaiveDateTime as if
that were UTC. An Ecto source compares it with the column's type: a
:naive_datetime column takes it in UTC.
One filter a column in the menu
The menu edits one filter a column. The filters attribute and
Masu.Test may give a column several, which all apply; the menu then
shows the first, and replaces them all.
Pages without LiveView
The grid is a LiveComponent: it needs a LiveView.
Copy of a large range
A copy takes at most ten thousand rows. When the browser lacks some of them, it asks the server, and writes the clipboard when they come; Firefox and Safari may refuse to write it that late, and the grid then says the rows could not be copied.
Live changes to a large list
A grid of a list takes a batch of changes by finding each row by its id and applying the query again: a fifth of a second for a hundred thousand rows. For a list that large that changes often, use an Ecto source, which asks the database instead.
Editing a large list
A grid of a list saves an edit by finding its row by its id and applying the query again, as for a live change: a fifth of a second for a hundred thousand rows. An Ecto source asks the database instead.
A paste or a fill of many cells
A paste, a fill or an emptied range saves at most five thousand cells at once, and only of rows that the browser can ask for.
A primary key of several fields
An Ecto source finds a row to edit by a primary key of one field.