Skip to content

Import: choose source format (SQL/JSON) and batch JSON inserts#1548

Merged
datlechin merged 2 commits into
mainfrom
feat/import-source-picker
Jun 1, 2026
Merged

Import: choose source format (SQL/JSON) and batch JSON inserts#1548
datlechin merged 2 commits into
mainfrom
feat/import-source-picker

Conversation

@datlechin
Copy link
Copy Markdown
Member

What

Two changes to the import flow, on one branch.

1. Import source picker

Import becomes a submenu so you choose the source up front instead of the app guessing from the file extension.

  • Import ▸ From SQL… / From JSON… in the app menu, the sidebar context menu, and the toolbar (native pull-down + submenu menu-form representation).
  • The submenu is built from the registered import plugins, so a future import format shows up automatically. It collapses to a single Import {Format}… item when only one format applies.
  • The coordinator entry point is now openImportDialog(formatId:); routing keys off the chosen plugin's requiresTargetTable instead of inferring from the picked file. The hardcoded "SQL" panel/error text is gone.
  • Cmd+Shift+I moves to the SQL leaf (a submenu parent can't own a shortcut, per HIG).

2. JSON import: accurate progress + batched inserts

  • Progress: the JSON-array path sets the exact total from the parsed row count instead of a fileSize / 256 estimate, so it no longer overshoots (e.g. "3000 of 2657" while the real count was 3503). Streaming .jsonl/.ndjson keeps an estimate, since a true count there needs a second file pass.
  • Speed: rows insert as batched multi-row INSERT … VALUES (…),(…),… (500/batch, clamped by each driver's bind-parameter limit: Postgres 65535, SQLite 32766, MSSQL 2100). Importing 3503 rows to a remote Postgres drops from ~113s to a few seconds (~7 round-trips instead of 3503).
  • Semantics preserved: one transaction; skip-and-continue still isolates bad rows (a failed batch replays row-by-row); cancellation checked per batch.
  • No PluginKit ABI bump: PluginImportDataSink is implemented only in-app and called only by the bundled JSON plugin.

Tests

  • Multi-row insertStatement (Postgres $N + MySQL ?, arity guards) and maxBindParameters per engine.
  • Progress count: exact total, batched-increment accuracy, no overshoot.
  • Routing decision (requiresTargetTable → row-mapping vs statement) and format-option labels.
  • Existing import/coordinator tests updated to the new signatures.

swiftlint --strict clean on all changed files. Not built locally (Xcode build is done separately); CI will compile.

Note

Unrelated in-progress toolbar work in the tree (layout .v2 reorder, Localizable.xcstrings) was intentionally left out of this branch.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6198afe92c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

batch.removeAll(keepingCapacity: true)

do {
try await sink.insertRows(entries.map(\.row))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid replaying rows already inserted by a partial batch

In skipAndContinue mode this assumes sink.insertRows(...) is all-or-nothing, but ImportDataSinkAdapter.insertRows can execute several statements for one batch (different column sets or bind-limit chunks) before a later statement throws. When that happens, the catch path replays every entry row-by-row, so any rows from earlier successful statements in the same batch are inserted a second time. This shows up with JSON rows that do not all have the same mapped columns and one later group has a bad value; either make the sink batch atomic for this path or only replay the rows that were not already committed.

Useful? React with 👍 / 👎.

@datlechin datlechin force-pushed the feat/import-source-picker branch from 6198afe to fbafddc Compare June 1, 2026 17:33
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fbafddc337

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +215 to +216
let sql =
"INSERT INTO \(quoteIdentifierFn(tableName)) (\(columnList)) VALUES \(rowTuples)"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve single-row insert syntax for Oracle

On Oracle connections, JSON row imports now batch same-shaped rows into INSERT ... VALUES (...), (...), but the Oracle dialect supported by this app does not use that multi-row VALUES form; previously insertRow emitted one INSERT ... VALUES (...) per row, which works. Because Oracle has supportsImport: true and importFormatOptions will expose JSON there, any JSON file with two consecutive rows mapping to the same columns will fail at execution instead of importing. Keep Oracle on single-row inserts or generate an Oracle-specific multi-row form.

Useful? React with 👍 / 👎.

@datlechin datlechin merged commit abf34b1 into main Jun 1, 2026
6 checks passed
@datlechin datlechin deleted the feat/import-source-picker branch June 2, 2026 01:04
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.

1 participant