Tests for new find types
[activemongo.git] / tests / QueryTest.php
blob825d788927a599d71572a7c0b525949921df9b43
1 <?php
3 class QueryTest extends PHPUnit_Framework_TestCase
6 function testConnect()
8 ActiveMongo::connect(DB, "localhost");
9 try {
10 Dummy::drop();
11 } catch (ActiveMongo_Exception $e) {}
12 try {
13 Model1::drop();
14 } catch (ActiveMongo_Exception $e) {}
15 try {
16 Model2::drop();
17 } catch (ActiveMongo_Exception $e) {}
18 try {
19 Model3::drop();
20 } catch (ActiveMongo_Exception $e) {}
21 $this->assertTrue(TRUE);
24 function testBulkInserts()
26 try {
27 Model3::drop();
28 } catch (ActiveMongo_Exception $e) {}
29 $data = array();
31 /* Valid data */
32 for ($i=0; $i < 5000; $i++) {
33 $data[] = array('int' => $i, 'str' => sha1(uniqid()));
36 /* Invalid data, shouldn't be inserted */
37 $data[] = array('xint' => $i, 'str' => sha1(uniqid()));
38 $data[] = array('xint' => $i, 'str' => sha1(uniqid()));
39 $data[] = array('xint' => $i, 'str' => sha1(uniqid()));
41 /* batchInsert */
42 Model3::batchInsert($data, TRUE, TRUE);
44 $c = new Model3;
45 $this->assertEquals($c->count(), 5000);
48 function testNamespace()
50 $this->assertFalse(ActiveMongo::setNamespace('bad namespace'));
51 $this->assertFalse(ActiveMongo::setNamespace('bad=namespace'));
52 $this->assertFalse(ActiveMongo::setNamespace('bad=namespace!'));
53 $this->assertTrue(ActiveMongo::setNamespace('good_namespace'));
54 ActiveMongo::setNamespace('testing');
55 Model2::setNamespace('foobar');
56 list($m1, $m2) = array(new model1, new model2);
57 $this->assertEquals($m1->collectionName(), 'testing.model1');
58 $this->assertEquals($m2->collectionName(), 'foobar.model2');
59 $this->assertTrue(ActiveMongo::setNamespace(NULL)); /* set no-namespace */
60 $this->assertTrue(Model2::setNamespace(NULL)); /* set no-namespace */
63 function testInstall()
65 ActiveMongo::install();
66 $index = Model1::getIndexes();
67 $this->assertTrue(isset($index[1]['key']['b']));
68 $this->assertTrue(isset($index[2]['key']['a']));
69 $this->assertEquals($index[1]['key']['b'], 1);
70 $this->assertEquals($index[2]['key']['a'], -1);
71 $this->asserTEquals(count($index), 3);
72 $index = Model2::getIndexes();
73 $this->assertTrue(isset($index[1]['key']['M1']));
74 $this->assertEquals($index[1]['key']['M1'], 1);
75 $this->asserTEquals(count($index), 2);
78 /**
79 * @depends testBulkInserts
81 function testReset()
83 $c = new Model3;
84 $c->doQuery();
86 $this->assertTrue(isset($c->int));
87 $this->assertTrue(isset($c['int']));
88 $c->reset();
89 $this->assertFalse(isset($c->int));
90 $this->assertFalse(isset($c['int']));
93 /**
94 * @depends testBulkInserts
96 function testModQuery()
98 $c = new Model3;
99 /* int % 2 == */
100 $c->properties('int');
101 $c->where('int %', array(2, 0));
102 $this->assertLessThan($c->count(), 0);
103 foreach ($c as $r) {
104 $this->assertEquals($r->int % 2, 0);
108 function testQuery()
110 $c = new Model1;
112 /* rand values */
113 $val1 = rand(1, 50);
114 $val2 = rand(1, 50);
115 $val3 = rand(1, 50);
116 $val4 = rand(1, 50);
117 $val5 = rand(1, 50);
120 /* prepare the query */
121 $c->properties('a,b')->where('a >', $val1)->where('b <', $val2)->where('c !=', $val3);
122 $c->where('h regexp', '/[a-f0-9]+/');
123 $c->where('x in', array(1, 2));
124 $c->where('x nin', array(4));
125 $c->where('y ==', array(4));
126 $c->where('f exists');
127 $c->where('f !=', array(5,6));
128 $c->where(array("bar exists", "a exists"));
129 $c->where('xxx ==', 5);
130 $c->where('bar >=', 5);
131 $c->sort('c DESC, a ASC')->limit($val4, $val5);
133 /* perform it */
134 $c->doQuery();
136 /* Get cursor info */
137 $sQuery = $c->getReference(TRUE);
139 /* expected cursor info */
140 $eQuery = array(
141 'ns' => DB.'.model1',
142 'limit' => $val4,
143 'skip' => $val5,
144 'query' => array(
145 '$query' => array(
146 'a' => array('$gt' => $val1, '$exists' => 1),
147 'b' => array('$lt' => $val2),
148 'c' => array('$ne' => $val3),
149 'h' => new MongoRegex('/[a-f0-9]+/'),
150 'x' => array('$in' => array(1,2), '$nin' => array(4)),
151 'y' => array('$all' => array(4)),
152 'f' => array('$exists' => 1, '$nin' => array(5,6)),
153 'xxx' => 5,
154 'bar' => array('$exists' => 1, '$gte' => 5),
156 '$orderby' => array(
157 'c' => -1,
158 'a' => 1,
161 'fields' => array(
162 'a' => 1,
163 'b' => 1,
164 '_id' => 1, /* from now on _id is included by default */
168 $this->assertEquals($sQuery['dynamic'], $eQuery);
172 function testQueryArray()
174 $c = new Model1;
176 /* rand values */
177 $val1 = rand(1, 50);
178 $val2 = rand(1, 50);
179 $val3 = rand(1, 50);
180 $val4 = rand(1, 50);
181 $val5 = rand(1, 50);
184 /* prepare the query */
185 $filter = array(
186 'a > ' => $val1,
187 'b < ' => $val2,
188 'c != ' => $val3,
189 'h regexp' => '/[a-f0-9]+/',
190 'x in ' => array(1,2),
191 'x nin ' => array(4),
192 'y == ' => array(4)
194 $c->properties('a,b')->sort('c DESC, a ASC')->limit($val4, $val5);;
195 $c->where($filter);
197 /* perform it */
198 $c->doQuery();
200 /* Get cursor info */
201 $sQuery = $c->getReference(TRUE);
203 /* expected cursor info */
204 $eQuery = array(
205 'ns' => DB.'.model1',
206 'limit' => $val4,
207 'skip' => $val5,
208 'query' => array(
209 '$query' => array(
210 'a' => array('$gt' => $val1),
211 'b' => array('$lt' => $val2),
212 'c' => array('$ne' => $val3),
213 'h' => new MongoRegex('/[a-f0-9]+/'),
214 'x' => array('$in' => array(1,2), '$nin' => array(4)),
215 'y' => array('$all' => array(4)),
217 '$orderby' => array(
218 'c' => -1,
219 'a' => 1,
222 'fields' => array(
223 'a' => 1,
224 'b' => 1,
225 '_id' => 1,
229 $this->assertEquals($sQuery['dynamic'], $eQuery);
232 function testQueryRequireArray()
234 $c = new Model1;
235 try {
236 $c->where('c near', 'string');
237 $this->assertTrue(FALSE);
238 } catch (ActiveMongo_Exception $e) {
239 $this->assertTrue(TRUE);
241 try {
242 $c->where('c in', 55);
243 $this->assertTrue(FALSE);
244 } catch (ActiveMongo_Exception $e) {
245 $this->assertTrue(TRUE);
247 try {
248 $c->where('c >', array(1));
249 $this->assertTrue(FALSE);
250 } catch (ActiveMongo_Exception $e) {
251 $this->assertTrue(TRUE);
253 try {
254 $c->where('c >>>', array(1));
255 $this->assertTrue(FALSE);
256 } catch (ActiveMongo_Exception $e) {
257 $this->assertTrue(TRUE);
259 try {
260 $c->where('c nin', 559);
261 $this->assertTrue(FALSE);
262 } catch (ActiveMongo_Exception $e) {
263 $this->assertTrue(TRUE);
267 function testMultipleOperationsPerProperty()
269 list($min, $max) = array(50, 100);
271 $c = new Model3;
272 foreach ($c->where('int >', $min)->where('int <', $max) as $item) {
273 $this->assertGreaterThan($min, $item['int']);
274 $this->assertLessThan($max, $item['int']);
277 /* this could be done with a single regexp but
278 * this test should cover the multiple ALL amoung
279 * properties
281 * str regexp '//' AND str regexp '//' AND str regexp '//'
283 $c = new Model3;
284 $c->where('str regex', '/^4/')->where('str regexp', '/a$/');
285 foreach ($c->where('str regex', '/[a-z0-9]+/') as $item) {
286 $this->assertEquals($item['str'][0], 4);
287 $this->assertEquals($item['str'][strlen($item['str'])-1], 'a');
291 $c = new Model3;
292 $c->where('int >', $min)->where('int <', $max);
293 foreach ($c->where('int nin', array($min+1, $min+2, $min+3)) as $item) {
294 $this->assertNotEquals($min+1, $item['int']);
295 $this->assertNotEquals($min+2, $item['int']);
296 $this->assertNotEquals($min+3, $item['int']);
300 function testMultipleUpdate()
302 $str = sha1(uniqid());
303 $query = array(
304 'int >' => 5,
305 'int <' => 30,
306 'int !=' => 6,
308 $c = new Model3;
309 $c->where($query);
310 $c->update(array('newproperty' => $str));
312 $c->where(array('int >' => 5, 'int <' => 30));
313 foreach ($c as $item) {
314 if ($item['int'] == 6) {
315 /* 6 is not included */
316 $this->assertFalse(isset($item['newproperty']));
317 } else {
318 $this->assertEquals($str, $item['newproperty']);
323 function testNullUpdate()
325 $id = 0;
328 $c = new Model3;
329 $c->int = 5;
330 $c->arr = array(5, array(1));
331 $c->bool = TRUE;
332 $c->null = NULL;
334 /* Testing Save also :-) */
335 $this->assertEquals(TRUE, $c->save());
336 /* Now nothing should be done */
337 $this->assertEquals(NULL, $c->save());
339 $c->int = 0;
340 $c->arr[] = 0;
341 $c->arr[1][] = 1;
342 $c->arr[1][] = 2;
343 $c->arr[1][] = 3;
344 $c->bool = FALSE;
345 $c->foobar = NULL;
346 $id = $c->getId();
348 /* Updating */
349 $this->assertEquals(TRUE, $c->save());
350 $this->assertEquals(NULL, $c->save());
352 unset($c->arr[1][1]);
353 unset($c->foobar);
355 /* Updating */
356 $this->assertEquals(TRUE, $c->save());
357 $this->assertEquals(NULL, $c->save());
360 /* now empty $c and query for `int` value */
361 $c->reset();
362 $c->where('_id', $id);
363 $c->doQuery();
364 $this->assertEquals($c->int, 0);
365 $this->assertEquals($c->arr, array(5,array(1,NULL, 2,3), 0));
366 $this->assertEquals($c->bool, FALSE);
367 $this->assertEquals($c->null, NULL);
370 function testOnQueryModifyError()
372 try {
373 $c = new Model1;
374 $c->where('a', 1);
375 $c->doQuery();
376 $c->where('b', 4);
377 $this->assertTrue(FALSE);
378 } catch (ActiveMongo_Exception $e) {
379 $this->assertTrue(TRUE);
384 * @depends testBulkInserts
386 function testClone()
388 $c = new Model1;
389 $c->a = 1;
390 $c->save();
392 $c->reset();
394 /* object with no results can't be cloned */
395 try {
396 $foo = clone $c;
397 $this->AssertTrue(FALSE);
398 } catch (ActiveMongo_Exception $e) {
399 $this->AssertTrue(TRUE);
402 foreach ($c as $item) {
403 $item_cloned = clone $item;
404 $item_cloned->c = 1;
405 $item_cloned->save();
406 try {
407 /* iterations are forbidden in cloned objects */
408 foreach ($item_cloned as $nitem) {
409 $this->assertTrue(FALSE);
411 } catch (ActiveMongo_Exception $e) {
412 $this->assertTrue(TRUE);
416 /* cloned object can't be reused */
417 try {
418 $item_cloned->reset();
419 $this->AssertTrue(FALSE);
420 } catch (ActiveMongo_Exception $e) {
421 $this->AssertTrue(TRUE);
423 try {
424 $item_cloned->where('a IN', array(1));
425 $this->AssertTrue(FALSE);
426 } catch (ActiveMongo_Exception $e) {
427 $this->AssertTrue(TRUE);
432 function testToSTring()
434 $c = new Model3;
435 $c->doQuery();
436 $this->assertEquals((string)$c, (string)$c->getID());
437 $this->assertEquals((string)$c, $c->key());
440 function testDelete()
442 /* Delete using a criteria */
443 $c = new Model3;
444 $c->where('int < ', 100);
445 $c->delete();
447 $this->assertEquals($c->count(), 4900);
449 /* delete on iteration (element by element) */
450 $c = new Model3;
451 $c->where('int', array(200, 300));
453 $i = 0;
454 foreach ($c as $d) {
455 $d->delete();
456 $this->assertFalse(isset($c->int));
457 $i++;
460 $c->reset();
462 $this->assertEquals(2, $i);
463 $this->assertEquals($c->count(), 4898);
466 function testDrop()
468 $c = new Dummy;
469 $c['foo'] = 'bar';
470 $c->save();
472 $this->assertFalse(ActiveMongo::drop());
473 $this->assertTrue(Dummy::drop());
474 try {
475 $this->assertFalse(Dummy::drop());
476 } catch (ActiveMongo_Exception $e) {
477 $this->assertTrue(TRUE);
481 function testInvalidLimits()
483 $c = new Model1;
484 $this->assertFalse($c->limit(-1, 5));
485 $this->assertFalse($c->limit(5, -1));
486 $this->assertFalse($c->limit(-1, -5));
489 function testInvalidProperties()
491 $c = new Model1;
492 $this->assertFalse($c->properties(1));
493 $this->assertFalse($c->columns(1));
494 $this->assertFalse($c->columns(NULL));
495 $this->assertFalse($c->columns(TRUE));
499 function testInvalidBatchInsert()
501 /* Invalid document for Model2 */
502 $documents = array(
503 array('foo' => 'bar'),
505 try {
506 /* Invalid call */
507 ActiveMongo::BatchInsert($documents);
508 $this->assertTrue(False);
509 } catch (ActiveMongo_Exception $e) {
510 $this->assertTrue(TRUE);
513 try {
514 Model2::BatchInsert($documents);
515 $this->assertTrue(False);
516 } catch (ActiveMongo_FilterException $e) {
517 $this->assertTrue(FALSE);
518 } catch (MongoException $e) {
519 $this->assertTrue(TRUE);
522 try {
523 Model2::BatchInsert($documents, TRUE, FALSE);
524 $this->assertTrue(False);
525 } catch (ActiveMongo_FilterException $e) {
526 $this->assertTrue(TRUE);
531 function testInvalidQueries()
533 $c = new Model3;
535 try {
536 $c->where("invalid field property", 3);
537 $this->assertTrue(FALSE);
538 } catch (ActiveMongo_Exception $e) {
539 $this->assertTrue(TRUE);
542 try {
543 $c->where(array(
544 "b" => 1,
545 ), TRUE);
546 $this->assertTrue(FALSE);
547 } catch (ActiveMongo_Exception $e) {
548 $this->assertTrue(TRUE);
552 try {
553 $c->sort(" , , ");
554 $this->assertTrue(FALSE);
555 } catch (ActiveMongo_Exception $e) {
556 $this->assertTrue(TRUE);
559 try {
560 $c->sort("c DESC, field BAR");
561 $this->assertTrue(FALSE);
562 } catch (ActiveMongo_Exception $e) {
563 $this->assertTrue(TRUE);
566 /* These are valid, so no exception should be thrown */
567 $c->sort("foo ASC, bar DESC");
568 $c->sort("foo DESC");
569 $c->sort("foo");
572 function testFindWithSingleID()
574 $d = new Model1;
575 $d->a = 5;
576 $d->save();
578 $c = new Model1;
579 $c->find($d->getID());
580 $this->assertEquals(1, $c->count());
581 $this->assertEquals($c->a, $d->a);
584 function testFindAndModify()
587 $c = new Model3;
588 $c->where('int <= ', 1000);
589 $c->where('processing exists', FALSE);
590 $c->limit(50);
591 $c->sort('int DESC');
592 $c->findAndModify(array("processing" => TRUE));
594 $i = 0;
595 $last = 0;
596 foreach ($c as $d) {
597 $this->assertEquals($d->processing, TRUE);
598 /* testing sort */
599 if ($last) {
600 $this->assertLessThan($last, $d->int);
602 $last = $d->int;
603 $i++;
605 $this->assertEquals($i, 50);
607 try {
608 $c->reset();
609 $c->where('int <= ', 1000);
610 $c->where('processing exists', FALSE);
611 $c->limit(50);
612 $c->findAndModify(array());
613 $this->assertTrue(FALSE);
614 } catch (ActiveMongo_Exception $e) {
615 $this->assertTrue(TRUE);
619 function testFindVariations()
621 // add a few entries:
622 $documents = array(
623 array('int' => '1', 'mod3' => '1'),
624 array('int' => '2', 'mod3' => '2'),
625 array('int' => '3', 'mod3' => '0'),
626 array('int' => '4', 'mod3' => '1'),
627 array('int' => '5', 'mod3' => '2'),
628 array('int' => '6', 'mod3' => '0'),
629 array('int' => '7', 'mod3' => '1'),
630 array('int' => '8', 'mod3' => '2'),
631 array('int' => '9', 'mod3' => '0'),
633 Model3::BatchInsert($documents, TRUE, FALSE);
635 // test findCol (which also tests findPairs and fields)
636 $c = new Model3;
637 $findCol = $c->findCol('mod3', array('int'=>array('$lt'=>'5')));
638 $this->assertEquals(array_values($findCol), array('1', '2', '0', '1'));
640 // test findOneValue (which will test findOne)
641 $this->assertEquals($c->findOneValue('mod3', array('int'=>'5')), '2');
643 // test findOneObj (which will test findOneAssoc)
644 $obj = $c->findOneObj(array('int'=>'5'));
645 $this->assertEquals($obj, (object)array('int'=>'5', 'mod3'=>'2', '_id'=>$obj->_id));
648 function testDisconnect()
650 $this->assertTrue(ActiveMongo::isConnected());
651 ActiveMongo::Disconnect();
652 $this->assertFalse(ActiveMongo::isConnected());