add test
authorMichael Wallner <mike@php.net>
Tue, 5 Mar 2013 17:28:01 +0000 (18:28 +0100)
committerMichael Wallner <mike@php.net>
Tue, 5 Mar 2013 17:28:01 +0000 (18:28 +0100)
lib/pq/Gateway/Cell.php
lib/pq/Gateway/Row.php
lib/pq/Gateway/Rowset.php
lib/pq/Gateway/Table.php
lib/pq/Query/Writer.php
tests/lib/pq/Gateway/TableTest.php [new file with mode: 0644]
tests/setup.inc [new file with mode: 0644]

index ba58404a7c190c261cb82c78ec2e2a42240147c5..f29fd1f5499cdf4f0ed2042378683d2d3eed880a 100644 (file)
@@ -21,15 +21,22 @@ class Cell
         */
        protected $data;
        
+       /**
+        * @var bool
+        */
+       protected $dirty;
+       
        /**
         * @param \pq\Gateway\Row $row
         * @param string $name
         * @param mixed $data
+        * @param bool $dirty
         */
-       function __construct(Row $row, $name, $data) {
+       function __construct(Row $row, $name, $data, $dirty = false) {
                $this->row = $row;
                $this->name = $name;
                $this->data = $data;
+               $this->dirty = $dirty;
        }
        
        /**
@@ -48,6 +55,14 @@ class Cell
                return $this->data instanceof Expr;
        }
        
+       /**
+        * Check whether the cell has been modified
+        * @return bool
+        */
+       function isDirty() {
+               return $this->dirty;
+       }
+       
        /**
         * Get value
         * @return mixed
@@ -65,15 +80,6 @@ class Cell
        function mod($data, $op = null) {
                if (!($this->data instanceof Expr)) {
                        $this->data = new Expr($this->name);
-                       /*
-                       if (!isset($this->data)) {
-                               $this->data = new Expr($this->name);
-                       } elseif (is_numeric($this->data)) {
-                               $this->data = new Expr($this->data);
-                       } else {
-                               $this->data = new Expr("%s", $this->row->getTable()->getConnection()->quote($this->data));
-                       }
-                       */
                }
                
                if ($data instanceof Expr) {
@@ -84,6 +90,9 @@ class Cell
                        $data = $this->row->getTable()->getConnection()->quote($data);
                        $this->data->add(new Expr("%s %s"), isset($op) ? $op : "||", $data);
                }
+               
+               $this->dirty = true;
+               
                return $this;
        }
        
@@ -94,6 +103,7 @@ class Cell
         */
        function set($data) {
                $this->data = $data;
+               $this->dirty = true;
                return $this;
        }
 }
index dc07e3f208e200cd0c1b87290619587d25d41882..5c0efa4ac19a30da22c3bb7627d8ffb4bd58ada5 100644 (file)
@@ -17,7 +17,7 @@ class Row implements \JsonSerializable
        /**
         * @var array
         */
