Files
espocrm/tests/unit/Espo/ORM/MapperTest.php
2023-12-31 10:49:50 +02:00

1282 lines
38 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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');
}
}