*/ private array $cachingStatements = []; private array $waitingForInsert = []; private bool $isInitialized = false; private ?string $currentSource = null; public function __construct(private readonly Connection $defaultConnection) {} public function finalize(): void { $this->doInsertPending(); if ($this->isInitialized && null !== $this->currentSource) { $this->defaultConnection->transactional(function (Connection $connection): void { $connection->executeStatement(self::UPSERT); $connection->executeStatement(self::DELETE_MISSING, [$this->currentSource]); }); $this->deleteTemporaryTable(); } $this->isInitialized = false; $this->currentSource = null; } public function importCode( string $countryCode, string $label, string $code, string $refPostalCodeId, string $refPostalCodeSource, float $centerLat, float $centerLon, int $centerSRID, ): void { if (!$this->isInitialized) { $this->initialize($refPostalCodeSource); } if ($this->currentSource !== $refPostalCodeSource) { throw new \LogicException('Cannot store postal codes from different sources during same import. Execute finalize to commit inserts before changing the source'); } $this->waitingForInsert[] = [ $countryCode, $label, $code, $refPostalCodeId, $refPostalCodeSource, $centerLon, $centerLat, $centerSRID, ]; if (100 <= \count($this->waitingForInsert)) { $this->doInsertPending(); } } private function initialize(string $source): void { $this->currentSource = $source; $this->deleteTemporaryTable(); $this->createTemporaryTable(); $this->isInitialized = true; } private function createTemporaryTable(): void { $this->defaultConnection->executeStatement(self::CREATE_TEMP_TABLE); } private function deleteTemporaryTable(): void { $this->defaultConnection->executeStatement('DROP TABLE IF EXISTS chill_main_postal_code_temp'); } private function doInsertPending(): void { if ([] == $this->waitingForInsert) { return; } if (!\array_key_exists($forNumber = \count($this->waitingForInsert), $this->cachingStatements)) { $sql = strtr(self::INSERT_TEMP, [ '{{ values }}' => implode( ', ', array_fill(0, $forNumber, self::VALUE) ), ]); $this->cachingStatements[$forNumber] = $this->defaultConnection->prepare($sql); } $statement = $this->cachingStatements[$forNumber]; try { $statement->executeStatement(array_merge(...$this->waitingForInsert)); } catch (\Exception $e) { // in some case, we can add debug code here // dump($this->waitingForInsert); throw $e; } finally { $this->waitingForInsert = []; } } }