Add PhabricatorQueryIterator, for buffered iteration over a CursorPagedPolicyAwareQuery
Summary:
See D19446. This should make it easier to process larger, more complex result sets in constant memory.
Today, `LiskMigrationIterator` takes constant memory but can't apply `needX()` reqeusts or `withY(...)` constraints.
Using a raw `Query` can handle this stuff, but requires memory proportional to the size of the result set.
Offer the best of both worlds: constant memory and full access to the power of `Query` classes.
Test Plan:
Used this script to iterate over every commit, saw sensible behavior:
```name=list-commits.php
<?php
require_once 'scripts/init/init-script.php';
$viewer = PhabricatorUser::getOmnipotentUser();
$query = id(new DiffusionCommitQuery())
  ->setViewer($viewer);
$iterator = new PhabricatorQueryIterator($query);
foreach ($iterator as $commit) {
  echo $commit->getID()."\n";
}
```
Reviewers: amckinley
Reviewed By: amckinley
Differential Revision: https://secure.phabricator.com/D19450
			
			
This commit is contained in:
		@@ -4032,6 +4032,7 @@ phutil_register_library_map(array(
 | 
			
		||||
    'PhabricatorPygmentSetupCheck' => 'applications/config/check/PhabricatorPygmentSetupCheck.php',
 | 
			
		||||
    'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php',
 | 
			
		||||
    'PhabricatorQueryConstraint' => 'infrastructure/query/constraint/PhabricatorQueryConstraint.php',
 | 
			
		||||
    'PhabricatorQueryIterator' => 'infrastructure/storage/lisk/PhabricatorQueryIterator.php',
 | 
			
		||||
    'PhabricatorQueryOrderItem' => 'infrastructure/query/order/PhabricatorQueryOrderItem.php',
 | 
			
		||||
    'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php',
 | 
			
		||||
    'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php',
 | 
			
		||||
@@ -9876,6 +9877,7 @@ phutil_register_library_map(array(
 | 
			
		||||
    'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck',
 | 
			
		||||
    'PhabricatorQuery' => 'Phobject',
 | 
			
		||||
    'PhabricatorQueryConstraint' => 'Phobject',
 | 
			
		||||
    'PhabricatorQueryIterator' => 'PhutilBufferedIterator',
 | 
			
		||||
    'PhabricatorQueryOrderItem' => 'Phobject',
 | 
			
		||||
    'PhabricatorQueryOrderTestCase' => 'PhabricatorTestCase',
 | 
			
		||||
    'PhabricatorQueryOrderVector' => array(
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								src/infrastructure/storage/lisk/PhabricatorQueryIterator.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/infrastructure/storage/lisk/PhabricatorQueryIterator.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
final class PhabricatorQueryIterator extends PhutilBufferedIterator {
 | 
			
		||||
 | 
			
		||||
  private $query;
 | 
			
		||||
  private $pager;
 | 
			
		||||
 | 
			
		||||
  public function __construct(PhabricatorCursorPagedPolicyAwareQuery $query) {
 | 
			
		||||
    $this->query = $query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function didRewind() {
 | 
			
		||||
    $this->pager = new AphrontCursorPagerView();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function key() {
 | 
			
		||||
    return $this->current()->getID();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function loadPage() {
 | 
			
		||||
    if (!$this->pager) {
 | 
			
		||||
      return array();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $pager = clone $this->pager;
 | 
			
		||||
    $query = clone $this->query;
 | 
			
		||||
 | 
			
		||||
    $results = $query->executeWithCursorPager($pager);
 | 
			
		||||
 | 
			
		||||
    // If we got less than a full page of results, this was the last set of
 | 
			
		||||
    // results. Throw away the pager so we end iteration.
 | 
			
		||||
    if (count($results) < $pager->getPageSize()) {
 | 
			
		||||
      $this->pager = null;
 | 
			
		||||
    } else {
 | 
			
		||||
      $this->pager->setAfterID($pager->getNextPageID());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $results;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user