Skip to content

Commit 7be9a74

Browse files
authored
Merge pull request #1 from phenixphp/feature/add-docs
Feature/add-docs
2 parents 49e0beb + ff424b5 commit 7be9a74

4 files changed

Lines changed: 343 additions & 0 deletions

File tree

.github/copilot-instructions.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# phenixphp/sqlite - AI Coding Instructions
2+
3+
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.
4+
5+
## Architecture Overview
6+
7+
**Core Components:**
8+
- `SqliteConnection` - Main connection abstraction wrapping `Internal\ConnectionProcessor`
9+
- `SqliteConfig` - File-based configuration (path, open flags, pragmas) instead of network config
10+
- `SqliteColumnDefinition` - Simplified metadata reflecting SQLite's 5 storage classes (NULL, INTEGER, REAL, TEXT, BLOB)
11+
- `SqliteDataType` enum - Type affinity system, NOT MySQL's 30+ types
12+
13+
**Key Design Decisions:**
14+
- SQLite uses **storage classes** not strict types - see `SqliteDataType::fromDeclaredType()` for affinity rules
15+
- No connection pooling needed (file-based, not network) - connection reuse pattern differs from MySQL
16+
- Uses Amp's parallel worker pools for potential multi-connection scenarios (see `amphp/parallel` in `knowledge/`)
17+
- Adapting MySQL protocol patterns to SQLite3 native extensions
18+
- Don't act condescendingly; adopt a technical, critical, and punctual approach.
19+
20+
## Critical Workflows
21+
22+
```bash
23+
# Format code (uses PSR-12 + custom rules)
24+
composer format
25+
26+
# Static analysis (PHPStan level max)
27+
composer analyze
28+
29+
# Run tests (uses Pest, not PHPUnit)
30+
composer test
31+
composer test:parallel # Uses parallel execution
32+
```
33+
34+
## Code Conventions
35+
36+
**Type Declarations:**
37+
- ALWAYS `Type|null` NEVER `?Type` (enforced by PHP-CS-Fixer `nullable_type_declaration`)
38+
- Blank line after `<?php` before `declare(strict_types=1);`
39+
- No `final` keyword on classes (project standard)
40+
- DocBlocks only when PHPStan requires them
41+
42+
**SQLite-Specific:**
43+
- Type affinity over strict types - `SqliteDataType::Blob` for empty declared types
44+
- `getLastInsertId()` returns `int|null` (supports RETURNING but maintains traditional pattern)
45+
- No charset/collation config (UTF-8 default)
46+
- Configuration uses `path`, `openFlags`, `busyTimeout`, `journalMode`, `synchronous`, `foreignKeys`, `cacheSize`
47+
48+
**Amp Patterns:**
49+
```php
50+
// NO async/await keywords in PHP - use Amp primitives
51+
use function Amp\async;
52+
use function Amp\delay;
53+
54+
$future = async(fn() => $connection->query($sql));
55+
$result = $future->await();
56+
```
57+
58+
## Reference Implementation
59+
60+
Look at `knowledge/amphp-mysql/` for database patterns adapted to SQLite:
61+
- Connection lifecycle management
62+
- Prepared statements with parameter binding
63+
- Result set handling with column definitions
64+
- Transaction isolation levels
65+
66+
Key differences from MySQL:
67+
- No `host`, `port`, `user`, `password` in config
68+
- No compression or network-related flags
69+
- Simpler column metadata (no charset field)
70+
- Different PRAGMA-based configuration vs SQL variables
71+
72+
## Integration Points
73+
74+
- Extends `Amp\Sql\SqlConnection` interface
75+
- Uses `Amp\Parallel\Worker` for potential concurrent file operations
76+
- Leverages `Amp\Parser\Parser` for protocol handling (adapted from MySQL patterns)
77+
- File operations via Amp event loop, not blocking I/O
78+
79+
## Testing
80+
81+
Uses **Pest** (not PHPUnit) - see `composer.json` scripts. Test structure follows Amp conventions with async test cases.

LICENSE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) Omar Barbosa
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,242 @@
11
# phenixphp/sqlite
22

