mirror of
https://github.com/espocrm/espocrm.git
synced 2026-07-01 08:26:04 +00:00
1282 lines
38 KiB
PHP
1282 lines
38 KiB
PHP
<?php
|
||
/************************************************************************
|
||
* This file is part of EspoCRM.
|
||
*
|
||
* EspoCRM – Open Source CRM application.
|
||
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||
* Website: https://www.espocrm.com
|
||
*
|
||
* This program is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU Affero General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU Affero General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Affero General Public License
|
||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of this program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU Affero General Public License version 3.
|
||
*
|
||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||
************************************************************************/
|
||
|
||
namespace tests\unit\Espo\ORM;
|
||
|
||
use Espo\ORM\CollectionFactory;
|
||
use Espo\ORM\EntityCollection;
|
||
use Espo\ORM\EntityFactory;
|
||
use Espo\ORM\EntityManager;
|
||
use Espo\ORM\Executor\DefaultQueryExecutor;
|
||
use Espo\ORM\Mapper\BaseMapper;
|
||
use Espo\ORM\Metadata;
|
||
use Espo\ORM\MetadataDataProvider;
|
||
use Espo\ORM\Query\Select;
|
||
use Espo\ORM\Query\SelectBuilder;
|
||
use Espo\ORM\QueryComposer\MysqlQueryComposer as QueryComposer;
|
||
use Espo\ORM\QueryComposer\QueryComposerWrapper;
|
||
use Espo\ORM\Executor\SqlExecutor;
|
||
use Espo\ORM\SthCollection;
|
||
|
||
use tests\unit\testData\DB\Comment;
|
||
use tests\unit\testData\DB\Note;
|
||
use tests\unit\testData\DB\Post;
|
||
use tests\unit\testData\DB\Tag;
|
||
|
||
use PDO;
|
||
use PDOStatement;
|
||
|
||
require_once 'tests/unit/testData/DB/Entities.php';
|
||
|
||
class MapperTest extends \PHPUnit\Framework\TestCase
|
||
{
|
||
protected $db;
|
||
protected $pdo;
|
||
protected $post;
|
||
protected $note;
|
||
protected $comment;
|
||
protected $entityFactory;
|
||
private ?CollectionFactory $collectionFactory = null;
|
||
|
||
protected function setUp() : void
|
||
{
|
||
$this->pdo = $this->getMockBuilder(PDO::class)->disableOriginalConstructor()->getMock();
|
||
$this->pdo
|
||
->expects($this->any())
|
||
->method('quote')
|
||
->will($this->returnCallback(function() {
|
||
$args = func_get_args();
|
||
|
||
return "'" . $args[0] . "'";
|
||
}));
|
||
|
||
$ormMetadata = include('tests/unit/testData/DB/ormMetadata.php');
|
||
|
||
$metadataDataProvider = $this->createMock(MetadataDataProvider::class);
|
||
|
||
$metadataDataProvider
|
||
->expects($this->any())
|
||
->method('get')
|
||
->willReturn($ormMetadata);
|
||
|
||
$this->metadata = new Metadata($metadataDataProvider);
|
||
|
||
$this->sqlExecutor = $this->createMock(SqlExecutor::class);
|
||
$entityManager = $this->createMock(EntityManager::class);
|
||
|
||
$entityManager
|
||
->method('getMetadata')
|
||
->will($this->returnValue($this->metadata));
|
||
|
||
$this->entityFactory = $this->createMock(EntityFactory::class);
|
||
|
||
$this->entityFactory
|
||
->expects($this->any())
|
||
->method('create')
|
||
->will($this->returnCallback(
|
||
function () use ($entityManager) {
|
||
$args = func_get_args();
|
||
|
||
$className = "tests\\unit\\testData\\DB\\" . $args[0];
|
||
|
||
$defs = $this->metadata->get($args[0]) ?? [];
|
||
|
||
return new $className($args[0], $defs, $entityManager);
|
||
}
|
||
));
|
||
|
||
$entityManager
|
||
->method('getEntityFactory')
|
||
->will($this->returnValue($this->entityFactory));
|
||
|
||
$entityFactory = $this->entityFactory;
|
||
|
||
$this->collectionFactory = $this->getMockBuilder(CollectionFactory::class)
|
||
->disableOriginalConstructor()
|
||
->getMock();
|
||
|
||
$this->query = new QueryComposer($this->pdo, $this->entityFactory, $this->metadata);
|
||
|
||
$queryExecutor = new DefaultQueryExecutor($this->sqlExecutor, new QueryComposerWrapper($this->query));
|
||
|
||
$this->db = new BaseMapper(
|
||
$this->pdo,
|
||
$this->entityFactory,
|
||
$this->collectionFactory,
|
||
$this->metadata,
|
||
$queryExecutor
|
||
);
|
||
|
||
$this->post = $entityFactory->create('Post');
|
||
$this->comment = $entityFactory->create('Comment');
|
||
$this->tag = $entityFactory->create('Tag');
|
||
$this->note = $entityFactory->create('Note');
|
||
$this->postData = $entityFactory->create('PostData');
|
||
|
||
$this->contact = $entityFactory->create('Contact');
|
||
$this->account = $entityFactory->create('Account');
|
||
$this->team = $entityFactory->create('Team');
|
||
}
|
||
|
||
protected function tearDown() : void
|
||
{
|
||
unset($this->pdo, $this->db, $this->post, $this->comment);
|
||
}
|
||
|
||
protected function createSthMock(array $data, bool $noIteration = false)
|
||
{
|
||
$sth = $this->getMockBuilder(PDOStatement::class)->disableOriginalConstructor()->getMock();
|
||
|
||
if (!$noIteration) {
|
||
$values = [];
|
||
|
||
foreach ($data as $i => $item) {
|
||
$values[] = $item;
|
||
}
|
||
|
||
$sth->expects($this->exactly(count($values)))
|
||
->method('fetch')
|
||
->willReturnOnConsecutiveCalls(...$values);
|
||
}
|
||
|
||
$sth->expects($this->any())
|
||
->method('fetchAll')
|
||
->will($this->returnValue($data));
|
||
|
||
return $sth;
|
||
}
|
||
|
||
protected function mockQuery(string $sql, $return = true, $any = false, bool $noIteration = false)
|
||
{
|
||
if ($any) {
|
||
$expects = $this->any();
|
||
} else {
|
||
$expects = $this->once();
|
||
}
|
||
|
||
if ($return === true) {
|
||
$return = $this->createSthMock([]);
|
||
} else
|
||
if (is_array($return)) {
|
||
$return = $this->createSthMock($return, $noIteration);
|
||
}
|
||
|
||
$this->sqlExecutor->expects($expects)
|
||
->method('execute')
|
||
->with($sql)
|
||
->will($this->returnValue($return));
|
||
}
|
||
|
||
protected function mockSqlCollection(string $entityType, string $sql, SthCollection $collection)
|
||
{
|
||
$this->collectionFactory
|
||
->expects($this->once())
|
||
->method('createFromSql')
|
||
->with($entityType, $sql)
|
||
->willReturn($collection);
|
||
}
|
||
|
||
protected function createCollectionMock(array $itemList) : SthCollection
|
||
{
|
||
$collection = $this->getMockBuilder(SthCollection::class)->disableOriginalConstructor()->getMock();
|
||
|
||
$itemList = $itemList ?? [];
|
||
|
||
$generator = (function () use ($itemList) {
|
||
foreach ($itemList as $item) {
|
||
yield $item;
|
||
}
|
||
})();
|
||
|
||
$collection
|
||
->expects($this->any())
|
||
->method('getIterator')
|
||
->will(
|
||
$this->returnValue($generator)
|
||
);
|
||
|
||
return $collection;
|
||
}
|
||
|
||
public function testSelectOne()
|
||
{
|
||
$query =
|
||
"SELECT post.id AS `id`, post.name AS `name`, NULLIF(TRIM(CONCAT(COALESCE(createdBy.salutation_name, ''), " .
|
||
"COALESCE(createdBy.first_name, ''), ' ', COALESCE(createdBy.last_name, ''))), '') AS `createdByName`, ".
|
||
"post.created_by_id AS `createdById`, post.deleted AS `deleted` ".
|
||
"FROM `post` AS `post` ".
|
||
"LEFT JOIN `user` AS `createdBy` ON post.created_by_id = createdBy.id " .
|
||
"WHERE post.id = '1' AND post.deleted = 0";
|
||
|
||
$return = [
|
||
[
|
||
'id' => '1',
|
||
'name' => 'test',
|
||
'deleted' => false,
|
||
],
|
||
];
|
||
|
||
$this->mockQuery($query, $return);
|
||
|
||
$select = Select::fromRaw([
|
||
'from' => 'Post',
|
||
'whereClause' => [
|
||
'id' => '1',
|
||
],
|
||
]);
|
||
|
||
$post = $this->db->selectOne($select);
|
||
|
||
$this->assertEquals($post->id, '1');
|
||
}
|
||
|
||
public function testSelect1(): void
|
||
{
|
||
$post1 = $this->entityFactory->create('Post');
|
||
$post1->set([
|
||
'id' => '2',
|
||
'name' => 'test_2',
|
||
'deleted' => false,
|
||
]);
|
||
|
||
$post2 = $this->entityFactory->create('Post');
|
||
$post2->set([
|
||
'id' => '1',
|
||
'name' => 'test_1',
|
||
'deleted' => false,
|
||
]);
|
||
|
||
$collection = $this->createCollectionMock([$post1, $post2]);
|
||
|
||
$query = Select::fromRaw([
|
||
'from' => 'Post',
|
||
'fromAlias' => 'post',
|
||
'whereClause' => [
|
||
'name' => 'test_1',
|
||
'OR' => [
|
||
'id' => '100',
|
||
'name*' => 'test_%',
|
||
],
|
||
'tags.name' => 'yoTag',
|
||
],
|
||
'order' => 'DESC',
|
||
'orderBy' => 'name',
|
||
'limit' => 10,
|
||
'joins' => [
|
||
'tags',
|
||
'comments',
|
||
],
|
||
]);
|
||
|
||
$this->collectionFactory
|
||
->expects($this->once())
|
||
->method('createFromQuery')
|
||
->with($query)
|
||
->willReturn($collection);
|
||
|
||
$list = $this->db->select($query);
|
||
|
||
$entity = null;
|
||
foreach ($list as $item) {
|
||
$entity = $item;
|
||
break;
|
||
}
|
||
|
||
$this->assertTrue($entity instanceof Post);
|
||
$this->assertTrue(isset($entity->id));
|
||
$this->assertEquals($entity->id, '2');
|
||
}
|
||
|
||
public function testSelectWithSpecifiedParams(): void
|
||
{
|
||
$contact = $this->entityFactory->create('Post');
|
||
$contact->set([
|
||
'id' => '1',
|
||
'name' => 'test',
|
||
'deleted' => false,
|
||
]);
|
||
|
||
$collection = $this->createCollectionMock([$contact]);
|
||
|
||
$query = Select::fromRaw([
|
||
'from' => 'Contact',
|
||
'fromAlias' => 'contact',
|
||
'whereClause' => [
|
||
'name*' => 'test%',
|
||
],
|
||
'order' => 'DESC',
|
||
'orderBy' => 'name',
|
||
'limit' => 10,
|
||
]);
|
||
|
||
$this->collectionFactory
|
||
->expects($this->once())
|
||
->method('createFromQuery')
|
||
->with($query)
|
||
->willReturn($collection);
|
||
|
||
$this->db->select($query);
|
||
}
|
||
|
||
public function testJoin(): void
|
||
{
|
||
$comment = $this->entityFactory->create('Comment');
|
||
$comment->set([
|
||
'id' => '11',
|
||
'postId' => '1',
|
||
'postName' => 'test',
|
||
'name' => 'test_comment',
|
||
'deleted' => false,
|
||
]);
|
||
|
||
$collection = $this->createCollectionMock([$comment]);
|
||
|
||
$query = Select::fromRaw([
|
||
'from' => 'Comment',
|
||
'fromAlias' => 'comment',
|
||
]);
|
||
|
||
$this->collectionFactory
|
||
->expects($this->once())
|
||
->method('createFromQuery')
|
||
->with($query)
|
||
->willReturn($collection);
|
||
|
||
$list = $this->db->select($query);
|
||
|
||
$entity = null;
|
||
foreach ($list as $item) {
|
||
$entity = $item;
|
||
break;
|
||
}
|
||
|
||
$this->assertTrue($entity instanceof Comment);
|
||
$this->assertTrue($entity->has('postName'));
|
||
$this->assertEquals($entity->get('postName'), 'test');
|
||
}
|
||
|
||
public function testSelectRelatedManyMany1()
|
||
{
|
||
$tag = $this->entityFactory->create('Tag');
|
||
$tag->set([
|
||
'id' => '1',
|
||
'name' => 'test',
|
||
'deleted' => false,
|
||
]);
|
||
$collection = $this->createCollectionMock([$tag]);
|
||
|
||
$this->post->id = '1';
|
||
|
||
$query = SelectBuilder::create()
|
||
->from('Tag', 'tag')
|
||
->select([
|
||
'*',
|
||
['postTag.role', 'postRole']
|
||
])
|
||
->join('PostTag', 'postTag', [
|
||
'tagId:' => 'id',
|
||
'postId' => '1',
|
||
'deleted' => false,
|
||
])
|
||
->where([])
|
||
->build();
|
||
|
||
$this->collectionFactory
|
||
->expects($this->once())
|
||
->method('createFromQuery')
|
||
->with($query)
|
||
->willReturn($collection);
|
||
|
||
$list = $this->db->selectRelated($this->post, 'tags');
|
||
|
||
$entity = null;
|
||
foreach ($list as $item) {
|
||
$entity = $item;
|
||
break;
|
||
}
|
||
|
||
$this->assertTrue($entity instanceof Tag);
|
||
$this->assertTrue($entity->has('name'));
|
||
$this->assertEquals($entity->get('name'), 'test');
|
||
}
|
||
|
||
public function testSelectRelatedManyMany2()
|
||
{
|
||
$select = Select::fromRaw([
|
||
'select' => ['id', 'postRole'],
|
||
'from' => 'Tag',
|
||
]);
|
||
|
||
$tag = $this->entityFactory->create('Tag');
|
||
$tag->set([
|
||
'id' => '1',
|
||
'name' => 'test',
|
||
'deleted' => false,
|
||
]);
|
||
$collection = $this->createCollectionMock([$tag]);
|
||
|
||
$this->post->id = '1';
|
||
|
||
$query = SelectBuilder::create()
|
||
->from('Tag', 'tag')
|
||
->select([
|
||
'id',
|
||
['postTag.role', 'postRole'],
|
||
])
|
||
->join('PostTag', 'postTag', [
|
||
'tagId:' => 'id',
|
||
'postId' => '1',
|
||
'deleted' => false,
|
||
])
|
||
->where([])
|
||
->build();
|
||
|
||
$this->collectionFactory
|
||
->expects($this->once())
|
||
->method('createFromQuery')
|
||
->with($query)
|
||
->willReturn($collection);
|
||
|
||
$this->db->selectRelated($this->post, 'tags', $select);
|
||
}
|
||
|
||
public function testSelectRelatedManyManyWithConditions()
|
||
{
|
||
$team = $this->entityFactory->create('Team');
|
||
$team->set([
|
||
'id' => '1',
|
||
'name' => 'test',
|
||
'deleted' => false,
|
||
]);
|
||
$collection = $this->createCollectionMock([$team]);
|
||
|
||
$this->account->id = '1';
|
||
|
||
$query = SelectBuilder::create()
|
||
->from('Team', 'team')
|
||
->select([
|
||
'*',
|
||
['entityTeam.teamId', 'stub'],
|
||
])
|
||
->join('EntityTeam', 'entityTeam', [
|
||
'teamId:' => 'id',
|
||
'entityId' => '1',
|
||
'entityType' => 'Account',
|
||
'deleted' => false,
|
||
])
|
||
->where([])
|
||
->build();
|
||
|
||
$this->collectionFactory
|
||
->expects($this->once())
|
||
->method('createFromQuery')
|
||
->with($query)
|
||
->willReturn($collection);
|
||
|
||
$select = Select::fromRaw([
|
||
'from' => 'Team',
|
||
'select' => [
|
||
'*',
|
||
['entityTeam.teamId', 'stub'],
|
||
],
|
||
]);
|
||
|
||
$this->db->selectRelated($this->account, 'teams', $select);
|
||
}
|
||
|
||
public function testSelectRelatedHasChildren()
|
||
{
|
||
$note = $this->entityFactory->create('Note');
|
||
|
||
$note->set([
|
||
'id' => '1',
|
||
'name' => 'test',
|
||
'deleted' => false,
|
||
]);
|
||
|
||
$collection = $this->createCollectionMock([$note]);
|
||
|
||
$query = SelectBuilder::create()
|
||
->from('Note', 'note')
|
||
->where([
|
||
['parentId' => '1'],
|
||
['parentType' => 'Post'],
|
||
])
|
||
->build();
|
||
|
||
$this->collectionFactory
|
||
->expects($this->once())
|
||
->method('createFromQuery')
|
||
->with($query)
|
||
->willReturn($collection);
|
||
|
||
$this->post->id = '1';
|
||
$list = $this->db->selectRelated($this->post, 'notes');
|
||
|
||
$entity = null;
|
||
|
||
foreach ($list as $item) {
|
||
$entity = $item;
|
||
break;
|
||
}
|
||
|
||
$this->assertTrue($entity instanceof Note);
|
||
$this->assertTrue($entity->has('name'));
|
||
$this->assertEquals($entity->get('name'), 'test');
|
||
}
|
||
|
||
public function testSelectRelatedBelongsTo()
|
||
{
|
||
$query =
|
||
"SELECT ".
|
||
"post.id AS `id`, post.name AS `name`, NULLIF(TRIM(CONCAT(COALESCE(createdBy.salutation_name, ''), ".
|
||
"COALESCE(createdBy.first_name, ''), ' ', COALESCE(createdBy.last_name, ''))), '') AS `createdByName`, ".
|
||
"post.created_by_id AS `createdById`, post.deleted AS `deleted` ".
|
||
"FROM `post` AS `post` ".
|
||
"LEFT JOIN `user` AS `createdBy` ON post.created_by_id = createdBy.id " .
|
||
"WHERE (post.id = '1') AND post.deleted = 0 ".
|
||
"LIMIT 0, 1";
|
||
$return = [
|
||
[
|
||
'id' => '1',
|
||
'name' => 'test',
|
||
'deleted' => false,
|
||
],
|
||
];
|
||
$this->mockQuery($query, $return);
|
||
|
||
$this->comment->id = '11';
|
||
$this->comment->set('postId', '1');
|
||
$post = $this->db->selectRelated($this->comment, 'post');
|
||
|
||
$this->assertTrue($post instanceof Post);
|
||
$this->assertTrue(($post->has('name')));
|
||
$this->assertEquals($post->get('name'), 'test');
|
||
}
|
||
|
||
public function testCountRelated()
|
||
{
|
||
$query =
|
||
"SELECT COUNT(tag.id) AS `value` ".
|
||
"FROM `tag` AS `tag` ".
|
||
"JOIN `post_tag` AS `postTag` ON postTag.tag_id = tag.id AND postTag.post_id = '1' AND postTag.deleted = 0 ".
|
||
"WHERE tag.deleted = 0";
|
||
|
||
$return = [
|
||
[
|
||
'value' => 1,
|
||
],
|
||
];
|
||
|
||
$this->mockQuery($query, $return);
|
||
|
||
$this->post->id = '1';
|
||
|
||
$count = $this->db->countRelated($this->post, 'tags');
|
||
|
||
$this->assertEquals($count, 1);
|
||
}
|
||
|
||
public function testCount1(): void
|
||
{
|
||
$sql = "SELECT COUNT(post.id) AS `value` FROM `post` AS `post` WHERE post.deleted = 0";
|
||
|
||
$select = SelectBuilder::create()
|
||
->from('Post')
|
||
->build();
|
||
|
||
$this->mockQuery($sql, ['value' => 1]);
|
||
|
||
$this->db->count($select);
|
||
}
|
||
|
||
public function testCountWithDistinct(): void
|
||
{
|
||
$sql = "SELECT COUNT(asq.id) AS `value` FROM (" .
|
||
"SELECT DISTINCT post.id AS `id` FROM `post` AS `post` WHERE post.deleted = 0" .
|
||
") AS `asq`";
|
||
|
||
$select = SelectBuilder::create()
|
||
->from('Post')
|
||
->distinct()
|
||
->order('id')
|
||
->build();
|
||
|
||
$this->mockQuery($sql, ['value' => 1]);
|
||
|
||
$this->db->count($select);
|
||
}
|
||
|
||
public function testInsert()
|
||
{
|
||
$query = "INSERT INTO `post` (`id`, `name`) VALUES ('1', 'test')";
|
||
$return = true;
|
||
|
||
$this->mockQuery($query, $return);
|
||
|
||
$this->post->reset();
|
||
$this->post->id = '1';
|
||
$this->post->set('name', 'test');
|
||
$this->post->set('privateField', 'dontStoreThis');
|
||
|
||
$this->db->insert($this->post);
|
||
}
|
||
|
||
public function testInsertUpdate()
|
||
{
|
||
$query =
|
||
"INSERT INTO `post` (`id`, `name`, `deleted`) VALUES ('1', 'test', 0) " .
|
||
"ON DUPLICATE KEY UPDATE `name` = 'test', `deleted` = 0";
|
||
$return = true;
|
||
$this->mockQuery($query, $return);
|
||
|
||
$this->post->reset();
|
||
$this->post->id = '1';
|
||
$this->post->set('name', 'test');
|
||
$this->post->set('deleted', false);
|
||
|
||
$this->db->insertOnDuplicateUpdate($this->post, ['name', 'deleted']);
|
||
}
|
||
|
||
public function testMassInsert()
|
||
{
|
||
$query = "INSERT INTO `post` (`id`, `name`) VALUES ('1', 'test1'), ('2', 'test2')";
|
||
$return = true;
|
||
$this->mockQuery($query, $return);
|
||
|
||
$post1 = $this->entityFactory->create('Post');
|
||
$post2 = $this->entityFactory->create('Post');
|
||
|
||
$post1->id = '1';
|
||
$post1->set('name', 'test1');
|
||
|
||
$post2->id = '2';
|
||
$post2->set('name', 'test2');
|
||
|
||
$collection = new EntityCollection([
|
||
$post1,
|
||
$post2,
|
||
]);
|
||
|
||
$this->db->massInsert($collection);
|
||
}
|
||
|
||
public function testUpdate1()
|
||
{
|
||
$query = "UPDATE `post` SET post.name = 'test' WHERE post.id = '1' AND post.deleted = 0";
|
||
$return = true;
|
||
$this->mockQuery($query, $return);
|
||
|
||
$this->post->reset();
|
||
$this->post->id = '1';
|
||
$this->post->set('name', 'test');
|
||
|
||
$this->db->update($this->post);
|
||
}
|
||
|
||
public function testUpdate2()
|
||
{
|
||
$query = "UPDATE `post` SET post.name = 'test', post.deleted = 0 WHERE post.id = '1' AND post.deleted = 0";
|
||
$return = true;
|
||
$this->mockQuery($query, $return);
|
||
|
||
$this->post->reset();
|
||
$this->post->id = '1';
|
||
$this->post->set('name', 'test');
|
||
$this->post->set('deleted', false);
|
||
|
||
$this->db->update($this->post);
|
||
}
|
||
|
||
public function testUpdateArray1()
|
||
{
|
||
$query = "UPDATE `job` SET job.array = '[\"2\",\"1\"]' WHERE job.id = '1' AND job.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$job = $this->entityFactory->create('Job');
|
||
$job->id = '1';
|
||
$job->setFetched('array', ['1', '2']);
|
||
$job->set('array', ['2', '1']);
|
||
|
||
$this->db->update($job);
|
||
}
|
||
|
||
public function testUpdateArray2()
|
||
{
|
||
$query = "UPDATE `job` SET job.array = NULL WHERE job.id = '1' AND job.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$job = $this->entityFactory->create('Job');
|
||
$job->id = '1';
|
||
$job->setFetched('array', ['1', '2']);
|
||
$job->set('array', null);
|
||
|
||
$this->db->update($job);
|
||
}
|
||
|
||
public function testRemoveManyToOne()
|
||
{
|
||
$query =
|
||
"UPDATE `comment` SET comment.post_id = NULL " .
|
||
"WHERE comment.id = 'commentId' AND comment.post_id = 'postId' AND comment.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->post->id = 'postId';
|
||
$this->comment->id = 'commentId';
|
||
|
||
$this->db->unrelate($this->comment, 'post', $this->post);
|
||
}
|
||
|
||
public function testRemoveAllManyToOne()
|
||
{
|
||
$query =
|
||
"UPDATE `comment` SET comment.post_id = NULL " .
|
||
"WHERE comment.id = 'commentId' AND comment.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->comment->id = 'commentId';
|
||
|
||
$this->db->unrelateAll($this->comment, 'post');
|
||
}
|
||
|
||
public function testRemoveChildrenToParent()
|
||
{
|
||
$query =
|
||
"UPDATE `note` SET note.parent_id = NULL, note.parent_type = NULL " .
|
||
"WHERE note.id = 'noteId' AND note.parent_id = 'postId' AND note.parent_type = 'Post' AND note.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->note->id = 'noteId';
|
||
$this->post->id = 'postId';
|
||
|
||
$this->db->unrelate($this->note, 'parent', $this->post);
|
||
}
|
||
|
||
public function testRemoveAllChildrenToParent()
|
||
{
|
||
$query =
|
||
"UPDATE `note` SET note.parent_id = NULL, note.parent_type = NULL " .
|
||
"WHERE note.id = 'noteId' AND note.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->note->id = 'noteId';
|
||
$this->db->unrelateAll($this->note, 'parent');
|
||
}
|
||
|
||
public function testRemoveOneToMany()
|
||
{
|
||
$query =
|
||
"UPDATE `comment` SET comment.post_id = NULL " .
|
||
"WHERE comment.id = 'commentId' AND comment.post_id = 'postId' AND comment.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->post->id = 'postId';
|
||
|
||
$this->db->unrelateById($this->post, 'comments', 'commentId');
|
||
}
|
||
|
||
public function testRemoveAllOneToMany()
|
||
{
|
||
$query =
|
||
"UPDATE `comment` SET comment.post_id = NULL " .
|
||
"WHERE comment.post_id = 'postId' AND comment.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->post->id = 'postId';
|
||
|
||
$this->db->unrelateAll($this->post, 'comments');
|
||
}
|
||
|
||
public function testRemoveOneToOne1()
|
||
{
|
||
$this->post->id = 'postId';
|
||
$this->postData->id = 'dataId';
|
||
|
||
$query =
|
||
"UPDATE `post_data` SET post_data.post_id = NULL " .
|
||
"WHERE post_data.post_id = 'postId' AND post_data.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->db->unrelateById($this->post, 'postData', 'dataId');
|
||
}
|
||
|
||
public function testRemovenParentToChildren()
|
||
{
|
||
$query =
|
||
"UPDATE `note` SET note.parent_id = NULL, note.parent_type = NULL " .
|
||
"WHERE note.id = 'noteId' AND note.parent_id = 'postId' AND note.parent_type = 'Post' AND note.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->post->id = 'postId';
|
||
|
||
$this->db->unrelateById($this->post, 'notes', 'noteId');
|
||
}
|
||
|
||
public function testRemoveAllParentToChildren()
|
||
{
|
||
$query =
|
||
"UPDATE `note` SET note.parent_id = NULL, note.parent_type = NULL " .
|
||
"WHERE note.parent_id = 'postId' AND note.parent_type = 'Post' AND note.deleted = 0";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->post->id = 'postId';
|
||
|
||
$this->db->unrelateAll($this->post, 'notes');
|
||
}
|
||
|
||
public function testRemoveManyMany()
|
||
{
|
||
$query = "UPDATE `post_tag` SET post_tag.deleted = 1 WHERE post_tag.post_id = '1' AND post_tag.tag_id = '100'";
|
||
$return = true;
|
||
$this->mockQuery($query, $return);
|
||
|
||
$this->post->id = '1';
|
||
|
||
$this->db->unrelateById($this->post, 'tags', '100');
|
||
}
|
||
|
||
public function testRemoveAllManyMany()
|
||
{
|
||
$query = "UPDATE `post_tag` SET post_tag.deleted = 1 WHERE post_tag.post_id = '1'";
|
||
$return = true;
|
||
$this->mockQuery($query, $return);
|
||
|
||
$this->post->id = '1';
|
||
|
||
$this->db->unrelateAll($this->post, 'tags');
|
||
}
|
||
|
||
public function testRemoveRelationManyManyWithCondition()
|
||
{
|
||
$query =
|
||
"UPDATE `entity_team` SET entity_team.deleted = 1 ".
|
||
"WHERE entity_team.entity_id = '1' AND entity_team.team_id = '100' AND entity_team.entity_type = 'Account'";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->account->id = '1';
|
||
|
||
$this->db->unrelateById($this->account, 'teams', '100');
|
||
}
|
||
|
||
public function testRemoveAllManyManyWithCondition()
|
||
{
|
||
$query =
|
||
"UPDATE `entity_team` SET entity_team.deleted = 1 ".
|
||
"WHERE entity_team.entity_id = '1' AND entity_team.entity_type = 'Account'";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->account->id = '1';
|
||
$this->db->unrelateAll($this->account, 'teams');
|
||
}
|
||
|
||
public function testUnrelateManyToMany()
|
||
{
|
||
$query = "UPDATE `post_tag` SET post_tag.deleted = 1 WHERE post_tag.post_id = 'postId' AND post_tag.tag_id = 'tagId'";
|
||
|
||
$this->mockQuery($query, true);
|
||
|
||
$this->post->id = 'postId';
|
||
$this->tag->id = 'tagId';
|
||
|
||
$this->db->unrelate($this->post, 'tags', $this->tag);
|
||
}
|
||
|
||
public function testRelateOneToMany()
|
||
{
|
||
$this->post->id = 'p';
|
||
$this->comment->id = 'c';
|
||
|
||
$query1 =
|
||
"SELECT COUNT(comment.id) AS `value` FROM `comment` AS `comment` " .
|
||
"WHERE comment.id = 'c' AND comment.deleted = 0";
|
||
|
||
$query2 =
|
||
"UPDATE `comment` SET comment.post_id = 'p' WHERE comment.id = 'c' AND comment.deleted = 0";
|
||
|
||
$this->sqlExecutor->expects($this->exactly(2))
|
||
->method('execute')
|
||
->withConsecutive([$query1], [$query2])
|
||
->willReturnOnConsecutiveCalls(
|
||
$this->createSthMock([['value' => 1]]),
|
||
$this->createSthMock([])
|
||
);
|
||
|
||
$this->db->relate($this->post, 'comments', $this->comment);
|
||
}
|
||
|
||
public function testRelateParentToChildren()
|
||
{
|
||
$this->post->id = 'p';
|
||
$this->note->id = 'n';
|
||
|
||
$query1 =
|
||
"SELECT COUNT(note.id) AS `value` FROM `note` AS `note` " .
|
||
"WHERE note.id = 'n' AND note.deleted = 0";
|
||
|
||
$query2 =
|
||
"UPDATE `note` SET note.parent_id = 'p', note.parent_type = 'Post' WHERE note.id = 'n' AND note.deleted = 0";
|
||
|
||
$this->sqlExecutor->expects($this->exactly(2))
|
||
->method('execute')
|
||
->withConsecutive([$query1], [$query2])
|
||
->willReturnOnConsecutiveCalls(
|
||
$this->createSthMock([['value' => 1]]),
|
||
$this->createSthMock([])
|
||
);
|
||
|
||
$this->db->relate($this->post, 'notes', $this->note);
|
||
}
|
||
|
||
public function testRelateManyToOne()
|
||
{
|
||
$this->comment->id = 'c';
|
||
$this->post->id = 'p';
|
||
|
||
$query1 =
|
||
"UPDATE `comment` SET comment.post_id = 'p' WHERE comment.id = 'c' AND comment.deleted = 0";
|
||
|
||
$this->sqlExecutor->expects($this->exactly(1))
|
||
->method('execute')
|
||
->withConsecutive([$query1])
|
||
->willReturnOnConsecutiveCalls($this->createSthMock([]));
|
||
|
||
$this->db->relate($this->comment, 'post', $this->post);
|
||
}
|
||
|
||
public function testRelateChildrenToParent()
|
||
{
|
||
$this->note->id = 'n';
|
||
$this->post->id = 'p';
|
||
|
||
$query1 =
|
||
"UPDATE `note` SET note.parent_id = 'p', note.parent_type = 'Post' WHERE note.id = 'n' AND note.deleted = 0";
|
||
|
||
$this->sqlExecutor->expects($this->exactly(1))
|
||
->method('execute')
|
||
->withConsecutive([$query1])
|
||
->willReturnOnConsecutiveCalls($this->createSthMock([]));
|
||
|
||
$this->db->relate($this->note, 'parent', $this->post);
|
||
}
|
||
|
||
public function testRelateOneToOne1()
|
||
{
|
||
$this->post->id = 'p';
|
||
$this->postData->id = 'd';
|
||
|
||
$query1 =
|
||
"UPDATE `post_data` SET post_data.post_id = NULL WHERE post_data.id <> 'd' AND post_data.post_id = 'p' AND post_data.deleted = 0";
|
||
|
||
$query2 =
|
||
"UPDATE `post_data` SET post_data.post_id = 'p' WHERE post_data.id = 'd' AND post_data.deleted = 0";
|
||
|
||
$this->sqlExecutor->expects($this->exactly(2))
|
||
->method('execute')
|
||
->withConsecutive([$query1], [$query2])
|
||
->willReturnOnConsecutiveCalls($this->createSthMock([]), $this->createSthMock([]));
|
||
|
||
$this->db->relate($this->postData, 'post', $this->post);
|
||
}
|
||
|
||
public function testRelateOneToOne2()
|
||
{
|
||
$this->post->id = 'p';
|
||
$this->postData->id = 'd';
|
||
|
||
$query1 =
|
||
"SELECT COUNT(postData.id) AS `value` FROM `post_data` AS `postData` " .
|
||
"WHERE postData.id = 'd' AND postData.deleted = 0";
|
||
|
||
$query2 =
|
||
"UPDATE `post_data` SET post_data.post_id = NULL WHERE post_data.post_id = 'p' AND post_data.deleted = 0";
|
||
|
||
$query3 =
|
||
"UPDATE `post_data` SET post_data.post_id = 'p' WHERE post_data.id = 'd' AND post_data.deleted = 0";
|
||
|
||
$this->sqlExecutor->expects($this->exactly(3))
|
||
->method('execute')
|
||
->withConsecutive([$query1], [$query2], [$query3])
|
||
->willReturnOnConsecutiveCalls(
|
||
$this->createSthMock([['value' => 1]]),
|
||
$this->createSthMock([]),
|
||
$this->createSthMock([])
|
||
);
|
||
|
||
$this->db->relate($this->post, 'postData', $this->postData);
|
||
}
|
||
|
||
public function testRelateManyToMany1Insert()
|
||
{
|
||
$this->post->id = 'postId';
|
||
$this->tag->id = 'tagId';
|
||
|
||
$query1 =
|
||
"SELECT COUNT(tag.id) AS `value` FROM `tag` AS `tag` " .
|
||
"WHERE tag.id = 'tagId' AND tag.deleted = 0";
|
||
|
||
$query2 =
|
||
"SELECT post_tag.id AS `id` FROM `post_tag` " .
|
||
"WHERE post_tag.post_id = 'postId' AND post_tag.tag_id = 'tagId'";
|
||
|
||
$query3 =
|
||
"INSERT INTO `post_tag` (`post_id`, `tag_id`, `role`) VALUES ('postId', 'tagId', 'Test') " .
|
||
"ON DUPLICATE KEY UPDATE `deleted` = 0, `role` = 'Test'";
|
||
|
||
$ps = $this->createMock(\PDOStatement::class);
|
||
$ps->expects($this->exactly(1))
|
||
->method('rowCount')
|
||
->willReturn(0);
|
||
|
||
$this->sqlExecutor
|
||
->expects($this->exactly(3))
|
||
->method('execute')
|
||
->withConsecutive([$query1], [$query2], [$query3])
|
||
->willReturnOnConsecutiveCalls(
|
||
$this->createSthMock([['value' => 1]]),
|
||
$ps,
|
||
$this->createSthMock([])
|
||
);
|
||
|
||
$this->db->relate($this->post, 'tags', $this->tag, ['role' => 'Test']);
|
||
}
|
||
|
||
public function testRelateManyToMany1Update()
|
||
{
|
||
$this->post->id = 'postId';
|
||
$this->tag->id = 'tagId';
|
||
|
||
$query1 =
|
||
"SELECT COUNT(tag.id) AS `value` FROM `tag` AS `tag` " .
|
||
"WHERE tag.id = 'tagId' AND tag.deleted = 0";
|
||
|
||
$query2 =
|
||
"SELECT post_tag.id AS `id` FROM `post_tag` " .
|
||
"WHERE post_tag.post_id = 'postId' AND post_tag.tag_id = 'tagId'";
|
||
|
||
$query3 =
|
||
"UPDATE `post_tag` SET post_tag.deleted = 0, post_tag.role = 'Test' " .
|
||
"WHERE post_tag.post_id = 'postId' AND post_tag.tag_id = 'tagId'";
|
||
|
||
$ps = $this->createMock(\PDOStatement::class);
|
||
$ps->expects($this->exactly(1))
|
||
->method('rowCount')
|
||
->willReturn(1);
|
||
|
||
$this->sqlExecutor
|
||
->expects($this->exactly(3))
|
||
->method('execute')
|
||
->withConsecutive([$query1], [$query2], [$query3])
|
||
->willReturnOnConsecutiveCalls(
|
||
$this->createSthMock([['value' => 1]]),
|
||
$ps,
|
||
$this->createSthMock([])
|
||
);
|
||
|
||
$this->db->relate($this->post, 'tags', $this->tag, ['role' => 'Test']);
|
||
}
|
||
|
||
public function testRelateManyToMany2Insert()
|
||
{
|
||
$this->account->id = 'accountId';
|
||
$this->team->id = 'teamId';
|
||
|
||
$query1 =
|
||
"SELECT COUNT(team.id) AS `value` FROM `team` AS `team` " .
|
||
"WHERE team.id = 'teamId' AND team.deleted = 0";
|
||
|
||
$query2 =
|
||
"SELECT entity_team.id AS `id` FROM `entity_team` " .
|
||
"WHERE entity_team.entity_id = 'accountId' AND entity_team.team_id = 'teamId' AND entity_team.entity_type = 'Account'";
|
||
|
||
$query3 =
|
||
"INSERT INTO `entity_team` (`entity_id`, `team_id`, `entity_type`) VALUES ('accountId', 'teamId', 'Account') " .
|
||
"ON DUPLICATE KEY UPDATE `deleted` = 0";
|
||
|
||
$ps = $this->createMock(\PDOStatement::class);
|
||
$ps->expects($this->exactly(1))
|
||
->method('rowCount')
|
||
->willReturn(0);
|
||
|
||
$this->sqlExecutor
|
||
->expects($this->exactly(3))
|
||
->method('execute')
|
||
->withConsecutive([$query1], [$query2], [$query3])
|
||
->willReturnOnConsecutiveCalls(
|
||
$this->createSthMock([['value' => 1]]),
|
||
$ps,
|
||
$this->createSthMock([])
|
||
);
|
||
|
||
$this->db->relate($this->account, 'teams', $this->team);
|
||
}
|
||
|
||
public function testRelateManyToMany2Update()
|
||
{
|
||
$this->account->id = 'accountId';
|
||
$this->team->id = 'teamId';
|
||
|
||
$query1 =
|
||
"SELECT COUNT(team.id) AS `value` FROM `team` AS `team` " .
|
||
"WHERE team.id = 'teamId' AND team.deleted = 0";
|
||
|
||
$query2 =
|
||
"SELECT entity_team.id AS `id` FROM `entity_team` " .
|
||
"WHERE entity_team.entity_id = 'accountId' AND entity_team.team_id = 'teamId' AND entity_team.entity_type = 'Account'";
|
||
|
||
$query3 =
|
||
"UPDATE `entity_team` SET entity_team.deleted = 0 " .
|
||
"WHERE entity_team.entity_id = 'accountId' AND entity_team.team_id = 'teamId' AND entity_team.entity_type = 'Account'";
|
||
|
||
$ps = $this->createMock(\PDOStatement::class);
|
||
$ps->expects($this->exactly(1))
|
||
->method('rowCount')
|
||
->willReturn(1);
|
||
|
||
$this->sqlExecutor
|
||
->expects($this->exactly(3))
|
||
->method('execute')
|
||
->withConsecutive([$query1], [$query2], [$query3])
|
||
->willReturnOnConsecutiveCalls(
|
||
$this->createSthMock([['value' => 1]]),
|
||
$ps,
|
||
$this->createSthMock([])
|
||
);
|
||
|
||
$this->db->relate($this->account, 'teams', $this->team);
|
||
}
|
||
|
||
public function testGetRelationColumn()
|
||
{
|
||
$this->post->id = 'postId';
|
||
$this->tag->id = 'tagId';
|
||
|
||
$query =
|
||
"SELECT post_tag.role AS `value` FROM `post_tag` " .
|
||
"WHERE post_tag.post_id = 'postId' AND post_tag.tag_id = 'tagId' AND post_tag.deleted = 0";
|
||
|
||
$this->mockQuery($query, [['value' => 'test']]);
|
||
|
||
$result = $this->db->getRelationColumn($this->post, 'tags', 'tagId', 'role');
|
||
|
||
$this->assertEquals('test', $result);
|
||
}
|
||
|
||
public function testUpdateRelationColumns()
|
||
{
|
||
$this->post->id = 'postId';
|
||
$this->tag->id = 'tagId';
|
||
|
||
$query =
|
||
"UPDATE `post_tag` SET post_tag.role = 'test' " .
|
||
"WHERE post_tag.post_id = 'postId' AND post_tag.tag_id = 'tagId' AND post_tag.deleted = 0";
|
||
|
||
$this->mockQuery($query);
|
||
|
||
$this->db->updateRelationColumns($this->post, 'tags', 'tagId', [
|
||
'role' => 'test'
|
||
]);
|
||
}
|
||
|
||
public function testMax()
|
||
{
|
||
$query = "SELECT MAX(post.id) AS `value` FROM `post` AS `post` WHERE post.deleted = 0";
|
||
|
||
$return = [
|
||
[
|
||
'value' => 10,
|
||
]
|
||
];
|
||
|
||
$this->mockQuery($query, $return);
|
||
|
||
$value = $this->db->max(Select::fromRaw(['from' => 'Post']), 'id');
|
||
|
||
$this->assertEquals($value, 10);
|
||
}
|
||
|
||
public function testMassRelate()
|
||
{
|
||
$query =
|
||
"INSERT INTO `post_tag` (`post_id`, `tag_id`) ".
|
||
"SELECT '1' AS `v0`, tag.id AS `id` FROM `tag` WHERE tag.name = 'test' AND tag.deleted = 0 ".
|
||
"ON DUPLICATE KEY UPDATE `deleted` = 0";
|
||
|
||
$return = true;
|
||
$this->mockQuery($query, $return);
|
||
|
||
$this->post->id = '1';
|
||
|
||
$select = Select::fromRaw([
|
||
'from' => 'Tag',
|
||
'whereClause' => [
|
||
'name' => 'test',
|
||
],
|
||
]);
|
||
|
||
$this->db->massRelate($this->post, 'tags', $select);
|
||
}
|
||
|
||
public function testDeleteFromDb1()
|
||
{
|
||
$query = "DELETE FROM `comment` WHERE comment.id = '1'";
|
||
$this->mockQuery($query);
|
||
|
||
$this->db->deleteFromDb('Comment', '1');
|
||
}
|
||
|
||
public function testDeleteFromDb2()
|
||
{
|
||
$query = "DELETE FROM `comment` WHERE comment.id = '1' AND comment.deleted = 1";
|
||
$this->mockQuery($query);
|
||
|
||
$this->db->deleteFromDb('Comment', '1', true);
|
||
}
|
||
|
||
public function testRestoreDeleted()
|
||
{
|
||
$query = "UPDATE `comment` SET comment.deleted = 0 WHERE comment.id = '1'";
|
||
$this->mockQuery($query);
|
||
|
||
$this->db->restoreDeleted('Comment', '1');
|
||
}
|
||
}
|