Commit e3df19d9 by Carsten Brandt

Redis AR WIP

- introduced RecordSchema class for schema definition
parent 82dc3b12
......@@ -268,7 +268,7 @@ class ActiveRecord extends Model
*/
public static function tableName()
{
return 'tbl_' . Inflector::camel2id(StringHelper::basename(get_called_class()), '_');
return static::getTableSchema()->name;
}
/**
......
......@@ -112,7 +112,7 @@ class ActiveQuery extends \yii\base\Component
}
$rows = array();
foreach($primaryKeys as $pk) {
$key = $modelClass::tableName() . ':a:' . (is_array($pk) ? implode('-', $pk) : $pk); // TODO escape PK glue
$key = $modelClass::tableName() . ':a:' . $modelClass::hashPk($pk);
// get attributes
$data = $db->executeCommand('HGETALL', array($key));
$row = array();
......@@ -148,7 +148,7 @@ class ActiveQuery extends \yii\base\Component
$primaryKeys = $db->executeCommand('LRANGE', array($modelClass::tableName(), $start, $start + 1));
}
$pk = reset($primaryKeys);
$key = $modelClass::tableName() . ':a:' . (is_array($pk) ? implode('-', $pk) : $pk); // TODO escape PK glue
$key = $modelClass::tableName() . ':a:' . $modelClass::hashPk($pk);
// get attributes
$data = $db->executeCommand('HGETALL', array($key));
if ($data === array()) {
......
......@@ -20,7 +20,7 @@ use yii\db\TableSchema;
/**
* ActiveRecord is the base class for classes representing relational data in terms of objects.
*
* @include @yii/db/ActiveRecord.md
*
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
......@@ -68,31 +68,19 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
return $query;
}
public static function hashPk($pk)
{
return (is_array($pk) ? implode('-', $pk) : $pk); // TODO escape PK glue
}
/**
* Creates an [[ActiveQuery]] instance with a given SQL statement.
*
* Note that because the SQL statement is already specified, calling additional
* query modification methods (such as `where()`, `order()`) on the created [[ActiveQuery]]
* instance will have no effect. However, calling `with()`, `asArray()` or `indexBy()` is
* still fine.
*
* Below is an example:
*
* ~~~
* $customers = Customer::findBySql('SELECT * FROM tbl_customer')->all();
* ~~~
*
* @param string $sql the SQL statement to be executed
* @param array $params parameters to be bound to the SQL statement during execution.
* @return ActiveQuery the newly created [[ActiveQuery]] instance
* @inheritdoc
*/
public static function findBySql($sql, $params = array())
{
throw new NotSupportedException('findBySql() is not supported by redis ActiveRecord');
}
/**
* Creates an [[ActiveQuery]] instance.
* This method is called by [[find()]], [[findBySql()]] and [[count()]] to start a SELECT query.
......@@ -107,6 +95,14 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
));
}
/**
* Declares the name of the database table associated with this AR class.
* @return string the table name
*/
public static function tableName()
{
return static::getTableSchema()->name;
}
/**
* Returns the schema information of the DB table associated with this AR class.
......@@ -114,6 +110,7 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
*/
public static function getTableSchema()
{
// TODO should be cached
throw new InvalidConfigException(__CLASS__.'::getTableSchema() needs to be overridden in subclasses and return a TableSchema.');
}
......@@ -173,9 +170,9 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
}
// }
// save pk in a findall pool
$db->executeCommand('RPUSH', array(static::tableName(), implode('-', $pk))); // TODO escape PK glue
$db->executeCommand('RPUSH', array(static::tableName(), static::hashPk($pk)));
$key = static::tableName() . ':a:' . implode('-', $pk); // TODO escape PK glue
$key = static::tableName() . ':a:' . static::hashPk($pk);
// save attributes
$args = array($key);
foreach($values as $attribute => $value) {
......@@ -216,7 +213,7 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
}
$n=0;
foreach($condition as $pk) {
$key = static::tableName() . ':a:' . (is_array($pk) ? implode('-', $pk) : $pk); // TODO escape PK glue
$key = static::tableName() . ':a:' . static::hashPk($pk);
// save attributes
$args = array($key);
foreach($attributes as $attribute => $value) {
......@@ -257,7 +254,7 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
}
$n=0;
foreach($condition as $pk) { // TODO allow multiple pks as condition
$key = static::tableName() . ':a:' . (is_array($pk) ? implode('-', $pk) : $pk); // TODO escape PK glue
$key = static::tableName() . ':a:' . static::hashPk($pk);
foreach($counters as $attribute => $value) {
$db->executeCommand('HINCRBY', array($key, $attribute, $value));
}
......@@ -292,13 +289,11 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
}
$attributeKeys = array();
foreach($condition as $pk) {
if (is_array($pk)) {
$pk = implode('-', $pk);
}
$db->executeCommand('LREM', array(static::tableName(), 0, $pk)); // TODO escape PK glue
$attributeKeys[] = static::tableName() . ':a:' . $pk; // TODO escape PK glue
$pk = static::hashPk($pk);
$db->executeCommand('LREM', array(static::tableName(), 0, $pk));
$attributeKeys[] = static::tableName() . ':a:' . $pk;
}
return $db->executeCommand('DEL', $attributeKeys);
return $db->executeCommand('DEL', $attributeKeys);// TODO make this atomic or document as NOT
}
/**
......
......@@ -12,6 +12,7 @@ namespace yii\db\redis;
use \yii\base\Component;
use yii\base\InvalidConfigException;
use \yii\db\Exception;
use yii\helpers\Inflector;
use yii\helpers\StringHelper;
/**
......@@ -337,7 +338,7 @@ class Connection extends Component
*/
public function __call($name, $params)
{
$redisCommand = strtoupper(StringHelper::camel2words($name, false));
$redisCommand = strtoupper(Inflector::camel2words($name, false));
if (in_array($redisCommand, $this->redisCommands)) {
return $this->executeCommand($name, $params);
} else {
......
<?php
/**
*
*
* @author Carsten Brandt <mail@cebe.cc>
*/
namespace yii\db\redis;
use yii\base\InvalidConfigException;
use yii\db\TableSchema;
/**
* Class RecordSchema defines the data schema for a redis active record
*
* As there is no schema in a redis DB this class is used to define one.
*
* @package yii\db\redis
*/
class RecordSchema extends TableSchema
{
/**
* @var string[] column names.
*/
public $columns = array();
/**
* @return string the column type
*/
public function getColumn($name)
{
parent::getColumn($name);
}
public function init()
{
if (empty($this->name)) {
throw new InvalidConfigException('name of RecordSchema must not be empty.');
}
if (empty($this->primaryKey)) {
throw new InvalidConfigException('primaryKey of RecordSchema must not be empty.');
}
if (!is_array($this->primaryKey)) {
$this->primaryKey = array($this->primaryKey);
}
foreach($this->primaryKey as $pk) {
if (!isset($this->columns[$pk])) {
throw new InvalidConfigException('primaryKey '.$pk.' is not a colum of RecordSchema.');
}
}
}
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
namespace yiiunit\data\ar\redis;
use yii\db\TableSchema;
use yii\db\redis\RecordSchema;
class Customer extends ActiveRecord
{
......@@ -21,7 +21,8 @@ class Customer extends ActiveRecord
public static function getTableSchema()
{
return new TableSchema(array(
return new RecordSchema(array(
'name' => 'customer',
'primaryKey' => array('id'),
'columns' => array(
'id' => 'integer',
......
......@@ -2,19 +2,19 @@
namespace yiiunit\data\ar\redis;
use yii\db\TableSchema;
use yii\db\redis\RecordSchema;
class Item extends ActiveRecord
{
public static function tableName()
{
return 'tbl_item';
}
public static function getTableSchema()
{
return new TableSchema(array(
return new RecordSchema(array(
'name' => 'item',
'primaryKey' => array('id'),
'sequenceName' => 'id',
'foreignKeys' => array(
// TODO for defining relations
),
'columns' => array(
'id' => 'integer',
'name' => 'string',
......
......@@ -2,15 +2,10 @@
namespace yiiunit\data\ar\redis;
use yii\db\TableSchema;
use yii\db\redis\RecordSchema;
class Order extends ActiveRecord
{
public static function tableName()
{
return 'tbl_order';
}
public function getCustomer()
{
return $this->hasOne('Customer', array('id' => 'customer_id'));
......@@ -49,7 +44,8 @@ class Order extends ActiveRecord
public static function getTableSchema()
{
return new TableSchema(array(
return new RecordSchema(array(
'name' => 'orders',
'primaryKey' => array('id'),
'columns' => array(
'id' => 'integer',
......
......@@ -2,15 +2,10 @@
namespace yiiunit\data\ar\redis;
use yii\db\TableSchema;
use yii\db\redis\RecordSchema;
class OrderItem extends ActiveRecord
{
public static function tableName()
{
return 'tbl_order_item';
}
public function getOrder()
{
return $this->hasOne('Order', array('id' => 'order_id'));
......@@ -23,7 +18,8 @@ class OrderItem extends ActiveRecord
public static function getTableSchema()
{
return new TableSchema(array(
return new RecordSchema(array(
'name' => 'order_item',
'primaryKey' => array('order_id', 'item_id'),
'columns' => array(
'order_id' => 'integer',
......
......@@ -9,10 +9,31 @@ use yiiunit\data\ar\redis\OrderItem;
use yiiunit\data\ar\redis\Order;
use yiiunit\data\ar\redis\Item;
/*
Users:
1 - user1
2 - user2
3 - user3
Items: 1-5
Order: 1-3
OrderItem:
1 - order: 1
2 - order: 1
3 - order: 2
4 - order: 2
5 - order: 2
6 - order: 3
*/
class ActiveRecordTest extends RedisTestCase
{
public function setUp()
{
parent::setUp();
ActiveRecord::$db = $this->getConnection();
$customer = new Customer();
......@@ -72,8 +93,6 @@ class ActiveRecordTest extends RedisTestCase
$orderItem = new OrderItem();
$orderItem->setAttributes(array('order_id' => 3, 'item_id' => 2, 'quantity' => 1, 'subtotal' => 40.0), false);
$orderItem->save(false);
parent::setUp();
}
public function testFind()
......@@ -332,6 +351,8 @@ class ActiveRecordTest extends RedisTestCase
$this->assertFalse($customer->isNewRecord);
}
// TODO test serial column incr
public function testUpdate()
{
// save
......
......@@ -4,7 +4,7 @@ namespace yiiunit\framework\db\redis;
use yii\db\redis\Connection;
class ConnectionTest extends RedisTestCase
class RedisConnectionTest extends RedisTestCase
{
/**
* Empty DSN should throw exception
......
......@@ -12,7 +12,10 @@ class RedisTestCase extends TestCase
{
protected function setUp()
{
$params = $this->getParam('redis');
$this->mockApplication();
$databases = $this->getParam('databases');
$params = isset($databases['redis']) ? $databases['redis'] : null;
if ($params === null || !isset($params['dsn'])) {
$this->markTestSkipped('No redis server connection configured.');
}
......@@ -34,7 +37,8 @@ class RedisTestCase extends TestCase
*/
public function getConnection($reset = true)
{
$params = $this->getParam('redis');
$databases = $this->getParam('databases');
$params = isset($databases['redis']) ? $databases['redis'] : array();
$db = new \yii\db\redis\Connection;
$db->dsn = $params['dsn'];
$db->password = $params['password'];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment