<?php

namespace RedUNIT\Postgres;

use RedUNIT\Postgres as Postgres;
use RedBeanPHP\Facade as R;

/**
 * Trees
 *
 * This class has been designed to test tree traversal using
 * R::children() and R::parents() relying on
 * recursive common table expressions.
 *
 * @file    RedUNIT/Postgres/Trees.php
 * @desc    Tests trees
 * @author  Gabor de Mooij and the RedBeanPHP Community
 * @license New BSD/GPLv2
 *
 * (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
 * This source file is subject to the New BSD/GPLv2 License that is bundled
 * with this source code in the file license.txt.
 */
class Trees extends Postgres
{
	protected function summarize( $beans )
	{
		$names = array();
		foreach( $beans as $bean ) {
			$names[] = $bean->title;
		}
		return implode( ',', $names );
	}
	
	/**
	 * Test trees
	 *
	 * @return void
	 */
	public function testCTETrees()
	{
		R::nuke();
		$pages = R::dispense(array(
			'_type' => 'page',
			'title' => 'home',
			'ownPageList' => array(array(
				'_type' => 'page',
				'title' => 'shop',
				'ownPageList' => array(array(
					'_type' => 'page',
					'title' => 'wines',
					'ownPageList' => array(array(
						'_type' => 'page',
						'title' => 'whiskies',
					))
				))
			))
		));
		R::store( $pages );
		$whiskyPage = R::findOne( 'page', 'title = ?', array('whiskies') );
		asrt( $this->summarize( R::parents( $whiskyPage, ' ORDER BY title ASC ' ) ), 'home,shop,whiskies,wines' );
		asrt( $this->summarize( R::children( $whiskyPage, ' ORDER BY title ASC ' ) ), 'whiskies' );
		$homePage = R::findOne( 'page', 'title = ?', array('home') );
		asrt( $this->summarize( R::parents( $homePage, ' ORDER BY title ASC ' ) ), 'home' );
		asrt( $this->summarize( R::children( $homePage, ' ORDER BY title ASC ' ) ), 'home,shop,whiskies,wines' );
		$shopPage = R::findOne( 'page', 'title = ?', array('shop') );
		asrt( $this->summarize( R::parents( $shopPage, ' ORDER BY title ASC ' ) ), 'home,shop' );
		asrt( $this->summarize( R::children( $shopPage, ' ORDER BY title ASC ' ) ), 'shop,whiskies,wines' );
		$winePage = R::findOne( 'page', 'title = ?', array('wines') );
		asrt( $this->summarize( R::parents( $winePage, ' ORDER BY title ASC ' ) ), 'home,shop,wines' );
		asrt( $this->summarize( R::children( $winePage, ' ORDER BY title ASC ' ) ), 'whiskies,wines' );
		asrt( $this->summarize( R::children( $winePage, ' title NOT IN (\'wines\') ORDER BY title ASC ' ) ), 'whiskies' );
		asrt( $this->summarize( R::parents( $winePage, '  title NOT IN (\'home\') ORDER BY title ASC ' ) ), 'shop,wines' );
		asrt( $this->summarize( R::parents( $winePage, ' ORDER BY title ASC ', array() ) ), 'home,shop,wines' );
		asrt( $this->summarize( R::children( $winePage, ' ORDER BY title ASC ', array() ) ), 'whiskies,wines' );
		asrt( $this->summarize( R::children( $winePage, ' title NOT IN (\'wines\') ORDER BY title ASC ', array() ) ), 'whiskies' );
		asrt( $this->summarize( R::parents( $winePage, '  title NOT IN (\'home\') ORDER BY title ASC ', array() ) ), 'shop,wines' );
		asrt( $this->summarize( R::children( $winePage, ' title != ? ORDER BY title ASC ', array( 'wines' ) ) ), 'whiskies' );
		asrt( $this->summarize( R::parents( $winePage, '  title != ? ORDER BY title ASC ', array( 'home' ) ) ), 'shop,wines' );
		asrt( $this->summarize( R::children( $winePage, ' title != :title ORDER BY title ASC ', array( ':title' => 'wines' ) ) ), 'whiskies' );
		asrt( $this->summarize( R::parents( $winePage, '  title != :title ORDER BY title ASC ', array( ':title' => 'home' ) ) ), 'shop,wines' );
		asrt( R::countChildren( $homePage ), 3 );
		asrt( R::countParents( $whiskyPage ), 3 );
		asrt( R::countChildren( $winePage, ' title != :title  ', array( ':title' => 'wines' ) ) , 0 );
		asrt( R::countParents( $winePage, '  title != :title  ', array( ':title' => 'home' ) ) , 1 );
	}
	
