Commit 9c7d2b23 by Paul Klimov

Mongo Active Record and Active Query fixed.

parent 0f7ded8f
......@@ -19,4 +19,76 @@ use yii\db\ActiveQueryTrait;
class ActiveQuery extends Query implements ActiveQueryInterface
{
use ActiveQueryTrait;
/**
* Executes query and returns all results as an array.
* @param Connection $db the DB connection used to create the DB command.
* If null, the DB connection returned by [[modelClass]] will be used.
* @return array the query results. If the query results in nothing, an empty array will be returned.
*/
public function all($db = null)
{
$cursor = $this->buildCursor($db);
$rows = [];
foreach ($cursor as $row) {
$rows[] = $row;
}
if (!empty($rows)) {
$models = $this->createModels($rows);
if (!empty($this->with)) {
$this->findWith($this->with, $models);
}
return $models;
} else {
return [];
}
}
/**
* Executes query and returns a single row of result.
* @param Connection $db the DB connection used to create the DB command.
* If null, the DB connection returned by [[modelClass]] will be used.
* @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]],
* the query result may be either an array or an ActiveRecord object. Null will be returned
* if the query results in nothing.
*/
public function one($db = null)
{
$row = parent::one($db);
if ($row !== false) {
if ($this->asArray) {
$model = $row;
} else {
/** @var ActiveRecord $class */
$class = $this->modelClass;
$model = $class::create($row);
}
if (!empty($this->with)) {
$models = [$model];
$this->findWith($this->with, $models);
$model = $models[0];
}
return $model;
} else {
return null;
}
}
/**
* Returns the Mongo collection for this query.
* @param Connection $db Mongo connection.
* @return Collection collection instance.
*/
public function getCollection($db = null)
{
/** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass;
if ($db === null) {
$db = $modelClass::getDb();
}
if ($this->from === null) {
$this->from = $modelClass::collectionName();
}
return $db->getCollection($this->from);
}
}
\ No newline at end of file
......@@ -162,11 +162,7 @@ abstract class ActiveRecord extends Model
if (!array_key_exists('multiple', $options)) {
$options['multiple'] = true;
}
$data = [];
foreach ($counters as $name => $value) {
$data[$name]['$inc'] = $value;
}
return static::getCollection()->update($condition, $data, $options);
return static::getCollection()->update($condition, ['$inc' => $counters], $options);
}
/**
......@@ -470,13 +466,20 @@ abstract class ActiveRecord extends Model
/**
* Returns the list of all attribute names of the model.
* The default implementation will return all column names of the table associated with this AR class.
* This method must be overridden by child classes to define available attributes.
* Note: primary key attribute "_id" should be always present in returned array.
* For example:
* ~~~
* public function attributes()
* {
* return ['_id', 'name', 'address', 'status'];
* }
* ~~~
* @return array list of attribute names.
*/
public function attributes()
{
// TODO: declare attributes
return [];
throw new InvalidConfigException('The attributes() method of mongo ActiveRecord has to be implemented by child classes.');
}
/**
......
......@@ -182,7 +182,11 @@ class Query extends Component implements QueryInterface
public function one($db = null)
{
$cursor = $this->buildCursor($db);
if ($cursor->hasNext()) {
return $cursor->getNext();
} else {
return false;
}
}
/**
......
<?php
namespace yiiunit\data\ar\mongo;
/**
* Test Mongo ActiveRecord
*/
class ActiveRecord extends \yii\mongo\ActiveRecord
{
public static $db;
public static function getDb()
{
return self::$db;
}
}
\ No newline at end of file
<?php
namespace yiiunit\data\ar\mongo;
class Customer extends ActiveRecord
{
public static function collectionName()
{
return 'customer';
}
public function attributes()
{
return [
'_id',
'name',
'email',
'address',
'status',
];
}
public static function activeOnly($query)
{
$query->andWhere(['status' => 2]);
}
}
\ No newline at end of file
<?php
namespace yiiunit\extensions\mongo;
use yii\mongo\ActiveQuery;
use yiiunit\data\ar\mongo\ActiveRecord;
use yiiunit\data\ar\mongo\Customer;
/**
* @group mongo
*/
class ActiveRecordTest extends MongoTestCase
{
/**
* @var array[] list of test rows.
*/
protected $testRows = [];
protected function setUp()
{
parent::setUp();
ActiveRecord::$db = $this->getConnection();
$this->setUpTestRows();
}
protected function tearDown()
{
$this->dropCollection(Customer::collectionName());
parent::tearDown();
}
/**
* Sets up test rows.
*/
protected function setUpTestRows()
{
$collection = $this->getConnection()->getCollection('customer');
$rows = [];
for ($i = 1; $i <= 10; $i++) {
$rows[] = [
'name' => 'name' . $i,
'email' => 'email' . $i,
'address' => 'address' . $i,
'status' => $i,
];
}
$collection->batchInsert($rows);
$this->testRows = $rows;
}
// Tests :
public function testFind()
{
// find one
$result = Customer::find();
$this->assertTrue($result instanceof ActiveQuery);
$customer = $result->one();
$this->assertTrue($customer instanceof Customer);
// find all
$customers = Customer::find()->all();
$this->assertEquals(10, count($customers));
$this->assertTrue($customers[0] instanceof Customer);
$this->assertTrue($customers[1] instanceof Customer);
// find by _id
$testId = $this->testRows[0]['_id'];
$customer = Customer::find($testId);
$this->assertTrue($customer instanceof Customer);
$this->assertEquals($testId, $customer->_id);
// find by column values
$customer = Customer::find(['name' => 'name5']);
$this->assertTrue($customer instanceof Customer);
$this->assertEquals($this->testRows[4]['_id'], $customer->_id);
$this->assertEquals('name5', $customer->name);
$customer = Customer::find(['name' => 'unexisting name']);
$this->assertNull($customer);
// find by attributes
$customer = Customer::find()->where(['status' => 4])->one();
$this->assertTrue($customer instanceof Customer);
$this->assertEquals(4, $customer->status);
// find count, sum, average, min, max, scalar
$this->assertEquals(10, Customer::find()->count());
$this->assertEquals(1, Customer::find()->where(['status' => 2])->count());
/*$this->assertEquals((1+10)/2*10, Customer::find()->sum('status'));
$this->assertEquals((1+10)/2, Customer::find()->average('status'));
$this->assertEquals(1, Customer::find()->min('status'));
$this->assertEquals(10, Customer::find()->max('status'));*/
// scope
$this->assertEquals(1, Customer::find()->activeOnly()->count());
// asArray
$testRow = $this->testRows[2];
$customer = Customer::find()->where(['_id' => $testRow['_id']])->asArray()->one();
$this->assertEquals($testRow, $customer);
// indexBy
$customers = Customer::find()->indexBy('name')->all();
$this->assertTrue($customers['name1'] instanceof Customer);
$this->assertTrue($customers['name2'] instanceof Customer);
// indexBy callable
$customers = Customer::find()->indexBy(function ($customer) {
return $customer->status . '-' . $customer->status;
})->all();
$this->assertTrue($customers['1-1'] instanceof Customer);
$this->assertTrue($customers['2-2'] instanceof Customer);
}
public function testInsert()
{
$record = new Customer;
$record->name = 'new name';
$record->email = 'new email';
$record->address = 'new address';
$record->status = 7;
$this->assertTrue($record->isNewRecord);
$record->save();
$this->assertTrue($record->_id instanceof \MongoId);
$this->assertFalse($record->isNewRecord);
}
/**
* @depends testInsert
*/
public function testUpdate()
{
$record = new Customer;
$record->name = 'new name';
$record->email = 'new email';
$record->address = 'new address';
$record->status = 7;
$record->save();
// save
$record = Customer::find($record->_id);
$this->assertTrue($record instanceof Customer);
$this->assertEquals(7, $record->status);
$this->assertFalse($record->isNewRecord);
$record->status = 9;
$record->save();
$this->assertEquals(9, $record->status);
$this->assertFalse($record->isNewRecord);
$record2 = Customer::find($record->_id);
$this->assertEquals(9, $record2->status);
// updateAll
$pk = ['_id' => $record->_id];
//$ret = Customer::updateAll(['status' => 55], $pk);
$ret = Customer::updateAll(['$set' => ['status' => 55]], $pk);
$this->assertEquals(1, $ret);
$record = Customer::find($pk);
$this->assertEquals(55, $record->status);
}
/**
* @depends testInsert
*/
public function testDelete()
{
// delete
$record = new Customer;
$record->name = 'new name';
$record->email = 'new email';
$record->address = 'new address';
$record->status = 7;
$record->save();
$record = Customer::find($record->_id);
$record->delete();
$record = Customer::find($record->_id);
$this->assertNull($record);
// deleteAll
$record = new Customer;
$record->name = 'new name';
$record->email = 'new email';
$record->address = 'new address';
$record->status = 7;
$record->save();
$ret = Customer::deleteAll(['name' => 'new name']);
$this->assertEquals(1, $ret);
$records = Customer::find()->where(['name' => 'new name'])->all();
$this->assertEquals(0, count($records));
}
public function testUpdateAllCounters()
{
$this->assertEquals(1, Customer::updateAllCounters(['status' => 10], ['status' => 10]));
$record = Customer::find(['status' => 10]);
$this->assertNull($record);
}
/**
* @depends testUpdateAllCounters
*/
public function testUpdateCounters()
{
$record = Customer::find($this->testRows[9]);
$originalCounter = $record->status;
$counterIncrement = 20;
$record->updateCounters(['status' => $counterIncrement]);
$this->assertEquals($originalCounter + $counterIncrement, $record->status);
$refreshedRecord = Customer::find($record->_id);
$this->assertEquals($originalCounter + $counterIncrement, $refreshedRecord->status);
}
}
\ No newline at end of file
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