<?php
spl_autoload_register(function($c) {
- if (substr($c, 0, 10) === "pq\\Gateway" || susbtr($c, 0, 8) === "pq\\Query") {
+ if (substr($c, 0, 10) === "pq\\Gateway" || substr($c, 0, 8) === "pq\\Query") {
return include __DIR__ . "/" . strtr($c, "\\", "/") . ".php";
}
});
}
/**
- * Export current state with security sensitive data removed. You should override that, just
- * calls export() by default.
+ * Export current state with security sensitive data removed. You should override that.
+ * Just calls export() by default.
* @return array
*/
function exportPublic() {
$where["$col IS"] = new QueryExpr("NULL");
}
}
-
- if (($lock = $this->getTable()->getLock())) {
- $lock->criteria($this, $where);
- }
return $where;
}
* @return \pq\Gateway\Row
*/
function update() {
- $rowset = $this->table->update($this->criteria(), $this->changes());
+ $criteria = $this->criteria();
+ if (($lock = $this->getTable()->getLock())) {
+ $lock->onUpdate($this, $criteria);
+ }
+ $rowset = $this->table->update($criteria, $this->changes());
if (!count($rowset)) {
throw new \UnexpectedValueException("No row updated");
}
namespace pq\Gateway;
+use \pq\Query\Expr as QueryExpr;
use \pq\Query\Writer as QueryWriter;
use \pq\Query\Executor as QueryExecutor;
* @param \pq\Connection $conn
* @param array $dependents
*/
- function __construct($name, \pq\Connection $conn = null) {
- $this->name = $name;
+ function __construct($name = null, \pq\Connection $conn = null) {
+ if (isset($name)) {
+ $this->name = $name;
+ } elseif (!isset($this->name)) {
+ throw new \InvalidArgumentException("Table must have a name");
+ }
$this->conn = $conn ?: static::$defaultConnection ?: new \pq\Connection;
}
$order, $limit, $offset
);
}
+
+ /**
+ * Get rows dependent on other rows by foreign keys
+ * @param array $relations
+ * @param array $where
+ * @param string $order
+ * @param int $limit
+ * @param int $offset
+ * @return mixed
+ */
+ function with(array $relations, array $where = null, $order = null, $limit = 0, $offset = 0) {
+ $qthis = $this->conn->quoteName($this->getName());
+ $query = $this->getQueryWriter()->reset();
+ $query->write("SELECT", "$qthis.*", "FROM", $qthis);
+ foreach ($relations as $relation) {
+ $query->write("JOIN", $relation->foreignTable)->write("ON")->criteria(
+ array(
+ "{$relation->referencedTable}.{$relation->referencedColumn}=" =>
+ new QueryExpr("{$relation->foreignTable}.{$relation->foreignColumn}")
+ )
+ );
+ }
+ if ($where) {
+ $query->write("WHERE")->criteria($where);
+ }
+ if ($order) {
+ $query->write("ORDER BY", $order);
+ }
+ if ($limit) {
+ $query->write("LIMIT", $limit);
+ }
+ if ($offset) {
+ $query->write("OFFSET", $offset);
+ }
+ return $this->execute($query);
+ }
/**
* Insert a row into the table
use \pq\Gateway\Row;
+/**
+ * Lazy row lock on update/delete
+ */
interface LockInterface
{
- function criteria(Row $row, array &$where);
+ function onUpdate(Row $row, array &$where);
}
}
/**
- * @implements LockInterface
+ * @inheritdoc
* @param \pq\Gateway\Row $row
* @param array $where reference to the criteria
*/
- function criteria(Row $row, array &$where) {
+ function onUpdate(Row $row, array &$where) {
$where["{$this->column}="] = $row->getData()[$this->column];
$row->{$this->column}->mod(+1);
}
* @param array $ignore
* @throws \UnexpectedValueException if the row has already been modified
*/
- function criteria(Row $row, array &$ignore) {
+ function onUpdate(Row $row, array &$ignore) {
$where = array();
foreach ($row->getIdentity() as $col => $val) {
if (isset($val)) {
$table->getQueryExecutor()->execute(
new \pq\Query\Writer(RELATION_SQL, array($table->getName())),
function($result) use($table, $cache) {
- $this->references = $result->map(array(0,1), array(2,3,4), \pq\Result::FETCH_OBJECT);
+ $this->references = $result->map(array(0,1), array(1,2,3,4), \pq\Result::FETCH_OBJECT);
$cache->set("$table#relations", $this->references);
}
);
function testOptimisticLockFail() {
$this->table->setLock(new Table\OptimisticLock("counter"));
$row = $this->table->find(null, null, 1)->current();
- $cnt = $row->counter->get();
$row->data = "foo";
executeInConcurrentTransaction(
$this->table->getQueryExecutor(),
function testRef() {
foreach ($this->table->find() as $row) {
foreach ($row->reftest() as $ref) {
- $this->assertEquals($row->id->get(), $ref->test->id->get());
+ $this->assertEquals($row->id->get(), $ref->test->current()->id->get());
}
}
}
$this->table->delete(array("id!=" => 0));
$this->assertCount(0, $this->table->find());
}
+
+ public function testWith() {
+ $relation = $this->table->getRelations("test")->reftest;
+ $rowset = $this->table->with([$relation], array("another_test_id=" => 2));
+ $this->assertCount(1, $rowset);
+ $this->assertEquals(array(
+ "id" => 2,
+ "created" => date_create("today")->format("Y-m-d H:i:s"),
+ "counter" => 0,
+ "number" => 0,
+ "data" => "today"
+ ), $rowset->current()->getData());
+ }
}
if (isset($result)) {
fprintf($this->fp, "[%s] R %s\n",
date_create()->format("Y-m-d H:i:s"),
- json_encode([
- "S" => $result->statusMessage,
- "N" => $result->numRows,
- "C" => $result->numCols,
- "A" => $result->affectedRows
- ]));
+ json_encode($result));
} elseif (($query = $executor->getQuery())) {
fprintf($this->fp, "[%s] Q %s %% %s\n",
date_create()->format("Y-m-d H:i:s"),