public function replaceTable(
        Connection $connection,
        string $databaseName,
        string $tableName,
        string $searchTerm,
        string $replaceTerm,
        int $batchSize = 100
    ): \Generator {
        $connection->query('START TRANSACTION');

        $rowCount = 0;

        $rowSearchResultList = (new Search())->searchTable($connection, $databaseName, $tableName, $searchTerm);
        foreach ($rowSearchResultList as $rowSearchResult) {
            $rowCount++;

            $rowReplaceResult = $this->replaceFields($rowSearchResult, $searchTerm, $replaceTerm);

            $queryBuilder = $connection->createQueryBuilder();

            // Build key => value mapping of replacement data
            $replacementData = [];
            foreach ($rowReplaceResult->getFieldResultList() as $fieldReplacementResult) {
                $replacementData[$fieldReplacementResult->getColumnMetadata()->getColumnName()] = $fieldReplacementResult->getNewValue();
            }

            $queryBuilder
                ->update(
                    '`' . $rowSearchResult->getTableMetadata()->getDatabaseName() . '`.`' . $rowSearchResult->getTableMetadata()->getTableName() . '`', 'subject'
                )
                ->setParameters($replacementData)
                ->setParameter('key', $rowSearchResult->getPrimaryKeyValue());

            foreach (array_keys($replacementData) as $columnName) {
                $queryBuilder->set('subject.' . $columnName, ':' . $columnName);
            }

            // Update using primary key
            if (null !== $rowSearchResult->getPrimaryKeyColumn()) {
                $queryBuilder->where('subject.' . $rowSearchResult->getPrimaryKeyColumn()->getColumnName() . ' = :key');

            // Update using original values
            } else {
                $whereCount = 0;
                foreach ($rowReplaceResult->getFieldResultList() as $fieldReplaceResult) {
                    $columnName = $fieldReplaceResult->getColumnMetadata()->getColumnName();
                    $whereClause = 'subject.' . $columnName . ' = :old_' . $columnName;

                    if (0 === $whereCount) {
                        $queryBuilder->where($whereClause);
                    } else {
                        $queryBuilder->andWhere($whereClause);
                    }

                    $queryBuilder->setParameter('old_' . $columnName, $fieldReplaceResult->getOldValue());
                }
            }

            // TODO: handle exception
            $queryBuilder->execute();

            if (0 === ($rowCount % $batchSize)) {
                $connection->query('COMMIT');
                $connection->query('START TRANSACTION');
            }

            yield $rowReplaceResult;
        }

        if (0 !== ($rowCount % $batchSize)) {
            $connection->query('COMMIT');
        }
    }