	/**
	 * Test CTE and Parsed Joins.
	 *
	 * @return void
	 */
	public function testCTETreesAndParsedJoins()
	{
		R::nuke();
		list($cards, $details, $colors) = R::dispenseAll('card*9,detail*4,color*2');
		$colors[0]->name = 'red';
		$colors[1]->name = 'black';
		$details[0]->points = 500;
		$details[1]->points = 200;
		$details[2]->points = 300;
		$details[3]->points = 100;
		$cards[0]->ownCardList = array( $cards[1] );
		$cards[1]->ownCardList = array( $cards[2], $cards[3] );
		$cards[2]->ownCardList = array( $cards[4], $cards[5] );
		$cards[3]->ownCardList = array( $cards[6], $cards[7], $cards[8] );
		$cards[0]->ownOwner[] = R::dispense(array('_type'=>'owner', 'name'=>'User0'));
		$cards[1]->ownOwner[] = R::dispense(array('_type'=>'owner', 'name'=>'User1'));
		$cards[2]->ownOwner[] = R::dispense(array('_type'=>'owner', 'name'=>'User2'));
		$cards[3]->ownOwner[] = R::dispense(array('_type'=>'owner', 'name'=>'User3'));
		$cards[4]->ownOwner[] = R::dispense(array('_type'=>'owner', 'name'=>'User4'));
		$cards[5]->ownOwner[] = R::dispense(array('_type'=>'owner', 'name'=>'User5'));
		$cards[6]->ownOwner[] = R::dispense(array('_type'=>'owner', 'name'=>'User6'));
		$cards[7]->ownOwner[] = R::dispense(array('_type'=>'owner', 'name'=>'User7'));
		$cards[8]->ownOwner[] = R::dispense(array('_type'=>'owner', 'name'=>'User8'));
		$cards[0]->detail = $details[0];
		$cards[1]->detail = $details[0];
		$cards[2]->detail = $details[1];
		$cards[3]->detail = $details[2];
		$cards[4]->detail = $details[3];
		$cards[5]->detail = $details[3];
		$cards[6]->detail = $details[3];
		$cards[7]->detail = $details[3];
		$cards[8]->detail = $details[3];
		$colors[0]->sharedCardList = array( $cards[0], $cards[2], $cards[4], $cards[6], $cards[8] );
		$colors[1]->sharedCardList = array( $cards[1], $cards[3], $cards[5], $cards[7] );
		R::storeAll(array_merge($cards,$details,$colors));
		$cardsWith100Points = R::children($cards[0], ' @joined.detail.points = ? ', array(100));
		asrt(count($cardsWith100Points),5);
		$cardsWith200Points = R::children($cards[0], ' @joined.detail.points = ? ', array(200));
		asrt(count($cardsWith200Points),1);
		$cardsWith300Points = R::children($cards[0], ' @joined.detail.points = ? ', array(300));
		asrt(count($cardsWith200Points),1);
		$cardsWith500Points = R::children($cards[0], ' @joined.detail.points = ? ', array(500));
		asrt(count($cardsWith200Points),1);
		for($i=8; $i>=4; $i--) {
			$cardsWithMoreThan100Points = R::parents($cards[$i], ' @joined.detail.points > ? ', array(100));
			asrt(count($cardsWithMoreThan100Points),3);
		}
		$cardsWithMoreThan200Points = R::parents($cards[8], ' @joined.detail.points > ? ', array(200));
		asrt(count($cardsWithMoreThan200Points),3);
		$cardsWithMoreThan200Points = R::parents($cards[7], ' @joined.detail.points > ? ', array(200));
		asrt(count($cardsWithMoreThan200Points),3);
		$cardsWithMoreThan200Points = R::parents($cards[6], ' @joined.detail.points > ? ', array(200));
		asrt(count($cardsWithMoreThan200Points),3);
		$cardsWithMoreThan200Points = R::parents($cards[5], ' @joined.detail.points > ? ', array(200));
		asrt(count($cardsWithMoreThan200Points),2);
		$cardsWithMoreThan200Points = R::parents($cards[4], ' @joined.detail.points > ? ', array(200));
		asrt(count($cardsWithMoreThan200Points),2);
		for($i=8; $i>=2; $i--) {
			$cardsWithMoreThan300Points = R::parents($cards[4], ' @joined.detail.points > ? ', array(300));
			asrt(count($cardsWithMoreThan200Points),2);
		}
		$black = R::children($cards[0], ' @shared.color.name = ? ', array('black'));
		asrt(count($black),4);
		$red = R::children($cards[0], ' @shared.color.name = ? ', array('red'));
		asrt(count($red),5);
		$black = R::parents($cards[8], ' @shared.color.name = ? ', array('black'));
		asrt(count($black),2);
		$red = R::parents($cards[6], ' @shared.color.name = ? ', array('red'));
		asrt(count($red),2);
		$found = R::children($cards[0], ' @own.owner.name = ? ', array('User0'));
		asrt(count($found),1);
		$found = R::children($cards[0], ' @own.owner.name IN (?,?) ', array('User1','User2'));
		asrt(count($found),2);
		$found = R::parents($cards[8], ' @own.owner.name IN (?,?) ', array('User3','User0'));
		asrt(count($found),2);
		$found = R::children($cards[8], ' @own.owner.name IN (?,?) ', array('User3','User0'));
		asrt(count($found),0);
		$found = R::children($cards[3], ' @own.owner.name IN (?,?) ', array('User3','User7'));
		asrt(count($found),2);
	}

