Skip to content

rows ​

Work with sheet rows as records. The rows branch is the heart of tbxl: read records, append them, and change or remove them by column conditions.

All matching is exact and case-sensitive with no type coercion, and every value is a string. Before reading the subcommands, it's worth understanding Matching & safety — --where, --all/--first, --yes, --dry-run, and what row means in a receipt.

list ​

Read rows below the header as records.

sh
tbxl rows list [options]
OptionDescription
--where <CONDITION>Filter by exact match Column=value. Repeatable; conditions are AND-combined. Column= matches empty cells.
--columns <NAMES>Comma-separated column names to include, in that order. Other columns are omitted (but --where can still filter on them).
--limit <N>Return at most N matching records. Default 100.
--offset <N>Skip the first N matching records before --limit is applied. Default 0.
sh
tbxl rows list --limit 10
tbxl rows list --offset 10 --limit 10
tbxl rows list --where "Status=Done" --columns "Name,Status"

The JSON response carries a total field — the number of records that matched before --offset/--limit were applied, which is what you page against.

Zero results is success

rows list returning no rows is a normal result (exit code 0). Zero matches is only treated specially for the mutation commands below (exit code 2).

add ​

Append one record. Values are laid out by column name from a JSON object passed as the single positional argument.

sh
tbxl rows add '<json>' [options]
  • Column names in the JSON are case-sensitive; unknown fields are rejected.
  • Fields missing from the object are left empty in the new row.
sh
tbxl rows add '{"Name":"John","Age":30}'
tbxl rows add '{"Id":"7","Name":"Sam","IsActive":"1"}' --sheet Users

The receipt reports row — the 1-based sheet row where the record was appended.

update ​

Set new values on the columns of rows matched by --where.

sh
tbxl rows update --where <CONDITION> --set <ASSIGNMENT> [options]
OptionDescription
--where <CONDITION>Select rows by exact match Column=value. Repeatable; AND-combined. Column= matches empty cells.
--set <ASSIGNMENT>New value as Column=value. Repeatable; at least one required. Column= clears the cell. Unknown columns rejected.
--allUpdate every matching row when more than one matches.
--firstUpdate only the first matching row when more than one matches.
--dry-runValidate and match against the live sheet, but write nothing.
sh
tbxl rows update --where "Name=Max" --set "IsActive=0"
tbxl rows update --where "Status=New" --set "Status=Done" --all

If more than one row matches and you pass neither --all nor --first, the command fails with ambiguous_match rather than guessing. Passing both --all and --first is an error.

upsert ​

Update the rows matched by --where, or insert a new record when nothing matches. The JSON object supplies the fields to write.

sh
tbxl rows upsert '<json>' --where <CONDITION> [options]
OptionDescription
--where <CONDITION>Required. Select rows by exact match Column=value. Repeatable; AND-combined. When nothing matches, the condition values become cells of the inserted row.
--allUpdate every matching row when more than one matches.
--firstUpdate only the first matching row when more than one matches.
--dry-runValidate and match against the live sheet, but write nothing.
sh
tbxl rows upsert '{"Status":"Done"}' --where "[email protected]"
tbxl rows upsert '{"IsActive":"0"}' --where "Id=7" --sheet Users
  • On update, only the columns in the JSON object are touched.
  • On insert, the JSON fields plus the --where condition values form the new row. A column named in both must carry the same value.
  • The receipt adds an action field: "inserted" or "updated".

delete ​

Delete rows matched by --where. Because this is destructive, it requires explicit confirmation.

sh
tbxl rows delete --where <CONDITION> --yes [options]
OptionDescription
--where <CONDITION>Select rows by exact match Column=value. Repeatable; AND-combined. Column= matches empty cells.
--yesRequired. Without it the command does nothing and fails with confirmation_required.
--allDelete every matching row when more than one matches.
--firstDelete only the first matching row when more than one matches.
--dry-runValidate and match against the live sheet, but write nothing. Previews without --yes.
sh
# Preview first — no --yes needed for a dry run
tbxl rows delete --where "Id=7" --dry-run

# Commit the deletion
tbxl rows delete --where "Id=7" --yes

The safe mutation workflow ​

Treat mutations deliberately: learn the names, preview the change, commit it, then verify against the live sheet.

sh
# 1. Learn the real sheet/column names — never assume them.
tbxl describe --spreadsheet-id <ID>
tbxl columns --spreadsheet-id <ID> --sheet Users

# 2. Dry-run the change and read the receipt (row = 1-based sheet row).
tbxl rows update --spreadsheet-id <ID> --sheet Users \
  --where "Name=Max" --set "IsActive=0" --dry-run

# 3. Commit it (single match → no --all/--first needed).
tbxl rows update --spreadsheet-id <ID> --sheet Users \
  --where "Name=Max" --set "IsActive=0"

# 4. Verify against the live sheet.
tbxl rows list --spreadsheet-id <ID> --sheet Users --where "Name=Max"

See Output formats for the JSON receipt shapes and Exit codes & errors for what each exit status means.