-       protected $mods = array();
+       protected $cell = array();
        
        /**
         * @param \pq\Gateway\Table $table
@@ -66,35 +66,53 @@ class Row implements \JsonSerializable
                return $this->data;
        }
        
+       /**
+        * Check whether the row contains modifications
+        * @return boolean
+        */
+       function isDirty() {
+               foreach ($this->cell as $cell) {
+                       if ($cell->isDirty()) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
        /**
         * Fill modified cells
         * @return \pq\Gateway\Row
         */
        protected function prime() {
-               $this->mods = array();
+               $this->cell = array();
                foreach ($this->data as $key => $val) {
-                       $this->mods[$key] = new Cell($this, $key, $val);
+                       $this->cell[$key] = new Cell($this, $key, $val, true);
                }
                return $this;
        }
        
        /**
         * Transform data array to where criteria
-        * @param array $data
         * @return array
         */
        protected function criteria() {
                $where = array();
-               array_walk($this->data, function($v, $k) use (&$where) {
+               foreach($this->data as $k => $v) {
                        $where["$k="] = $v;
-               });
+               }
                return $where;
        }
        
+       /**
+        * Get an array of changed properties
+        * @return array
+        */
        protected function changes() {
                $changes = array();
-               foreach ($this->mods as $name => $cell) {
-                       $changes[$name] = $cell->get();
+               foreach ($this->cell as $name => $cell) {
+                       if ($cell->isDirty()) {
+                               $changes[$name] = $cell->get();
+                       }
                }
                return $changes;
        }
@@ -105,10 +123,10 @@ class Row implements \JsonSerializable
         * @return \pq\Gateway\Cell
         */
        function __get($p) {
-               if (!isset($this->mods[$p])) {
-                       $this->mods[$p] = new Cell($this, $p, $this->data[$p]);
+               if (!isset($this->cell[$p])) {
+                       $this->cell[$p] = new Cell($this, $p, $this->data[$p]);
                }
-               return $this->mods[$p];
+               return $this->cell[$p];
        }
        
        /**
@@ -126,7 +144,7 @@ class Row implements \JsonSerializable
         */
        function create() {
                $this->data = $this->table->create($this->changes())->current()->data;
-               $this->mods = array();
+               $this->cell = array();
                return $this;
        }
        
@@ -136,7 +154,7 @@ class Row implements \JsonSerializable
         */
        function update() {
                $this->data = $this->table->update($this->criteria(), $this->changes())->current()->data;
-               $this->mods = array();
+               $this->cell = array();
                return $this;
        }
        
index 2527b029a1f629cad222161c05e73cf84540a216..2b039935dfb42eb10d7cac0a9cc70009def49269 100644 (file)
@@ -20,18 +20,16 @@ class Rowset implements \SeekableIterator, \Countable, \JsonSerializable
        protected $rows;
        
        /**
-        * @var string
+        * @var mixed
         */
-       protected $row;
+       protected $row = "\\pq\\Gateway\\Row";
        
        /**
         * @param \pq\Gateway\Table $table
         * @param \pq\Result $result
         */
-       function __construct(Table $table, \pq\Result $result, $row = "\\pq\\Gateway\\Row") {
+       function __construct(Table $table, \pq\Result $result = null) {
                $this->table = $table;
-               $this->row   = $row;
-               
                $this->hydrate($result);
        }
        
@@ -51,20 +49,36 @@ class Rowset implements \SeekableIterator, \Countable, \JsonSerializable
         * @param \pq\Result $result
         * @return array
         */
-       protected function hydrate(\pq\Result $result) {
+       protected function hydrate(\pq\Result $result = null) {
                $this->index = 0;
                $this->rows  = array();
-               $row = $this->row;
                
-               if (is_callable($row)) {
-                       while (($data = $result->fetchRow(\pq\Result::FETCH_ASSOC))) {
-                               $this->rows[] = $row($data);
-                       }
-               } else {
-                       while (($data = $result->fetchRow(\pq\Result::FETCH_ASSOC))) {
-                               $this->rows[] = new $row($this->table, $data);
+               if ($result) {
+                       $row = $this->row;
+
+                       if (is_callable($row)) {
+                               while (($data = $result->fetchRow(\pq\Result::FETCH_ASSOC))) {
+                                       $this->rows[] = $row($data);
+                               }
+                       } elseif ($row) {
+                               while (($data = $result->fetchRow(\pq\Result::FETCH_ASSOC))) {
+                                       $this->rows[] = new $row($this->table, $data);
+                               }
+                       } else {
+                               $this->rows = $result->fetchAll(\pq\Result::FETCH_OBJECT);
                        }
                }
+               
+               return $this;
+       }
+       
+       /**
+        * Set the row prototype
+        * @param mixed $row
+        * @return \pq\Gateway\Table
+        */
+       function setRowPrototype($row) {
+               $this->row = $row;
                return $this;
        }
        
index 0807626f42156bf6e09e0b1be50c0f7dfec0664b..805ed79353a0926461cc86ce53030e369676f5e3 100644 (file)
@@ -6,6 +6,11 @@ use \pq\Query\Writer as QueryWriter;
 
 class Table
 {
+       /**
+        * @var \pq\Connection
+        */
+       public static $defaultConnection;
+       
        /**
         * @var \pq\Connection
         */
@@ -19,16 +24,25 @@ class Table
        /**
         * @var string
         */
-       protected $rowset;
+       protected $rowset = "\\pq\\Gateway\\Rowset";
 
        /**
-        * @param \pq\Connection $conn
         * @param string $name
+        * @param \pq\Connection $conn
+        */
+       function __construct($name, \pq\Connection $conn = null) {
+               $this->name = $name;
+               $this->conn = $conn ?: static::$defaultConnection ?: new \pq\Connection;
+       }
+       
+       /**
+        * Set the rowset prototype
+        * @param mixed $rowset
+        * @return \pq\Gateway\Table
         */
-       function __construct(\pq\Connection $conn, $name, $rowset = "\\pq\\Gateway\\Rowset") {
-               $this->conn   = $conn;
-               $this->name   = $name;
+       function setRowsetPrototype($rowset) {
                $this->rowset = $rowset;
+               return $this;
        }
        
        /**
@@ -98,14 +112,21 @@ class Table
         * @param string $returning
         * @return \pq\Result
         */
-       function create(array $data, $returning = "*") {
-               $params = array();
-               $query = new QueryWriter("INSERT INTO ".$this->conn->quoteName($this->name)." (");
-               foreach ($data as $key => $val) {
-                       $query->write($key);
-                       $params[] = $query->param($val);
+       function create(array $data = null, $returning = "*") {
+               $query = new QueryWriter("INSERT INTO ".$this->conn->quoteName($this->name));
+               if ($data) {
+                       $first = true;
+                       $params = array();
+                       foreach ($data as $key => $val) {
+                               $query->write($first ? "(" : ",", $key);
+                               $params[] = $query->param($val);
+                               $first and $first = false;
+                       }
+                       $query->write(") VALUES (", $params, ")");
+               } else {
+                       $query->write("DEFAULT VALUES");
                }
-               $query->write(") VALUES (", $params, ")");
+               
                if (strlen($returning)) {
                        $query->write("RETURNING", $returning);
                }
@@ -120,9 +141,12 @@ class Table
         * @retunr \pq\Result
         */
        function update(array $where, array $data, $returning = "*") {
-               $query = new QueryWriter("UPDATE ".$this->conn->quoteName($this->name)." SET");
+               $query = new QueryWriter("UPDATE ".$this->conn->quoteName($this->name));
+               $first = true;
+               $params = array();
                foreach ($data as $key => $val) {
-                       $query->write($key, "=", $query->param($val));
+                       $query->write($first ? "SET" : ",", $key, "=", $query->param($val));
+                       $first and $first = false;
                }
                $query->write("WHERE")->criteria($where);
                if (strlen($returning)) {
index bfd7094715d76a175a99b8fc7a32783a287ebd8d..55cb5a2089cfc1a5102b4465fe2b24205bd01dcd 100644 (file)
@@ -94,10 +94,11 @@ class Writer
         * @return string
         */
        function param($param, $type = null) {
+               if ($param instanceof \pq\Gateway\Cell) {
+                       $param = $param->get();
+               }
                if ($param instanceof Expr) {
                        return (string) $param;
-               } else {
-                       var_dump($param);
                }
                
                $this->params[] = $param;
@@ -113,14 +114,13 @@ class Writer
         */
        function criteria(array $criteria) {
                if ((list($left, $right) = each($criteria))) {
-                       array_shift($criteria);
                        $this->write("(");
                        if (is_array($right)) {
                                $this->criteria($right);
                        } else {
                                $this->write("(", $left, $this->param($right), ")");
                        }
-                       foreach ($criteria as $left => $right) {
+                       while ((list($left, $right) = each($criteria))) {
                                $this->write(is_int($left) && is_array($right) ? "OR" : "AND");
                                if (is_array($right)) {
                                        $this->criteria($right);
@@ -139,8 +139,6 @@ class Writer
         * @return \pq\Result
         */
        function exec(\pq\Connection $c) {
-               fprintf(STDERR, "Q: %s\n", $this);
-               fprintf(STDERR, "P: %s\n", implode(", ", $this->params));
                return $c->execParams($this, $this->params, $this->types);
        }
 }
diff --git a/tests/lib/pq/Gateway/TableTest.php b/tests/lib/pq/Gateway/TableTest.php
new file mode 100644 (file)
index 0000000..bee7bdd
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+
+namespace pq\Gateway;
+
+include __DIR__."/../../../setup.inc";
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-03-05 at 16:08:03.
+ */
+class TableTest extends \PHPUnit_Framework_TestCase {
+
+       /**
+        * @var \pq\Connection
+        */
+       protected $conn;
+       
+       /**
+        * @var Table
+        */
+       protected $object;
+
+       /**
+        * Sets up the fixture, for example, opens a network connection.
+        * This method is called before a test is executed.
+        */
+       protected function setUp() {
+               $this->conn = new \pq\Connection(PQ_DSN);
+               $this->conn->exec(PQ_TEST_DROP_TABLE);
+               $this->conn->exec(PQ_TEST_CREATE_TABLE);
+               Table::$defaultConnection = $this->conn;
+               $this->object = new Table(PQ_TEST_TABLE_NAME);
+       }
+
+       /**
+        * Tears down the fixture, for example, closes a network connection.
+        * This method is called after a test is executed.
+        */
+       protected function tearDown() {
+               $this->conn->exec(PQ_TEST_DROP_TABLE);
+       }
+       
+       /**
+        * Creates test data in the test table
+        */
+       protected function createTestData() {
+               $this->conn->exec(PQ_TEST_CREATE_DATA);
+       }
+
+       /**
+        * @covers pq\Gateway\Table::setRowsetPrototype
+        */
+       public function testSetRowsetPrototype() {
+               $prop = new \ReflectionProperty("\\pq\\Gateway\\Table", "rowset");
+               $prop->setAccessible(true);
+               $this->assertEquals("\\pq\\Gateway\\Rowset", $prop->getValue($this->object));
+               $this->object->setRowsetPrototype(null);
+               $this->assertNull($prop->getValue($this->object));
+               $rowset = new \pq\Gateway\Rowset($this->object);
+               $this->object->setRowsetPrototype($rowset);
+               $this->assertSame($rowset, $prop->getValue($this->object));
+       }
+
+       /**
+        * @covers pq\Gateway\Table::getConnection
+        */
+       public function testGetConnection() {
+               $this->assertSame($this->conn, $this->object->getConnection());
+       }
+
+       /**
+        * @covers pq\Gateway\Table::getName
+        */
+       public function testGetName() {
+               $this->assertSame(PQ_TEST_TABLE_NAME, $this->object->getName());
+       }
+
+       /**
+        * @covers pq\Gateway\Table::find
+        */
+       public function testFind() {
+               $rowset = $this->object->find();
+               $this->assertInstanceOf("\\pq\\Gateway\\Rowset", $rowset);
+               $rowset = $this->object->find(array("id = " => 1));
+               $this->assertInstanceOf("\\pq\\Gateway\\Rowset", $rowset);
+               $rowset = $this->object->find(array("id = " => 0));
+               $this->assertInstanceOf("\\pq\\Gateway\\Rowset", $rowset);
+               $rowset = $this->object->find(array(array("id<" => 2), array("id>" => 2)));
+               $this->assertInstanceOf("\\pq\\Gateway\\Rowset", $rowset);
+       }
+
+       /**
+        * @covers pq\Gateway\Table::create
+        */
+       public function testCreate() {
+               $rowset = $this->object->create(array("id" => new \pq\Query\Expr("DEFAULT")));
+               $this->assertInstanceOf("\\pq\\Gateway\\Rowset", $rowset);
+               $this->assertCount(1, $rowset);
+       }
+
+       /**
+        * @covers pq\Gateway\Table::update
+        */
+       public function testUpdate() {
+               $row = $this->object->create(array())->current();
+               $data = array(
+                       "created" => "2013-03-03 03:03:03",
+                       "counter" => 2,
+                       "number" => 2.2,
+                       "data" => "this is a test",
+               );
+               $row = $this->object->update(array("id = " => $row->id), $data)->current();
+               $data = array("id" => $row->id->get()) + $data;
+               $this->assertSame(array_map(function($v){return strval($v);}, $data), $row->getData());
+       }
+
+       /**
+        * @covers pq\Gateway\Table::delete
+        */
+       public function testDelete() {
+               $this->object->delete(array("id!=" => 0));
+               $this->assertCount(0, $this->object->find());
+       }
+
+}
diff --git a/tests/setup.inc b/tests/setup.inc
new file mode 100644 (file)
index 0000000..798d4a4
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+define("PQ_DSN", "");
+define("PQ_TEST_TABLE_NAME", "test");
+define("PQ_TEST_CREATE_TABLE", sprintf(
+<<<SQL
+       create table %s (
+               id serial primary key, 
+               created timestamp, 
+               counter int, 
+               number decimal, 
+               data text
+       )
+SQL
+       , PQ_TEST_TABLE_NAME));
+define("PQ_TEST_DROP_TABLE", sprintf("drop table if exists %s", PQ_TEST_TABLE_NAME));
+define("PQ_TEST_CREATE_DATA", sprintf(
+<<<SQL
+       insert into %1\$s values (default, 'yesterday', -1, -1.1, 'yesterday');
+       insert into %1\$s values (default, 'today', 0, 0, 'today');
+       insert into %1\$s values (default, 'tomorrow', 1, 1.1, 'tomorrow');
+SQL
+       , PQ_TEST_TABLE_NAME
+));
+
+spl_autoload_register(function($c) {
+       if (substr($c,0,3) == "pq\\") return require_once sprintf("%s/../lib/%s.php", __DIR__, strtr($c, "\\", "/"));
+});