Skip to content

Commit 7fd9f00

Browse files
committed
Initial import
0 parents  commit 7fd9f00

File tree

13 files changed

+1562
-0
lines changed

13 files changed

+1562
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/composer.lock
2+
/vendor/

.travis.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
language: php
2+
3+
php:
4+
- 5.4
5+
- 5.5
6+
- 5.6
7+
- 7.0
8+
- 7.1
9+
- 7.2
10+
- 7.3
11+
# - hhvm # requires legacy phpunit & ignore errors, see below
12+
13+
# lock distro so new future defaults will not break the build
14+
dist: trusty
15+
16+
matrix:
17+
include:
18+
- php: hhvm
19+
install: composer require phpunit/phpunit:^5 --dev --no-interaction
20+
allow_failures:
21+
- php: hhvm
22+
23+
install:
24+
- composer install --no-interaction
25+
26+
script:
27+
- vendor/bin/phpunit --coverage-text

LICENSE

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) 2019 Christian Lück
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 furnished
10+
to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
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: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
# clue/reactphp-sqlite [![Build Status](https://travis-ci.org/clue/reactphp-sqlite.svg?branch=master)](https://travis-ci.org/clue/reactphp-sqlite)
2+
3+
Async SQLite database, lightweight non-blocking process wrapper around file-based database extension (`ext-sqlite3`),
4+
built on top of [ReactPHP](https://reactphp.org/).
5+
6+
**Table of contents**
7+
8+
* [Quickstart example](#quickstart-example)
9+
* [Usage](#usage)
10+
* [Database](#database)
11+
* [exec()](#exec)
12+
* [query()](#query)
13+
* [quit()](#quit)
14+
* [close()](#close)
15+
* [Events](#events)
16+
* [error event](#error-event)
17+
* [close event](#close-event)
18+
* [Install](#install)
19+
* [Tests](#tests)
20+
* [License](#license)
21+
22+
## Quickstart example
23+
24+
The following example code demonstrates how this library can be used to open an
25+
existing SQLite database file (or automatically create it on first run) and then
26+
`INSERT` a new record to the database:
27+
28+
```php
29+
$loop = React\EventLoop\Factory::create();
30+
31+
$name = 'Alice';
32+
Clue\React\SQLite\Database::open($loop, 'users.db')->then(
33+
function (Clue\React\SQLite\Database $db) use ($name) {
34+
$db->exec('CREATE TABLE IF NOT EXISTS foo (id INTEGER PRIMARY KEY AUTOINCREMENT, bar STRING)');
35+
36+
$db->query('INSERT INTO foo (bar) VALUES (?)', array($name))->then(
37+
function (Clue\React\SQLite\Result $result) use ($name) {
38+
echo 'New ID for ' . $name . ': ' . $result->insertId . PHP_EOL;
39+
}
40+
);
41+
42+
$db->quit();
43+
},
44+
function (Exception $e) {
45+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
46+
}
47+
);
48+
49+
$loop->run();
50+
```
51+
52+
See also the [examples](examples).
53+
54+
## Usage
55+
56+
### Database
57+
58+
The `Database` class represents a connection that is responsible for
59+
comunicating with your SQLite database wrapper, managing the connection state
60+
and sending your database queries.
61+
62+
#### open()
63+
64+
The static `open(LoopInterface $loop, string $filename, int $flags = null): PromiseInterface<Database>` method can be used to
65+
open a new database connection for the given SQLite database file.
66+
67+
This method returns a promise that will resolve with a `Database` on
68+
success or will reject with an `Exception` on error. The SQLite extension
69+
is inherently blocking, so this method will spawn an SQLite worker process
70+
to run all SQLite commands and queries in a separate process without
71+
blocking the main process.
72+
73+
```php
74+
Database::open($loop, 'users.db')->then(function (Database $db) {
75+
// database ready
76+
// $db->query('INSERT INTO users (name) VALUES ("test")');
77+
// $db->quit();
78+
}, function (Exception $e) {
79+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
80+
});
81+
```
82+
83+
The optional `$flags` parameter is used to determine how to open the
84+
SQLite database. By default, open uses `SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE`.
85+
86+
```php
87+
Database::open($loop, 'users.db', SQLITE3_OPEN_READONLY)->then(function (Database $db) {
88+
// database ready (read-only)
89+
// $db->quit();
90+
}, function (Exception $e) {
91+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
92+
});
93+
```
94+
95+
#### exec()
96+
97+
The `exec(string $query): PromiseInterface<Result>` method can be used to
98+
execute an async query.
99+
100+
This method returns a promise that will resolve with a `Result` on
101+
success or will reject with an `Exception` on error. The SQLite wrapper
102+
is inherently sequential, so that all queries will be performed in order
103+
and outstanding queries will be put into a queue to be executed once the
104+
previous queries are completed.
105+
106+
```php
107+
$db->exec('CREATE TABLE test ...');
108+
$db->exec('INSERT INTO test (id) VALUES (1)');
109+
```
110+
111+
This method is specifically designed for queries that do not return a
112+
result set (such as a `UPDATE` or `INSERT` statement). Queries that do
113+
return a result set (such as from a `SELECT` or `EXPLAIN` statement) will
114+
not allow access to this data, so you're recommended to use the `query()`
115+
method instead.
116+
117+
```php
118+
$db->exec($query)->then(function (Result $result) {
119+
// this is an OK message in response to an UPDATE etc.
120+
if ($result->insertId !== 0) {
121+
var_dump('last insert ID', $result->insertId);
122+
}
123+
echo 'Query OK, ' . $result->changed . ' row(s) changed' . PHP_EOL;
124+
}, function (Exception $error) {
125+
// the query was not executed successfully
126+
echo 'Error: ' . $error->getMessage() . PHP_EOL;
127+
});
128+
```
129+
130+
Unlike the `query()` method, this method does not support passing an
131+
array of placeholder parameters that will be bound to the query. If you
132+
want to pass user-supplied data, you're recommended to use the `query()`
133+
method instead.
134+
135+
#### query()
136+
137+
The `query(string $query, array $params = array()): PromiseInterface<Result>` method can be used to
138+
perform an async query.
139+
140+
141+
This method returns a promise that will resolve with a `Result` on
142+
success or will reject with an `Exception` on error. The SQLite wrapper
143+
is inherently sequential, so that all queries will be performed in order
144+
and outstanding queries will be put into a queue to be executed once the
145+
previous queries are completed.
146+
147+
```php
148+
$db->query('CREATE TABLE test ...');
149+
$db->query('INSERT INTO test (id) VALUES (1)');
150+
```
151+
152+
If this SQL statement returns a result set (such as from a `SELECT`
153+
statement), this method will buffer everything in memory until the result
154+
set is completed and will then resolve the resulting promise.
155+
156+
```php
157+
$db->query($query)->then(function (Result $result) {
158+
if (isset($result->rows)) {
159+
// this is a response to a SELECT etc. with some rows (0+)
160+
print_r($result->columns);
161+
print_r($result->rows);
162+
echo count($result->rows) . ' row(s) in set' . PHP_EOL;
163+
} else {
164+
// this is an OK message in response to an UPDATE etc.
165+
if ($result->insertId !== 0) {
166+
var_dump('last insert ID', $result->insertId);
167+
}
168+
echo 'Query OK, ' . $result->changed . ' row(s) changed' . PHP_EOL;
169+
}
170+
}, function (Exception $error) {
171+
// the query was not executed successfully
172+
echo 'Error: ' . $error->getMessage() . PHP_EOL;
173+
});
174+
```
175+
176+
You can optionally pass an array of `$params` that will be bound to the
177+
query like this:
178+
179+
```php
180+
$db->query('SELECT * FROM user WHERE id > ?', [$id]);
181+
```
182+
183+
Likewise, you can also use named placeholders that will be bound to the
184+
query like this:
185+
186+
```php
187+
$db->query('SELECT * FROM user WHERE id > :id', ['id' => $id]);
188+
```
189+
190+
#### quit()
191+
192+
The `quit(): PromiseInterface<void, Exception>` method can be used to
193+
quit (soft-close) the connection.
194+
195+
This method returns a promise that will resolve (with a void value) on
196+
success or will reject with an `Exception` on error. The SQLite wrapper
197+
is inherently sequential, so that all commands will be performed in order
198+
and outstanding commands will be put into a queue to be executed once the
199+
previous commands are completed.
200+
201+
```php
202+
$db->query('CREATE TABLE test ...');
203+
$db->quit();
204+
```
205+
206+
#### close()
207+
208+
The `close(): void` method can be used to
209+
force-close the connection.
210+
211+
Unlike the `quit()` method, this method will immediately force-close the
212+
connection and reject all oustanding commands.
213+
214+
```php
215+
$db->close();
216+
```
217+
218+
Forcefully closing the connection should generally only be used as a last
219+
resort. See also [`quit()`](#quit) as a safe alternative.
220+
221+
#### Events
222+
223+
Besides defining a few methods, this interface also implements the
224+
`EventEmitterInterface` which allows you to react to certain events:
225+
226+
##### error event
227+
228+
The `error` event will be emitted once a fatal error occurs, such as
229+
when the connection is lost or is invalid.
230+
The event receives a single `Exception` argument for the error instance.
231+
232+
```php
233+
$db->on('error', function (Exception $e) {
234+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
235+
});
236+
```
237+
238+
This event will only be triggered for fatal errors and will be followed
239+
by closing the connection. It is not to be confused with "soft" errors
240+
caused by invalid SQL queries.
241+
242+
##### close event
243+
244+
The `close` event will be emitted once the connection closes (terminates).
245+
246+
```php
247+
$db->on('close', function () {
248+
echo 'Connection closed' . PHP_EOL;
249+
});
250+
```
251+
252+
See also the [`close()`](#close) method.
253+
254+
255+
## Install
256+
257+
The recommended way to install this library is [through Composer](https://getcomposer.org).
258+
[New to Composer?](https://getcomposer.org/doc/00-intro.md)
259+
260+
This will install the latest supported version:
261+
262+
```bash
263+
$ composer require clue/reactphp-sqlite:dev-master
264+
```
265+
266+
This project aims to run on any platform and thus only requires `ext-sqlite3` and
267+
supports running on legacy PHP 5.4 through current PHP 7+ and HHVM.
268+
It's *highly recommended to use PHP 7+* for this project.
269+
270+
This project is implemented as a lightweight process wrapper around the `ext-sqlite3`
271+
PHP extension, so you'll have to make sure that you have a suitable version
272+
installed. On Debian/Ubuntu-based systems, you may simply install it like this:
273+
274+
```bash
275+
$ sudo apt install php-sqlite3
276+
```
277+
278+
## Tests
279+
280+
To run the test suite, you first need to clone this repo and then install all
281+
dependencies [through Composer](https://getcomposer.org):
282+
283+
```bash
284+
$ composer install
285+
```
286+
287+
To run the test suite, go to the project root and run:
288+
289+
```bash
290+
$ php vendor/bin/phpunit
291+
```
292+
293+
## License
294+
295+
This project is released under the permissive [MIT license](LICENSE).
296+
297+
> Did you know that I offer custom development services and issuing invoices for
298+
sponsorships of releases and for contributions? Contact me (@clue) for details.

composer.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "clue/reactphp-sqlite",
3+
"description": "Async SQLite database, lightweight non-blocking process wrapper around file-based database extension (ext-sqlite3), built on top of ReactPHP.",
4+
"keywords": ["SQLite", "database", "non-blocking", "async", "ReactPHP"],
5+
"homepage": "https://github.com/clue/reactphp-sqlite",
6+
"license": "MIT",
7+
"authors": [
8+
{
9+
"name": "Christian Lück",
10+
"email": "[email protected]"
11+
}
12+
],
13+
"autoload": {
14+
"psr-4": { "Clue\\React\\SQLite\\": "src/" }
15+
},
16+
"require": {
17+
"php": ">=5.4",
18+
"ext-sqlite3": "*",
19+
"clue/ndjson-react": "^1.0",
20+
"react/child-process": "^0.6",
21+
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
22+
"react/promise": "^2.7 || ^1.2.1"
23+
},
24+
"require-dev": {
25+
"phpunit/phpunit": "^7.0 || ^6.0 || ^5.7 || ^4.8.35"
26+
}
27+
}

0 commit comments

Comments
 (0)