Skip to content

feat(project): add sql and restore commands - #1326

Open
Soner (shyim) wants to merge 1 commit into
nextfrom
feat/project-sql-restore
Open

feat(project): add sql and restore commands#1326
Soner (shyim) wants to merge 1 commit into
nextfrom
feat/project-sql-restore

Conversation

@shyim

@shyim Soner (shyim) commented Aug 4, 2026

Copy link
Copy Markdown
Member

What

Two new project commands that talk to the project database without the user needing to know which MySQL/MariaDB, host or credentials are in play:

project sql [query]

  • One-shot: shopware-cli project sql "SELECT id, tax_rate FROM tax"
  • Scripting: shopware-cli project sql < script.sql, --format json | jq
  • Interactive shell with sql> / -> continuation prompts, multi-line statements, exit/quit/\q
  • Output formats: mysql-style table (default on a TTY), tsv (default when piped), json (numeric columns as real JSON numbers)
  • Binary columns (e.g. BINARY(16) ids) render as 0x… hex

project restore <file> (alias project import)

  • Accepts plain .sql, gzip and zstd dumps — compression detected from magic bytes, not the filename; - reads from stdin
  • Streams in 1 MB chunks (dumps larger than memory work), progress at 10% steps, aborts on the first failing statement with the statement quoted

How

  • New Executor.DatabaseConnection(ctx) method resolves host-reachable credentials:
    • local / symfony-cli: DATABASE_URL with Symfony precedence (executor env > real env > env files), defaults matching project dump
    • docker: reads DATABASE_URL from the web container, then swaps the compose service host for the port published on the host (docker compose port); external DB hosts pass through
  • The generated dev compose now publishes the database on a random loopback port (127.0.0.1::3306) so host-side tools can connect without port conflicts; picked up on the next project dev run
  • Both commands run on a single dedicated *sql.Conn so session state (SET FOREIGN_KEY_CHECKS, SET NAMES, USE) sticks; max_allowed_packet is fetched from the server
  • New internal/sqlshell package with a statement splitter that understands quotes, escapes, line/block comments, executable comments (/*!40014 … */) and DELIMITER directives (as emitted by our dumper around triggers) — delimiter state survives stream chunk boundaries and REPL lines

Testing

  • Unit tests for splitter (incl. trigger dumps fed 3 bytes at a time), renderers, keyword classification, connection resolution and decompression sniffing
  • Verified live against MariaDB 11.8: project dumpproject restore round trip in all three compressions, stdin restore, trigger round trip (restored trigger fires), 10 MB / 100k-row gzipped dump in ~0.8 s, error paths
  • go test ./... and golangci-lint run clean

Limitations

  • REPL has no readline-style line editing/history
  • DELIMITER support covers directive lines as dumps emit them; interactive redefinition mid-line is not supported

🤖 Generated with Claude Code

fixes #1243

Summary by CodeRabbit

  • New Features
    • Added project sql for direct queries, piped SQL, and interactive sessions.
    • Added table, TSV, and JSON output formats.
    • Added project restore/project import for plain, gzip, and zstd SQL dumps from files or standard input.
    • Restore supports confirmation prompts, force mode, progress updates, and completion statistics.
  • Improvements
    • SQL processing supports multiline statements, custom delimiters, and multiple result sets.
    • Database connections are resolved automatically for local and containerized projects.
    • Container databases are accessible through localhost-assigned ports.
    • Improved database connection handling for dump operations.

@codecov-commenter

Codecov Comments Bot (codecov-commenter) commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.36922% with 212 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.17%. Comparing base (5b6ef06) to head (2cc4c47).
⚠️ Report is 6 commits behind head on next.

Files with missing lines Patch % Lines
cmd/project/project_restore.go 6.00% 47 Missing ⚠️
internal/account-api/producer_store_upload.go 79.05% 31 Missing ⚠️
cmd/project/project_sql.go 37.50% 20 Missing ⚠️
internal/account-api/producer_store_pull.go 88.82% 20 Missing ⚠️
internal/account-api/producer_store_push.go 91.55% 19 Missing ⚠️
internal/sqlshell/interactive.go 90.97% 12 Missing ⚠️
internal/sqlshell/run.go 95.27% 12 Missing ⚠️
cmd/project/executor.go 37.50% 10 Missing ⚠️
cmd/account/account_producer_extension_list.go 0.00% 9 Missing ⚠️
internal/account-api/producer_store_list.go 92.68% 6 Missing ⚠️
... and 11 more
Additional details and impacted files
@@            Coverage Diff             @@
##             next    #1326      +/-   ##
==========================================
+ Coverage   54.01%   59.17%   +5.15%     
==========================================
  Files         303      318      +15     
  Lines       23457    24319     +862     
==========================================
+ Hits        12671    14390    +1719     
+ Misses      10758     9901     -857     
  Partials       28       28              
Flag Coverage Δ
go-test 59.17% <85.36%> (+5.15%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d20261e2-9a10-48f5-8c06-cf6c79236418

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change adds host-accessible project database resolution, project SQL and restore commands, Compose database port publishing, and a delimiter-aware SQL shell with streaming execution and multiple output formats.

Changes

Project database tools

Layer / File(s) Summary
Database connection resolution
internal/executor/..., internal/docker/..., cmd/project/project_dump.go
Executors resolve database URLs from overrides, environment variables, envfiles, or Docker containers. Docker executors translate container ports to published host ports. Dump connection assembly uses the shared connection model.
SQL parsing and streaming execution
internal/sqlshell/split.go, internal/sqlshell/stream.go, internal/sqlshell/*_test.go
The SQL shell parses quoted text, comments, and DELIMITER directives. Streamed input executes complete statements and reports progress.
SQL execution and output rendering
internal/sqlshell/run.go, internal/sqlshell/shell.go, internal/sqlshell/interactive.go, internal/sqlshell/*_test.go
SQL execution supports query, execution, RETURNING, interactive sessions, cancellation, and table, TSV, or JSON output.
Project SQL and restore commands
cmd/project/executor.go, cmd/project/project_sql.go, cmd/project/project_restore.go, cmd/project/*_test.go, internal/docker/*
Project commands connect to databases, execute SQL from arguments or stdin, open interactive shells, and restore plain, gzip, or zstd SQL dumps. Compose publishes the database on a random loopback port.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant projectSQLCmd
  participant connectProjectDatabase
  participant Executor.DatabaseConnection
  participant sqlshell.InteractiveShell
  participant MySQL
  projectSQLCmd->>connectProjectDatabase: resolve project database
  connectProjectDatabase->>Executor.DatabaseConnection: request host credentials
  Executor.DatabaseConnection-->>connectProjectDatabase: return DatabaseConnection
  connectProjectDatabase->>MySQL: open dedicated connection
  projectSQLCmd->>sqlshell.InteractiveShell: execute interactive SQL
  sqlshell.InteractiveShell->>MySQL: execute statements and queries
  MySQL-->>sqlshell.InteractiveShell: return formatted results
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The extensive project SQL command and interactive SQL shell are not covered by the directly linked restore issue [#1243]. Link an issue that covers project SQL, or move the SQL command and related shell changes into a separate pull request.
Docstring Coverage ⚠️ Warning Docstring coverage is 20.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The restore implementation meets the linked issue requirements for supported formats, database resolution, confirmation, bypass, streaming, and failure handling [#1243].
Title check ✅ Passed The title clearly summarizes the main changes: adding the project SQL and restore commands.
Description check ✅ Passed The description covers the changes, implementation, testing, limitations, and related issue, despite using different section headings than the template.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/project-sql-restore

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (5)
cmd/project/project_sql.go (2)

29-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Validate --format before you open the database connection.

connectProjectDatabase runs first. An invalid --format value therefore starts a container lookup and a database handshake, and only then fails with a usage error. Move resolveSQLFormat above the connect call.

♻️ Proposed reorder
-		conn, dbConn, cleanup, err := connectProjectDatabase(cmd)
-		if err != nil {
-			return err
-		}
-		defer cleanup()
-
-		format, err := resolveSQLFormat(cmd)
-		if err != nil {
-			return err
-		}
+		format, err := resolveSQLFormat(cmd)
+		if err != nil {
+			return err
+		}
+
+		conn, dbConn, cleanup, err := connectProjectDatabase(cmd)
+		if err != nil {
+			return err
+		}
+		defer cleanup()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/project/project_sql.go` around lines 29 - 40, Move the resolveSQLFormat
call before connectProjectDatabase in the RunE command handler, returning its
error immediately before any database connection or cleanup setup occurs.
Preserve the existing format value and subsequent connection flow.

41-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Terminal detection uses the process streams, but I/O uses the Cobra streams.

Line 45 checks os.Stdin, and Line 46 reads from cmd.InOrStdin(). Line 68 checks os.Stdout, and the output goes to cmd.OutOrStdout(). If a caller or a test replaces the Cobra streams with cmd.SetIn/cmd.SetOut, the command still inspects the real process descriptors. The command then selects the wrong mode, for example the interactive shell on a piped test input.

Derive the check from the Cobra streams instead, and fall back to non-terminal when the stream is not an *os.File.

♻️ Proposed helper
func isTerminalStream(s any) bool {
	f, ok := s.(*os.File)
	return ok && term.IsTerminal(f.Fd())
}
-		if !term.IsTerminal(os.Stdin.Fd()) {
+		if !isTerminalStream(cmd.InOrStdin()) {
-		if term.IsTerminal(os.Stdout.Fd()) {
+		if isTerminalStream(cmd.OutOrStdout()) {

Also applies to: 64-76

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/project/project_sql.go` around lines 41 - 52, Update terminal detection
in the command’s input and output mode selection to inspect cmd.InOrStdin() and
cmd.OutOrStdout() rather than os.Stdin and os.Stdout. Add or reuse an
isTerminalStream helper that only calls term.IsTerminal for *os.File values and
returns false for other stream types, preserving non-terminal behavior for
Cobra-injected buffers and pipes.
internal/sqlshell/shell.go (1)

30-34: 🩺 Stability & Availability | 🔵 Trivial | ⚖️ Poor tradeoff

Context cancellation does not interrupt the blocking read.

scanner.Scan() blocks until the user sends a line. The ctx.Err() check runs only after Scan returns. If the root command cancels the context, for example on SIGINT, the shell stays blocked until the user presses Enter or Ctrl+D.

For an interactive shell the process normally terminates on the signal, so the impact is limited. If you want the loop to react, read lines in a goroutine and select on ctx.Done().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/sqlshell/shell.go` around lines 30 - 34, Update the scanner loop
around scanner.Scan so context cancellation can interrupt a blocking interactive
read: perform line reads in a goroutine and select between the read result and
ctx.Done(), returning ctx.Err() immediately when the context is canceled while
preserving normal EOF and scan-error handling.
internal/sqlshell/run.go (1)

376-397: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

Numeric-column JSON passthrough can emit values that consumers cannot read back.

renderJSON converts a numeric column value to json.RawMessage when json.Valid accepts it. json.Valid accepts any well-formed JSON document, not only numbers. For a numeric column the driver returns a numeric literal, so this is safe today. Two edge cases remain:

  • A DECIMAL with high precision, for example 12345678901234567890.123, is emitted as a raw number. Many JSON consumers parse it as a float64 and lose precision.
  • numeric[i] is derived from DatabaseTypeName(), which is driver-dependent for aliases such as UNSIGNED BIGINT.

If precision matters for downstream jq use, consider restricting the raw passthrough to integer types and emitting DECIMAL as a string.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/sqlshell/run.go` around lines 376 - 397, Update renderJSON to
distinguish integer numeric columns from DECIMAL and other high-precision values
instead of treating every numeric[i] value as a raw JSON number. Preserve
raw-number passthrough only for supported integer database types, including
driver aliases such as UNSIGNED BIGINT, and emit DECIMAL values as strings so
downstream consumers do not lose precision.
internal/sqlshell/stream.go (1)

42-55: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Buffer growth is quadratic for very large single statements.

buffer += string(chunk[:n]) copies the whole pending buffer on every read. Normal dumps split statements below max_allowed_packet, so the pending buffer stays small. A dump with one very large statement (for example a multi-hundred-MB extended INSERT or a LOAD payload) makes each 1 MiB read copy the full buffer again.

If you want to bound this, accumulate into a strings.Builder (or []byte) and only materialize a string when you call the splitter, resetting the builder from the returned remainder. The remainder itself is a substring and stays cheap.

This is not blocking for typical dumps.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/sqlshell/stream.go` around lines 42 - 55, The statement streaming
loop in stream.go is growing the pending buffer with repeated string
concatenation, which becomes quadratic for very large statements. Update the
read/execute path around buffer and SplitStatementsWithDelimiter to accumulate
chunks in a strings.Builder or []byte, materialize a string only when splitting,
and then reset the accumulator to the returned remainder so large single
statements stay linear-time.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/project/executor.go`:
- Around line 50-60: Update the MySQL configuration setup around mysqlCfg to
require certificate-validating TLS when dbConn targets a non-loopback host,
while leaving loopback connections unchanged as appropriate. Configure the
driver with a strict TLS mode or registered TLS configuration that verifies
certificates and hostnames; do not use the "preferred" mode or allow plaintext
fallback. Ensure the existing connection fields and MaxAllowedPacket behavior
remain intact.

In `@cmd/project/project_restore.go`:
- Around line 33-49: Update the project restore command’s RunE flow to prompt
for confirmation before executing the dump when interaction is enabled, using
system.IsInteractionEnabled as in project_sql.go; bypass the prompt when
interaction is disabled or the --force flag is provided. Add and honor the
--force command option, and abort without restoring when the user declines.

In `@internal/executor/database.go`:
- Around line 42-67: Update applyDatabaseURL in database.go to reject
DATABASE_URL values unless url.Parse returns both a non-empty parsed.Scheme and
parsed.Hostname() before mutating conn; if either is missing, return an error
instead of preserving the default connection settings. Keep the existing parsing
of parsed.User, parsed.Port(), and parsed.Path for valid URLs, and add
regression tests covering the shopware and mysql:///shopware inputs so project
restore cannot fall back to the default database.

In `@internal/sqlshell/run.go`:
- Around line 162-171: Update returnsResultSet and the statement-dispatch logic
to recognize MariaDB INSERT, REPLACE, and single-table DELETE statements
containing RETURNING as result sets. Ensure these statements use
Query/QueryContext and flow through renderResultSet instead of ExecContext,
while preserving existing handling for other statements.

---

Nitpick comments:
In `@cmd/project/project_sql.go`:
- Around line 29-40: Move the resolveSQLFormat call before
connectProjectDatabase in the RunE command handler, returning its error
immediately before any database connection or cleanup setup occurs. Preserve the
existing format value and subsequent connection flow.
- Around line 41-52: Update terminal detection in the command’s input and output
mode selection to inspect cmd.InOrStdin() and cmd.OutOrStdout() rather than
os.Stdin and os.Stdout. Add or reuse an isTerminalStream helper that only calls
term.IsTerminal for *os.File values and returns false for other stream types,
preserving non-terminal behavior for Cobra-injected buffers and pipes.

In `@internal/sqlshell/run.go`:
- Around line 376-397: Update renderJSON to distinguish integer numeric columns
from DECIMAL and other high-precision values instead of treating every
numeric[i] value as a raw JSON number. Preserve raw-number passthrough only for
supported integer database types, including driver aliases such as UNSIGNED
BIGINT, and emit DECIMAL values as strings so downstream consumers do not lose
precision.

In `@internal/sqlshell/shell.go`:
- Around line 30-34: Update the scanner loop around scanner.Scan so context
cancellation can interrupt a blocking interactive read: perform line reads in a
goroutine and select between the read result and ctx.Done(), returning ctx.Err()
immediately when the context is canceled while preserving normal EOF and
scan-error handling.

In `@internal/sqlshell/stream.go`:
- Around line 42-55: The statement streaming loop in stream.go is growing the
pending buffer with repeated string concatenation, which becomes quadratic for
very large statements. Update the read/execute path around buffer and
SplitStatementsWithDelimiter to accumulate chunks in a strings.Builder or
[]byte, materialize a string only when splitting, and then reset the accumulator
to the returned remainder so large single statements stay linear-time.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d7fac925-d7a0-48e9-a8fb-20809b7e44f6

📥 Commits

Reviewing files that changed from the base of the PR and between 3d39a5c and 8e4cef1.

📒 Files selected for processing (19)
  • cmd/project/executor.go
  • cmd/project/project_restore.go
  • cmd/project/project_restore_test.go
  • cmd/project/project_sql.go
  • internal/docker/compose.go
  • internal/docker/compose_test.go
  • internal/executor/database.go
  • internal/executor/database_test.go
  • internal/executor/docker.go
  • internal/executor/executor.go
  • internal/executor/local.go
  • internal/executor/symfony_cli.go
  • internal/sqlshell/run.go
  • internal/sqlshell/run_test.go
  • internal/sqlshell/shell.go
  • internal/sqlshell/split.go
  • internal/sqlshell/split_test.go
  • internal/sqlshell/stream.go
  • internal/sqlshell/stream_test.go

Comment thread cmd/project/executor.go Outdated
Comment thread cmd/project/project_restore.go
Comment thread internal/executor/database.go
Comment thread internal/sqlshell/run.go
@shyim
Soner (shyim) marked this pull request as ready for review August 6, 2026 05:58
@shyim
Soner (shyim) marked this pull request as draft August 6, 2026 06:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/sqlshell/run.go`:
- Around line 203-218: Update hasReturningClause’s comment scanner so -- starts
a line comment only when its following character is whitespace, while still
recognizing valid end-of-line comments. Treat completed block comments as token
separators when checking RETURNING boundaries, including comments before or
after the clause; preserve detection for 1--1 RETURNING, /* comment */RETURNING,
and RETURNING/* comment */id. Add regression tests covering these cases.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a459f546-472a-4bb8-9ce6-c1a6f27e5595

📥 Commits

Reviewing files that changed from the base of the PR and between 8e4cef1 and 5ed677d.

📒 Files selected for processing (11)
  • cmd/project/project_restore.go
  • cmd/project/project_sql.go
  • cmd/project/project_sql_test.go
  • internal/executor/database.go
  • internal/executor/database_docker_test.go
  • internal/executor/database_test.go
  • internal/sqlshell/fakedb_test.go
  • internal/sqlshell/run.go
  • internal/sqlshell/run_db_test.go
  • internal/sqlshell/run_test.go
  • internal/sqlshell/split_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/sqlshell/split_test.go
  • cmd/project/project_sql.go
  • cmd/project/project_restore.go
  • internal/executor/database_test.go

Comment thread internal/sqlshell/run.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
internal/sqlshell/interactive_test.go (2)

146-153: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

This test locks in the no-cancel behavior.

TestInteractiveIgnoresKeysWhileRunning asserts that every key is ignored while m.running is true. I raised the missing cancellation path at internal/sqlshell/interactive.go lines 94-97. If you add ctrl+c cancellation there, narrow this test to keys that must stay ignored, and add a case that asserts ctrl+c cancels the running statement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/sqlshell/interactive_test.go` around lines 146 - 153, Update
TestInteractiveIgnoresKeysWhileRunning to cover only non-cancellation keys that
remain ignored while m.running is true. Add a separate test case for ctrl+c that
verifies the running statement is cancelled, matching the cancellation handling
in the interactive model.

128-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Clean up the package-level fake query.

Register fakeQueries.Delete("SELECT 3") with t.Cleanup after the store call. This keeps the test isolated if another test later uses the same query key.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/sqlshell/interactive_test.go` around lines 128 - 132, After the
fakeQueries.Store call for "SELECT 3" in the test, register
fakeQueries.Delete("SELECT 3") with t.Cleanup so the package-level fake query is
removed when the test finishes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/sqlshell/interactive.go`:
- Around line 94-97: Update the execution flow around Update’s tea.KeyPressMsg
handling to create a per-statement cancellable context derived from the session
context, retain its cancel function, and invoke it for ctrl+c while m.running
instead of dropping the key. Propagate that statement context into query
execution, and update View to render a running indicator such as a spinner or
“running…” line while execution is active.
- Around line 17-21: Update InteractiveShell to return nil when errors.Is(err,
context.Canceled) matches, accounting for Bubble Tea’s wrapped cancellation
error; preserve all other errors, including unrelated tea.ErrProgramKilled
cases, and return them unchanged.

---

Nitpick comments:
In `@internal/sqlshell/interactive_test.go`:
- Around line 146-153: Update TestInteractiveIgnoresKeysWhileRunning to cover
only non-cancellation keys that remain ignored while m.running is true. Add a
separate test case for ctrl+c that verifies the running statement is cancelled,
matching the cancellation handling in the interactive model.
- Around line 128-132: After the fakeQueries.Store call for "SELECT 3" in the
test, register fakeQueries.Delete("SELECT 3") with t.Cleanup so the
package-level fake query is removed when the test finishes.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3c3714d6-8837-4288-aa86-92678f3197eb

📥 Commits

Reviewing files that changed from the base of the PR and between c5aa363 and e480d89.

📒 Files selected for processing (13)
  • cmd/project/executor.go
  • cmd/project/project_dump.go
  • cmd/project/project_dump_test.go
  • cmd/project/project_restore.go
  • cmd/project/project_sql.go
  • cmd/project/project_sql_test.go
  • internal/executor/database.go
  • internal/executor/database_test.go
  • internal/sqlshell/fakedb_test.go
  • internal/sqlshell/interactive.go
  • internal/sqlshell/interactive_test.go
  • internal/sqlshell/run.go
  • internal/sqlshell/shell.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • cmd/project/project_sql.go
  • internal/sqlshell/shell.go
  • cmd/project/project_sql_test.go
  • cmd/project/project_restore.go
  • internal/sqlshell/run.go

Comment thread internal/sqlshell/interactive.go
Comment thread internal/sqlshell/interactive.go
@shyim
Soner (shyim) changed the base branch from main to next August 6, 2026 09:38
@shyim
Soner (shyim) changed the base branch from next to main August 6, 2026 09:38
@shyim
Soner (shyim) force-pushed the feat/project-sql-restore branch from 18c61d9 to 2cc4c47 Compare August 6, 2026 09:39
@shyim
Soner (shyim) changed the base branch from main to next August 6, 2026 09:40
Adds `project sql` and `project restore` (alias `import`), working
against the database of the current environment so no host or
credentials knowledge is needed.

project sql:
- one-shot queries, piped scripts and an interactive shell
- the interactive shell is an inline bubbletea program with real line
  editing (alt+backspace/ctrl+w/alt+d word deletion, cursor movement),
  arrow-key session history and cancellable queries via ctrl+c
- output formats: mysql-style table (tty), tsv (piped), json; binary
  columns render as hex, numeric columns as real JSON numbers

project restore:
- plain, gzip or zstd compressed dumps, detected via magic bytes,
  streamed in chunks so dumps larger than memory work
- progress reporting, confirmation prompt (skippable with --force,
  auto-skipped for stdin dumps and --no-interaction)

Infrastructure:
- Executor gains DatabaseConnection() resolving host-reachable
  credentials: DATABASE_URL with Symfony precedence for local and
  symfony-cli, the published compose port for docker; MySQLConfig()
  and Open() keep all driver knowledge in the executor package
- the generated dev compose publishes the database on a random
  loopback port so host-side tools can connect without conflicts
- project dump resolves its base connection through the executor too,
  gaining docker support; flags still override individual parts
- internal/sqlshell statement splitter handles quotes, comments,
  executable comments (/*!40014 ... */) and DELIMITER directives as
  emitted by the dumper around triggers, with state that survives
  stream chunks and shell lines
- commands run on a single dedicated connection so session state like
  SET FOREIGN_KEY_CHECKS sticks
- reusable CountingReader and DecompressReader in internal/system

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

Add project restore command to import database dumps

2 participants