diff --git a/README.md b/README.md
index 136a92a..86005e2 100644
--- a/README.md
+++ b/README.md
@@ -3,16 +3,127 @@
[![PHP Support](https://img.shields.io/badge/php-%3E%3D%205.6-777BB4?logo=PHP)](https://php.net/)
![Build Status](https://github.com/Icinga/ipl-sql/workflows/PHP%20Tests/badge.svg?branch=master)
-The package `ipl\Sql` provides a [database connection
-abstraction](#sql-connection) and an [SQL query abstraction layer](#sql-queries)
-for building SQL queries via an OOP API.
-
-For details please see the [features](doc/01-Features.md) description.
+The package `ipl\Sql` provides a [database connection abstraction](#connection)
+and an [SQL query abstraction layer](#queries) for building SQL queries via an OOP API.
## Installation
-The recommended way to install this library is via [Composer](https://getcomposer.org):
+The recommended way to install this package is via [Composer](https://getcomposer.org):
```
composer require ipl/sql
```
+
+## Connection
+
+`ipl\Sql\Connection` is an extension to the native [PDO](https://www.php.net/PDO)
+and adds the following features on top:
+
+**Lazy connection**
+
+`ipl\Sql\Connection` connects to database only if you make a query or start a transaction.
+
+**Exceptions enabled by default**
+
+`ipl\Sql\Connection` starts in the `ERRMODE_EXCEPTION` mode for error reporting instead of `ERRMODE_SILENT`.
+
+**New methods for common actions**
+
+The `prepexec()` method acts like [PDO::query()](https://www.php.net/manual/en/pdo.query.php)
+but automatically creates a prepared statement and binds values to that as part of the call.
+
+The `fetch*()` methods support common fetch actions and combine preparing the statement, binding values, execution and
+the actual fetch from the prepared statement into a single function call.
+
+The `yield*()` methods act like their `fetch*()` equivalents but yield results instead of returning them.
+
+**Straightforward construction**
+
+With `PDO`, you have to do formalities such as assembling the platform-dependent DSN string.
+With `ipl\Sql\Connection`, you just do your thing straightforward:
+
+```php
+$connection = new Connection([
+ 'db' => 'mysql',
+ 'host' => '193.20.23.148',
+ 'dbname' => 'icinga',
+ 'username' => 'icinga',
+ 'password' => 'secret',
+ 'charset' => 'utf8mb4',
+ 'attributes' => [
+ PDO::MYSQL_ATTR_SSL_CA => '/etc/acme/mysql/ca.pem',
+ PDO::MYSQL_ATTR_SSL_CERT => '/etc/acme/mysql/cert.pem',
+ PDO::MYSQL_ATTR_SSL_KEY => '/etc/acme/mysql/key.pem'
+ ]
+]);
+```
+
+**Transaction wrapper**
+
+Use the `transaction()` method which accepts a callback in order to wrap your statements in a transaction, e.g.
+
+```php
+$connection->transaction(function ($connection) use ($table, $data) {
+ $connection->insert($table, $data);
+});
+```
+
+You may still use the unified methods for transaction handling `beginTransaction()`, `commitTransaction()` and
+`rollBackTransaction()` on your own.
+
+**Prepared statements only**
+
+In order to protect from SQL injection and prevent worrying about value quoting,
+`ipl/Sql` uses prepared statements only.
+That means that the query and the data are sent to the database server separately.
+
+**No automatic identifier quoting**
+
+Since automatic identifier quoting is prone to errors and superfluous in most cases,
+you have to apply identifier quoting as needed by using `Connection::quoteIdentifier()`.
+Be aware that it is a must to quote identifiers if you allow user input for field names or
+if you are using special field names, e.g. reserved keywords for your DBMS.
+
+**Automatic array quoting**
+
+Throughout `ipl/Sql` you can bind an array of values to a placeholder used within an `IN (?)` condition for example.
+Placeholders having array values will be expanded automatically.
+
+## Queries
+
+`ipl/Sql` is capable to build queries for MySQL, PostgreSQL, MSSQL and SQLite. (Oracle and IBM will follow).
+Building queries is independent of any particular database connection and there are no database-specific classes to use.
+
+The following examples should give you an idea about what's possible and how to use the OOP API:
+
+```php
+$connection->prepexec(
+ (new Insert())
+ ->into('customer')
+ ->values([
+ 'id' => 42,
+ 'name' => 'John Doe'
+ ])
+);
+$connection->prepexec(
+ (new Select())
+ ->columns(['name'])
+ ->from('customer')
+ ->where(['id IN (?)' => [42]])
+)->fetchAll();
+$connection->prepexec(
+ (new Update())
+ ->table('customer')
+ ->set(['name' => 'John Doe'])
+ ->where(['id = ?' => 42])
+);
+$connection->prepexec(
+ (new Delete())
+ ->from('customer')
+ ->where(['id = ?' => 42])
+);
+```
+
+Granted, the query objects look a bit overkill here and you may use `Connection::insert()`, `Connection::update()`
+and `Connection::delete()` for simple tasks instead. But when it comes to `INSERT INTO ... SELECT`,
+complex `WHERE` clauses, CTEs, ... and reusable and parameterised queries, you'll love the flexiblity.
diff --git a/doc/01-Features.md b/doc/01-Features.md
index 2b63f62..c529ceb 100644
--- a/doc/01-Features.md
+++ b/doc/01-Features.md
@@ -29,7 +29,7 @@ $connection = new Connection([ // (1)
$connection->connect(); // optional (12)
-var_dump($connection->exec(
+var_dump($connection->prepexec(
'SELECT * FROM customer WHERE id = ?;', [42] // (13)
)->fetchRow());
@@ -45,7 +45,7 @@ the SSL certificates (9-11) are likely not to be neccessary depending on your
database driver (2). Explicit initialization (12) and disconnecting (14) are
always optional.
-`$connection->exec()` returns a
+`$connection->prepexec()` returns a
[PDOStatement](https://secure.php.net/manual/en/class.pdostatement.php) - see
its documentation for details.
@@ -61,30 +61,30 @@ use ipl\Sql\Insert;
use ipl\Sql\Select;
use ipl\Sql\Update;
-$connection->exec(
+$connection->prepexec(
(new Insert())
->into('customer')
->values([
'id' => 42,
- 'name' => 'John Deo'
+ 'name' => 'John Doe'
])
);
-$connection->exec(
+$connection->prepexec(
(new Select())
->columns(['name'])
->from('customer')
- ->where(['id = ?' => 42])
+ ->where(['id IN (?)' => [42]])
)->fetchAll();
-$connection->exec(
+$connection->prepexec(
(new Update())
->table('customer')
->set(['name' => 'John Doe'])
->where(['id = ?' => 42])
);
-$connection->exec(
+$connection->prepexec(
(new Delete())
->from('customer')
->where(['id = ?' => 42])
@@ -100,12 +100,12 @@ Insert data into a table, provided either explicitly ...
->into('customer')
->values([
'id' => 42,
- 'name' => 'John Deo'
+ 'name' => 'John Doe'
])
```
```mysql
-INSERT INTO customer (id,name) VALUES(42,'John Deo')
+INSERT INTO customer (id,name) VALUES(42,'John Doe')
```
... or by a [select](#sql-select) query: