Skip to content

Fix six more bugs (phone DB push on reads, JSON export, json/xml/geometric edits, env bools, SQLite row counts) - #6

Merged
robertsolves merged 7 commits into
mainfrom
claude/project-thread-sroiel
Nov 3, 2026
Merged

robertsolves merged 7 commits into
mainfrom
claude/project-thread-sroiel

Conversation

@robertsolves

@robertsolves robertsolves commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Requested by Robert · project thread

What & why

Follow-up to #5, which is now merged. This PR targets main.

  • Phone databases pushed the whole file back after every read. DeviceSqliteExecutor took affectedRows > 0 to mean "wrote", but SQLite reports a SELECT's row count there. It now decides from what the statement did: SQLite's total_changes() or schema_version moved, or a write keyword with no counter (VACUUM, ANALYZE, PRAGMA x = y). Writes inside BEGIN … COMMIT push once, at the COMMIT, rather than sending the device an uncommitted file. The old keyword check also only skipped -- comments, so a /* … */ SELECT pushed too.
  • JSON export failed on any date or timestamp column. The driver returns DateTime, which jsonEncode refuses. The export now writes non-JSON values as text (dates as UTC ISO-8601) and suffixes repeated column names instead of letting b.id overwrite a.id. New lib/grid/export_json.dart, used by the io and web exporters.
  • json, xml and geometric cells could never be saved on Postgres. The optimistic guard col IS NOT DISTINCT FROM $old errors with "operator does not exist" for these types. Most geometric types fail even earlier: the driver can't bind them back ("Could not infer type of value").
    • json is now compared as jsonb, and xml as text.
    • For point, line, lseg, box, path, polygon and circle, the old value is sent in Postgres syntax (new lib/db/pg_geometry.dart). The guard compares the server's text of both sides: col::text IS NOT DISTINCT FROM ($n::point)::text.
    • The cell editor now starts from that syntax, so saving an untouched (1,2) works. Before, it started from Point(1.0,2.0), which Postgres rejects.
  • DBSCOPE_AUTO_READ_ONLY=1 opened the connection writable. Only the exact string true counted. It now accepts true/1/yes/on and false/0/no/off in any case, and anything else falls back to the name heuristic. DBSCOPE_AUTO_ASSIGN_IP uses the same parser.
  • SQLite reported a stale "rows affected" count. sqlite3_changes() keeps the count from the last write, so a CREATE TABLE after an UPDATE of 5 rows said 5. It now reports 0 unless this statement changed rows.

Records: closed the BUGS.md entry for the phone push. BUGS.md has no open entries now. Added 6 changelog lines, and updated the on-device write path in docs/architecture.md.

How it was tested

  • Linux, Flutter 3.47.7.
  • test/device_sqlite_push_test.dart runs the real executor against a fake device backend: reads don't push, writes push once, a transaction pushes once at COMMIT. It fails on the old code (4 pushes for 4 reads).
  • test/dml_live_pg_test.dart saves json, xml and all seven geometric types against a real Postgres, and checks that a stale old value is still a conflict. It is skipped unless DBSCOPE_LIVE_PG is set. I ran it against a local Postgres 16; on the old code it fails with the operator error. There are also SQL-shape cases in dml_test.
  • New tests: pg_geometry_test, export_json_test, cli_auto_connect_test, sqlite_executor_test.
  • Not run on a real phone.

Checklist

  • fvm flutter analyze is clean (and the sqflite plugin package)
  • fvm flutter test passes (306 passed, 16 skipped live-PG)
  • SQL safety invariants still hold (quoted identifiers, parameterised values, optimistic guard on every UPDATE)
  • No credentials in the diff

🤖 Generated with Claude Code

https://claude.ai/code/session_01EqzDdWjzbRhR11uqy5k4wL

…dits, env bools, SQLite row counts

- On-device SQLite pushes the file back only when a statement changed it
  (total_changes / schema_version / write keyword), once per transaction.
- JSON export writes DateTime/BigInt as text and keeps repeated columns.
- Postgres cell edits on json and xml columns compare as jsonb / text.
- DBSCOPE_AUTO_READ_ONLY and DBSCOPE_AUTO_ASSIGN_IP accept 1/0, yes/no.
- SqliteExecutor reports 0 affected rows for DDL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EqzDdWjzbRhR11uqy5k4wL
…to claude/project-thread-sroiel

# Conflicts:
#	CHANGELOG.md
The optimistic guard has no usable = for point/line/lseg/box/path/polygon/
circle, and the driver can't bind most of them back. Send the old value as
Postgres text and compare the server's text of both sides. The editor starts
from Postgres syntax instead of the driver's toString.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EqzDdWjzbRhR11uqy5k4wL
…to claude/project-thread-sroiel

# Conflicts:
#	CHANGELOG.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EqzDdWjzbRhR11uqy5k4wL
@robertsolves robertsolves changed the title Fix five more bugs (phone DB push on reads, JSON export, json/xml edits, env bools, SQLite row counts) Fix six more bugs (phone DB push on reads, JSON export, json/xml/geometric edits, env bools, SQLite row counts) Nov 3, 2026
…to claude/project-thread-sroiel

# Conflicts:
#	CHANGELOG.md
@robertsolves
robertsolves changed the base branch from claude/project-thread-ecky3x to main November 3, 2026 09:13
@robertsolves
robertsolves merged commit 7a16796 into main Nov 3, 2026
4 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants