Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ composer.lock
phpunit.xml
phpcs.xml
*.log
.idea/
.idea/
.claude/
124 changes: 124 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# wp-cli-sqlite-command

WP-CLI package for importing and exporting SQLite databases.
Copy link
Contributor

Choose a reason for hiding this comment

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

We could mention where it is used:

Suggested change
WP-CLI package for importing and exporting SQLite databases.
WP-CLI package for importing and exporting SQLite databases.
It's used by WordPress Studio to power the Import, Export and sync features.


## SQLiteCommands

### `wp sqlite import <file>`

Imports a MySQL dump file into the SQLite database. Parses SQL statements using a streaming character-by-character parser, sets default SQL modes (`NO_AUTO_VALUE_ON_ZERO`, disables unique/foreign key checks) to match `mysqldump` defaults, and attempts UTF-8 encoding conversion as a fallback when queries fail.

**Parameters:**

- `<file>` (required), Path to the SQL dump file. Use `-` to read from STDIN.
- `[--enable-ast-driver]` Use the new AST-based `WP_SQLite_Driver` instead of the legacy `WP_SQLite_Translator` for full MySQL compatibility.

### `wp sqlite export [<file>]`

Exports the SQLite database to a MySQL-compatible SQL dump file. Generates `DROP TABLE IF EXISTS`, `CREATE TABLE`, and `INSERT INTO` statements for each table. Automatically excludes internal SQLite system tables (`_mysql_data_types_cache`, `sqlite_master`, `sqlite_sequence`, `_wp_sqlite_*`).

**Parameters:**

- `[<file>]` (optional), Output file path. Use `-` to write to STDOUT. Defaults to `{Y-m-d}-{random-hash}.sql`.
- `[--tables=<tables>]` Comma-separated list of tables to include. If omitted, all tables are exported.
- `[--exclude_tables=<tables>]` Comma-separated list of tables to skip.
- `[--porcelain]` Output only the filename (for scripting).
- `[--enable-ast-driver]` Use the new AST-based driver.

### `wp sqlite tables`

Lists all user tables in the SQLite database, excluding internal/system tables. With the legacy driver, results are sorted alphabetically.

**Parameters:**

- `[--format=<format>]` Output format: `list` (default, one table per line), `csv`, or `json`.
- `[--enable-ast-driver]` Use the new AST-based driver.

## Tech Stack

- PHP >=7.4, WP-CLI package (`wp-cli/wp-cli ^2.5`)
- WordPress SQLite Database Integration plugin, translation layer between MySQL queries and SQLite
- Two driver modes: legacy `WP_SQLite_Translator` and new AST-based `WP_SQLite_Driver` (via `--enable-ast-driver`)

## Directory Structure

```txt
command.php # Entry point, registers the `wp sqlite` CLI command
src/ # Core classes: SQLite_Command, Import, Export, Tables
features/ # Behat BDD test scenarios (.feature files)
features/bootstrap/ # Behat step definitions (SQLiteFeatureContext)
manual_wp_test/ # Manual testing utilities
```

## Validation

### Lint

```sh
composer lint
```

### Code Style (PHPCS)

```sh
composer phpcs
```

Autofix:

```sh
composer phpcbf
```

Uses the `WP_CLI_CS` ruleset (WordPress Coding Standards). Config in `phpcs.xml.dist`.

### Test

```sh
WP_CLI_TEST_DBTYPE=sqlite vendor/bin/behat
```

Tests require a WordPress installation. Using `WP_CLI_TEST_DBTYPE=sqlite` avoids the MySQL dependency.

### All Checks

```sh
composer test
```

Runs lint, phpcs, phpunit, and behat sequentially.

**IMPORTANT - Post-Change Verification**: After applying code changes, always run the linter (`composer lint`), code style checks (`composer phpcs`), and relevant tests (`WP_CLI_TEST_DBTYPE=sqlite vendor/bin/behat`) before considering the work complete.

## Conventions

- **Namespace:** `Automattic\WP_CLI\SQLite` all classes under `src/`
- **Global prefix:** `automattic_wpcli_sqlite` for any global variables or functions
- **Commits:** Imperative mood, descriptive subject. Reference PR/issue numbers (e.g., `Fix import query parsing #14`)
- **Branches:** Create from `main`. Prefixed with `fix/`, `update/`, or `add/` followed by a descriptive name
- **PRs:** Target `main` branch. MUST pass all CI checks (code quality + testing) before merge
- **Indentation:** Tabs for PHP files, spaces (2) for YAML, JSON, and `.feature` files (see `.editorconfig`)
- **Code style:** Enforced by PHPCS with `WP_CLI_CS` ruleset, do not duplicate linter rules
- **IMPORTANT:** Prefer merging `main` into your branch over rebasing. Avoid force pushes to `main` or already-pushed branches

## Architecture

- `command.php` is the entry point, it registers `wp sqlite` as a WP-CLI command pointing to `SQLite_Command`
- `SQLite_Command` delegates to `Import`, `Export`, and `Tables` classes
- `SQLiteDatabaseIntegrationLoader::load_plugin()` bootstraps the WordPress SQLite Database Integration plugin, which MUST be loaded before any database operations
- `SQLiteDriverFactory::create_driver()` creates the appropriate driver based on whether the AST driver is enabled
- The import parser (`Import::parse_statements()`) is a streaming SQL parser using PHP generators, it handles quotes, comments, escape sequences, and multi-line statements character by character

## Common Pitfalls

- **MUST load the SQLite plugin first:** All database operations require `SQLiteDatabaseIntegrationLoader::load_plugin()` to be called before creating a driver. The driver depends on classes from the WordPress SQLite Database Integration plugin.
- **Two driver APIs:** The legacy `WP_SQLite_Translator` and new `WP_SQLite_Driver` (AST) have different class names. Use `SQLiteDriverFactory::create_driver()` to get the correct one,do not instantiate drivers directly.
- **SQL parser edge cases:** The `Import::parse_statements()` method handles escape sequences, nested quotes, and multi-line comments manually. Changes to this parser MUST be tested with the existing Behat scenarios in `features/sqlite-import.feature`.
- **Encoding handling:** Import attempts UTF-8 conversion as a fallback when queries fail. This is intentional error recovery, not a bug.
- **`@when after_wp_config_load`:** All command methods use this WP-CLI hook annotation. New commands MUST include it to ensure WordPress config is loaded before execution.
- **PHPCS inline suppressions:** The codebase uses `@phpcs:disable` / `@phpcs:enable` comments around `define('WP_SQLITE_AST_DRIVER')` because the constant name doesn't follow the project prefix convention. This is intentional.

## Documentation

- **Testing guide:** `TESTING.md` How to run the Behat test suite locally with SQLite
- **README:** `README.md` CLI usage, options, and examples for all commands
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
Loading