flush
authorMichael Wallner <mike@php.net>
Mon, 13 Oct 2014 12:32:55 +0000 (14:32 +0200)
committerMichael Wallner <mike@php.net>
Mon, 13 Oct 2014 12:32:55 +0000 (14:32 +0200)
47 files changed:
pq-gateway.md [new file with mode: 0644]
pq-gateway.mdref [new file with mode: 0644]
pq-gateway/pq/Gateway.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Rowset.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Attributes.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Attributes/__construct.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Attributes/count.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Attributes/getColumn.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Attributes/getColumns.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Attributes/getIterator.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Identity.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Identity/__construct.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Identity/count.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Identity/getColumns.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Identity/getIterator.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Relations.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Relations/__construct.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Relations/count.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Relations/getIterator.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/Relations/getReference.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/__construct.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/__toString.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/attach.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/by.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/detach.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/execute.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/find.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/getAttributes.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/getConnection.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/getIdentity.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/getMetadataCache.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/getName.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/getQueryExecutor.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/getQueryWriter.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/getRelations.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/getRowsetPrototype.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/hasRelation.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/notify.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/of.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/onResult.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/resolve.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/setMetadataCache.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/setQueryExecutor.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/setQueryWriter.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/setRowsetPrototype.md [new file with mode: 0644]
pq-gateway/pq/Gateway/Table/with.md [new file with mode: 0644]

diff --git a/pq-gateway.md b/pq-gateway.md
new file mode 100644 (file)
index 0000000..1d5b33a
--- /dev/null
@@ -0,0 +1,13 @@
+# m6w6/pq-gateway
+
+## About:
+
+This is a PHP userland implementation of a [Table Data Gateway](http://martinfowler.com/eaaCatalog/tableDataGateway.html) for [pecl/pq](pq).
+
+## Install with composer:
+
+       $ composer --require m6w6/pq-gateway ~2.0
+
+## Source:
+
+* https://github.com/m6w6/pq-gateway
diff --git a/pq-gateway.mdref b/pq-gateway.mdref
new file mode 100644 (file)
index 0000000..0c864c7
--- /dev/null
@@ -0,0 +1 @@
+https://github.com/m6w6/mdref-pq-gateway/edit/master/%s.md
diff --git a/pq-gateway/pq/Gateway.md b/pq-gateway/pq/Gateway.md
new file mode 100644 (file)
index 0000000..23f5d97
--- /dev/null
@@ -0,0 +1,3 @@
+# namespace pq\Gateway
+
+The pq\Gateway namespace holds implementations and interfaces related to the table data gateway implementation for [pecl/pq](pq).
\ No newline at end of file
diff --git a/pq-gateway/pq/Gateway/Rowset.md b/pq-gateway/pq/Gateway/Rowset.md
new file mode 100644 (file)
index 0000000..2a43335
--- /dev/null
@@ -0,0 +1,15 @@
+# class pq\Gateway\Rowset implements SeekableIterator, JsonSerialize, Countable
+
+The rowset gateway.
+
+## Properties:
+
+* protected pq\Table $table  
+  The originating table.
+* protected int $index = 0  
+  The iterator index.
+* protected array $rows  
+  The rows of the set.
+* protected mixed $row = "\pq\Gateway\Row"  
+  The row prototype.
+
diff --git a/pq-gateway/pq/Gateway/Table.md b/pq-gateway/pq/Gateway/Table.md
new file mode 100644 (file)
index 0000000..f9edcd4
--- /dev/null
@@ -0,0 +1,33 @@
+# class pq\Gateway\Table implements SplSubject
+
+The table gateway.
+
+## Propertries:
+
+* public static pq\Connection $defaultConnection  
+  A default connection to use.
+* public static callable $defaultResolver as function($table_name)  
+  A callback whiuch resolves table names to classes.
+* public static pq\Gateway\Table\CacheInterface $defaultMetadataCache  
+  A default cache implementation. See pq\Gateway\Table\StaticCache.
+
+* protected pq\Connection $conn  
+  The PostgreSQL connection.
+* protected string $name  
+  The table name.
+* protected mixed $rowset = "pq\\Gateway\\Rowset"  
+  The rowset prototype.
+* protected pq\Query\WriterInterface $query  
+  A query writer.
+* protected pq\Query\ExecutorInterface $exec  
+  A query executor.
+* protected pq\Gateway\Table\Identity $identity  
+  The table identity implementation.
+* protected pq\Gateway\Table\Attributes $attributes  
+  The table attributes implementation.
+* protected pq\Gateway\Table\Relations $relations  
+  The table relations implementation.
+* protected pq\Gateway\Table\CacheInterface $metadataCache  
+  The metadata cache to use for this table.
+* protected SplObjectStorage $observers  
+  Table observers.
diff --git a/pq-gateway/pq/Gateway/Table/Attributes.md b/pq-gateway/pq/Gateway/Table/Attributes.md
new file mode 100644 (file)
index 0000000..37ec4b2
--- /dev/null
@@ -0,0 +1,30 @@
+# class pq\Gateway\Table\Attributes implements IteratorAggregate
+
+The table attributes (columns) of a table.
+
+## Query:
+
+The following query is executed by the current executor of the table to retrieve the table attributes:
+
+       select 
+                attnum         as index
+               ,attname        as name
+               ,atttypid       as type
+               ,atthasdef      as hasdefault
+               ,not attnotnull as nullable
+       from
+                pg_attribute 
+       where attrelid = \$1::regclass 
+       and   attnum   > 0
+
+## Cache:
+
+The result of this query is cached in the metadata cache under the following key, where $table is converted to a string by pq\Gateway\Table::__toString():
+
+       "$table:attributes"
+
+## Properties:
+
+* protected array $columns  
+  The table attributes.
+  
diff --git a/pq-gateway/pq/Gateway/Table/Attributes/__construct.md b/pq-gateway/pq/Gateway/Table/Attributes/__construct.md
new file mode 100644 (file)
index 0000000..09823af
--- /dev/null
@@ -0,0 +1,8 @@
+# void pq\Gateway\Table\Attributes::__construct(pq\Gateway\Table $table)
+
+Retrieve the table attributes (columns).
+
+## Params:
+
+* pq\Gateway\Table $table  
+  The table to retrieve the attributes of.
diff --git a/pq-gateway/pq/Gateway/Table/Attributes/count.md b/pq-gateway/pq/Gateway/Table/Attributes/count.md
new file mode 100644 (file)
index 0000000..65de834
--- /dev/null
@@ -0,0 +1,11 @@
+# int pq\Gateway\Table\Attributes::count()
+
+Implements countable.
+
+## Params:
+
+None.
+
+## Returns:
+
+* int, the number of columns of the table.
diff --git a/pq-gateway/pq/Gateway/Table/Attributes/getColumn.md b/pq-gateway/pq/Gateway/Table/Attributes/getColumn.md
new file mode 100644 (file)
index 0000000..87b691c
--- /dev/null
@@ -0,0 +1,16 @@
+# stdClass pq\Gateway\Table\Attributes::getColumn(mixed $col)
+
+Get a specific column.
+
+## Params:
+
+* mixed $col  
+  The column index or name.
+
+## Returns:
+
+* stdClass, the attribute info.
+
+## Throws:
+
+* OutOfBoundsException
diff --git a/pq-gateway/pq/Gateway/Table/Attributes/getColumns.md b/pq-gateway/pq/Gateway/Table/Attributes/getColumns.md
new file mode 100644 (file)
index 0000000..f42de12
--- /dev/null
@@ -0,0 +1,105 @@
+# array pq\Gateway\Table\Attributes::getColumns()
+
+Retrieve all columns of the table.
+
+## Params:
+
+None.
+
+## Returns:
+
+* array, attributes list (indexed by column number **and** columnd name).
+
+## Example:
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       $atts = new Table\Attributes(new Table("account"));
+       var_dump($atts->getColumns());
+       
+       ?>
+
+Yields:
+
+       array(6) {
+         ["id"]=>
+         object(stdClass)#12 (5) {
+               ["index"]=>
+               int(1)
+               ["name"]=>
+               string(2) "id"
+               ["type"]=>
+               int(2950)
+               ["hasdefault"]=>
+               bool(true)
+               ["nullable"]=>
+               bool(false)
+         }
+         [1]=>
+         object(stdClass)#12 (5) {
+               ["index"]=>
+               int(1)
+               ["name"]=>
+               string(2) "id"
+               ["type"]=>
+               int(2950)
+               ["hasdefault"]=>
+               bool(true)
+               ["nullable"]=>
+               bool(false)
+         }
+         ["password"]=>
+         object(stdClass)#13 (5) {
+               ["index"]=>
+               int(2)
+               ["name"]=>
+               string(8) "password"
+               ["type"]=>
+               int(1042)
+               ["hasdefault"]=>
+               bool(false)
+               ["nullable"]=>
+               bool(true)
+         }
+         [2]=>
+         object(stdClass)#13 (5) {
+               ["index"]=>
+               int(2)
+               ["name"]=>
+               string(8) "password"
+               ["type"]=>
+               int(1042)
+               ["hasdefault"]=>
+               bool(false)
+               ["nullable"]=>
+               bool(true)
+         }
+         ["name"]=>
+         object(stdClass)#14 (5) {
+               ["index"]=>
+               int(3)
+               ["name"]=>
+               string(4) "name"
+               ["type"]=>
+               int(1043)
+               ["hasdefault"]=>
+               bool(false)
+               ["nullable"]=>
+               bool(true)
+         }
+         [3]=>
+         object(stdClass)#14 (5) {
+               ["index"]=>
+               int(3)
+               ["name"]=>
+               string(4) "name"
+               ["type"]=>
+               int(1043)
+               ["hasdefault"]=>
+               bool(false)
+               ["nullable"]=>
+               bool(true)
+         }
+       }
diff --git a/pq-gateway/pq/Gateway/Table/Attributes/getIterator.md b/pq-gateway/pq/Gateway/Table/Attributes/getIterator.md
new file mode 100644 (file)
index 0000000..0c52f30
--- /dev/null
@@ -0,0 +1,40 @@
+# ArrayIterator pq\Gateway\Table\Attributes::getIterator()
+
+Implements IteratorAggregate.
+
+## Params:
+
+None.
+
+## Returns:
+
+ArrayIterator, columnd list (indexed by column number **and** name).
+
+## Example:
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       class ColNameIterator extends FilterIterator {
+               public function __construct(Table\Attributes $attrs) {
+                       parent::__construct($attrs->getIterator());
+               }
+               public function accept() {
+                       return !is_numeric($this->key());
+               }
+       }
+       
+       $table = new pq\Gateway\Table("account");
+       $attrs = $table->getAttributes();
+       foreach (new ColNameIterator($attrs) as $col => $att) {
+               printf("%10s: %s\n", $col, http_build_query($att, null, ", "));
+       }
+       
+       ?>
+
+Yields:
+
+                       id: index=1, name=id, type=2950, hasdefault=1, nullable=0
+         password: index=2, name=password, type=1042, hasdefault=0, nullable=1
+                 name: index=3, name=name, type=1043, hasdefault=0, nullable=1
diff --git a/pq-gateway/pq/Gateway/Table/Identity.md b/pq-gateway/pq/Gateway/Table/Identity.md
new file mode 100644 (file)
index 0000000..f299849
--- /dev/null
@@ -0,0 +1,31 @@
+# class pq\Gateway\Table\Identity implements Countable, ITeratorAggregate
+
+The primary key of a table.
+
+## Query:
+
+The following query is executed by the current executor of the table to retrieve the primary key columns:
+
+       select
+        a.attname as column
+       from  pg_class     c
+        join pg_index     i  on c.oid    = i.indrelid
+        join pg_attribute a  on c.oid    = a.attrelid
+       where 
+                c.relname = \$1
+        and a.attnum  = any(i.indkey)
+        and i.indisprimary
+       order by 
+        a.attnum
+
+## Cache:
+
+The result of this query is cached in the metadata cache under the following key, where $table is converted to a string by pq\Gateway\Table::__toString():
+
+       "$table:identity"
+
+## Properties:
+
+* protected array $columns  
+  The columns making up the primary key of the table.
+
diff --git a/pq-gateway/pq/Gateway/Table/Identity/__construct.md b/pq-gateway/pq/Gateway/Table/Identity/__construct.md
new file mode 100644 (file)
index 0000000..a1993a5
--- /dev/null
@@ -0,0 +1,9 @@
+# void pq\Gateway\Table\Identity::__construct(pq\Gateway\Table $table)
+
+Lookup the primary key of a table.
+See pq\Gateway\Table::getIdentity().
+
+## Params:
+
+* pq\Gateway\Table $table  
+  The table to look up the primary key for.
diff --git a/pq-gateway/pq/Gateway/Table/Identity/count.md b/pq-gateway/pq/Gateway/Table/Identity/count.md
new file mode 100644 (file)
index 0000000..675cb94
--- /dev/null
@@ -0,0 +1,12 @@
+# int pq\Gateway\Table\Identity::count()
+
+Implements Countable.
+
+## Params:
+
+None.
+
+## Returns:
+
+* int, the number of columns making up the primary key.
+
diff --git a/pq-gateway/pq/Gateway/Table/Identity/getColumns.md b/pq-gateway/pq/Gateway/Table/Identity/getColumns.md
new file mode 100644 (file)
index 0000000..366f956
--- /dev/null
@@ -0,0 +1,11 @@
+# array pq\Gateway\Table\Identity::getColumns()
+
+Retrieve the columns of the table identity.
+
+## Params:
+
+None.
+
+## Returns:
+
+* array, the columns of the table's primary key.
diff --git a/pq-gateway/pq/Gateway/Table/Identity/getIterator.md b/pq-gateway/pq/Gateway/Table/Identity/getIterator.md
new file mode 100644 (file)
index 0000000..058672d
--- /dev/null
@@ -0,0 +1,12 @@
+# ArrayIterator pq\Gateway\Table\Identity::getIterator()
+
+Implements IteratorAggregate.
+See pq\Gateway\Table\Identity::getColumns().
+
+## Params:
+
+None.
+
+## Returns:
+
+* ArrayIterator, the columns making up the table's primary key.
diff --git a/pq-gateway/pq/Gateway/Table/Relations.md b/pq-gateway/pq/Gateway/Table/Relations.md
new file mode 100644 (file)
index 0000000..65fb833
--- /dev/null
@@ -0,0 +1,67 @@
+# class pq\Gateway\Table\Relations implements Countable, IteratorAggregate
+
+Retrieve any relations referenced by the table through foreign keys.
+See pq\Gateway\Table::by() and pq\Gateway\Table::with().
+
+## Query:
+
+The following query is executed by the current executor of the table to retrieve the table references:
+
+       select
+                case when att1.attname like '%\_'||att2.attname then
+                       substring(att1.attname from '^.*(?=_'||att2.attname||'$)')
+                else
+                       att1.attname
+                end          as "id"
+               ,cl1.relname  as "foreignTable"
+               ,att1.attname as "foreignColumn"
+               ,cl2.relname  as "referencedTable"
+               ,att2.attname as "referencedColumn"
+       from
+                pg_constraint co
+               ,pg_class      cl1
+               ,pg_class      cl2
+               ,pg_attribute  att1
+               ,pg_attribute  att2
+       where
+               (       cl1.relname = \$1
+               or      cl2.relname = \$1)
+       and co.confrelid != 0
+       and co.conrelid   = cl1.oid
+       and co.conkey[1]  = att1.attnum and cl1.oid = att1.attrelid
+       and co.confrelid  = cl2.oid
+       and co.confkey[1] = att2.attnum and cl2.oid = att2.attrelid
+       order by 
+                cl1.relname
+               ,att1.attnum
+
+## Cache:
+
+The result of this query is cached in the metadata cache under the following key, where $table is converted to a string by pq\Gateway\Table::__toString():
+
+       "$table:relations"
+
+## Foreign key access:
+
+Relations can be accessed as virtual properties or through pq\Gateway\Table\Relations::getReference().
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       $relations = new Table\Relations(new Table("account_email"));
+       
+       // $relations->reference->account
+       $account_rel = $relations->getReference("account");
+       $account_rel = $relations->account;
+       
+       ?>
+
+> ***NOTE:***  
+  The relation name is the column name of the foreign key with the column name of the referenced column cut off the end.
+
+## Properties:
+
+* protected array $references  
+  The table's foreign keys.
+
diff --git a/pq-gateway/pq/Gateway/Table/Relations/__construct.md b/pq-gateway/pq/Gateway/Table/Relations/__construct.md
new file mode 100644 (file)
index 0000000..0804e47
--- /dev/null
@@ -0,0 +1,10 @@
+# void pq\Gateway\Table\Relations::__construct(pq\Gateway\Table $table)
+
+Retrieve the table's relations (foreign keys).
+
+## Params:
+
+* pq\Gateway\Table $table  
+  The table to get the relations for.
+
+
diff --git a/pq-gateway/pq/Gateway/Table/Relations/count.md b/pq-gateway/pq/Gateway/Table/Relations/count.md
new file mode 100644 (file)
index 0000000..0829c9d
--- /dev/null
@@ -0,0 +1,11 @@
+# int pq\Gateway\Table\Relations::count()
+
+Implements Countable.
+
+## Params:
+
+None.
+
+## Returns:
+
+* int, number of foreign keys.
diff --git a/pq-gateway/pq/Gateway/Table/Relations/getIterator.md b/pq-gateway/pq/Gateway/Table/Relations/getIterator.md
new file mode 100644 (file)
index 0000000..87832dc
--- /dev/null
@@ -0,0 +1,12 @@
+# ArrayIterator pq\Gateway\Table\Relations::getIterator()
+
+Implements IteratorAggregate.
+See pq\Gateway\Table\Relations::getReference().
+
+## Params:
+
+None.
+
+## Returns:
+
+* ArrayIterator, list of foreign keys.
diff --git a/pq-gateway/pq/Gateway/Table/Relations/getReference.md b/pq-gateway/pq/Gateway/Table/Relations/getReference.md
new file mode 100644 (file)
index 0000000..78714ad
--- /dev/null
@@ -0,0 +1,44 @@
+# stdClass pq\Gateway\Table\Relations::getReference(string $to)
+
+Retrieve the foreign key of the table to another table.
+
+## Params:
+
+* string $to  
+  The table name referenced by a foreign key of the table.
+
+## Returns:
+
+* stdClass, the table relation.
+* NULL, if the tables are not related.
+
+## Example:
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       $email = new Table("account_email");
+       $relation = new Table\Relations($email);
+       $account = $relation->getReference("account");
+       
+       var_dump($account);
+       
+       ?>
+
+Yields:
+
+       object(stdClass)#13 (1) {
+         ["account_email"]=>
+         object(stdClass)#14 (4) {
+               ["foreignTable"]=>
+               string(13) "account_email"
+               ["foreignColumn"]=>
+               string(10) "account_id"
+               ["referencedTable"]=>
+               string(7) "account"
+               ["referencedColumn"]=>
+               string(2) "id"
+         }
+       }
+
diff --git a/pq-gateway/pq/Gateway/Table/__construct.md b/pq-gateway/pq/Gateway/Table/__construct.md
new file mode 100644 (file)
index 0000000..69651d2
--- /dev/null
@@ -0,0 +1,15 @@
+# void pq\Gateway\Table::__construct([string $name = NULL[, pq\Connection $conn = NULL]])
+
+Create a new table gateway.
+
+## Params:
+
+* Optional string $name = NULL  
+  The table name.
+* Optional pq\Connection $conn = NULL  
+  The connection (defaults to pq\Gateway\Table::$defaultConnection).
+
+## Throws:
+
+* InvalidArgumentException
+* pq\Exception
diff --git a/pq-gateway/pq/Gateway/Table/__toString.md b/pq-gateway/pq/Gateway/Table/__toString.md
new file mode 100644 (file)
index 0000000..e514707
--- /dev/null
@@ -0,0 +1,24 @@
+# string pq\Gateway\Table::__toString()
+
+Format an identifying postgresql:// URL.
+
+## Params:
+
+None.
+
+## Returns:
+
+* string, the formatted URL.
+
+## Example:
+
+       <?php
+       
+       echo new pq\Gateway\Table("account",
+               new pq\Connection("application_name='pq-gateway-docs' connect_timeout=10"));
+       
+       ?>
+
+Yields:
+
+       postgresql://mike:@:5432/mike?#account
diff --git a/pq-gateway/pq/Gateway/Table/attach.md b/pq-gateway/pq/Gateway/Table/attach.md
new file mode 100644 (file)
index 0000000..3914d71
--- /dev/null
@@ -0,0 +1,12 @@
+# pq\Gateway\Table pq\Gateway\Table::attach(SplObserver $observer)
+
+Implements SplSubject.
+
+## Params:
+
+* SplObserver $observer  
+  The observer to update with actions on the table's rows.
+
+## Returns:
+
+* pq\Gateway\Table, self.
diff --git a/pq-gateway/pq/Gateway/Table/by.md b/pq-gateway/pq/Gateway/Table/by.md
new file mode 100644 (file)
index 0000000..ca55689
--- /dev/null
@@ -0,0 +1,38 @@
+# mixed pq\Gateway\Table::by(pq\Gateway\Row $me, string $foreign[, $order = NULL[, int $limit = 0[, int $offset = 0]]])
+
+Find rows in another table by foreign key.
+See pq\Gateway\Table::find(), pq\Gateway\Table::of() and pq\Gateway\Row::ofWhich().
+
+## Params:
+
+* pq\Gateway\Row $row  
+  A row of this table referenced by another table through a foreign key.
+* Optional string $name = NULL  
+  The identifying name of the relation.
+* Optional string $order = NULL  
+  Sorting clause.
+* Optional int $limit = 0  
+  Row count limit.
+* Optional int $offset = 0  
+  Row count offset.
+
+## Returns:
+
+* a [deferred promise of React/Promise](https://github.com/reactphp/promise#deferred-1), when using pq\Query\AsyncExecutor, the asynchronous executor.  
+  Else:
+* pq\Result, if pq\Result::$status != pq\Result::TUPLES_OK.
+* pq\Result, if the rowset prototype pq\Gateway\Table::$rowset is empty.
+* pq\Gateway\Rowset, an instance of the rowset prototype.
+
+## Example:
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       $account_emails = new Table("account_emails");
+       $email = $account_emails->find(["email=" => "mike@php.net"])->current();
+       
+       $account = $account_emails->by($email, "account")->current();
+       
+       ?>
diff --git a/pq-gateway/pq/Gateway/Table/detach.md b/pq-gateway/pq/Gateway/Table/detach.md
new file mode 100644 (file)
index 0000000..891b063
--- /dev/null
@@ -0,0 +1,12 @@
+# pq\Gateway\Table pq\Gateway\Table::detach(SplObserver $observer)
+
+Implemnts SplSubject.
+
+## Params:
+
+* SplObserver $observer  
+  The observer to remove.
+
+## Returns:
+
+* pq\Gateway\Table, self.
diff --git a/pq-gateway/pq/Gateway/Table/execute.md b/pq-gateway/pq/Gateway/Table/execute.md
new file mode 100644 (file)
index 0000000..a0eb341
--- /dev/null
@@ -0,0 +1,14 @@
+# protected mixed pq\Gateway\Table::execute(pq\Query\Writer $query)
+
+Execute the query on behalf of this table.
+The executed query's result will be forwarded to pq\Gateway\Table::onResult().
+
+## Params:
+
+* pq\Query\Writer $query  
+  The query to execute.
+
+## Returns:
+
+* pq\Result, when using pq\Query\Executor, the synchronous executor.
+* a [deferred promise of React/Promise](https://github.com/reactphp/promise#deferred-1), when using pq\Query\AsyncExecutor, the asynchronous executor.
diff --git a/pq-gateway/pq/Gateway/Table/find.md b/pq-gateway/pq/Gateway/Table/find.md
new file mode 100644 (file)
index 0000000..d5dda10
--- /dev/null
@@ -0,0 +1,45 @@
+# mixed pq\Gateway\Table::find([array $where = NULL[, string $order = NULL[, int $limit = 0[, int $offset = 0[, string $lock = NULL]]]]])
+
+Find rows in the table.
+See pq\Gateway\Table::execute() and pq\Gateway\Table::onResult().
+
+## Params:
+
+* Optional array $where = NULL  
+  Lookup criteria.
+* Optional string $order = NULL  
+  Sorting clauses.
+* Optional int $limit = 0  
+  A row count limit.
+* Optional int $offset = 0  
+  A row count offset.
+* Optional string $lock = NULL  
+  A FOR lock clause (SHARE/UPDATE/KEY SHARE/NO KEY UPDATE).
+
+## Returns:
+
+* a [deferred promise of React/Promise](https://github.com/reactphp/promise#deferred-1), when using pq\Query\AsyncExecutor, the asynchronous executor.  
+  Else:
+* pq\Result, if pq\Result::$status != pq\Result::TUPLES_OK.
+* pq\Result, if the rowset prototype pq\Gateway\Table::$rowset is empty.
+* pq\Gateway\Rowset, an instance of the rowset prototype.
+
+## Example:
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       $table = new Table("account_email");
+       $transaction = $table->getConnection()->startTransaction();
+       
+       $rowset = $table->find(["email=" => "mike@php.net"], null, 0, 0, "UPDATE");
+       
+       $rowset->apply(function(pq\Gateway\Row $row) {
+               $row->email = "mike@PHP.net";
+       });
+       
+       $rowset->update(false);
+       $transaction->commit();
+       
+       ?>
diff --git a/pq-gateway/pq/Gateway/Table/getAttributes.md b/pq-gateway/pq/Gateway/Table/getAttributes.md
new file mode 100644 (file)
index 0000000..8bd537c
--- /dev/null
@@ -0,0 +1,11 @@
+# pq\Gateway\Table\Attributes pq\Gateway\Table::getAttributes()
+
+Retrieve the attributes (columns) of this table.
+
+## Params:
+
+None.
+
+## Returns:
+
+* pq\Gateway\Table\Attributes, the table attributes (columns) list.
diff --git a/pq-gateway/pq/Gateway/Table/getConnection.md b/pq-gateway/pq/Gateway/Table/getConnection.md
new file mode 100644 (file)
index 0000000..6ccd427
--- /dev/null
@@ -0,0 +1,11 @@
+# pq\Connection pq\Gateway\Table::getConnection()
+
+Retrieve the connection currently in use by the table gateway.
+
+## Params:
+
+None.
+
+## Returns:
+
+* pq\Connection, the current PostgreSQL connection.
diff --git a/pq-gateway/pq/Gateway/Table/getIdentity.md b/pq-gateway/pq/Gateway/Table/getIdentity.md
new file mode 100644 (file)
index 0000000..0d9b624
--- /dev/null
@@ -0,0 +1,11 @@
+# pq\Gateway\Table\Identity pq\Gateway\Table::getIdentity()
+
+Retrieve the table identity (primary key).
+
+## Params:
+
+None.
+
+## Returns:
+
+* pq\Gateway\Table\Identity, the primary key.
diff --git a/pq-gateway/pq/Gateway/Table/getMetadataCache.md b/pq-gateway/pq/Gateway/Table/getMetadataCache.md
new file mode 100644 (file)
index 0000000..daee2ee
--- /dev/null
@@ -0,0 +1,12 @@
+# pq\Gateway\Table\CacheInterface pq\Gateway\Table::getMetadataCache()
+
+Retrieve the metadata cache used by this table.
+See pq\Gateway\Table::setMetadataCache().
+
+## Params:
+
+None.
+
+## Returns:
+
+* pq\Gateway\Table\CacheInterface, the metadata cache currently in use.
diff --git a/pq-gateway/pq/Gateway/Table/getName.md b/pq-gateway/pq/Gateway/Table/getName.md
new file mode 100644 (file)
index 0000000..57ec7fd
--- /dev/null
@@ -0,0 +1,11 @@
+# string pq\Gateway\Table::getName()
+
+Retrieve the table name.
+
+## Params:
+
+None.
+
+## Returns:
+
+* string, the name of the table.
diff --git a/pq-gateway/pq/Gateway/Table/getQueryExecutor.md b/pq-gateway/pq/Gateway/Table/getQueryExecutor.md
new file mode 100644 (file)
index 0000000..3bd439e
--- /dev/null
@@ -0,0 +1,12 @@
+# pq\Query\ExecutorInterface pq\Gateway\Table::getQueryExecutor()
+
+Retrieve the query executor used by this table.
+See pq\Gateway\Table::setQueryExecutor(), pq\Query\Executor and pq\Query\AsyncExecutor.
+
+## Params:
+
+None.
+
+## Returns:
+
+* pq\Query\ExecutorInterface, the query executor currently in use.
diff --git a/pq-gateway/pq/Gateway/Table/getQueryWriter.md b/pq-gateway/pq/Gateway/Table/getQueryWriter.md
new file mode 100644 (file)
index 0000000..e8dca87
--- /dev/null
@@ -0,0 +1,12 @@
+# pq\Query\WriterInterface pq\Gateway\Table::getQueryWriter()
+
+Retrieve the query writer of this table.
+See pq\Query\Writer and pq\Gateway\Table::setQueryWriter().
+
+## Params:
+
+None.
+
+## Returns:
+
+* pq\Query\WriterInterface, the query writer currentyl in use.
diff --git a/pq-gateway/pq/Gateway/Table/getRelations.md b/pq-gateway/pq/Gateway/Table/getRelations.md
new file mode 100644 (file)
index 0000000..352f423
--- /dev/null
@@ -0,0 +1,120 @@
+# \pq\Gateway\Table\Relations|stdClass pq\Gateway\Table::getRelations([string $to = NULL])
+
+Get the relations (by foreign key) of this table.
+See pq\Gateway\Table::hasRelation().
+
+> ***NOTE:***  
+  The relation name is the column name of the foreign key with the column name of the referenced column cut off the end.
+
+## Params:
+
+* Optional string $to = NULL  
+  The table name of which to get the relation to.
+
+## Returns:
+
+* stdClass, if $to is given and a relation exists.
+* NULL, if $to is given and a relation does not exist.
+* pq\Gateway\Table\Relations, all relations if $to is omitted.
+
+## Example:
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       $conn = new pq\Connection;
+       $conn->exec("
+               drop table if exists reftable cascade;
+               -- drop table if exists account cascade;
+               -- drop table if exists account_email cascade;
+
+               -- create table account (
+               --      id uuid default uuid_generate_v4() primary key,
+               --      password char(60),
+               --      name varchar(68)
+               -- );
+
+               -- create table account_email (
+               --      account_id uuid not null references account(id) on delete cascade,
+               --      email varchar(255) not null unique,
+               --      primary key (account_id, email)
+               -- );
+               
+               create table reftable (
+                       id serial primary key,
+                       my_account integer references account(id),
+                       account_id integer references account(id),
+                       second_account_id integer references account(id),
+                       email integer references account_email(email)
+               );
+       ");
+       
+       $fgn_table = new Table("reftable");
+       var_dump($fgn_table->getRelations());
+       
+       ?>
+
+Yields:
+
+       object(pq\Gateway\Table\Relations)#10 (1) {
+         ["references":protected]=>
+         object(stdClass)#17 (4) {
+               ["my_account"]=>
+               object(stdClass)#18 (1) {
+                 ["reftable"]=>
+                 object(stdClass)#19 (4) {
+                       ["foreignTable"]=>
+                       string(8) "reftable"
+                       ["foreignColumn"]=>
+                       string(10) "my_account"
+                       ["referencedTable"]=>
+                       string(7) "account"
+                       ["referencedColumn"]=>
+                       string(2) "id"
+                 }
+               }
+               ["account"]=>
+               object(stdClass)#20 (1) {
+                 ["reftable"]=>
+                 object(stdClass)#21 (4) {
+                       ["foreignTable"]=>
+                       string(8) "reftable"
+                       ["foreignColumn"]=>
+                       string(10) "account_id"
+                       ["referencedTable"]=>
+                       string(7) "account"
+                       ["referencedColumn"]=>
+                       string(2) "id"
+                 }
+               }
+               ["second_account"]=>
+               object(stdClass)#22 (1) {
+                 ["reftable"]=>
+                 object(stdClass)#23 (4) {
+                       ["foreignTable"]=>
+                       string(8) "reftable"
+                       ["foreignColumn"]=>
+                       string(17) "second_account_id"
+                       ["referencedTable"]=>
+                       string(7) "account"
+                       ["referencedColumn"]=>
+                       string(2) "id"
+                 }
+               }
+               ["email"]=>
+               object(stdClass)#24 (1) {
+                 ["reftable"]=>
+                 object(stdClass)#25 (4) {
+                       ["foreignTable"]=>
+                       string(8) "reftable"
+                       ["foreignColumn"]=>
+                       string(5) "email"
+                       ["referencedTable"]=>
+                       string(13) "account_email"
+                       ["referencedColumn"]=>
+                       string(5) "email"
+                 }
+               }
+         }
+       }
diff --git a/pq-gateway/pq/Gateway/Table/getRowsetPrototype.md b/pq-gateway/pq/Gateway/Table/getRowsetPrototype.md
new file mode 100644 (file)
index 0000000..a00e5b8
--- /dev/null
@@ -0,0 +1,13 @@
+# mixed pq\Gateway\Table::getRowsetPrototype()
+
+Retrieve the rowset prototype of this table.
+See pq\Gateway\Table::setRowsetPrototype() and pq\Gateway\Table::$rowset.
+
+## Params:
+
+None.
+
+## Returns:
+
+* callable.
+* string, class name.
diff --git a/pq-gateway/pq/Gateway/Table/hasRelation.md b/pq-gateway/pq/Gateway/Table/hasRelation.md
new file mode 100644 (file)
index 0000000..987c9ae
--- /dev/null
@@ -0,0 +1,58 @@
+# bool pq\Gateway\Table::hasRelation(string $name[, string $table = NULL])
+
+Check whether a relation to another table exists with the specified name.
+See pq\Gateway\Table\Relations
+
+> ***NOTE:***  
+  The relation name is the column name of the foreign key with the column name of the referenced column cut off the end.
+
+## Params:
+
+* string $name  
+  The name of the relation.
+* Optional string $table = NULL  
+  The bare table name, if the relation has another name (e.g. because of multiple foreign keys to the same table).
+
+## Returns:
+
+* bool, whether the specified relation exists.
+
+## Example:
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       $conn = new pq\Connection;
+       $conn->exec("
+               drop table if exists account cascade;
+               drop table if exists email cascade;
+               drop table if exists reftable cascade;
+               
+               create table account (
+                       id serial primary key
+               );
+               
+               create table email (
+                       id serial primary key,
+                       account_id integer references account(id),
+                       email text
+               );
+               
+               create table reftable (
+                       id serial primary key,
+                       my_account integer references account(id),
+                       account_id integer references account(id),
+                       second_account_id integer references account(id),
+                       email integer references email(id)
+               );
+       ");
+       
+       $fgn_table = new Table("reftable");
+       var_dump($fgn_table->hasRelation("my_account"));
+       
+       ?>
+
+Yields:
+
+       TRUE
diff --git a/pq-gateway/pq/Gateway/Table/notify.md b/pq-gateway/pq/Gateway/Table/notify.md
new file mode 100644 (file)
index 0000000..bbe0e94
--- /dev/null
@@ -0,0 +1,19 @@
+# void pq\Gateway\Table::notify([pq\Gateway\Row $row = NULL[, string $event = NULL[, array &$criteria = NULL]]])
+
+Implements SplSubject.
+
+## Params:
+
+* Optional pq\Gateway\Row $row = NULL  
+  The row which created the event.
+* Optional string $event = NULL  
+  The row's event (create/update/delete).
+* Optional array &$criteria = NULL  
+  The criteria for the row update.
+
+> ***NOTE:***  
+  All these params will be passed through to the table's observers after the table itself.
+  
+       <?php
+       $observer->update($table, $row, $event, $criteria);
+       ?>
diff --git a/pq-gateway/pq/Gateway/Table/of.md b/pq-gateway/pq/Gateway/Table/of.md
new file mode 100644 (file)
index 0000000..68134b7
--- /dev/null
@@ -0,0 +1,39 @@
+# mixed pq\Gateway\Table::of(pq\Gateway\Row $foreign[, string $name = NULL[, string $order = NULL[, int $limit = 0[, int $offset = 0]]]])
+
+Find rows in table by foreign key.
+See pq\Gateway\Table::find(), pq\Gateway\Table::by() and pq\Gateway\Row::allOf().
+
+## Params:
+
+* pq\Gateway\Row $row  
+  A row of a table referencing this table through a foreign key.
+* Optional string $name = NULL  
+  The identifying name of the relation.
+* Optional string $order = NULL  
+  Sorting clause.
+* Optional int $limit = 0  
+  Row count limit.
+* Optional int $offset = 0  
+  Row count offset.
+
+## Returns:
+
+* a [deferred promise of React/Promise](https://github.com/reactphp/promise#deferred-1), when using pq\Query\AsyncExecutor, the asynchronous executor.  
+  Else:
+* pq\Result, if pq\Result::$status != pq\Result::TUPLES_OK.
+* pq\Result, if the rowset prototype pq\Gateway\Table::$rowset is empty.
+* pq\Gateway\Rowset, an instance of the rowset prototype.
+
+## Example:
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       $accounts = new Table("account");
+       $account = $accounts->find(["id=" => 1])->current();
+       
+       $account_emails = new Table("account_emails");
+       $emails = $account_emails->of($account);
+       
+       ?>
diff --git a/pq-gateway/pq/Gateway/Table/onResult.md b/pq-gateway/pq/Gateway/Table/onResult.md
new file mode 100644 (file)
index 0000000..862b669
--- /dev/null
@@ -0,0 +1,14 @@
+# mixed pq\Gateway\Table::onResult([pq\Result $result = NULL])
+
+Executor result callback.
+
+## Params:
+
+* Optional pq\Result $result = NULL  
+  The result of any executed query on behalf of this table.
+
+## Returns:
+
+* pq\Result, if pq\Result::$status != pq\Result::TUPLES_OK.
+* pq\Result, if the rowset prototype pq\Gateway\Table::$rowset is empty.
+* pq\Gateway\Rowset, an instance of the rowset prototype.
diff --git a/pq-gateway/pq/Gateway/Table/resolve.md b/pq-gateway/pq/Gateway/Table/resolve.md
new file mode 100644 (file)
index 0000000..45833c1
--- /dev/null
@@ -0,0 +1,12 @@
+# static pq\Table pq\Table::resolve(mixed $table)
+
+Resolve a table name.
+
+## Params:
+
+* mixed $table  
+  The table name (may well be already a pq\Gateway\Table instance).
+
+## Returns:
+
+* pq\Gateway\Table, instance of $table (might be a no-op).
diff --git a/pq-gateway/pq/Gateway/Table/setMetadataCache.md b/pq-gateway/pq/Gateway/Table/setMetadataCache.md
new file mode 100644 (file)
index 0000000..f506200
--- /dev/null
@@ -0,0 +1,13 @@
+# pq\Gateway\Table pq\Gateway\Table::setMetadataCache(pq\Gateway\Table\CacheInterface $cache)
+
+Set the metadata cache implementation.
+See pq\Gateway\Table::getMetadataCache().
+
+## Params:
+
+* pq\Gateway\Table\CacheInterface $cache  
+  The metadata cache to use.
+
+## Returns:
+
+* pq\Gateway\Table, self.
diff --git a/pq-gateway/pq/Gateway/Table/setQueryExecutor.md b/pq-gateway/pq/Gateway/Table/setQueryExecutor.md
new file mode 100644 (file)
index 0000000..d2683a0
--- /dev/null
@@ -0,0 +1,13 @@
+# pq\Gateway\Table pq\Gateway\Table::setQueryExecutor(pq\Query\ExecutorInterface $exec)
+
+Set the query executor implementation.
+See pq\Gateway\Table::getQueryExecutor(), pq\Query\Executor and pq\Query\AsyncExecutor.
+
+## Params:
+
+* pq\Query\ExecutorInterface $exec  
+  A query executor interface implementation.
+
+## Returns:
+
+* pq\Gateway\Table, self.
diff --git a/pq-gateway/pq/Gateway/Table/setQueryWriter.md b/pq-gateway/pq/Gateway/Table/setQueryWriter.md
new file mode 100644 (file)
index 0000000..fca1e24
--- /dev/null
@@ -0,0 +1,13 @@
+# pq\Gateway\Table pq\Gateway\Table::setQueryWriter(pq\Query\WriterInterface $query)
+
+Set the internal query writer.
+See pq\Query\Writer and pq\Gateway\Table::getQueryWriter().
+
+## Params:
+
+* pq\Query\WriterInterface $query  
+  A query writer implementation.
+
+## Returns:
+
+* pq\Gateway\Table, self.
diff --git a/pq-gateway/pq/Gateway/Table/setRowsetPrototype.md b/pq-gateway/pq/Gateway/Table/setRowsetPrototype.md
new file mode 100644 (file)
index 0000000..c68f193
--- /dev/null
@@ -0,0 +1,16 @@
+# pq\Gateway\Table pq\Gateway\Table::setRowsetPrototype(mixed $rowset)
+
+Set the prototype of the return value of rowset generating methods.
+See pq\Gateway\Table::getRowsetPrototype() and pq\Gateway\Table::$rowset.
+
+## Params:
+
+* mixed $rowset  
+  Either
+  * a class name with a constructor as function(pq\Gateway\Table $this, pq\Result $result)
+  or 
+  * a callable as function(pq\Result $result)
+
+## Returns:
+
+* pq\Gateway\Table, self.
diff --git a/pq-gateway/pq/Gateway/Table/with.md b/pq-gateway/pq/Gateway/Table/with.md
new file mode 100644 (file)
index 0000000..8e3a054
--- /dev/null
@@ -0,0 +1,44 @@
+# mixed pq\Gateway\Table::with(array $relations[, array $where = NULL[, string $order = NULL[, int $limit = 0[, int $offset = 0]]]])
+
+Find rows dependent on other rows by foreign keys.
+See pq\Gateway\Table::of(), pq\Gateway\Table::by() and pq\Gateway\Table::find().
+
+## Params:
+
+* array $relations  
+  list of stdClass instances representing relations to join for the query; see pq\Gateway\Table::getRelations().
+* Optional array $where = NULL  
+  Additional lookup criteria.
+* Optional string $order = NULL  
+  Sorting clause.
+* Optional int $limit = 0  
+  Row count limit.
+* Optional int $offset = 0  
+  Row count offset.
+
+## Returns:
+
+* a [deferred promise of React/Promise](https://github.com/reactphp/promise#deferred-1), when using pq\Query\AsyncExecutor, the asynchronous executor.  
+  Else:
+* pq\Result, if pq\Result::$status != pq\Result::TUPLES_OK.
+* pq\Result, if the rowset prototype pq\Gateway\Table::$rowset is empty.
+* pq\Gateway\Rowset, an instance of the rowset prototype.
+
+## Example:
+
+       <?php
+       
+       use pq\Gateway\Table;
+       
+       $emails = new Table("account_email");
+       $accounts = new Table("account");
+       $notifications = new Table("notification");
+       
+       $relations = [
+               $emails->getRelations("account")->account_email,
+               $notifications->getRelations("email")->notification
+       ];
+       
+       $bouncers = $accounts->with($relations, ["bounces>" => 3]);
+       
+       ?>