--- /dev/null
+<?php
+
+namespace pq\Gateway;
+
+class Cell
+{
+}
--- /dev/null
+<?php
+
+namespace pq\Gateway;
+
+class Row
+{
+ /**
+ * @var \pq\Gateway\Table
+ */
+ protected $table;
+
+ /**
+ * @var array
+ */
+ protected $data;
+
+ /**
+ * @var array
+ */
+ protected $mods = array();
+
+ /**
+ * @param \pq\Gateway\Table $table
+ * @param array $data
+ */
+ function __construct(Table $table, array $data = null) {
+ $this->table = $table;
+ $this->data = $data;
+ }
+
+ function __get($p) {
+ if (!isset($this->mod[$p])) {
+ $this->mod[$p] = new Cell($this, $p);
+ }
+ return $this->mod[$p];
+ }
+
+ function create() {
+ $this->data = $this->table->create($this->mods)->getIterator()->current()->data;
+ $this->mods = array();
+ return $this;
+ }
+
+ function update() {
+ $this->data = $this->table->update($this->data, $this->mods)->getIterator()->current()->data;
+ $this->mods = array();
+ return $this;
+ }
+
+ function delete() {
+ $this->data = $this->table->delete($this->data, "*")->getIterator()->current()->data;
+ $this->mods = array();
+ return $this;
+ }
+}
--- /dev/null
+<?php
+
+namespace pq\Gateway;
+
+class Rowset implements \IteratorAggregate
+{
+ /**
+ * @var \pq\Gateway\Table
+ */
+ protected $table;
+
+ /**
+ * @var array
+ */
+ protected $rows;
+
+ /**
+ * @param \pq\Gateway\Table $table
+ * @param \pq\Result $result
+ */
+ function __construct(Table $table, \pq\Result $result, $rowClass = "\\pq\\Gateway\\Row") {
+ $this->table = $table;
+ while (($row = $result->fetchRow(\pq\Result::FETCH_ASSOC))) {
+ $this->rows[] = new $rowClass($this->table, $row);
+ }
+ }
+
+ /**
+ * @implements \IteratorAggregate
+ * @return \pq\Gateway\ArrayIterator
+ */
+ function getIterator() {
+ return new \ArrayIterator($this->rows);
+ }
+
+ /**
+ * Filter by callback
+ * @param callable $cb
+ * @return \pq\Gateway\Rowset
+ */
+ function filter(callable $cb) {
+ $rowset = clone $this;
+ $rowset->rows = array_filter($this->rows, $cb);
+ return $rowset;
+ }
+}
--- /dev/null
+<?php
+
+namespace pq\Gateway;
+
+use \pq\Query\Writer as QueryWriter;
+
+class Table
+{
+ /**
+ * @var \pq\Connection
+ */
+ protected $connection;
+
+ /**
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * @var string
+ */
+ protected $rowset;
+
+ /**
+ * @param \pq\Connection $c
+ * @param string $name
+ */
+ function __construct(\pq\Connection $c, $name, $rowset = "\\pq\\Gateway\\Rowset") {
+ $this->connection = $c;
+ $this->name = $name;
+ $this->rowset = $rowset;
+ }
+
+ /**
+ * Accessor to read-only properties
+ * @param string $p
+ */
+ function __get($p) {
+ return $this->$p;
+ }
+
+ /**
+ * @param \pq\Query\Writer $query
+ * @param array $criteria
+ * @param string $join
+ */
+ protected function criteria(QueryWriter $query, array $criteria, $join = "AND") {
+ $joinable = false;
+ $query->write("(");
+ foreach ($criteria as $lop => $rop) {
+ if (is_array($rop)) {
+ if ($joinable) {
+ $query->write(")", $join, "(");
+ }
+ $this->criteria($query, $rop, is_int($lop) ? "AND" : $lop);
+ } else {
+ if ($joinable) {
+ $query->write(")", $join, "(");
+ }
+ if (!is_int($lop)) {
+ $query->write($lop);
+ }
+ $query->write($query->param($rop));
+ }
+ $joinable or $joinable = true;
+ }
+ $query->write(")");
+ }
+
+ /**
+ * Find rows in the table
+ * @param array $where
+ * @param array|string $order
+ * @param int $limit
+ * @param int $offset
+ * @return \pq\Result
+ */
+ function find(array $where = null, $order = null, $limit = 0, $offset = 0) {
+ $query = new QueryWriter("SELECT * FROM ". $this->connection->quoteName($this->name));
+ if ($where) {
+ $this->criteria($query->write("WHERE"), $where);
+ }
+ if ($order) {
+ $query->write("ORDER BY", $order);
+ }
+ if ($limit) {
+ $query->write("LIMIT", $limit);
+ }
+ $query->write("OFFSET", $offset);
+ return new Rowset($this, $query->exec($this->connection));
+ }
+
+ /**
+ * Insert a row into the table
+ * @param array $data
+ * @param string $returning
+ * @return \pq\Result
+ */
+ function create(array $data, $returning = "*") {
+ $params = array();
+ $query = new QueryWriter("INSERT INTO ".$this->connection->quoteName($this->name)." (");
+ foreach ($data as $key => $val) {
+ $query->write($key);
+ $params[] = $query->param($val);
+ }
+ $query->write(") VALUES (", $params, ")");
+ if (strlen($returning)) {
+ $query->write("RETURNING", $returning);
+ }
+ $result = $query->exec($this->connection);
+ if ($result->status == \pq\Result::TUPLES_OK) {
+ $rowset = $this->rowset;
+ return new $rowset($this, $result);
+ }
+ return $result;
+ }
+
+ /**
+ * Update rows in the table
+ * @param array $where
+ * @param array $data
+ * @param string $returning
+ * @retunr \pq\Result
+ */
+ function update(array $where, array $data, $returning = "*") {
+ $query = new QueryWriter("UPDATE ".$this->connection->quoteName($this->name)." SET");
+ foreach ($data as $key => $val) {
+ $query->write($key, "=", $query->param($val));
+ }
+ $this->criteria($query->write("WHERE"), $where);
+ if (strlen($returning)) {
+ $query->write("RETURNING", $returning);
+ }
+ $result = $query->exec($this->connection);
+ if ($result->status == \pq\Result::TUPLES_OK) {
+ $rowset = $this->rowset;
+ return new $rowset($this, $result);
+ }
+ return $result;
+ }
+
+ /**
+ * Delete rows from the table
+ * @param array $where
+ * @param string $returning
+ * @return pq\Result
+ */
+ function delete(array $where, $returning = null) {
+ $query = new QueryWriter("DELETE FROM ".$this->connection->quoteName($this->name));
+ $this->criteria($query->write("WHERE"), $where);
+ if (strlen($returning)) {
+ $query->write("RETURNING", $returning);
+ }
+ $result = $query->exec($this->connection);
+ if ($result->status == \pq\Result::TUPLES_OK) {
+ $rowset = $this->rowset;
+ return new $rowset($this, $result);
+ }
+ return $result;
+ }
+}
+
--- /dev/null
+<?php
+
+namespace pq\Query;
+
+class Expr
+{
+ /**
+ * @var string
+ */
+ protected $expression;
+
+ /**
+ * @param string $e the expression or a format string followed by arguments
+ * @param string ...
+ */
+ function __construct($e) {
+ if (func_num_args() > 1) {
+ $this->expression = call_user_func_array("sprintf", func_get_args());
+ } else {
+ $this->expression = $e;
+ }
+ }
+
+ /**
+ * Get the string expression
+ * @return string
+ */
+ function __toString() {
+ return (string) $this->expression;
+ }
+}
--- /dev/null
+<?php
+
+namespace pq\Query;
+
+/**
+ * A very simple query writer used by \pq\Gateway
+ */
+class Writer
+{
+ /**
+ * @var string
+ */
+ protected $query;
+
+ /**
+ * @var array
+ */
+ protected $params;
+
+ /**
+ * @var array
+ */
+ protected $types;
+
+ /**
+ * @param string $query initial query string
+ * @param array $params intial set of params
+ * @param array $types the types of the params
+ */
+ function __construct($query = "", array $params = array(), array $types = array()) {
+ $this->query = $query;
+ $this->params = $params;
+ $this->types = $types;
+ }
+
+ /**
+ * Get the query string
+ * @return string
+ */
+ function __toString() {
+ return $this->query;
+ }
+
+ /**
+ * Get the query params
+ * @return array
+ */
+ function getParams() {
+ return $this->params;
+ }
+
+ /**
+ * Get the param types
+ * @return array
+ */
+ function getTypes() {
+ return $this->types;
+ }
+
+ /**
+ * Reset
+ * @return \pq\Query\Writer
+ */
+ function reset() {
+ $this->query = "";
+ $this->params = array();
+ $this->types = array();
+ return $this;
+ }
+
+ /**
+ * Append to the query string
+ * @return \pq\Query\Writer
+ */
+ function write() {
+ $this->query .= array_reduce(func_get_args(), function($q, $v) {
+ return $q . " " . (is_array($v) ? implode(", ", $v) : $v);
+ });
+ return $this;
+ }
+
+ /**
+ * Write a param placeholder and push the param onto the param list
+ * @param mixed $param
+ * @param string $type
+ * @return string
+ */
+ function param($param, $type = null) {
+ if ($param instanceof Expr) {
+ return (string) $param;
+ }
+ $this->params[] = $param;
+ $this->types[] = $type;
+ return "\$".count($this->params);
+ }
+
+ /**
+ * Execute the query through \pq\Connection::execParams($this, $this->params, $this->types)
+ * @param \pq\Connection $c
+ * @return \pq\Result
+ */
+ function exec(\pq\Connection $c) {
+ return $c->execParams($this, $this->params, $this->types);
+ }
+}
--- /dev/null
+<?php
+
+require "./pq/Query/Expr.php";
+require "./pq/Query/Writer.php";
+require "./pq/Gateway/Table.php";
+require "./pq/Gateway/Rowset.php";
+require "./pq/Gateway/Row.php";
+require "./pq/Gateway/Cell.php";
+
+class FooModel extends \pq\Gateway\Table {
+ function __construct(\pq\Connection $c) {
+ parent::__construct($c, "foo", "FooCollection");
+ }
+}
+
+class Foo extends \pq\Gateway\Row {
+
+}
+
+class FooCollection extends \pq\Gateway\Rowset {
+ function __construct(\pq\Gateway\Table $table, \pq\Result $result) {
+ parent::__construct($table, $result, "Foo");
+ }
+}
+
+$conn = new \pq\Connection;
+$types = new \pq\Types($conn);
+$table = new FooModel($conn);
+print_r( $table->find(array("dt" => new \pq\Query\Expr("between %s and %s", $conn->quote("2013-03-01"), $conn->quote("2013-03-04")))) );
+echo PHP_EOL;
+print_r( $table->find(array("id>" => 1, "OR" => array(array("id=" => 1), array("id="=>2)))));
+echo PHP_EOL;
+print_r( $table->find(array("OR" => array("id>" => 1, "OR" => array(array("id=" => 1), array("id="=>2))))));
+echo PHP_EOL;
+print_r( $table->create(array("data" => "blabla")) );
+echo PHP_EOL;
+print_r( $table->create(array("data" => new \pq\Query\Expr("DEFAULT"))) );
+echo PHP_EOL;
+print_r( $table->update(array("id=" => 4), array("data" => "die 4")) );
+echo PHP_EOL;
+print_r( $table->delete(array(new \pq\Query\Expr("data is null"))) );
+echo PHP_EOL;
\ No newline at end of file