/** * @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(); }); }
public function testVersionString() { $mock = $this->getMockBuilder(\stdClass::class)->setMethods(['fetchColumn'])->disableOriginalConstructor()->getMock(); $mock->expects($this->once())->method('fetchColumn')->will($this->returnValue("3.0.2")); $this->adapter->expects($this->once())->method('query')->with("show variables like 'version'")->will($this->returnValue($mock)); $this->assertEquals("3.0.2", $this->helper->versionString()); }
/** * @param integer $lowest * @param integer $highest * @return string */ protected function copy($lowest, $highest) { $originName = $this->adapter->quoteTableName($this->origin->getName()); $destinationName = $this->adapter->quoteTableName($this->destination->getName()); $destinationColumns = implode(',', $this->sqlHelper->quoteColumns($this->intersection->destination())); $originColumns = implode(',', $this->sqlHelper->typedColumns($originName, $this->sqlHelper->quoteColumns($this->intersection->origin()))); return implode(" ", ["INSERT IGNORE INTO {$destinationName} ({$destinationColumns})", "SELECT {$originColumns} FROM {$originName}", "WHERE {$originName}.{$this->primaryKey} BETWEEN {$lowest} AND {$highest}"]); }
/** * @return string */ protected function createDeleteTrigger() { $name = $this->trigger('delete'); $primaryKey = $this->sqlHelper->extractPrimaryKey($this->origin); if (empty($primaryKey)) { throw new \RuntimeException("Table `{$this->origin->getName()}` does not have a primary key."); } $primaryKey = $this->sqlHelper->quoteColumn($primaryKey); $originName = $this->adapter->quoteTableName($this->origin->getName()); $destinationName = $this->adapter->quoteTableName($this->destination->getName()); return implode("\n ", ["CREATE TRIGGER {$name}", "AFTER DELETE ON {$originName} FOR EACH ROW", "DELETE IGNORE FROM {$destinationName} {$this->sqlHelper->annotation()}", "WHERE {$destinationName}.{$primaryKey} = OLD.{$primaryKey}"]); }
public function testTypedColumns() { $expected = ['NEW.id', 'NEW.name', 'NEW.test']; $this->assertEquals($expected, $this->helper->typedColumns('NEW', ['id', 'name', 'test'])); }