3+
<p>Asynchronous SQLite 3 client for PHP based on <a href="https://amphp.org/">Amp</a>.</p>
4+
5+
[![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)
6+
[![Latest Version on Packagist](https://img.shields.io/packagist/v/phenixphp/sqlite.svg?style=flat-square)](https://packagist.org/packages/phenixphp/sqlite)
7+
[![Total Downloads](https://img.shields.io/packagist/dt/phenixphp/sqlite.svg?style=flat-square)](https://packagist.org/packages/phenixphp/sqlite)
8+
[![PHP Version](https://img.shields.io/packagist/php/phenixphp/sqlite.svg?style=flat-square)](https://packagist.org/packages/phenixphp/sqlite)
9+
[![License](https://img.shields.io/packagist/license/phenixphp/sqlite.svg?style=flat-square)](https://packagist.org/packages/phenixphp/sqlite)
10+
11+
---
12+
13+
**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.
14+
15+
---
16+
17+
## Table of Contents
18+
19+
- [Requirements](#requirements)
20+
- [Installation](#installation)
21+
- [Configuration](#configuration)
22+
- [Usage](#usage)
23+
- [Establishing a Connection](#establishing-a-connection)
24+
- [Executing Queries](#executing-queries)
25+
- [Prepared Statements](#prepared-statements)
26+
- [Transactions](#transactions)
27+
- [Dependencies](#dependencies)
28+
- [License](#license)
29+
30+
---
31+
32+
## Requirements
33+
34+
| Requirement | Version |
35+
| --- | --- |
36+
| PHP | `^8.2` |
37+
| ext-sqlite3 | `*` |
38+
39+
---
40+
41+
## Installation
42+
43+
Install the package via [Composer](https://getcomposer.org/):
44+
45+
```bash
46+
composer require phenixphp/sqlite
47+
```
48+
49+
---
50+
51+
## Configuration
52+
53+
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.
54+
55+
```php
56+
<?php
57+
58+
use Phenix\Sqlite\SqliteConfig;
59+
60+
$config = new SqliteConfig(
61+
database: __DIR__ . '/database.db',
62+
);
63+
```
64+
65+
> You can use `:memory:` as the database path to create an in-memory SQLite database, which is ideal for testing scenarios.
66+
67+
```php
68+
$config = new SqliteConfig(
69+
database: ':memory:',
70+
);
71+
```
72+
73+
---
74+
75+
## Usage
76+
77+
### Establishing a Connection
78+
79+
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.
80+
81+
```php
82+
<?php
83+
84+
declare(strict_types=1);
85+
86+
use Phenix\Sqlite\SqliteConfig;
87+
88+
use function Phenix\Sqlite\connect;
89+
90+
$config = new SqliteConfig(
91+
database: __DIR__ . '/database.db',
92+
);
93+
94+
$connection = connect($config);
95+
96+
// ... use connection ...
97+
98+
$connection->close();
99+
```
100+
101+
---
102+
103+
### Executing Queries
104+
105+
Once you have an active connection, you can execute SQL statements — `CREATE`, `INSERT`, `SELECT`, `UPDATE`, and `DELETE` — all asynchronously without blocking the event loop.
106+
107+
#### Creating a Table
108+
109+
```php
110+
$connection->execute(
111+
'CREATE TABLE IF NOT EXISTS users (
112+
id INTEGER PRIMARY KEY AUTOINCREMENT,
113+
name TEXT NOT NULL,
114+
email TEXT NOT NULL
115+
)'
116+
);
117+
```
118+
119+
#### Inserting Records
120+
121+
```php
122+
$connection->execute(
123+
"INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com')"
124+
);
125+
```
126+
127+
#### Selecting Records
128+
129+
```php
130+
$result = $connection->query('SELECT * FROM users');
131+
132+
foreach ($result as $row) {
133+
echo $row['id'] . ': ' . $row['name'] . ' — ' . $row['email'] . PHP_EOL;
134+
}
135+
```
136+
137+
#### Updating Records
138+
139+
```php
140+
$connection->execute(
141+
"UPDATE users SET name = 'Jane Doe' WHERE id = 1"
142+
);
143+
```
144+
145+
#### Deleting Records
146+
147+
```php
148+
$connection->execute(
149+
"DELETE FROM users WHERE id = 1"
150+
);
151+
```
152+
153+
---
154+
155+
### Prepared Statements
156+
157+
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.
158+
159+
#### Preparing and Executing a Statement
160+
161+
```php
162+
$statement = $connection->prepare(
163+
'INSERT INTO users (name, email) VALUES (?, ?)'
164+
);
165+
166+
$statement->execute(['Alice', 'alice@example.com']);
167+
$statement->execute(['Bob', 'bob@example.com']);
168+
```
169+
170+
#### Prepared Statement with Named Parameters
171+
172+
```php
173+
$statement = $connection->prepare(
174+
'SELECT * FROM users WHERE name = ? AND email = ?'
175+
);
176+
177+
$result = $statement->execute(['Alice', 'alice@example.com']);
178+
179+
foreach ($result as $row) {
180+
echo $row['name'] . PHP_EOL;
181+
}
182+
```
183+
184+
#### Closing a Prepared Statement
185+
186+
```php
187+
$statement->close();
188+
```
189+
190+
---
191+
192+
### Transactions
193+
194+
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.
195+
196+
#### Basic Transaction
197+
198+
```php
199+
$transaction = $connection->beginTransaction();
200+
201+
try {
202+
$transaction->execute(
203+
"INSERT INTO users (name, email) VALUES ('Charlie', 'charlie@example.com')"
204+
);
205+
$transaction->execute(
206+
"INSERT INTO users (name, email) VALUES ('Diana', 'diana@example.com')"
207+
);
208+
209+
$transaction->commit();
210+
} catch (\Throwable $e) {
211+
$transaction->rollback();
212+
213+
throw $e;
214+
}
215+
```
216+
217+
#### Transaction with Prepared Statements
218+
219+
```php
220+
$transaction = $connection->beginTransaction();
221+
222+
try {
223+
$statement = $transaction->prepare(
224+
'INSERT INTO users (name, email) VALUES (?, ?)'
225+
);
226+
227+
$statement->execute(['Eve', 'eve@example.com']);
228+
$statement->execute(['Frank', 'frank@example.com']);
229+
230+
$transaction->commit();
231+
} catch (\Throwable $e) {
232+
$transaction->rollback();
233+
234+
throw $e;
235+
}
236+
```
237+
238+
---
239+
240+
## License
241+
242+
This package is open-sourced software licensed under the [MIT](https://opensource.org/licenses/MIT) license.

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
],
1313
"require": {
1414
"php": "^8.2",
15+
"ext-sqlite3": "*",
1516
"amphp/amp": "^3",
1617
"amphp/parser": "^1.1",
1718
"amphp/pipeline": "^1",

0 commit comments

Comments
 (0)