diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..d7880fa --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,81 @@ +# phenixphp/sqlite - AI Coding Instructions + +Asynchronous SQLite client for PHP built on Amp v3 framework. This library adapts patterns from `amphp/mysql` to work with SQLite's file-based architecture. + +## Architecture Overview + +**Core Components:** +- `SqliteConnection` - Main connection abstraction wrapping `Internal\ConnectionProcessor` +- `SqliteConfig` - File-based configuration (path, open flags, pragmas) instead of network config +- `SqliteColumnDefinition` - Simplified metadata reflecting SQLite's 5 storage classes (NULL, INTEGER, REAL, TEXT, BLOB) +- `SqliteDataType` enum - Type affinity system, NOT MySQL's 30+ types + +**Key Design Decisions:** +- SQLite uses **storage classes** not strict types - see `SqliteDataType::fromDeclaredType()` for affinity rules +- No connection pooling needed (file-based, not network) - connection reuse pattern differs from MySQL +- Uses Amp's parallel worker pools for potential multi-connection scenarios (see `amphp/parallel` in `knowledge/`) +- Adapting MySQL protocol patterns to SQLite3 native extensions +- Don't act condescendingly; adopt a technical, critical, and punctual approach. + +## Critical Workflows + +```bash +# Format code (uses PSR-12 + custom rules) +composer format + +# Static analysis (PHPStan level max) +composer analyze + +# Run tests (uses Pest, not PHPUnit) +composer test +composer test:parallel # Uses parallel execution +``` + +## Code Conventions + +**Type Declarations:** +- ALWAYS `Type|null` NEVER `?Type` (enforced by PHP-CS-Fixer `nullable_type_declaration`) +- Blank line after ` $connection->query($sql)); +$result = $future->await(); +``` + +## Reference Implementation + +Look at `knowledge/amphp-mysql/` for database patterns adapted to SQLite: +- Connection lifecycle management +- Prepared statements with parameter binding +- Result set handling with column definitions +- Transaction isolation levels + +Key differences from MySQL: +- No `host`, `port`, `user`, `password` in config +- No compression or network-related flags +- Simpler column metadata (no charset field) +- Different PRAGMA-based configuration vs SQL variables + +## Integration Points + +- Extends `Amp\Sql\SqlConnection` interface +- Uses `Amp\Parallel\Worker` for potential concurrent file operations +- Leverages `Amp\Parser\Parser` for protocol handling (adapted from MySQL patterns) +- File operations via Amp event loop, not blocking I/O + +## Testing + +Uses **Pest** (not PHPUnit) - see `composer.json` scripts. Test structure follows Amp conventions with async test cases. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..1929f39 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Omar Barbosa + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 93a8384..1b1aa29 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,242 @@ # phenixphp/sqlite +

Asynchronous SQLite 3 client for PHP based on Amp.

