--- /dev/null
+<?php
+
+spl_autoload_register(function($c) {
+ if (substr($c, 0, 10) === "pq\\Gateway" || susbtr($c, 0, 8) === "pq\\Query") {
+ return include __DIR__ . "/" . strtr($c, "\\", "/") . ".php";
+ }
+});
*/
public static $defaultResolver;
+ /**
+ * @var \pq\Gateway\Table\CacheInterface
+ */
+ public static $defaultMetadataCache;
+
/**
* @var \pq\Connection
*/
*/
protected $relations;
+ /**
+ * @var \pq\Gateway\Table\CacheInterface
+ */
+ protected $metadataCache;
+
/**
* @param string $table
* @return \pq\Gateway\Table
$this->conn = $conn ?: static::$defaultConnection ?: new \pq\Connection;
}
+ /**
+ * Get the complete PostgreSQL connection string
+ * @return string
+ */
+ function __toString() {
+ return sprintf("postgresql://%s:%s@%s:%d/%s?%s#%s",
+ $this->conn->user,
+ $this->conn->pass,
+ $this->conn->host,
+ $this->conn->port,
+ $this->conn->db,
+ $this->conn->options,
+ $this->getName()
+ );
+ }
+
/**
* Set the rowset prototype
* @param mixed $rowset
return $this->exec;
}
+ /**
+ * Get the metadata cache
+ * @return \pq\Gateway\Table\CacheInterface
+ */
+ function getMetadataCache() {
+ if (!isset($this->metadatCache)) {
+ $this->metadataCache = static::$defaultMetadataCache ?: new Table\StaticCache;
+ }
+ return $this->metadataCache;
+ }
+
+ /**
+ * Set the metadata cache
+ * @param \pq\Gateway\Table\CacheInterface $cache
+ */
+ function setMetadataCache(Table\CacheInterface $cache) {
+ $this->metadataCache = $cache;
+ return $this;
+ }
+
/**
* Get foreign key relations
* @param string $to fkey
* @return mixed
*/
protected function execute(QueryWriter $query) {
- echo $query,"\n",json_encode($query->getParams()),"\n";
return $this->getQueryExecutor()->execute($query, array($this, "onResult"));
}
--- /dev/null
+<?php
+
+namespace pq\Gateway\Table;
+
+interface CacheInterface
+{
+ /**
+ * Set an item
+ * @param string $key
+ * @param mixed $val
+ * @param int $ttl
+ * @return \pq\Gateway\Table\CacheInterface
+ */
+ function set($key, $val, $ttl = 0);
+
+ /**
+ * Get an item
+ * @param string $key
+ * @param bool $exists
+ * @return mixed
+ */
+ function get($key, &$exists = null);
+
+ /**
+ * Delete an item
+ * @param string $key
+ * @return \pq\Gateway\Table\CacheInterface
+ */
+ function del($key);
+}
,att2.attname as "referencedColumn"
from
pg_constraint co
- ,pg_class cl2
,pg_class cl1
- ,pg_attribute att2
+ ,pg_class cl2
,pg_attribute att1
+ ,pg_attribute att2
where
( cl1.relname = \$1
or cl2.relname = \$1)
and co.confrelid != 0
-and co.confrelid = cl2.oid
and co.conrelid = cl1.oid
-and co.confkey[1] = att2.attnum and cl2.oid = att2.attrelid
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
public $references;
function __construct(Table $table) {
- // FIXME cache
- $this->references = $table->getConnection()
- ->execParams(RELATION_SQL, array($table->getName()))
- ->map(array(0,1), array(2,3,4), \pq\Result::FETCH_OBJECT);
+ $cache = $table->getMetadataCache();
+ if (!($this->references = $cache->get("$table:references"))) {
+ $this->references = $table->getConnection()
+ ->execParams(RELATION_SQL, array($table->getName()))
+ ->map(array(0,1), array(2,3,4), \pq\Result::FETCH_OBJECT);
+ $cache->set("$table:references", $this->references);
+ }
}
function __isset($r) {
--- /dev/null
+<?php
+
+namespace pq\Gateway\Table;
+
+class StaticCache implements CacheInterface
+{
+ protected static $cache = array();
+
+ /**
+ * @inheritdoc
+ * @param string $key
+ * @param bool $exists
+ * @return mixed
+ */
+ function get($key, &$exists = null) {
+ if (($exists = array_key_exists($key, static::$cache))) {
+ list($ttl, $data) = static::$cache[$key];
+ if ($ttl && $ttl < time()) {
+ unset(static::$cache[$key]);
+ $exists = false;
+ return null;
+ }
+ return $data;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ * @param string $key
+ * @param mixed $val
+ * @param int $ttl
+ * @return \pq\Gateway\Table\StaticCache
+ */
+ function set($key, $val, $ttl = 0) {
+ static::$cache[$key] = array(
+ $ttl ? $ttl + time() : 0,
+ $val
+ );
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ * @param string $key
+ * @return \pq\Gateway\Table\StaticCache
+ */
+ function del($key) {
+ unset(static::$cache[$key]);
+ return $this;
+ }
+}
protected $table;
protected function setUp() {
- $this->conn = new \pq\Connection(PQ_DSN);
- $this->conn->exec(PQ_TEST_DROP_TABLE);
- $this->conn->exec(PQ_TEST_CREATE_TABLE);
- $this->conn->exec(PQ_TEST_CREATE_DATA);
- $this->table = new Table(PQ_TEST_TABLE_NAME, $this->conn);
+ $this->conn = new \pq\Connection(PQ_TEST_DSN);
+ $this->conn->exec(PQ_TEST_TABLE_CREATE);
+ $this->conn->exec(PQ_TEST_REFTABLE_CREATE);
+ $this->conn->exec(PQ_TEST_DATA);
+ Table::$defaultConnection = $this->conn;
+ $this->table = new Table("test");
}
protected function tearDown() {
- $this->conn->exec(PQ_TEST_DROP_TABLE);
+ $this->conn->exec(PQ_TEST_REFTABLE_DROP);
+ $this->conn->exec(PQ_TEST_TABLE_DROP);
}
/**
- * This is very bad test…
+ * This is a very bad test…
*/
public function testBasic() {
$row = $this->table->find(null, "id desc", 1)->current();
protected $table;
protected function setUp() {
- $this->conn = new \pq\Connection(PQ_DSN);
- $this->conn->exec(PQ_TEST_DROP_TABLE);
- $this->conn->exec(PQ_TEST_CREATE_TABLE);
- $this->conn->exec(PQ_TEST_CREATE_DATA);
-
- $this->table = new Table(PQ_TEST_TABLE_NAME, $this->conn);
+ $this->conn = new \pq\Connection(PQ_TEST_DSN);
+ $this->conn->exec(PQ_TEST_TABLE_CREATE);
+ $this->conn->exec(PQ_TEST_REFTABLE_CREATE);
+ $this->conn->exec(PQ_TEST_DATA);
+ Table::$defaultConnection = $this->conn;
+ $this->table = new Table("test");
}
protected function tearDown() {
- $this->conn->exec(PQ_TEST_DROP_TABLE);
+ $this->conn->exec(PQ_TEST_REFTABLE_DROP);
+ $this->conn->exec(PQ_TEST_TABLE_DROP);
}
function testBasic() {
protected $table;
protected function setUp() {
- $this->conn = new \pq\Connection(PQ_DSN);
- $this->conn->exec(PQ_TEST_DROP_TABLE);
- $this->conn->exec(PQ_TEST_CREATE_TABLE);
- $this->conn->exec(PQ_TEST_CREATE_DATA);
-
- $this->table = new Table(PQ_TEST_TABLE_NAME, $this->conn);
+ $this->conn = new \pq\Connection(PQ_TEST_DSN);
+ $this->conn->exec(PQ_TEST_TABLE_CREATE);
+ $this->conn->exec(PQ_TEST_REFTABLE_CREATE);
+ $this->conn->exec(PQ_TEST_DATA);
+ Table::$defaultConnection = $this->conn;
+ $this->table = new Table("test");
}
protected function tearDown() {
- $this->conn->exec(PQ_TEST_DROP_TABLE);
+ $this->conn->exec(PQ_TEST_REFTABLE_DROP);
+ $this->conn->exec(PQ_TEST_TABLE_DROP);
}
public function test__invoke() {
protected $table;
protected function setUp() {
- $this->conn = new \pq\Connection(PQ_DSN);
- $this->conn->exec(PQ_TEST_DROP_TABLE);
- $this->conn->exec(PQ_TEST_CREATE_TABLE);
+ $this->conn = new \pq\Connection(PQ_TEST_DSN);
+ $this->conn->exec(PQ_TEST_TABLE_CREATE);
+ $this->conn->exec(PQ_TEST_REFTABLE_CREATE);
+ $this->conn->exec(PQ_TEST_DATA);
Table::$defaultConnection = $this->conn;
- $this->table = new Table(PQ_TEST_TABLE_NAME);
+ $this->table = new Table("test");
}
protected function tearDown() {
- $this->conn->exec(PQ_TEST_DROP_TABLE);
+ $this->conn->exec(PQ_TEST_REFTABLE_DROP);
+ $this->conn->exec(PQ_TEST_TABLE_DROP);
}
- protected function createTestData() {
- $this->conn->exec(PQ_TEST_CREATE_DATA);
- }
-
public function testSetRowsetPrototype() {
$prop = new \ReflectionProperty("\\pq\\Gateway\\Table", "rowset");
$prop->setAccessible(true);
}
public function testGetName() {
- $this->assertSame(PQ_TEST_TABLE_NAME, $this->table->getName());
+ $this->assertSame("test", $this->table->getName());
}
public function testFind() {
<?php
-define("PQ_DSN", "");
-define("PQ_TEST_TABLE_NAME", "test");
-define("PQ_TEST_CREATE_TABLE", sprintf(
-<<<SQL
- create table %s (
+const PQ_TEST_DSN = "";
+
+const PQ_TEST_TABLE_CREATE = <<<SQL
+ drop table if exists test cascade;
+ create table test (
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
-));
+SQL;
+
+const PQ_TEST_TABLE_DROP = <<<SQL
+ drop table if exists test cascade;
+SQL;
+
+const PQ_TEST_REFTABLE_CREATE = <<<SQL
+ drop table if exists reftest cascade;
+ create table reftest (
+ test_id integer not null references test on delete cascade,
+ another_test_id integer not null references test on delete cascade
+ );
+SQL;
+
+const PQ_TEST_REFTABLE_DROP = <<<SQL
+ drop table if exists reftest cascade;
+SQL;
+
+const PQ_TEST_DATA = <<<SQL
+ insert into test values (default, 'yesterday', -1, -1.1, 'yesterday');
+ insert into test values (default, 'today', 0, 0, 'today');
+ insert into test values (default, 'tomorrow', 1, 1.1, 'tomorrow');
+
+ insert into reftest values (1,3);
+ insert into reftest values (2,2);
+ insert into reftest values (3,1);
+SQL;
spl_autoload_register(function($c) {
if (substr($c,0,3) == "pq\\") return require_once sprintf("%s/../lib/%s.php", __DIR__, strtr($c, "\\", "/"));