libredb / libredb/libredb-studio

Inline cell editing cannot apply changes on a default-named tab

Closed
#836 3 comments 0 reactions 1 assignee Claimed by @Dharshni-gth View on GitHub
enhancement
Dominant language
TypeScript
Stars
726
Forks
119
Avg merge
7h 41m
Merged PRs (30d)
284

Description

## What happens

Inline cell editing stages an edit correctly, but applying it fails on any tab that still has its default name. The grid shows "1 change", and clicking apply raises:

> Cannot Apply Changes — Could not read a table name from this tab ("2"). Edit the SQL manually.

The edit is never written, and the change stays pending until it is discarded or the page reloads.

## Steps to reproduce

1. Open a new query tab (it is named "Query 2").
2. Run `SELECT id, name, category FROM products ORDER BY id`.
3. Turn on inline editing (the "Enable inline data editing" toggle).
4. Double-click a `name` cell, type a new value, press Enter. The footer shows "1 change".
5. Click apply.

Expected: the row is updated.
Actual: the toast above, and nothing is written. Same result inside an explicit transaction (BEGIN first) — no request is sent at all.

Reproduced on v0.15.0 against PostgreSQL 16 with a table-owner account, so it is not a permissions problem.

## Why

`handleApplyChanges` in `src/hooks/use-inline-editing.ts` derives the table name like this:

```ts
const tableName =
currentTab.name.replace(/^Query[: ]*/, "") || currentTab.query.match(/FROM\s+(\S+)/i)?.[1] || "table_name";
```

For a tab named "Query 2" the replace leaves `"2"`, which is truthy, so the `FROM` fallback never runs. `isBareIdentifier("2")` then fails and the apply is refused.

The fallback chain only works for a tab whose name is empty after the prefix is stripped. Any default tab name carries a digit, so the `FROM` clause — which is right there in the query and names the table correctly — is never consulted.

## Suggestion

Read the `FROM` clause first and treat the tab name as the fallback, or reject a stripped tab name that is not a bare identifier before it shadows the query. Something like:

```ts
const fromQuery = currentTab.query.match(/FROM\s+(\S+)/i)?.[1];
const fromTab = currentTab.name.replace(/^Query[: ]*/, "");
const tableName = (isBareIdentifier(fromQuery ?? "") && fromQuery) || fromTab || "table_name";
```

I have not opened a PR because the ordering here is a product decision — a tab the user renamed deliberately may be meant to win over the query. Happy to write one if you tell me which way you want it.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.