+ +[![Tests](https://github.com/phenixphp/sqlite/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/phenixphp/sqlite/actions/workflows/run-tests.yml) +[![Latest Version on Packagist](https://img.shields.io/packagist/v/phenixphp/sqlite.svg?style=flat-square)](https://packagist.org/packages/phenixphp/sqlite) +[![Total Downloads](https://img.shields.io/packagist/dt/phenixphp/sqlite.svg?style=flat-square)](https://packagist.org/packages/phenixphp/sqlite) +[![PHP Version](https://img.shields.io/packagist/php/phenixphp/sqlite.svg?style=flat-square)](https://packagist.org/packages/phenixphp/sqlite) +[![License](https://img.shields.io/packagist/license/phenixphp/sqlite.svg?style=flat-square)](https://packagist.org/packages/phenixphp/sqlite) + +--- + +**phenixphp/sqlite** is part of the **Phenix PHP** framework ecosystem. Phenix is a web framework built on pure PHP, without external extensions, based on the [Amphp](https://amphp.org/) ecosystem, which provides non-blocking operations, asynchronism and parallel code execution natively. It runs in the PHP SAPI CLI and on its own server — it is simply powerful. + +--- + +## Table of Contents + +- [Requirements](#requirements) +- [Installation](#installation) +- [Configuration](#configuration) +- [Usage](#usage) + - [Establishing a Connection](#establishing-a-connection) + - [Executing Queries](#executing-queries) + - [Prepared Statements](#prepared-statements) + - [Transactions](#transactions) +- [Dependencies](#dependencies) +- [License](#license) + +--- + +## Requirements + +| Requirement | Version | +| --- | --- | +| PHP | `^8.2` | +| ext-sqlite3 | `*` | + +--- + +## Installation + +Install the package via [Composer](https://getcomposer.org/): + +```bash +composer require phenixphp/sqlite +``` + +--- + +## Configuration + +The `SqliteConfig` class is the entry point for configuring the SQLite connection. It allows you to define the database path and connection parameters aligned with the Amphp SQL ecosystem. + +```php + You can use `:memory:` as the database path to create an in-memory SQLite database, which is ideal for testing scenarios. + +```php +$config = new SqliteConfig( + database: ':memory:', +); +``` + +--- + +## Usage + +### Establishing a Connection + +Use `SqliteConfig` to create and manage asynchronous connections to your SQLite database. Since this package is built on top of Amphp, all database operations are **non-blocking** and run asynchronously using fibers. + +```php +close(); +``` + +--- + +### Executing Queries + +Once you have an active connection, you can execute SQL statements — `CREATE`, `INSERT`, `SELECT`, `UPDATE`, and `DELETE` — all asynchronously without blocking the event loop. + +#### Creating a Table + +```php +$connection->execute( + 'CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + email TEXT NOT NULL + )' +); +``` + +#### Inserting Records + +```php +$connection->execute( + "INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com')" +); +``` + +#### Selecting Records + +```php +$result = $connection->query('SELECT * FROM users'); + +foreach ($result as $row) { + echo $row['id'] . ': ' . $row['name'] . ' — ' . $row['email'] . PHP_EOL; +} +``` + +#### Updating Records + +```php +$connection->execute( + "UPDATE users SET name = 'Jane Doe' WHERE id = 1" +); +``` + +#### Deleting Records + +```php +$connection->execute( + "DELETE FROM users WHERE id = 1" +); +``` + +--- + +### Prepared Statements + +Prepared statements allow you to precompile a SQL template and execute it repeatedly with different bound parameters. This improves both performance and security by preventing SQL injection. + +#### Preparing and Executing a Statement + +```php +$statement = $connection->prepare( + 'INSERT INTO users (name, email) VALUES (?, ?)' +); + +$statement->execute(['Alice', 'alice@example.com']); +$statement->execute(['Bob', 'bob@example.com']); +``` + +#### Prepared Statement with Named Parameters + +```php +$statement = $connection->prepare( + 'SELECT * FROM users WHERE name = ? AND email = ?' +); + +$result = $statement->execute(['Alice', 'alice@example.com']); + +foreach ($result as $row) { + echo $row['name'] . PHP_EOL; +} +``` + +#### Closing a Prepared Statement + +```php +$statement->close(); +``` + +--- + +### Transactions + +Transactions group multiple SQL operations into a single atomic unit. If any operation fails, all changes within the transaction are rolled back, ensuring data consistency. + +#### Basic Transaction + +```php +$transaction = $connection->beginTransaction(); + +try { + $transaction->execute( + "INSERT INTO users (name, email) VALUES ('Charlie', 'charlie@example.com')" + ); + $transaction->execute( + "INSERT INTO users (name, email) VALUES ('Diana', 'diana@example.com')" + ); + + $transaction->commit(); +} catch (\Throwable $e) { + $transaction->rollback(); + + throw $e; +} +``` + +#### Transaction with Prepared Statements + +```php +$transaction = $connection->beginTransaction(); + +try { + $statement = $transaction->prepare( + 'INSERT INTO users (name, email) VALUES (?, ?)' + ); + + $statement->execute(['Eve', 'eve@example.com']); + $statement->execute(['Frank', 'frank@example.com']); + + $transaction->commit(); +} catch (\Throwable $e) { + $transaction->rollback(); + + throw $e; +} +``` + +--- + +## License + +This package is open-sourced software licensed under the [MIT](https://opensource.org/licenses/MIT) license. diff --git a/composer.json b/composer.json index 58fd909..8c74504 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ ], "require": { "php": "^8.2", + "ext-sqlite3": "*", "amphp/amp": "^3", "amphp/parser": "^1.1", "amphp/pipeline": "^1",