You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+23-18
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@ Squirrel Queries
5
5
6
6
Provides a slimmed down concise interface for low level database queries and transactions (DBInterface) as well as a query builder to make it easier and more expressive to create queries (DBBuilderInterface). The interfaces are limited to avoid confusion/misuse and encourage fail-safe usage.
7
7
8
-
Doctrine is used as the underlying connection (and abstraction), what we add are an insertOrUpdate functionality (known as UPSERT), structured queries which are easier to write and read (and for which the query builder can be used), and the possibility to layer database concerns (like actual implementation, connections retries, performance measurements, logging, etc.). This library also smoothes over some differences between MySQL, Postgres and SQLite.
8
+
Doctrine DBAL is used for the underlying connection (and abstraction) handling, what we add are an insertOrUpdate functionality (known as UPSERT), structured queries which are easier to write and read (and for which the query builder can be used), and the possibility to layer database concerns (like actual implementation, connections retries, performance measurements, logging, etc.). This library also smoothes over some differences between MySQL, Postgres and SQLite. While DBAL is a dependency for now, when using this library you only need to configure/create the necessary DBAL connections in your code, no other parts of DBAL are relevant.
9
9
10
10
By default this library provides two layers, one dealing with Doctrine DBAL (passing the queries, processing and returning the results) and one dealing with errors (DBErrorHandler). DBErrorHandler catches deadlocks and connection problems and tries to repeat the query or transaction, and it unifies the exceptions coming from DBAL so the originating call to DBInterface is provided and the error can easily be found.
11
11
@@ -29,7 +29,7 @@ Setting up
29
29
30
30
Use Squirrel\Queries\DBInterface as a type hint in your services for the low-level interface, and/or Squirrel\Queries\DBBuilderInterface for the query builder. The low-level interface options are based upon Doctrine and PDO with some tweaks, and the builder interface is an expressive way to write structured (and not too complex) queries.
31
31
32
-
If you know Doctrine or PDO you should be able to use this library easily. You should especially have an extra look at structured queries and UPSERT, as these are an addition to the low-level interface, helping you to make readable queries and taking care of your column field names and parameters automatically, making it easier to write secure queries.
32
+
If you know Doctrine or PDO you should be able to use this library easily. You should especially have an extra look at structured queries and UPSERT, as these are additions to the low-level interface, helping you to make readable queries and taking care of your column field names and parameters automatically, making it easier to write secure queries.
33
33
34
34
For a solution which integrates easily with the Symfony framework, check out [squirrelphp/queries-bundle](https://github.com/squirrelphp/queries-bundle), and for entity and repository support check out [squirrelphp/entities](https://github.com/squirrelphp/entities) and [squirrelphp/entities-bundle](https://github.com/squirrelphp/entities-bundle).
35
35
@@ -67,7 +67,7 @@ If you want to assemble a DBInterface object yourself, something like the follow
67
67
// anywhere you need it. Typehint it with
68
68
// \Squirrel\Queries\DBInterface
69
69
70
-
$fetchEntry = function(DBInterface $db) {
70
+
$fetchEntry = function(DBInterface $db): array {
71
71
return $db->fetchOne('SELECT * FROM table');
72
72
};
73
73
@@ -108,7 +108,7 @@ This library has support for the three main open-source databases:
108
108
109
109
- MySQL, all versions (at least 5.5+ is recommended)
110
110
- MariaDB, all versions (MariaDB behaves almost identical to MySQL)
111
-
- SQLite, all versions, although native UPSERT queries are only supported in SQLite 3.24+ (which is included in PHP 7.3+), the functionality is emulated in lower versions
111
+
- SQLite, all versions, although native UPSERT queries are only supported in SQLite 3.24+, the functionality is emulated in lower versions
112
112
- Postgres version 9.5 and above, because UPSERT queries were implemented in 9.5
113
113
114
114
The functionality in this library has been tested against real versions of these databases to make sure it works, although there might be edge cases which warrant adjustments. If you find any issues please report them.
- If an expression contains something like :fieldname: it is assumed that it is a field or table name which will then be escaped. For simple WHERE restrictions or fields definitions field names are escaped automatically.
216
216
- You can use "field" if there is just one field, or "fields" for multiple fields. The same with "table" and "tables".
217
217
- If you set "lock" to true "FOR UPDATE" is added to the query, so the results are locked within the current transaction.
218
-
- The arguments are checked as much as possible and if an option/expression is not valid, a DBInvalidOptionException is thrown. This does not include SQL errors, as the SQL components knows nothing of the allowed field names, table names or what constitutes a valid SQL expression.
218
+
- The arguments are checked as much as possible and if an option/expression is not valid, a DBInvalidOptionException is thrown. This does not include SQL errors, as the SQL components know nothing of the allowed field names, table names or what constitutes a valid SQL expression.
219
219
220
220
You can pass a structured SELECT query directly to `fetchOne` and `fetchAll` to retrieve one or all results.
221
221
@@ -377,7 +377,7 @@ Just pass a callable/function to the `transaction` method and DBInterface will t
377
377
#### Examples
378
378
379
379
```php
380
-
$db->transaction(function(){
380
+
$db->transaction(function(){
381
381
// Do queries in here as much as you want, it will all be one transaction
382
382
// and committed as soon as this function ends
383
383
});
@@ -392,9 +392,9 @@ $db->transaction(function() use ($db) {
392
392
], 'tableId');
393
393
394
394
$db->update('otherTable', [
395
-
'tableName' => 'Henry',
396
-
], [
397
395
'tableId' => $tableId,
396
+
], [
397
+
'tableName' => 'Henry',
398
398
]);
399
399
});
400
400
```
@@ -415,30 +415,30 @@ $db->transaction(function() use ($db) {
415
415
// transaction function, which is what you would want / expect, so it starts
416
416
// with the Henry insert again
417
417
$db->update('otherTable', [
418
-
'tableName' => 'Henry',
419
-
], [
420
418
'tableId' => $tableId,
419
+
], [
420
+
'tableName' => 'Henry',
421
421
]);
422
422
});
423
423
});
424
424
```
425
425
426
426
If there is a deadlock or connection problem, the error handler (DBErrorHandler) will roll back the transaction and attempt to retry it 10 times, with increasing wait times inbetween. Only if there are 10 failures within about 30 seconds will the exception be escalated with a DBException.
427
427
428
-
If you want to pass arguments to $func, this would be an example:
428
+
If you want to pass arguments to $func, this would be an example (you can also add them to the `use` part):
$db->transaction(function(string $table, string $tableName) use ($db) {
432
432
$tableId = $db->insert('myTable', [
433
433
'tableName' => 'Henry',
434
434
], 'tableId');
435
435
436
436
$db->update('otherTable', [
437
-
'tableName' => $tableName,
438
-
], [
439
437
'tableId' => $tableId,
438
+
], [
439
+
'tableName' => $tableName,
440
440
]);
441
-
}, $db, 'myTable', 'Henry');
441
+
}, 'myTable', 'Henry');
442
442
```
443
443
444
444
When using SELECT queries within a transaction you should always remember that the results are usually not locked (so not protected from UPDATE or DELETE), except if you apply "... FOR UPDATE" (in a string SELECT query) or by setting `lock` to true in a structured SELECT.
@@ -479,13 +479,14 @@ DBBuilderInterface offers the following functions:
479
479
- transaction (to do a function within a transaction)
480
480
- getDBInterface (to get the underlying DBInterface object)
481
481
482
-
All except the last two return a builder object which helps you easily create a query and get the results. Compared to DBInterface you do not have to remember what data can be contained in a structured query - your IDE will suggest whatever is available. You can also have a look at the builder objects themselves - they are all very short.
482
+
All except the last two return a builder object which helps you easily create a query and get the results. Compared to DBInterface you do not have to remember what data can be contained in a structured query - your IDE will suggest whatever is available.
483
483
484
484
Looking at some examples should make the usage quite clear - here are some for each of the 6 builder functions:
485
485
486
486
### Count
487
487
488
488
```php
489
+
// $usersNumber will be an integer
489
490
$usersNumber = $dbBuilder
490
491
->count()
491
492
->inTables([
@@ -675,6 +676,8 @@ $rowsAffected = $dbBuilder
675
676
->writeAndReturnAffectedNumber();
676
677
```
677
678
679
+
This explicit confirmation clause is needed to avoid executing queries where the `where` part was omitted by accident, which is a common mistake when writing/executing queries.
680
+
678
681
### Insert or Update
679
682
680
683
This makes the insertOrUpdate functionality in DBInterface a bit easier to digest, using the same information:
@@ -738,6 +741,8 @@ $rowsAffected = $dbBuilder
738
741
->writeAndReturnAffectedNumber();
739
742
```
740
743
744
+
This explicit confirmation clause is needed to avoid executing queries where the `where` part was omitted by accident, which is a common mistake when writing/executing queries.
745
+
741
746
### Transaction
742
747
743
748
The transaction function works the same as the one in DBInterface - in fact, DBBuilderInterface just passes it as-is to DBInterface.
@@ -806,7 +811,7 @@ This should make it easy to read and write queries, even if you don't know much
806
811
BLOB handling for Postgres
807
812
--------------------------
808
813
809
-
For MySQL and SQLite retrieving or inserting/updating BLOBs (Binary Large Objects) works just the same as with shorter/non-binary string fields. Postgres needs some adjustments, but these are made very easy bis this library:
814
+
For MySQL and SQLite retrieving or inserting/updating BLOBs (Binary Large Objects) works just the same as with shorter/non-binary string fields. Postgres needs some adjustments, but these are streamlined by this library:
810
815
811
816
- For SELECT queries, streams returned by Postgres are automatically converted into strings, mimicking how MySQL and SQLite are doing it
812
817
- For INSERT/UPDATE queries, you need to wrap BLOB values with an instance of LargeObject provided by this library.
@@ -905,6 +910,6 @@ Sometimes a complex query can make more sense, but it should be the rare excepti
905
910
906
911
[squirrelphp/queries-bundle](https://github.com/squirrelphp/queries-bundle) is an integration of this library into Symfony, so you can get started quickly.
907
912
908
-
[squirrelphp/entities](https://github.com/squirrelphp/entities) is a library built on top of `squirrelphp/queries` and offers support for entities and repositories while following all the above guidelines.
913
+
[squirrelphp/entities](https://github.com/squirrelphp/entities) is a library built on top of `squirrelphp/queries` and offers support for typed entities and repositories while following all the above guidelines.
909
914
910
915
[squirrelphp/entities-bundle](https://github.com/squirrelphp/entities-bundle) is the Symfony bundle integrating entities and repositories into a Symfony project.
0 commit comments