	/**
	 * Test CTE and Parsed Joins with aliases as well
	 * as chained parsed joins.
	 *
	 * @return void
	 */
	public function testCTETreesAndParsedJoinsAndAliases() {
		R::nuke();
		R::aliases(array( 'author' => 'person', 'chart' => 'image' ));
		$person = R::dispense( 'person' );
		$ceo = R::dispense('person');
		$ceo->name = 'John';
		$role = R::dispense('role');
		$role->label = 'CEO';
		$ceo->sharedRoleList = array( $role );
		$person->name = 'James';
		$editor = R::dispense('role');
		$editor->label = 'editor';
		$person->sharedRoleList = array( $editor );
		$website = R::dispense('page');
		$about = R::dispense('page');
		$investor = R::dispense('page');
		$links = R::dispense('page');
		$category = R::dispense('category');
		$category->title = 'business';
		$about->sharedCategoryList = array( $category );
		$blog = R::dispense('page');
		$article = R::dispense('page');
		$investor->title = 'investors';
		$links->title = 'links';
		$about->title = 'about';
		$chart = R::dispense('image');
		$chart->file = 'report.jpg';
		$picture = R::dispense('image');
		$picture->file = 'logo.jpg';
		$picture->source = $website;
		$website->ownImageList = array( $picture );
		$article->ownImageList = array( $picture );
		$investor->ownImageList = array( $picture );
		$about->ownImageList = array( $chart );
		$about->author = $ceo;
		$about->coauthor = $person;
		$article->title = 'a walk in the park';
		$website->ownPageList = array( $about, $blog );
		$blog->ownPageList = array( $article );
		$article->ownPageList = array( $links );
		$about->ownPageList = array( $investor );
		$article->author = $person;
		R::store( $website );
		//joined-alias
		$pages = R::children( $website, ' @joined.author.name = ? ', array('James') );
		asrt(count($pages), 1);
		$page = reset($pages);
		asrt($page->title, 'a walk in the park');
		//Chained joined-alias+shared
		$pages = R::children( $website, ' @joined.author.shared.role.label = ? ', array('CEO') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		//joined-alias+shared parents
		$pages = R::parents( $investor, ' @joined.author.shared.role.label = ? ', array('CEO') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		//joined-alias parents
		$pages = R::parents( $links, ' @joined.author.name = ? ', array('James') );
		asrt(count($pages), 1);
		$page = reset($pages);
		asrt($page->title, 'a walk in the park');
		//own-alias
		$pages = R::children( $website, '@own.chart.file = ?', array('report.jpg') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		//own-alias parent
		$pages = R::parents( $investor, '@own.chart.file = ?', array('report.jpg') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		//own-alias parent + joined-alias+shared parents
		$pages = R::parents( $investor, '@own.chart.file = ? AND @joined.author.shared.role.label = ? ', array('report.jpg', 'CEO') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		//own-alias + Chained joined-alias+shared
		$pages = R::children( $website, ' @own.chart.file = ? AND @joined.author.shared.role.label = ? ',  array('report.jpg', 'CEO') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		//own-alias + Chained joined-alias+shared + joined-alias
		$pages = R::children( $website, ' @joined.author.name = ? AND @own.chart.file = ? AND @joined.author.shared.role.label = ? ',  array('John', 'report.jpg', 'CEO') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		//own-alias + Chained joined-alias+shared + joined-alias parents
		$pages = R::parents( $investor, ' @joined.author.name = ? AND @own.chart.file = ? AND @joined.author.shared.role.label = ? ',  array('John', 'report.jpg', 'CEO') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		$pages = R::parents( $links, ' @joined.author.name = ? AND @own.chart.file = ? AND @joined.author.shared.role.label = ? ',  array('James', 'logo.jpg', 'editor') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'a walk in the park');
		$pages = R::parents( $links, ' @joined.author.name = ? AND @own.chart.file = ? AND @joined.author.shared.role.label = ? ',  array('James', 'report.jpg', 'editor') );
		asrt(count($pages),0);
		//other variations
		$pages = R::parents( $investor, ' @shared.category.title = ? ',  array('business') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		R::aliases(array());
		//joined-alias - explicit/non-global
		$pages = R::children( $website, ' @joined.person[as:author].name = ? ', array('James') );
		asrt(count($pages), 1);
		$page = reset($pages);
		asrt($page->title, 'a walk in the park');
		//Chained joined-alias+shared - explicit/non-global
		$pages = R::children( $website, ' @joined.person[as:author].shared.role.label = ? ', array('CEO') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		//joined-alias+shared parents - explicit/non-global
		$pages = R::parents( $investor, ' @joined.person[as:author].shared.role.label = ? ', array('CEO') );
		asrt(count($pages),1);
		$page = reset($pages);
		asrt($page->title,'about');
		//joined-alias parents - explicit/non-global
		$pages = R::parents( $links, ' @joined.person[as:author].name = ? ', array('James') );
		asrt(count($pages), 1);
		$page = reset($pages);
		asrt($page->title, 'a walk in the park');
		//double joined-alias parents - explicit/non-global
		$pages = R::children( $website, ' @joined.person[as:author/coauthor].name = ? ', array('James') );
		asrt(count($pages), 2);
		//own-alias - explicit/non-global
		$pages = R::children( $website, ' @own.image[alias:source].file = ?', array('logo.jpg') );
		asrt(count($pages),1);
		$pages = R::children( $website, ' @own.image[alias:source].file = ?', array('report.jpg') );
		asrt(count($pages),0);
		$pages = R::children( $about, ' @own.image[alias:source].file = ?', array('logo.jpg') );
		asrt(count($pages),0);
	}
}
