| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207 |
- <?php
- /**
- * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://cakephp.org CakePHP(tm) Project
- * @since 3.0.0
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- */
- namespace Cake\Test\TestCase\Database;
- use Cake\Core\Configure;
- use Cake\Database\Expression\IdentifierExpression;
- use Cake\Database\Query;
- use Cake\Datasource\ConnectionManager;
- use Cake\TestSuite\TestCase;
- /**
- * Tests Query class
- *
- */
- class QueryTest extends TestCase
- {
- public $fixtures = ['core.articles', 'core.authors', 'core.comments'];
- const ARTICLE_COUNT = 3;
- const AUTHOR_COUNT = 4;
- const COMMENT_COUNT = 6;
- public function setUp()
- {
- parent::setUp();
- $this->connection = ConnectionManager::get('test');
- $this->autoQuote = $this->connection->driver()->autoQuoting();
- }
- public function tearDown()
- {
- parent::tearDown();
- $this->connection->driver()->autoQuoting($this->autoQuote);
- unset($this->connection);
- }
- /**
- * Queries need a default type to prevent fatal errors
- * when an uninitialized query has its sql() method called.
- *
- * @return void
- */
- public function testDefaultType()
- {
- $query = new Query($this->connection);
- $this->assertEquals('', $query->sql());
- $this->assertEquals('select', $query->type());
- }
- /**
- * Tests that it is possible to obtain expression results from a query
- *
- * @return void
- */
- public function testSelectFieldsOnly()
- {
- $this->connection->driver()->autoQuoting(false);
- $query = new Query($this->connection);
- $result = $query->select('1 + 1')->execute();
- $this->assertInstanceOf('Cake\Database\StatementInterface', $result);
- $this->assertEquals([2], $result->fetch());
- //This new field should be appended
- $result = $query->select(['1 + 3'])->execute();
- $this->assertInstanceOf('Cake\Database\StatementInterface', $result);
- $this->assertEquals([2, 4], $result->fetch());
- //This should now overwrite all previous fields
- $result = $query->select(['1 + 2', '1 + 5'], true)->execute();
- $this->assertEquals([3, 6], $result->fetch());
- }
- /**
- * Tests that it is possible to pass a closure as fields in select()
- *
- * @return void
- */
- public function testSelectClosure()
- {
- $this->connection->driver()->autoQuoting(false);
- $query = new Query($this->connection);
- $result = $query->select(function ($q) use ($query) {
- $this->assertSame($query, $q);
- return ['1 + 2', '1 + 5'];
- })->execute();
- $this->assertEquals([3, 6], $result->fetch());
- }
- /**
- * Tests it is possible to select fields from tables with no conditions
- *
- * @return void
- */
- public function testSelectFieldsFromTable()
- {
- $query = new Query($this->connection);
- $result = $query->select(['body', 'author_id'])->from('articles')->execute();
- $this->assertEquals(['body' => 'First Article Body', 'author_id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['body' => 'Second Article Body', 'author_id' => 3], $result->fetch('assoc'));
- //Append more tables to next execution
- $result = $query->select('name')->from(['authors'])->order(['name' => 'desc', 'articles.id' => 'asc'])->execute();
- $this->assertEquals(['body' => 'First Article Body', 'author_id' => 1, 'name' => 'nate'], $result->fetch('assoc'));
- $this->assertEquals(['body' => 'Second Article Body', 'author_id' => 3, 'name' => 'nate'], $result->fetch('assoc'));
- $this->assertEquals(['body' => 'Third Article Body', 'author_id' => 1, 'name' => 'nate'], $result->fetch('assoc'));
- // Overwrite tables and only fetch from authors
- $result = $query->select('name', true)->from('authors', true)->order(['name' => 'desc'], true)->execute();
- $this->assertEquals(['nate'], $result->fetch());
- $this->assertEquals(['mariano'], $result->fetch());
- $this->assertCount(4, $result);
- }
- /**
- * Tests it is possible to select aliased fields
- *
- * @return void
- */
- public function testSelectAliasedFieldsFromTable()
- {
- $query = new Query($this->connection);
- $result = $query->select(['text' => 'body', 'author_id'])->from('articles')->execute();
- $this->assertEquals(['text' => 'First Article Body', 'author_id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['text' => 'Second Article Body', 'author_id' => 3], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query->select(['text' => 'body', 'author' => 'author_id'])->from('articles')->execute();
- $this->assertEquals(['text' => 'First Article Body', 'author' => 1], $result->fetch('assoc'));
- $this->assertEquals(['text' => 'Second Article Body', 'author' => 3], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $query->select(['text' => 'body'])->select(['author_id', 'foo' => 'body']);
- $result = $query->from('articles')->execute();
- $this->assertEquals(['foo' => 'First Article Body', 'text' => 'First Article Body', 'author_id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['foo' => 'Second Article Body', 'text' => 'Second Article Body', 'author_id' => 3], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $exp = $query->newExpr('1 + 1');
- $comp = $query->newExpr(['author_id +' => 2]);
- $result = $query->select(['text' => 'body', 'two' => $exp, 'three' => $comp])
- ->from('articles')->execute();
- $this->assertEquals(['text' => 'First Article Body', 'two' => 2, 'three' => 3], $result->fetch('assoc'));
- $this->assertEquals(['text' => 'Second Article Body', 'two' => 2, 'three' => 5], $result->fetch('assoc'));
- }
- /**
- * Tests that tables can also be aliased and referenced in the select clause using such alias
- *
- * @return void
- */
- public function testSelectAliasedTables()
- {
- $query = new Query($this->connection);
- $result = $query->select(['text' => 'a.body', 'a.author_id'])
- ->from(['a' => 'articles'])->execute();
- $this->assertEquals(['text' => 'First Article Body', 'author_id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['text' => 'Second Article Body', 'author_id' => 3], $result->fetch('assoc'));
- $result = $query->select(['name' => 'b.name'])->from(['b' => 'authors'])
- ->order(['text' => 'desc', 'name' => 'desc'])
- ->execute();
- $this->assertEquals(
- ['text' => 'Third Article Body', 'author_id' => 1, 'name' => 'nate'],
- $result->fetch('assoc')
- );
- $this->assertEquals(
- ['text' => 'Third Article Body', 'author_id' => 1, 'name' => 'mariano'],
- $result->fetch('assoc')
- );
- }
- /**
- * Tests it is possible to add joins to a select query
- *
- * @return void
- */
- public function testSelectWithJoins()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['title', 'name'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
- ->order(['title' => 'asc'])
- ->execute();
- $this->assertCount(3, $result);
- $this->assertEquals(['title' => 'First Article', 'name' => 'mariano'], $result->fetch('assoc'));
- $this->assertEquals(['title' => 'Second Article', 'name' => 'larry'], $result->fetch('assoc'));
- $result = $query->join('authors', [], true)->execute();
- $this->assertCount(12, $result, 'Cross join results in 12 records');
- $result = $query->join([
- ['table' => 'authors', 'type' => 'INNER', 'conditions' => 'author_id = authors.id']
- ], [], true)->execute();
- $this->assertCount(3, $result);
- $this->assertEquals(['title' => 'First Article', 'name' => 'mariano'], $result->fetch('assoc'));
- $this->assertEquals(['title' => 'Second Article', 'name' => 'larry'], $result->fetch('assoc'));
- }
- /**
- * Tests it is possible to add joins to a select query using array or expression as conditions
- *
- * @return void
- */
- public function testSelectWithJoinsConditions()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['title', 'name'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => ['author_id = a.id']])
- ->order(['title' => 'asc'])
- ->execute();
- $this->assertEquals(['title' => 'First Article', 'name' => 'mariano'], $result->fetch('assoc'));
- $this->assertEquals(['title' => 'Second Article', 'name' => 'larry'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $conditions = $query->newExpr('author_id = a.id');
- $result = $query
- ->select(['title', 'name'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => $conditions])
- ->order(['title' => 'asc'])
- ->execute();
- $this->assertEquals(['title' => 'First Article', 'name' => 'mariano'], $result->fetch('assoc'));
- $this->assertEquals(['title' => 'Second Article', 'name' => 'larry'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $time = new \DateTime('2007-03-18 10:50:00');
- $types = ['created' => 'datetime'];
- $result = $query
- ->select(['title', 'comment' => 'c.comment'])
- ->from('articles')
- ->join(['table' => 'comments', 'alias' => 'c', 'conditions' => ['created <=' => $time]], $types)
- ->execute();
- $this->assertEquals(['title' => 'First Article', 'comment' => 'First Comment for First Article'], $result->fetch('assoc'));
- }
- /**
- * Tests that joins can be aliased using array keys
- *
- * @return void
- */
- public function testSelectAliasedJoins()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['title', 'name'])
- ->from('articles')
- ->join(['a' => 'authors'])
- ->order(['name' => 'desc', 'articles.id' => 'asc'])
- ->execute();
- $this->assertEquals(['title' => 'First Article', 'name' => 'nate'], $result->fetch('assoc'));
- $this->assertEquals(['title' => 'Second Article', 'name' => 'nate'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $conditions = $query->newExpr('author_id = a.id');
- $result = $query
- ->select(['title', 'name'])
- ->from('articles')
- ->join(['a' => ['table' => 'authors', 'conditions' => $conditions]])
- ->order(['title' => 'asc'])
- ->execute();
- $this->assertEquals(['title' => 'First Article', 'name' => 'mariano'], $result->fetch('assoc'));
- $this->assertEquals(['title' => 'Second Article', 'name' => 'larry'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $time = new \DateTime('2007-03-18 10:45:23');
- $types = ['created' => 'datetime'];
- $result = $query
- ->select(['title', 'name' => 'c.comment'])
- ->from('articles')
- ->join(['c' => ['table' => 'comments', 'conditions' => ['created' => $time]]], $types)
- ->execute();
- $this->assertEquals(['title' => 'First Article', 'name' => 'First Comment for First Article'], $result->fetch('assoc'));
- }
- /**
- * Tests the leftJoin method
- *
- * @return void
- */
- public function testSelectLeftJoin()
- {
- $query = new Query($this->connection);
- $time = new \DateTime('2007-03-18 10:45:23');
- $types = ['created' => 'datetime'];
- $result = $query
- ->select(['title', 'name' => 'c.comment'])
- ->from('articles')
- ->leftJoin(['c' => 'comments'], ['created <' => $time], $types)
- ->execute();
- $this->assertEquals(['title' => 'First Article', 'name' => null], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['title', 'name' => 'c.comment'])
- ->from('articles')
- ->leftJoin(['c' => 'comments'], ['created >' => $time], $types)
- ->execute();
- $this->assertEquals(
- ['title' => 'First Article', 'name' => 'Second Comment for First Article'],
- $result->fetch('assoc')
- );
- }
- /**
- * Tests the innerJoin method
- *
- * @return void
- */
- public function testSelectInnerJoin()
- {
- $query = new Query($this->connection);
- $time = new \DateTime('2007-03-18 10:45:23');
- $types = ['created' => 'datetime'];
- $result = $query
- ->select(['title', 'name' => 'c.comment'])
- ->from('articles')
- ->innerJoin(['c' => 'comments'], ['created <' => $time], $types)
- ->execute();
- $this->assertCount(0, $result->fetchAll());
- $query = new Query($this->connection);
- $result = $query
- ->select(['title', 'name' => 'c.comment'])
- ->from('articles')
- ->leftJoin(['c' => 'comments'], ['created >' => $time], $types)
- ->execute();
- $this->assertEquals(
- ['title' => 'First Article', 'name' => 'Second Comment for First Article'],
- $result->fetch('assoc')
- );
- }
- /**
- * Tests the rightJoin method
- *
- * @return void
- */
- public function testSelectRightJoin()
- {
- $this->skipIf(
- $this->connection->driver() instanceof \Cake\Database\Driver\Sqlite,
- 'SQLite does not support RIGHT joins'
- );
- $query = new Query($this->connection);
- $time = new \DateTime('2007-03-18 10:45:23');
- $types = ['created' => 'datetime'];
- $result = $query
- ->select(['title', 'name' => 'c.comment'])
- ->from('articles')
- ->rightJoin(['c' => 'comments'], ['created <' => $time], $types)
- ->execute();
- $this->assertCount(6, $result);
- $this->assertEquals(
- ['title' => null, 'name' => 'First Comment for First Article'],
- $result->fetch('assoc')
- );
- }
- /**
- * Tests that it is possible to pass a callable as conditions for a join
- *
- * @return void
- */
- public function testSelectJoinWithCallback()
- {
- $query = new Query($this->connection);
- $types = ['created' => 'datetime'];
- $result = $query
- ->select(['title', 'name' => 'c.comment'])
- ->from('articles')
- ->innerJoin(['c' => 'comments'], function ($exp, $q) use ($query, $types) {
- $this->assertSame($q, $query);
- $exp->add(['created <' => new \DateTime('2007-03-18 10:45:23')], $types);
- return $exp;
- })
- ->execute();
- $this->assertCount(0, $result->fetchAll());
- $query = new Query($this->connection);
- $types = ['created' => 'datetime'];
- $result = $query
- ->select(['title', 'name' => 'comments.comment'])
- ->from('articles')
- ->innerJoin('comments', function ($exp, $q) use ($query, $types) {
- $this->assertSame($q, $query);
- $exp->add(['created >' => new \DateTime('2007-03-18 10:45:23')], $types);
- return $exp;
- })
- ->execute();
- $this->assertEquals(
- ['title' => 'First Article', 'name' => 'Second Comment for First Article'],
- $result->fetch('assoc')
- );
- }
- /**
- * Tests it is possible to filter a query by using simple AND joined conditions
- *
- * @return void
- */
- public function testSelectSimpleWhere()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['id' => 1, 'title' => 'First Article'])
- ->execute();
- $this->assertCount(1, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['id' => 100], ['id' => 'integer'])
- ->execute();
- $this->assertCount(0, $result);
- }
- /**
- * Tests using where conditions with operators and scalar values works
- *
- * @return void
- */
- public function testSelectWhereOperators()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['id >' => 1])
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['title' => 'Second Article'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['id <' => 2])
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['title' => 'First Article'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['id <=' => 2])
- ->execute();
- $this->assertCount(2, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['id >=' => 1])
- ->execute();
- $this->assertCount(3, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['id <=' => 1])
- ->execute();
- $this->assertCount(1, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['id !=' => 2])
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['title' => 'First Article'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['title LIKE' => 'First Article'])
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['title' => 'First Article'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['title like' => '%Article%'])
- ->execute();
- $this->assertCount(3, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(['title not like' => '%Article%'])
- ->execute();
- $this->assertCount(0, $result);
- }
- /**
- * Tests selecting with conditions and specifying types for those
- *
- * @return void
- */
- public function testSelectWhereTypes()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['created >' => new \DateTime('2007-03-18 10:46:00')], ['created' => 'datetime'])
- ->execute();
- $this->assertCount(5, $result);
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(
- [
- 'created >' => new \DateTime('2007-03-18 10:40:00'),
- 'created <' => new \DateTime('2007-03-18 10:46:00')
- ],
- ['created' => 'datetime']
- )
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(
- [
- 'id' => '3something-crazy',
- 'created <' => new \DateTime('2013-01-01 12:00')
- ],
- ['created' => 'datetime', 'id' => 'integer']
- )
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(
- [
- 'id' => '1something-crazy',
- 'created <' => new \DateTime('2013-01-01 12:00')
- ],
- ['created' => 'datetime', 'id' => 'float']
- )
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- }
- /**
- * Tests that passing an array type to any where condition will replace
- * the passed array accordingly as a proper IN condition
- *
- * @return void
- */
- public function testSelectWhereArrayType()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['id' => ['1', '3']], ['id' => 'integer[]'])
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- }
- /**
- * Tests that passing an empty array type to any where condition will not
- * result in an error, but in an empty result set
- *
- * @return void
- */
- public function testSelectWhereArrayTypeEmpty()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['id' => []], ['id' => 'integer[]'])
- ->execute();
- $this->assertCount(0, $result);
- }
- /**
- * Tests that Query::orWhere() can be used to concatenate conditions with OR
- *
- * @return void
- */
- public function testSelectOrWhere()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
- ->orWhere(['created' => new \DateTime('2007-03-18 10:47:23')], ['created' => 'datetime'])
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- }
- /**
- * Tests that Query::andWhere() can be used to concatenate conditions with AND
- *
- * @return void
- */
- public function testSelectAndWhere()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
- ->andWhere(['id' => 1])
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['created' => new \DateTime('2007-03-18 10:50:55')], ['created' => 'datetime'])
- ->andWhere(['id' => 2])
- ->execute();
- $this->assertCount(0, $result);
- }
- /**
- * Tests that combining Query::andWhere() and Query::orWhere() produces
- * correct conditions nesting
- *
- * @return void
- */
- public function testSelectExpressionNesting()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
- ->orWhere(['id' => 2])
- ->andWhere(['created >=' => new \DateTime('2007-03-18 10:40:00')], ['created' => 'datetime'])
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
- ->orWhere(['id' => 2])
- ->andWhere(['created >=' => new \DateTime('2007-03-18 10:40:00')], ['created' => 'datetime'])
- ->orWhere(['created' => new \DateTime('2007-03-18 10:49:23')], ['created' => 'datetime'])
- ->execute();
- $this->assertCount(3, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- }
- /**
- * Tests that Query::orWhere() can be used without calling where() before
- *
- * @return void
- */
- public function testSelectOrWhereNoPreviousCondition()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->orWhere(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
- ->orWhere(['created' => new \DateTime('2007-03-18 10:47:23')], ['created' => 'datetime'])
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- }
- /**
- * Tests that Query::andWhere() can be used without calling where() before
- *
- * @return void
- */
- public function testSelectAndWhereNoPreviousCondition()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->andWhere(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
- ->andWhere(['id' => 1])
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- }
- /**
- * Tests that it is possible to pass a closure to where() to build a set of
- * conditions and return the expression to be used
- *
- * @return void
- */
- public function testSelectWhereUsingClosure()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->eq('id', 1);
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp
- ->eq('id', 1)
- ->eq('created', new \DateTime('2007-03-18 10:45:23'), 'datetime');
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp
- ->eq('id', 1)
- ->eq('created', new \DateTime('2021-12-30 15:00'), 'datetime');
- })
- ->execute();
- $this->assertCount(0, $result);
- }
- /**
- * Tests generating tuples in the values side containing closure expressions
- *
- * @return void
- */
- public function testTupleWithClosureExpression()
- {
- $query = new Query($this->connection);
- $query->select(['id'])
- ->from('comments')
- ->where([
- 'OR' => [
- 'id' => 1,
- function ($exp) {
- return $exp->eq('id', 2);
- }
- ]
- ]);
- $result = $query->sql();
- $this->assertQuotedQuery(
- 'SELECT <id> FROM <comments> WHERE \(<id> = :c0 OR <id> = :c1\)',
- $result,
- true
- );
- }
- /**
- * Tests that it is possible to pass a closure to andWhere() to build a set of
- * conditions and return the expression to be used
- *
- * @return void
- */
- public function testSelectAndWhereUsingClosure()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['id' => '1'])
- ->andWhere(function ($exp) {
- return $exp->eq('created', new \DateTime('2007-03-18 10:45:23'), 'datetime');
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['id' => '1'])
- ->andWhere(function ($exp) {
- return $exp->eq('created', new \DateTime('2022-12-21 12:00'), 'datetime');
- })
- ->execute();
- $this->assertCount(0, $result);
- }
- /**
- * Tests that it is possible to pass a closure to orWhere() to build a set of
- * conditions and return the expression to be used
- *
- * @return void
- */
- public function testSelectOrWhereUsingClosure()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['id' => '1'])
- ->orWhere(function ($exp) {
- return $exp->eq('created', new \DateTime('2007-03-18 10:47:23'), 'datetime');
- })
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['id' => '1'])
- ->orWhere(function ($exp) {
- return $exp
- ->eq('created', new \DateTime('2012-12-22 12:00'), 'datetime')
- ->eq('id', 3);
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- }
- /**
- * Tests that expression objects can be used as the field in a comparison
- * and the values will be bound correctly to the query
- *
- * @return void
- */
- public function testSelectWhereUsingExpressionInField()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- $field = clone $exp;
- $field->add('SELECT min(id) FROM comments');
- return $exp
- ->eq($field, 100, 'integer');
- })
- ->execute();
- $this->assertCount(0, $result);
- }
- /**
- * Tests using where conditions with operator methods
- *
- * @return void
- */
- public function testSelectWhereOperatorMethods()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(function ($exp) {
- return $exp->gt('id', 1);
- })
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['title' => 'Second Article'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query->select(['title'])
- ->from('articles')
- ->where(function ($exp) {
- return $exp->lt('id', 2);
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['title' => 'First Article'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query->select(['title'])
- ->from('articles')
- ->where(function ($exp) {
- return $exp->lte('id', 2);
- })
- ->execute();
- $this->assertCount(2, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(function ($exp) {
- return $exp->gte('id', 1);
- })
- ->execute();
- $this->assertCount(3, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(function ($exp) {
- return $exp->lte('id', 1);
- })
- ->execute();
- $this->assertCount(1, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(function ($exp) {
- return $exp->notEq('id', 2);
- })
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['title' => 'First Article'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(function ($exp) {
- return $exp->like('title', 'First Article');
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['title' => 'First Article'], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(function ($exp) {
- return $exp->like('title', '%Article%');
- })
- ->execute();
- $this->assertCount(3, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['title'])
- ->from('articles')
- ->where(function ($exp) {
- return $exp->notLike('title', '%Article%');
- })
- ->execute();
- $this->assertCount(0, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->isNull('published');
- })
- ->execute();
- $this->assertCount(0, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->isNotNull('published');
- })
- ->execute();
- $this->assertCount(6, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->in('published', ['Y', 'N']);
- })
- ->execute();
- $this->assertCount(6, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->in(
- 'created',
- [new \DateTime('2007-03-18 10:45:23'), new \DateTime('2007-03-18 10:47:23')],
- 'datetime'
- );
- })
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->notIn(
- 'created',
- [new \DateTime('2007-03-18 10:45:23'), new \DateTime('2007-03-18 10:47:23')],
- 'datetime'
- );
- })
- ->execute();
- $this->assertCount(4, $result);
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- }
- /**
- * Tests that calling "in" and "notIn" will cast the passed values to an array
- *
- * @return void
- */
- public function testInValueCast()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->in('created', '2007-03-18 10:45:23', 'datetime');
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->notIn('created', '2007-03-18 10:45:23', 'datetime');
- })
- ->execute();
- $this->assertCount(5, $result);
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $this->assertEquals(['id' => 4], $result->fetch('assoc'));
- $this->assertEquals(['id' => 5], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp, $q) {
- return $exp->in(
- 'created',
- $q->newExpr("'2007-03-18 10:45:23'"),
- 'datetime'
- );
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp, $q) {
- return $exp->notIn(
- 'created',
- $q->newExpr("'2007-03-18 10:45:23'"),
- 'datetime'
- );
- })
- ->execute();
- $this->assertCount(5, $result);
- }
- /**
- * Tests that calling "in" and "notIn" will cast the passed values to an array
- *
- * @return void
- */
- public function testInValueCast2()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['created IN' => '2007-03-18 10:45:23'])
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(['created NOT IN' => '2007-03-18 10:45:23'])
- ->execute();
- $this->assertCount(5, $result);
- }
- /**
- * Tests that it is possible to use a between expression
- * in a where condition
- *
- * @return void
- */
- public function testWhereWithBetween()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->between('id', 5, 6, 'integer');
- })
- ->execute();
- $this->assertCount(2, $result);
- $first = $result->fetch('assoc');
- $this->assertEquals(5, $first['id']);
- $second = $result->fetch('assoc');
- $this->assertEquals(6, $second['id']);
- }
- /**
- * Tests that it is possible to use a between expression
- * in a where condition with a complex data type
- *
- * @return void
- */
- public function testWhereWithBetweenComplex()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- $from = new \DateTime('2007-03-18 10:51:00');
- $to = new \DateTime('2007-03-18 10:54:00');
- return $exp->between('created', $from, $to, 'datetime');
- })
- ->execute();
- $this->assertCount(2, $result);
- $first = $result->fetch('assoc');
- $this->assertEquals(4, $first['id']);
- $second = $result->fetch('assoc');
- $this->assertEquals(5, $second['id']);
- }
- /**
- * Tests that it is possible to use an expresison object
- * as the field for a between expression
- *
- * @return void
- */
- public function testWhereWithBetweenWithExpressionField()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp, $q) {
- $field = $q->newExpr('COALESCE(id, 1)');
- return $exp->between($field, 5, 6, 'integer');
- })
- ->execute();
- $this->assertCount(2, $result);
- $first = $result->fetch('assoc');
- $this->assertEquals(5, $first['id']);
- $second = $result->fetch('assoc');
- $this->assertEquals(6, $second['id']);
- }
- /**
- * Tests nesting query expressions both using arrays and closures
- *
- * @return void
- */
- public function testSelectExpressionComposition()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- $and = $exp->and_(['id' => 2, 'id >' => 1]);
- return $exp->add($and);
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- $and = $exp->and_(['id' => 2, 'id <' => 2]);
- return $exp->add($and);
- })
- ->execute();
- $this->assertCount(0, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- $and = $exp->and_(function ($and) {
- return $and->eq('id', 1)->gt('id', 0);
- });
- return $exp->add($and);
- })
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- $or = $exp->or_(['id' => 1]);
- $and = $exp->and_(['id >' => 2, 'id <' => 4]);
- return $or->add($and);
- })
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- $or = $exp->or_(function ($or) {
- return $or->eq('id', 1)->eq('id', 2);
- });
- return $or;
- })
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- }
- /**
- * Tests that conditions can be nested with an unary operator using the array notation
- * and the not() method
- *
- * @return void
- */
- public function testSelectWhereNot()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->not(
- $exp->and_(['id' => 2, 'created' => new \DateTime('2007-03-18 10:47:23')], ['created' => 'datetime'])
- );
- })
- ->execute();
- $this->assertCount(5, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('comments')
- ->where(function ($exp) {
- return $exp->not(
- $exp->and_(['id' => 2, 'created' => new \DateTime('2012-12-21 12:00')], ['created' => 'datetime'])
- );
- })
- ->execute();
- $this->assertCount(6, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('articles')
- ->where([
- 'not' => ['or' => ['id' => 1, 'id >' => 2], 'id' => 3]
- ])
- ->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- }
- /**
- * Tests order() method both with simple fields and expressions
- *
- * @return void
- */
- public function testSelectOrderBy()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id'])
- ->from('articles')
- ->order(['id' => 'desc'])
- ->execute();
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $result = $query->order(['id' => 'asc'])->execute();
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $result = $query->order(['title' => 'asc'])->execute();
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $result = $query->order(['title' => 'asc'], true)->execute();
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $result = $query->order(['title' => 'asc', 'published' => 'asc'], true)
- ->execute();
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $expression = $query->newExpr(['(id + :offset) % 2']);
- $result = $query
- ->order([$expression, 'id' => 'desc'], true)
- ->bind(':offset', 1, null)
- ->execute();
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $result = $query
- ->order($expression, true)
- ->order(['id' => 'asc'])
- ->bind(':offset', 1, null)
- ->execute();
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- }
- /**
- * Tests that group by fields can be passed similar to select fields
- * and that it sends the correct query to the database
- *
- * @return void
- */
- public function testSelectGroup()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['total' => 'count(author_id)', 'author_id'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
- ->group('author_id')
- ->execute();
- $expected = [['total' => 2, 'author_id' => 1], ['total' => '1', 'author_id' => 3]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $result = $query->select(['total' => 'count(title)', 'name'], true)
- ->group(['name'], true)
- ->order(['total' => 'asc'])
- ->execute();
- $expected = [['total' => 1, 'name' => 'larry'], ['total' => 2, 'name' => 'mariano']];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $result = $query->select(['articles.id'])
- ->group(['articles.id'])
- ->execute();
- $this->assertCount(3, $result);
- }
- /**
- * Tests that it is possible to select distinct rows
- *
- * @return void
- */
- public function testSelectDistinct()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['author_id'])
- ->from(['a' => 'articles'])
- ->execute();
- $this->assertCount(3, $result);
- $result = $query->distinct()->execute();
- $this->assertCount(2, $result);
- $result = $query->select(['id'])->distinct(false)->execute();
- $this->assertCount(3, $result);
- }
- /**
- * Tests that it is possible to select distinct rows, even filtering by one column
- * this is testing that there is a specific implementation for DISTINCT ON
- *
- * @return void
- */
- public function testSelectDistinctON()
- {
- $this->skipIf(
- $this->connection->driver() instanceof \Cake\Database\Driver\Sqlserver,
- 'Not implemented yet in SqlServer'
- );
- $query = new Query($this->connection);
- $result = $query
- ->select(['id', 'author_id'])
- ->distinct(['author_id'])
- ->from(['a' => 'articles'])
- ->execute();
- $this->assertCount(2, $result);
- }
- /**
- * Test use of modifiers in the query
- *
- * Testing the generated SQL since the modifiers are usually different per driver
- *
- * @return void
- */
- public function testSelectModifiers()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['city', 'state', 'country'])
- ->from(['addresses'])
- ->modifier('DISTINCTROW');
- $this->assertQuotedQuery(
- 'SELECT DISTINCTROW <city>, <state>, <country> FROM <addresses>',
- $result->sql(),
- true
- );
- $query = new Query($this->connection);
- $result = $query
- ->select(['city', 'state', 'country'])
- ->from(['addresses'])
- ->modifier(['DISTINCTROW', 'SQL_NO_CACHE']);
- $this->assertQuotedQuery(
- 'SELECT DISTINCTROW SQL_NO_CACHE <city>, <state>, <country> FROM <addresses>',
- $result->sql(),
- true
- );
- $query = new Query($this->connection);
- $result = $query
- ->select(['city', 'state', 'country'])
- ->from(['addresses'])
- ->modifier('DISTINCTROW')
- ->modifier('SQL_NO_CACHE');
- $this->assertQuotedQuery(
- 'SELECT DISTINCTROW SQL_NO_CACHE <city>, <state>, <country> FROM <addresses>',
- $result->sql(),
- true
- );
- $query = new Query($this->connection);
- $result = $query
- ->select(['city', 'state', 'country'])
- ->from(['addresses'])
- ->modifier(['TOP 10']);
- $this->assertQuotedQuery(
- 'SELECT TOP 10 <city>, <state>, <country> FROM <addresses>',
- $result->sql(),
- true
- );
- }
- /**
- * Tests that having() behaves pretty much the same as the where() method
- *
- * @return void
- */
- public function testSelectHaving()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['total' => 'count(author_id)', 'author_id'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
- ->group('author_id')
- ->having(['count(author_id) <' => 2], ['count(author_id)' => 'integer'])
- ->execute();
- $expected = [['total' => 1, 'author_id' => 3]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $result = $query->having(['count(author_id)' => 2], ['count(author_id)' => 'integer'], true)
- ->execute();
- $expected = [['total' => 2, 'author_id' => 1]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $result = $query->having(function ($e) {
- return $e->add('count(author_id) = 1 + 1');
- }, [], true)
- ->execute();
- $expected = [['total' => 2, 'author_id' => 1]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- }
- /**
- * Tests that Query::orHaving() can be used to concatenate conditions with OR
- * in the having clause
- *
- * @return void
- */
- public function testSelectOrHaving()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['total' => 'count(author_id)', 'author_id'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
- ->group('author_id')
- ->having(['count(author_id) >' => 2], ['count(author_id)' => 'integer'])
- ->orHaving(['count(author_id) <' => 2], ['count(author_id)' => 'integer'])
- ->execute();
- $expected = [['total' => 1, 'author_id' => 3]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['total' => 'count(author_id)', 'author_id'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
- ->group('author_id')
- ->having(['count(author_id) >' => 2], ['count(author_id)' => 'integer'])
- ->orHaving(['count(author_id) <=' => 2], ['count(author_id)' => 'integer'])
- ->execute();
- $expected = [['total' => 2, 'author_id' => 1], ['total' => 1, 'author_id' => 3]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['total' => 'count(author_id)', 'author_id'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
- ->group('author_id')
- ->having(['count(author_id) >' => 2], ['count(author_id)' => 'integer'])
- ->orHaving(function ($e) {
- return $e->add('count(author_id) = 1 + 1');
- })
- ->execute();
- $expected = [['total' => 2, 'author_id' => 1]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- }
- /**
- * Tests that Query::andHaving() can be used to concatenate conditions with AND
- * in the having clause
- *
- * @return void
- */
- public function testSelectAndHaving()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['total' => 'count(author_id)', 'author_id'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
- ->group('author_id')
- ->having(['count(author_id) >' => 2], ['count(author_id)' => 'integer'])
- ->andHaving(['count(author_id) <' => 2], ['count(author_id)' => 'integer'])
- ->execute();
- $this->assertCount(0, $result);
- $query = new Query($this->connection);
- $result = $query
- ->select(['total' => 'count(author_id)', 'author_id'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
- ->group('author_id')
- ->having(['count(author_id)' => 2], ['count(author_id)' => 'integer'])
- ->andHaving(['count(author_id) >' => 1], ['count(author_id)' => 'integer'])
- ->execute();
- $expected = [['total' => 2, 'author_id' => 1]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['total' => 'count(author_id)', 'author_id'])
- ->from('articles')
- ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
- ->group('author_id')
- ->andHaving(function ($e) {
- return $e->add('count(author_id) = 2 - 1');
- })
- ->execute();
- $expected = [['total' => 1, 'author_id' => 3]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- }
- /**
- * Tests selecting rows using a limit clause
- *
- * @return void
- */
- public function testSelectLimit()
- {
- $query = new Query($this->connection);
- $result = $query->select('id')->from('articles')->limit(1)->execute();
- $this->assertCount(1, $result);
- $query = new Query($this->connection);
- $result = $query->select('id')->from('articles')->limit(2)->execute();
- $this->assertCount(2, $result);
- }
- /**
- * Tests selecting rows combining a limit and offset clause
- *
- * @return void
- */
- public function testSelectOffset()
- {
- $query = new Query($this->connection);
- $result = $query->select('id')->from('comments')
- ->limit(1)
- ->offset(0)
- ->order(['id' => 'ASC'])
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query->select('id')->from('comments')
- ->limit(1)
- ->offset(1)
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query->select('id')->from('comments')
- ->limit(1)
- ->offset(2)
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query->select('id')->from('articles')
- ->order(['id' => 'DESC'])
- ->limit(1)
- ->offset(0)
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 3], $result->fetch('assoc'));
- $result = $query->limit(2)->offset(1)->execute();
- $this->assertCount(2, $result);
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- }
- /**
- * Test selecting rows using the page() method.
- *
- * @return void
- */
- public function testSelectPage()
- {
- $query = new Query($this->connection);
- $result = $query->select('id')->from('comments')
- ->limit(1)
- ->page(1)
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 1], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $result = $query->select('id')->from('comments')
- ->limit(1)
- ->page(2)
- ->order(['id' => 'asc'])
- ->execute();
- $this->assertCount(1, $result);
- $this->assertEquals(['id' => 2], $result->fetch('assoc'));
- $query = new Query($this->connection);
- $query->select('id')->from('comments')->page(3, 10);
- $this->assertEquals(10, $query->clause('limit'));
- $this->assertEquals(20, $query->clause('offset'));
- $query = new Query($this->connection);
- $query->select('id')->from('comments')->page(1);
- $this->assertEquals(25, $query->clause('limit'));
- $this->assertEquals(0, $query->clause('offset'));
- $query->select('id')->from('comments')->page(2);
- $this->assertEquals(25, $query->clause('limit'));
- $this->assertEquals(25, $query->clause('offset'));
- }
- /**
- * Tests that Query objects can be included inside the select clause
- * and be used as a normal field, including binding any passed parameter
- *
- * @return void
- */
- public function testSubqueryInSelect()
- {
- $query = new Query($this->connection);
- $subquery = (new Query($this->connection))
- ->select('name')
- ->from(['b' => 'authors'])
- ->where(['b.id = a.id']);
- $result = $query
- ->select(['id', 'name' => $subquery])
- ->from(['a' => 'comments'])->execute();
- $expected = [
- ['id' => 1, 'name' => 'mariano'],
- ['id' => 2, 'name' => 'nate'],
- ['id' => 3, 'name' => 'larry'],
- ['id' => 4, 'name' => 'garrett'],
- ['id' => 5, 'name' => null],
- ['id' => 6, 'name' => null],
- ];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $query = new Query($this->connection);
- $subquery = (new Query($this->connection))
- ->select('name')
- ->from(['b' => 'authors'])
- ->where(['name' => 'mariano'], ['name' => 'string']);
- $result = $query
- ->select(['id', 'name' => $subquery])
- ->from(['a' => 'articles'])->execute();
- $expected = [
- ['id' => 1, 'name' => 'mariano'],
- ['id' => 2, 'name' => 'mariano'],
- ['id' => 3, 'name' => 'mariano'],
- ];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- }
- /**
- * Tests that Query objects can be included inside the from clause
- * and be used as a normal table, including binding any passed parameter
- *
- * @return void
- */
- public function testSuqueryInFrom()
- {
- $query = new Query($this->connection);
- $subquery = (new Query($this->connection))
- ->select(['id', 'comment'])
- ->from('comments')
- ->where(['created >' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime']);
- $result = $query
- ->select(['say' => 'comment'])
- ->from(['b' => $subquery])
- ->where(['id !=' => 3])
- ->execute();
- $expected = [
- ['say' => 'Second Comment for First Article'],
- ['say' => 'Fourth Comment for First Article'],
- ['say' => 'First Comment for Second Article'],
- ['say' => 'Second Comment for Second Article'],
- ];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- }
- /**
- * Tests that Query objects can be included inside the where clause
- * and be used as a normal condition, including binding any passed parameter
- *
- * @return void
- */
- public function testSubqueryInWhere()
- {
- $query = new Query($this->connection);
- $subquery = (new Query($this->connection))
- ->select(['id'])
- ->from('authors')
- ->where(['id' => 1]);
- $result = $query
- ->select(['name'])
- ->from(['authors'])
- ->where(['id !=' => $subquery])
- ->execute();
- $expected = [
- ['name' => 'nate'],
- ['name' => 'larry'],
- ['name' => 'garrett'],
- ];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $query = new Query($this->connection);
- $subquery = (new Query($this->connection))
- ->select(['id'])
- ->from('comments')
- ->where(['created >' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime']);
- $result = $query
- ->select(['name'])
- ->from(['authors'])
- ->where(['id not in' => $subquery])
- ->execute();
- $expected = [
- ['name' => 'mariano'],
- ];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- }
- /**
- * Tests that it is possible to use a subquery in a join clause
- *
- * @return void
- */
- public function testSubqueyInJoin()
- {
- $subquery = (new Query($this->connection))->select('*')->from('authors');
- $query = new Query($this->connection);
- $result = $query
- ->select(['title', 'name'])
- ->from('articles')
- ->join(['b' => $subquery])
- ->execute();
- $this->assertCount(self::ARTICLE_COUNT * self::AUTHOR_COUNT, $result, 'Cross join causes multiplication');
- $subquery->where(['id' => 1]);
- $result = $query->execute();
- $this->assertCount(3, $result);
- $query->join(['b' => ['table' => $subquery, 'conditions' => ['b.id = articles.id']]], [], true);
- $result = $query->execute();
- $this->assertCount(1, $result);
- }
- /**
- * Tests that it is possible to one or multiple UNION statements in a query
- *
- * @return void
- */
- public function testUnion()
- {
- $union = (new Query($this->connection))->select(['id', 'title'])->from(['a' => 'articles']);
- $query = new Query($this->connection);
- $result = $query->select(['id', 'comment'])
- ->from(['c' => 'comments'])
- ->union($union)
- ->execute();
- $this->assertCount(self::COMMENT_COUNT + self::ARTICLE_COUNT, $result);
- $rows = $result->fetchAll();
- $union->select(['foo' => 'id', 'bar' => 'title']);
- $union = (new Query($this->connection))
- ->select(['id', 'name', 'other' => 'id', 'nameish' => 'name'])
- ->from(['b' => 'authors'])
- ->where(['id ' => 1])
- ->order(['id' => 'desc']);
- $query->select(['foo' => 'id', 'bar' => 'comment'])->union($union);
- $result = $query->execute();
- $this->assertCount(self::COMMENT_COUNT + self::AUTHOR_COUNT, $result);
- $this->assertNotEquals($rows, $result->fetchAll());
- $union = (new Query($this->connection))
- ->select(['id', 'title'])
- ->from(['c' => 'articles']);
- $query->select(['id', 'comment'], true)->union($union, true);
- $result = $query->execute();
- $this->assertCount(self::COMMENT_COUNT + self::ARTICLE_COUNT, $result);
- $this->assertEquals($rows, $result->fetchAll());
- }
- /**
- * Tests that UNION ALL can be built by setting the second param of union() to true
- *
- * @return void
- */
- public function testUnionAll()
- {
- $union = (new Query($this->connection))->select(['id', 'title'])->from(['a' => 'articles']);
- $query = new Query($this->connection);
- $result = $query->select(['id', 'comment'])
- ->from(['c' => 'comments'])
- ->union($union)
- ->execute();
- $this->assertCount(self::ARTICLE_COUNT + self::COMMENT_COUNT, $result);
- $rows = $result->fetchAll();
- $union->select(['foo' => 'id', 'bar' => 'title']);
- $union = (new Query($this->connection))
- ->select(['id', 'name', 'other' => 'id', 'nameish' => 'name'])
- ->from(['b' => 'authors'])
- ->where(['id ' => 1])
- ->order(['id' => 'desc']);
- $query->select(['foo' => 'id', 'bar' => 'comment'])->unionAll($union);
- $result = $query->execute();
- $this->assertCount(1 + self::COMMENT_COUNT + self::ARTICLE_COUNT, $result);
- $this->assertNotEquals($rows, $result->fetchAll());
- }
- /**
- * Tests stacking decorators for results and resetting the list of decorators
- *
- * @return void
- */
- public function testDecorateResults()
- {
- $query = new Query($this->connection);
- $result = $query
- ->select(['id', 'title'])
- ->from('articles')
- ->order(['id' => 'ASC'])
- ->decorateResults(function ($row) {
- $row['modified_id'] = $row['id'] + 1;
- return $row;
- })
- ->execute();
- while ($row = $result->fetch('assoc')) {
- $this->assertEquals($row['id'] + 1, $row['modified_id']);
- }
- $result = $query->decorateResults(function ($row) {
- $row['modified_id']--;
- return $row;
- })->execute();
- while ($row = $result->fetch('assoc')) {
- $this->assertEquals($row['id'], $row['modified_id']);
- }
- $result = $query
- ->decorateResults(function ($row) {
- $row['foo'] = 'bar';
- return $row;
- }, true)
- ->execute();
- while ($row = $result->fetch('assoc')) {
- $this->assertEquals('bar', $row['foo']);
- $this->assertArrayNotHasKey('modified_id', $row);
- }
- $results = $query->decorateResults(null, true)->execute();
- while ($row = $result->fetch('assoc')) {
- $this->assertArrayNotHasKey('foo', $row);
- $this->assertArrayNotHasKey('modified_id', $row);
- }
- }
- /**
- * Test a basic delete using from()
- *
- * @return void
- */
- public function testDeleteWithFrom()
- {
- $query = new Query($this->connection);
- $query->delete()
- ->from('authors')
- ->where('1 = 1');
- $result = $query->sql();
- $this->assertQuotedQuery('DELETE FROM <authors>', $result, true);
- $result = $query->execute();
- $this->assertInstanceOf('Cake\Database\StatementInterface', $result);
- $this->assertCount(self::AUTHOR_COUNT, $result);
- }
- /**
- * Test delete with from and alias.
- *
- * @return void
- */
- public function testDeleteWithAliasedFrom()
- {
- $query = new Query($this->connection);
- $query->delete()
- ->from(['a ' => 'authors'])
- ->where(['a.id !=' => 99]);
- $result = $query->sql();
- $this->assertQuotedQuery('DELETE FROM <authors> WHERE <id> != :c0', $result, true);
- $result = $query->execute();
- $this->assertInstanceOf('Cake\Database\StatementInterface', $result);
- $this->assertCount(self::AUTHOR_COUNT, $result);
- }
- /**
- * Test a basic delete with no from() call.
- *
- * @return void
- */
- public function testDeleteNoFrom()
- {
- $query = new Query($this->connection);
- $query->delete('authors')
- ->where('1 = 1');
- $result = $query->sql();
- $this->assertQuotedQuery('DELETE FROM <authors>', $result, true);
- $result = $query->execute();
- $this->assertInstanceOf('Cake\Database\StatementInterface', $result);
- $this->assertCount(self::AUTHOR_COUNT, $result);
- }
- /**
- * Test setting select() & delete() modes.
- *
- * @return void
- */
- public function testSelectAndDeleteOnSameQuery()
- {
- $query = new Query($this->connection);
- $result = $query->select()
- ->delete('authors')
- ->where('1 = 1');
- $result = $query->sql();
- $this->assertQuotedQuery('DELETE FROM <authors>', $result, true);
- $this->assertContains(' WHERE 1 = 1', $result);
- }
- /**
- * Test a simple update.
- *
- * @return void
- */
- public function testUpdateSimple()
- {
- $query = new Query($this->connection);
- $query->update('authors')
- ->set('name', 'mark')
- ->where(['id' => 1]);
- $result = $query->sql();
- $this->assertQuotedQuery('UPDATE <authors> SET <name> = :', $result, true);
- $result = $query->execute();
- $this->assertCount(1, $result);
- }
- /**
- * Test update with multiple fields.
- *
- * @return void
- */
- public function testUpdateMultipleFields()
- {
- $query = new Query($this->connection);
- $query->update('articles')
- ->set('title', 'mark', 'string')
- ->set('body', 'some text', 'string')
- ->where(['id' => 1]);
- $result = $query->sql();
- $this->assertQuotedQuery(
- 'UPDATE <articles> SET <title> = :c0 , <body> = :c1',
- $result,
- true
- );
- $this->assertQuotedQuery(' WHERE <id> = :c2$', $result, true);
- $result = $query->execute();
- $this->assertCount(1, $result);
- }
- /**
- * Test updating multiple fields with an array.
- *
- * @return void
- */
- public function testUpdateMultipleFieldsArray()
- {
- $query = new Query($this->connection);
- $query->update('articles')
- ->set([
- 'title' => 'mark',
- 'body' => 'some text'
- ], ['title' => 'string', 'body' => 'string'])
- ->where(['id' => 1]);
- $result = $query->sql();
- $this->assertQuotedQuery(
- 'UPDATE <articles> SET <title> = :c0 , <body> = :c1',
- $result,
- true
- );
- $this->assertQuotedQuery('WHERE <id> = :', $result, true);
- $result = $query->execute();
- $this->assertCount(1, $result);
- }
- /**
- * Test updates with an expression.
- *
- * @return void
- */
- public function testUpdateWithExpression()
- {
- $query = new Query($this->connection);
- $expr = $query->newExpr('title = author_id');
- $query->update('articles')
- ->set($expr)
- ->where(['id' => 1]);
- $result = $query->sql();
- $this->assertQuotedQuery(
- 'UPDATE <articles> SET title = author_id WHERE <id> = :',
- $result,
- true
- );
- $result = $query->execute();
- $this->assertCount(1, $result);
- }
- /**
- * Test update with array fields and types.
- *
- * @return void
- */
- public function testUpdateArrayFields()
- {
- $query = new Query($this->connection);
- $date = new \DateTime;
- $query->update('comments')
- ->set(['comment' => 'mark', 'created' => $date], ['created' => 'date'])
- ->where(['id' => 1]);
- $result = $query->sql();
- $this->assertQuotedQuery(
- 'UPDATE <comments> SET <comment> = :c0 , <created> = :c1',
- $result,
- true
- );
- $this->assertQuotedQuery(' WHERE <id> = :c2$', $result, true);
- $result = $query->execute();
- $this->assertCount(1, $result);
- $query = new Query($this->connection);
- $result = $query->select('created')->from('comments')->where(['id' => 1])->execute();
- $result = $result->fetchAll('assoc')[0]['created'];
- $this->assertStringStartsWith($date->format('Y-m-d'), $result);
- }
- /**
- * You cannot call values() before insert() it causes all sorts of pain.
- *
- * @expectedException \Cake\Database\Exception
- * @return void
- */
- public function testInsertValuesBeforeInsertFailure()
- {
- $query = new Query($this->connection);
- $query->select('*')->values([
- 'id' => 1,
- 'title' => 'mark',
- 'body' => 'test insert'
- ]);
- }
- /**
- * Inserting nothing should not generate an error.
- *
- * @expectedException \RuntimeException
- * @expectedExceptionMessage At least 1 column is required to perform an insert.
- * @return void
- */
- public function testInsertNothing()
- {
- $query = new Query($this->connection);
- $query->insert([]);
- }
- /**
- * Test inserting a single row.
- *
- * @return void
- */
- public function testInsertSimple()
- {
- $query = new Query($this->connection);
- $query->insert(['title', 'body'])
- ->into('articles')
- ->values([
- 'title' => 'mark',
- 'body' => 'test insert'
- ]);
- $result = $query->sql();
- $this->assertQuotedQuery(
- 'INSERT INTO <articles> \(<title>, <body>\) (OUTPUT INSERTED\.\* )?' .
- 'VALUES \(:c0, :c1\)',
- $result,
- true
- );
- $result = $query->execute();
- $result->closeCursor();
- //PDO_SQLSRV returns -1 for successful inserts when using INSERT ... OUTPUT
- if (!$this->connection->driver() instanceof \Cake\Database\Driver\Sqlserver) {
- $this->assertCount(1, $result, '1 row should be inserted');
- }
- $expected = [
- [
- 'id' => 4,
- 'author_id' => null,
- 'title' => 'mark',
- 'body' => 'test insert',
- 'published' => 'N',
- ]
- ];
- $this->assertTable('articles', 1, $expected, ['id >=' => 4]);
- }
- /**
- * Test an insert when not all the listed fields are provided.
- * Columns should be matched up where possible.
- *
- * @return void
- */
- public function testInsertSparseRow()
- {
- $query = new Query($this->connection);
- $query->insert(['title', 'body'])
- ->into('articles')
- ->values([
- 'title' => 'mark',
- ]);
- $result = $query->sql();
- $this->assertQuotedQuery(
- 'INSERT INTO <articles> \(<title>, <body>\) (OUTPUT INSERTED\.\* )?' .
- 'VALUES \(:c0, :c1\)',
- $result,
- true
- );
- $result = $query->execute();
- $result->closeCursor();
- //PDO_SQLSRV returns -1 for successful inserts when using INSERT ... OUTPUT
- if (!$this->connection->driver() instanceof \Cake\Database\Driver\Sqlserver) {
- $this->assertCount(1, $result, '1 row should be inserted');
- }
- $expected = [
- [
- 'id' => 4,
- 'author_id' => null,
- 'title' => 'mark',
- 'body' => null,
- 'published' => 'N',
- ]
- ];
- $this->assertTable('articles', 1, $expected, ['id >= 4']);
- }
- /**
- * Test inserting multiple rows with sparse data.
- *
- * @return void
- */
- public function testInsertMultipleRowsSparse()
- {
- $query = new Query($this->connection);
- $query->insert(['title', 'body'])
- ->into('articles')
- ->values([
- 'body' => 'test insert'
- ])
- ->values([
- 'title' => 'jose',
- ]);
- $result = $query->execute();
- $result->closeCursor();
- //PDO_SQLSRV returns -1 for successful inserts when using INSERT ... OUTPUT
- if (!$this->connection->driver() instanceof \Cake\Database\Driver\Sqlserver) {
- $this->assertCount(2, $result, '2 rows should be inserted');
- }
- $expected = [
- [
- 'id' => 4,
- 'author_id' => null,
- 'title' => null,
- 'body' => 'test insert',
- 'published' => 'N',
- ],
- [
- 'id' => 5,
- 'author_id' => null,
- 'title' => 'jose',
- 'body' => null,
- 'published' => 'N',
- ],
- ];
- $this->assertTable('articles', 2, $expected, ['id >=' => 4]);
- }
- /**
- * Test that INSERT INTO ... SELECT works.
- *
- * @return void
- */
- public function testInsertFromSelect()
- {
- $select = (new Query($this->connection))->select(['name', "'some text'", 99])
- ->from('authors')
- ->where(['id' => 1]);
- $query = new Query($this->connection);
- $query->insert(
- ['title', 'body', 'author_id'],
- ['title' => 'string', 'body' => 'string', 'author_id' => 'integer']
- )
- ->into('articles')
- ->values($select);
- $result = $query->sql();
- $this->assertQuotedQuery(
- 'INSERT INTO <articles> \(<title>, <body>, <author_id>\) (OUTPUT INSERTED\.\* )?SELECT',
- $result,
- true
- );
- $this->assertQuotedQuery(
- 'SELECT <name>, \'some text\', 99 FROM <authors>',
- $result,
- true
- );
- $result = $query->execute();
- $result->closeCursor();
- //PDO_SQLSRV returns -1 for successful inserts when using INSERT ... OUTPUT
- if (!$this->connection->driver() instanceof \Cake\Database\Driver\Sqlserver) {
- $this->assertCount(1, $result);
- }
- $result = (new Query($this->connection))->select('*')
- ->from('articles')
- ->where(['author_id' => 99])
- ->execute();
- $this->assertCount(1, $result);
- $expected = [
- 'id' => 4,
- 'title' => 'mariano',
- 'body' => 'some text',
- 'author_id' => 99,
- 'published' => 'N',
- ];
- $this->assertEquals($expected, $result->fetch('assoc'));
- }
- /**
- * Test that an exception is raised when mixing query + array types.
- *
- * @expectedException \Cake\Database\Exception
- */
- public function testInsertFailureMixingTypesArrayFirst()
- {
- $query = new Query($this->connection);
- $query->insert(['name'])
- ->into('articles')
- ->values(['name' => 'mark'])
- ->values(new Query($this->connection));
- }
- /**
- * Test that an exception is raised when mixing query + array types.
- *
- * @expectedException \Cake\Database\Exception
- */
- public function testInsertFailureMixingTypesQueryFirst()
- {
- $query = new Query($this->connection);
- $query->insert(['name'])
- ->into('articles')
- ->values(new Query($this->connection))
- ->values(['name' => 'mark']);
- }
- /**
- * Test that insert can use expression objects as values.
- *
- * @return void
- */
- public function testInsertExpressionValues()
- {
- $query = new Query($this->connection);
- $query->insert(['title', 'author_id'])
- ->into('articles')
- ->values(['title' => $query->newExpr("SELECT 'jose'"), 'author_id' => 99]);
- $result = $query->execute();
- $result->closeCursor();
- //PDO_SQLSRV returns -1 for successful inserts when using INSERT ... OUTPUT
- if (!$this->connection->driver() instanceof \Cake\Database\Driver\Sqlserver) {
- $this->assertCount(1, $result);
- }
- $result = (new Query($this->connection))->select('*')
- ->from('articles')
- ->where(['author_id' => 99])
- ->execute();
- $this->assertCount(1, $result);
- $expected = [
- 'id' => 4,
- 'title' => 'jose',
- 'body' => null,
- 'author_id' => '99',
- 'published' => 'N',
- ];
- $this->assertEquals($expected, $result->fetch('assoc'));
- $subquery = new Query($this->connection);
- $subquery->select(['name'])
- ->from('authors')
- ->where(['id' => 1]);
- $query = new Query($this->connection);
- $query->insert(['title', 'author_id'])
- ->into('articles')
- ->values(['title' => $subquery, 'author_id' => 100]);
- $result = $query->execute();
- $result->closeCursor();
- //PDO_SQLSRV returns -1 for successful inserts when using INSERT ... OUTPUT
- if (!$this->connection->driver() instanceof \Cake\Database\Driver\Sqlserver) {
- $this->assertCount(1, $result);
- }
- $result = (new Query($this->connection))->select('*')
- ->from('articles')
- ->where(['author_id' => 100])
- ->execute();
- $this->assertCount(1, $result);
- $expected = [
- 'id' => 5,
- 'title' => 'mariano',
- 'body' => null,
- 'author_id' => '100',
- 'published' => 'N',
- ];
- $this->assertEquals($expected, $result->fetch('assoc'));
- }
- /**
- * Tests that functions are correctly transformed and their parameters are bound
- *
- * @group FunctionExpression
- * @return void
- */
- public function testSQLFunctions()
- {
- $query = new Query($this->connection);
- $result = $query->select(
- function ($q) {
- return ['total' => $q->func()->count('*')];
- }
- )
- ->from('articles')
- ->execute();
- $expected = [['total' => 3]];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $query = new Query($this->connection);
- $result = $query->select([
- 'c' => $query->func()->concat(['title' => 'literal', ' is appended'])
- ])
- ->from('articles')
- ->order(['c' => 'ASC'])
- ->execute();
- $expected = [
- ['c' => 'First Article is appended'],
- ['c' => 'Second Article is appended'],
- ['c' => 'Third Article is appended']
- ];
- $this->assertEquals($expected, $result->fetchAll('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['d' => $query->func()->dateDiff(['2012-01-05', '2012-01-02'])])
- ->execute()
- ->fetchAll('assoc');
- $this->assertEquals(3, abs($result[0]['d']));
- $query = new Query($this->connection);
- $result = $query
- ->select(['d' => $query->func()->now('date')])
- ->execute();
- $this->assertEquals([['d' => date('Y-m-d')]], $result->fetchAll('assoc'));
- $query = new Query($this->connection);
- $result = $query
- ->select(['d' => $query->func()->now('time')])
- ->execute();
- $this->assertWithinRange(
- date('U'),
- (new \DateTime($result->fetchAll('assoc')[0]['d']))->format('U'),
- 1
- );
- $query = new Query($this->connection);
- $result = $query
- ->select(['d' => $query->func()->now()])
- ->execute();
- $this->assertWithinRange(
- date('U'),
- (new \DateTime($result->fetchAll('assoc')[0]['d']))->format('U'),
- 1
- );
- }
- /**
- * Tests that default types are passed to functions accepting a $types param
- *
- * @return void
- */
- public function testDefaultTypes()
- {
- $query = new Query($this->connection);
- $this->assertEquals([], $query->defaultTypes());
- $types = ['id' => 'integer', 'created' => 'datetime'];
- $this->assertSame($query, $query->defaultTypes($types));
- $this->assertSame($types, $query->defaultTypes());
- $results = $query->select(['id', 'comment'])
- ->from('comments')
- ->where(['created >=' => new \DateTime('2007-03-18 10:55:00')])
- ->execute();
- $expected = [['id' => '6', 'comment' => 'Second Comment for Second Article']];
- $this->assertEquals($expected, $results->fetchAll('assoc'));
- // Now test default can be overridden
- $types = ['created' => 'date'];
- $results = $query
- ->where(['created >=' => new \DateTime('2007-03-18 10:50:00')], $types, true)
- ->execute();
- $this->assertCount(6, $results, 'All 6 rows should match.');
- }
- /**
- * Tests parameter binding
- *
- * @return void
- */
- public function testBind()
- {
- $query = new Query($this->connection);
- $results = $query->select(['id', 'comment'])
- ->from('comments')
- ->where(['created BETWEEN :foo AND :bar'])
- ->bind(':foo', new \DateTime('2007-03-18 10:50:00'), 'datetime')
- ->bind(':bar', new \DateTime('2007-03-18 10:52:00'), 'datetime')
- ->execute();
- $expected = [['id' => '4', 'comment' => 'Fourth Comment for First Article']];
- $this->assertEquals($expected, $results->fetchAll('assoc'));
- $query = new Query($this->connection);
- $results = $query->select(['id', 'comment'])
- ->from('comments')
- ->where(['created BETWEEN :foo AND :bar'])
- ->bind(':foo', '2007-03-18 10:50:00')
- ->bind(':bar', '2007-03-18 10:52:00')
- ->execute();
- $this->assertEquals($expected, $results->fetchAll('assoc'));
- }
- /**
- * Test that epilog() will actually append a string to a select query
- *
- * @return void
- */
- public function testAppendSelect()
- {
- $query = new Query($this->connection);
- $sql = $query
- ->select(['id', 'title'])
- ->from('articles')
- ->where(['id' => 1])
- ->epilog('FOR UPDATE')
- ->sql();
- $this->assertContains('SELECT', $sql);
- $this->assertContains('FROM', $sql);
- $this->assertContains('WHERE', $sql);
- $this->assertEquals(' FOR UPDATE', substr($sql, -11));
- }
- /**
- * Test that epilog() will actually append a string to an insert query
- *
- * @return void
- */
- public function testAppendInsert()
- {
- $query = new Query($this->connection);
- $sql = $query
- ->insert(['id', 'title'])
- ->into('articles')
- ->values([1, 'a title'])
- ->epilog('RETURNING id')
- ->sql();
- $this->assertContains('INSERT', $sql);
- $this->assertContains('INTO', $sql);
- $this->assertContains('VALUES', $sql);
- $this->assertEquals(' RETURNING id', substr($sql, -13));
- }
- /**
- * Test that epilog() will actually append a string to an update query
- *
- * @return void
- */
- public function testAppendUpdate()
- {
- $query = new Query($this->connection);
- $sql = $query
- ->update('articles')
- ->set(['title' => 'foo'])
- ->where(['id' => 1])
- ->epilog('RETURNING id')
- ->sql();
- $this->assertContains('UPDATE', $sql);
- $this->assertContains('SET', $sql);
- $this->assertContains('WHERE', $sql);
- $this->assertEquals(' RETURNING id', substr($sql, -13));
- }
- /**
- * Test that epilog() will actually append a string to a delete query
- *
- * @return void
- */
- public function testAppendDelete()
- {
- $query = new Query($this->connection);
- $sql = $query
- ->delete('articles')
- ->where(['id' => 1])
- ->epilog('RETURNING id')
- ->sql();
- $this->assertContains('DELETE FROM', $sql);
- $this->assertContains('WHERE', $sql);
- $this->assertEquals(' RETURNING id', substr($sql, -13));
- }
- /**
- * Tests automatic identifier quoting in the select clause
- *
- * @return void
- */
- public function testQuotingSelectFieldsAndAlias()
- {
- $this->connection->driver()->autoQuoting(true);
- $query = new Query($this->connection);
- $sql = $query->select(['something'])->sql();
- $this->assertQuotedQuery('SELECT <something>$', $sql);
- $query = new Query($this->connection);
- $sql = $query->select(['foo' => 'something'])->sql();
- $this->assertQuotedQuery('SELECT <something> AS <foo>$', $sql);
- $query = new Query($this->connection);
- $sql = $query->select(['foo' => 1])->sql();
- $this->assertQuotedQuery('SELECT 1 AS <foo>$', $sql);
- $query = new Query($this->connection);
- $sql = $query->select(['foo' => '1 + 1'])->sql();
- $this->assertQuotedQuery('SELECT <1 \+ 1> AS <foo>$', $sql);
- $query = new Query($this->connection);
- $sql = $query->select(['foo' => $query->newExpr('1 + 1')])->sql();
- $this->assertQuotedQuery('SELECT \(1 \+ 1\) AS <foo>$', $sql);
- $query = new Query($this->connection);
- $sql = $query->select(['foo' => new IdentifierExpression('bar')])->sql();
- $this->assertQuotedQuery('<bar>', $sql);
- }
- /**
- * Tests automatic identifier quoting in the from clause
- *
- * @return void
- */
- public function testQuotingFromAndAlias()
- {
- $this->connection->driver()->autoQuoting(true);
- $query = new Query($this->connection);
- $sql = $query->select('*')->from(['something'])->sql();
- $this->assertQuotedQuery('FROM <something>', $sql);
- $query = new Query($this->connection);
- $sql = $query->select('*')->from(['foo' => 'something'])->sql();
- $this->assertQuotedQuery('FROM <something> <foo>$', $sql);
- $query = new Query($this->connection);
- $sql = $query->select('*')->from(['foo' => $query->newExpr('bar')])->sql();
- $this->assertQuotedQuery('FROM \(bar\) <foo>$', $sql);
- }
- /**
- * Tests automatic identifier quoting for DISTINCT ON
- *
- * @return void
- */
- public function testQuotingDistinctOn()
- {
- $this->connection->driver()->autoQuoting(true);
- $query = new Query($this->connection);
- $sql = $query->select('*')->distinct(['something'])->sql();
- $this->assertQuotedQuery('<something>', $sql);
- }
- /**
- * Tests automatic identifier quoting in the join clause
- *
- * @return void
- */
- public function testQuotingJoinsAndAlias()
- {
- $this->connection->driver()->autoQuoting(true);
- $query = new Query($this->connection);
- $sql = $query->select('*')->join(['something'])->sql();
- $this->assertQuotedQuery('JOIN <something>', $sql);
- $query = new Query($this->connection);
- $sql = $query->select('*')->join(['foo' => 'something'])->sql();
- $this->assertQuotedQuery('JOIN <something> <foo>', $sql);
- $query = new Query($this->connection);
- $sql = $query->select('*')->join(['foo' => $query->newExpr('bar')])->sql();
- $this->assertQuotedQuery('JOIN \(bar\) <foo>', $sql);
- }
- /**
- * Tests automatic identifier quoting in the group by clause
- *
- * @return void
- */
- public function testQuotingGroupBy()
- {
- $this->connection->driver()->autoQuoting(true);
- $query = new Query($this->connection);
- $sql = $query->select('*')->group(['something'])->sql();
- $this->assertQuotedQuery('GROUP BY <something>', $sql);
- $query = new Query($this->connection);
- $sql = $query->select('*')->group([$query->newExpr('bar')])->sql();
- $this->assertQuotedQuery('GROUP BY \(bar\)', $sql);
- $query = new Query($this->connection);
- $sql = $query->select('*')->group([new IdentifierExpression('bar')])->sql();
- $this->assertQuotedQuery('GROUP BY \(<bar>\)', $sql);
- }
- /**
- * Tests automatic identifier quoting strings inside conditions expressions
- *
- * @return void
- */
- public function testQuotingExpressions()
- {
- $this->connection->driver()->autoQuoting(true);
- $query = new Query($this->connection);
- $sql = $query->select('*')
- ->where(['something' => 'value'])
- ->sql();
- $this->assertQuotedQuery('WHERE <something> = :c0', $sql);
- $query = new Query($this->connection);
- $sql = $query->select('*')
- ->where([
- 'something' => 'value',
- 'OR' => ['foo' => 'bar', 'baz' => 'cake']
- ])
- ->sql();
- $this->assertQuotedQuery('<something> = :c0 AND', $sql);
- $this->assertQuotedQuery('\(<foo> = :c1 OR <baz> = :c2\)', $sql);
- }
- /**
- * Tests that insert query parts get quoted automatically
- *
- * @return void
- */
- public function testQuotingInsert()
- {
- $this->connection->driver()->autoQuoting(true);
- $query = new Query($this->connection);
- $sql = $query->insert(['bar', 'baz'])
- ->into('foo')
- ->where(['something' => 'value'])
- ->sql();
- $this->assertQuotedQuery('INSERT INTO <foo> \(<bar>, <baz>\)', $sql);
- $query = new Query($this->connection);
- $sql = $query->insert([$query->newExpr('bar')])
- ->into('foo')
- ->where(['something' => 'value'])
- ->sql();
- $this->assertQuotedQuery('INSERT INTO <foo> \(\(bar\)\)', $sql);
- }
- /**
- * Tests converting a query to a string
- *
- * @return void
- */
- public function testToString()
- {
- $query = new Query($this->connection);
- $query
- ->select(['title'])
- ->from('articles');
- $result = (string)$query;
- $this->assertQuotedQuery('SELECT <title> FROM <articles>', $result, true);
- }
- /**
- * Tests __debugInfo
- *
- * @return void
- */
- public function testDebugInfo()
- {
- $query = (new Query($this->connection))->select('*')
- ->from('articles')
- ->defaultTypes(['id' => 'integer'])
- ->where(['id' => '1']);
- $expected = [
- 'sql' => $query->sql(),
- 'params' => [
- ':c0' => ['value' => '1', 'type' => 'integer', 'placeholder' => 'c0']
- ],
- 'defaultTypes' => ['id' => 'integer'],
- 'decorators' => 0,
- 'executed' => false
- ];
- $result = $query->__debugInfo();
- $this->assertEquals($expected, $result);
- $query->execute();
- $expected = [
- 'sql' => $query->sql(),
- 'params' => [
- ':c0' => ['value' => '1', 'type' => 'integer', 'placeholder' => 'c0']
- ],
- 'defaultTypes' => ['id' => 'integer'],
- 'decorators' => 0,
- 'executed' => true
- ];
- $result = $query->__debugInfo();
- $this->assertEquals($expected, $result);
- }
- /**
- * Tests that it is possible to pass ExpressionInterface to isNull and isNotNull
- *
- * @return void
- */
- public function testIsNullWithExpressions()
- {
- $query = new Query($this->connection);
- $subquery = (new Query($this->connection))
- ->select(['id'])
- ->from('authors')
- ->where(['id' => 1]);
- $result = $query
- ->select(['name'])
- ->from(['authors'])
- ->where(function ($exp) use ($subquery) {
- return $exp->isNotNull($subquery);
- })
- ->execute();
- $this->assertNotEmpty($result->fetchAll('assoc'));
- $result = (new Query($this->connection))
- ->select(['name'])
- ->from(['authors'])
- ->where(function ($exp) use ($subquery) {
- return $exp->isNull($subquery);
- })
- ->execute();
- $this->assertEmpty($result->fetchAll('assoc'));
- }
- /**
- * Tests that strings passed to isNull and isNotNull will be treated as identifiers
- * when using autoQuoting
- *
- * @return void
- */
- public function testIsNullAutoQuoting()
- {
- $this->connection->driver()->autoQuoting(true);
- $query = new Query($this->connection);
- $query->select('*')->from('things')->where(function ($exp) {
- return $exp->isNull('field');
- });
- $this->assertQuotedQuery('WHERE \(<field>\) IS NULL', $query->sql());
- $query = new Query($this->connection);
- $query->select('*')->from('things')->where(function ($exp) {
- return $exp->isNotNull('field');
- });
- $this->assertQuotedQuery('WHERE \(<field>\) IS NOT NULL', $query->sql());
- }
- /**
- * Tests that using the IS operator will automatically translate to the best
- * possible operator depending on the passed value
- *
- * @return void
- */
- public function testDirectIsNull()
- {
- $sql = (new Query($this->connection))
- ->select(['name'])
- ->from(['authors'])
- ->where(['name IS' => null])
- ->sql();
- $this->assertQuotedQuery('WHERE \(<name>\) IS NULL', $sql, true);
- $results = (new Query($this->connection))
- ->select(['name'])
- ->from(['authors'])
- ->where(['name IS' => 'larry'])
- ->execute();
- $this->assertCount(1, $results);
- $this->assertEquals(['name' => 'larry'], $results->fetch('assoc'));
- }
- /**
- * Tests that using the IS NOT operator will automatically translate to the best
- * possible operator depending on the passed value
- *
- * @return void
- */
- public function testDirectIsNotNull()
- {
- $sql = (new Query($this->connection))
- ->select(['name'])
- ->from(['authors'])
- ->where(['name IS NOT' => null])
- ->sql();
- $this->assertQuotedQuery('WHERE \(<name>\) IS NOT NULL', $sql, true);
- $results = (new Query($this->connection))
- ->select(['name'])
- ->from(['authors'])
- ->where(['name IS NOT' => 'larry'])
- ->execute();
- $this->assertCount(3, $results);
- $this->assertNotEquals(['name' => 'larry'], $results->fetch('assoc'));
- }
- /**
- * Tests that case statements work correctly for various use-cases.
- *
- * @return void
- */
- public function testSqlCaseStatement()
- {
- $query = new Query($this->connection);
- $publishedCase = $query
- ->newExpr()
- ->addCase(
- $query
- ->newExpr()
- ->add(['published' => 'Y']),
- 1,
- 'integer'
- );
- $notPublishedCase = $query
- ->newExpr()
- ->addCase(
- $query
- ->newExpr()
- ->add(['published' => 'N']),
- 1,
- 'integer'
- );
- //Postgres requires the case statement to be cast to a integer
- if ($this->connection->driver() instanceof \Cake\Database\Driver\Postgres) {
- $publishedCase = $query->func()->cast([$publishedCase, 'integer' => 'literal'])->type(' AS ');
- $notPublishedCase = $query->func()->cast([$notPublishedCase, 'integer' => 'literal'])->type(' AS ');
- }
- $results = $query
- ->select([
- 'published' => $query->func()->sum($publishedCase),
- 'not_published' => $query->func()->sum($notPublishedCase)
- ])
- ->from(['comments'])
- ->execute()
- ->fetchAll('assoc');
- $this->assertEquals(5, $results[0]['published']);
- $this->assertEquals(1, $results[0]['not_published']);
- $query = new Query($this->connection);
- $query
- ->insert(['article_id', 'user_id', 'comment', 'published'])
- ->into('comments')
- ->values([
- 'article_id' => 2,
- 'user_id' => 1,
- 'comment' => 'In limbo',
- 'published' => 'L'
- ])
- ->execute()
- ->closeCursor();
- $query = new Query($this->connection);
- $conditions = [
- $query
- ->newExpr()
- ->add(['published' => 'Y']),
- $query
- ->newExpr()
- ->add(['published' => 'N'])
- ];
- $values = [
- 'Published',
- 'Not published',
- 'None'
- ];
- $results = $query
- ->select([
- 'id',
- 'comment',
- 'status' => $query->newExpr()->addCase($conditions, $values)
- ])
- ->from(['comments'])
- ->execute()
- ->fetchAll('assoc');
- $this->assertEquals('Published', $results[2]['status']);
- $this->assertEquals('Not published', $results[3]['status']);
- $this->assertEquals('None', $results[6]['status']);
- }
- /**
- * Shows that bufferResults(false) will prevent client-side results buffering
- *
- * @return void
- */
- public function testUnbufferedQuery()
- {
- $query = new Query($this->connection);
- $result = $query->select(['body', 'author_id'])
- ->from('articles')
- ->bufferResults(false)
- ->execute();
- $this->skipIf(
- !method_exists($result, 'bufferResults'),
- 'This driver does not support unbuffered queries'
- );
- $this->assertCount(0, $result);
- $list = $result->fetchAll('assoc');
- $this->assertCount(3, $list);
- $result->closeCursor();
- $query = new Query($this->connection);
- $result = $query->select(['body', 'author_id'])
- ->from('articles')
- ->execute();
- $this->assertCount(3, $result);
- $list = $result->fetchAll('assoc');
- $this->assertCount(3, $list);
- $result->closeCursor();
- }
- /**
- * Assertion for comparing a table's contents with what is in it.
- *
- * @param string $table
- * @param int $count
- * @param array $rows
- * @param array $conditions
- * @return void
- */
- public function assertTable($table, $count, $rows, $conditions = [])
- {
- $result = (new Query($this->connection))->select('*')
- ->from($table)
- ->where($conditions)
- ->execute();
- $this->assertCount($count, $result, 'Row count is incorrect');
- $this->assertEquals($rows, $result->fetchAll('assoc'));
- }
- /**
- * Assertion for comparing a regex pattern against a query having its identifiers
- * quoted. It accepts queries quoted with the characters `<` and `>`. If the third
- * parameter is set to true, it will alter the pattern to both accept quoted and
- * unquoted queries
- *
- * @param string $pattern
- * @param string $query the result to compare against
- * @param bool $optional
- * @return void
- */
- public function assertQuotedQuery($pattern, $query, $optional = false)
- {
- if ($optional) {
- $optional = '?';
- }
- $pattern = str_replace('<', '[`"\[]' . $optional, $pattern);
- $pattern = str_replace('>', '[`"\]]' . $optional, $pattern);
- $this->assertRegExp('#' . $pattern . '#', $query);
- }
- }
|