Example #1
0
 /**
  * @param callable $migration Closure that receives the table to operate on.
  *
  *  <example>
  *  $migration->execute(function($table) {
  *      $table
  *          ->removeColumn('name')
  *          ->save();
  *  });
  *  </example>
  */
 public function execute(callable $migration)
 {
     $this->logger->info("Starting LHM run on table={$this->origin->getName()}");
     $sqlHelper = new SqlHelper($this->adapter);
     if (!isset($options['atomic_switch'])) {
         if ($sqlHelper->supportsAtomicSwitch()) {
             $this->options['atomic_switch'] = true;
         } else {
             $version = $sqlHelper->versionString();
             throw new \RuntimeException("Using mysql {$version}. You must explicitly set `options['atomic_switch']` (re SqlHelper::supportsAtomicSwitch)");
         }
     }
     if (!$this->destination) {
         $this->destination = $this->temporaryTable();
     }
     $this->setSessionLockWaitTimeouts();
     $entangler = new Entangler($this->adapter, $this->origin, $this->destination, $sqlHelper);
     $entangler->setLogger($this->logger);
     if ($this->options['atomic_switch']) {
         $switcher = new AtomicSwitcher($this->adapter, $this->origin, $this->destination, $this->options);
     } else {
         $switcher = new LockedSwitcher($this->adapter, $this->origin, $this->destination, $this->options);
     }
     $switcher->setLogger($this->logger);
     $chunker = new Chunker($this->adapter, $this->origin, $this->destination, $sqlHelper, $this->options);
     $chunker->setLogger($this->logger);
     $migration($this->destination);
     $entangler->run(function () use($chunker, $switcher) {
         $chunker->run();
         $switcher->run();
     });
 }
Example #2
0
 public function testRun()
 {
     /** @var Column[] $originColumns */
     $originColumns = [new Column(), new Column(), new Column()];
     $originColumns[0]->setName('id');
     $originColumns[1]->setName('name');
     $originColumns[2]->setName('something');
     /** @var Column[] $destinationColumns */
     $destinationColumns = [new Column(), new Column(), new Column()];
     $destinationColumns[0]->setName('id');
     $destinationColumns[1]->setName('name');
     $destinationColumns[2]->setName('something_else');
     $this->origin->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users'));
     $this->origin->expects($this->atLeastOnce())->method('getColumns')->will($this->returnValue($originColumns));
     $this->destination->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users_new'));
     $this->destination->expects($this->atLeastOnce())->method('getColumns')->will($this->returnValue($destinationColumns));
     $this->destination->expects($this->atLeastOnce())->method('getRenamedColumns')->will($this->returnValue([]));
     $matcher = $this->atLeastOnce();
     $this->adapter->expects($matcher)->method('fetchRow')->will($this->returnCallback(function ($query) use($matcher) {
         switch ($matcher->getInvocationCount()) {
             case 1:
                 $this->assertEquals("SELECT MIN(id) FROM 'users'", $query);
                 return [1];
             case 2:
                 $this->assertEquals("SELECT MAX(id) FROM 'users'", $query);
                 return [500];
             default:
                 return null;
                 break;
         }
     }));
     $matcher = $this->atLeastOnce();
     $this->adapter->expects($matcher)->method('query')->will($this->returnCallback(function ($query) use($matcher) {
         switch ($matcher->getInvocationCount()) {
             case 1:
                 $this->assertEquals("SELECT `COLUMN_NAME` FROM `information_schema`.`COLUMNS` WHERE (`TABLE_SCHEMA` = '') AND (`TABLE_NAME` = 'users') AND (`COLUMN_KEY` = 'PRI');", $query);
                 return 'id';
             case 2:
                 $this->assertEquals("INSERT IGNORE INTO 'users_new' (`id`,`name`) SELECT 'users'.`id`,'users'.`name` FROM 'users' WHERE 'users'.`id` BETWEEN 1 AND 200", $query);
                 break;
             case 3:
                 $this->assertEquals("INSERT IGNORE INTO 'users_new' (`id`,`name`) SELECT 'users'.`id`,'users'.`name` FROM 'users' WHERE 'users'.`id` BETWEEN 201 AND 400", $query);
                 break;
             case 4:
                 $this->assertEquals("INSERT IGNORE INTO 'users_new' (`id`,`name`) SELECT 'users'.`id`,'users'.`name` FROM 'users' WHERE 'users'.`id` BETWEEN 401 AND 500", $query);
                 break;
             default:
                 $this->fail('Unexpected query: ' . $query);
                 break;
         }
     }));
     $chunker = new Chunker($this->adapter, $this->origin, $this->destination, $this->sqlHelper, ['stride' => 200]);
     $chunker->run();
 }