Commit 96039491 authored by Jens Segers's avatar Jens Segers

Use aggregations for pagination, fixes #437 and #428

parent 9d048222
......@@ -29,6 +29,13 @@ class Builder extends BaseBuilder {
*/
public $timeout;
/**
* Indicate if we are executing a pagination query.
*
* @var bool
*/
public $paginating = false;
/**
* All of the available clause operators.
*
......@@ -140,7 +147,7 @@ class Builder extends BaseBuilder {
$wheres = $this->compileWheres();
// Use MongoDB's aggregation framework when using grouping or aggregation functions.
if ($this->groups or $this->aggregate)
if ($this->groups or $this->aggregate or $this->paginating)
{
$group = array();
......@@ -155,12 +162,14 @@ class Builder extends BaseBuilder {
// this mimics MySQL's behaviour a bit.
$group[$column] = array('$last' => '$' . $column);
}
}
else
{
// If we don't use grouping, set the _id to null to prepare the pipeline for
// other aggregation functions.
$group['_id'] = null;
// Do the same for other columns that are selected.
foreach ($this->columns as $column)
{
$key = str_replace('.', '_', $column);
$group[$key] = array('$last' => '$' . $column);
}
}
// Add aggregation functions to the $group part of the aggregation pipeline,
......@@ -184,22 +193,26 @@ class Builder extends BaseBuilder {
}
}
// If no aggregation functions are used, we add the additional select columns
// to the pipeline here, aggregating them by $last.
else
// When using pagination, we limit the number of returned columns
// by adding a projection.
if ($this->paginating)
{
foreach ($this->columns as $column)
{
$key = str_replace('.', '_', $column);
$group[$key] = array('$last' => '$' . $column);
$this->projections[$column] = 1;
}
}
// The _id field is mandatory when using grouping.
if ($group and empty($group['_id']))
{
$group['_id'] = null;
}
// Build the aggregation pipeline.
$pipeline = array();
if ($wheres) $pipeline[] = array('$match' => $wheres);
$pipeline[] = array('$group' => $group);
if ($group) $pipeline[] = array('$group' => $group);
// Apply order and limit
if ($this->orders) $pipeline[] = array('$sort' => $this->orders);
......@@ -370,6 +383,20 @@ class Builder extends BaseBuilder {
return $this;
}
/**
* Set the limit and offset for a given page.
*
* @param int $page
* @param int $perPage
* @return \Illuminate\Database\Query\Builder|static
*/
public function forPage($page, $perPage = 15)
{
$this->paginating = true;
return $this->skip(($page - 1) * $perPage)->take($perPage);
}
/**
* Insert a new record into the database.
*
......
......@@ -7,10 +7,6 @@ class QueryTest extends TestCase {
public function setUp()
{
parent::setUp();
// only run this stuff once
if (self::$started) return;
User::create(array('name' => 'John Doe', 'age' => 35, 'title' => 'admin'));
User::create(array('name' => 'Jane Doe', 'age' => 33, 'title' => 'admin'));
User::create(array('name' => 'Harry Hoe', 'age' => 13, 'title' => 'user'));
......@@ -20,8 +16,12 @@ class QueryTest extends TestCase {
User::create(array('name' => 'Tommy Toe', 'age' => 33, 'title' => 'user'));
User::create(array('name' => 'Yvonne Yoe', 'age' => 35, 'title' => 'admin'));
User::create(array('name' => 'Error', 'age' => null, 'title' => null));
}
self::$started = true;
public function tearDown()
{
User::truncate();
parent::tearDown();
}
public function testWhere()
......@@ -311,16 +311,7 @@ class QueryTest extends TestCase {
$this->assertEquals(2, $results->count());
$this->assertNull($results->first()->title);
$this->assertEquals(9, $results->total());
}
/*
* FIXME: This should be done in tearDownAfterClass, but something doens't work:
* https://travis-ci.org/duxet/laravel-mongodb/jobs/46657530
*/
public function testTruncate()
{
User::truncate();
$this->assertEquals(0, User::count());
$this->assertEquals(1, $results->currentPage());
}
}
......@@ -27,13 +27,9 @@ class TestCase extends Orchestra\Testbench\TestCase {
// reset base path to point to our package's src directory
//$app['path.base'] = __DIR__ . '/../src';
// load custom config
$config = require 'config/database.php';
// set mongodb as default connection
$app['config']->set('database.default', 'mongodb');
// overwrite database configuration
$app['config']->set('database.connections.mysql', $config['connections']['mysql']);
$app['config']->set('database.connections.mongodb', $config['connections']['mongodb']);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment