feat: establish catalog identity and atomic file ownership
This commit is contained in:
1 parent
390a7a557a
commit
6b9fb54b4f
16 files changed
+1381
-23
No files matched your search
@@ -16,6 +16,45 @@ final class RepositoryDatabase
|
||||
/** @var array<string, array{schema: string, connection: PDO}> */
|
||||
private static array $schemas = [];
|
||||
|
||||
/** @var array<string, Config> */
|
||||
private static array $configs = [];
|
||||
|
||||
public static function migrateTo(string $path, int $target): void
|
||||
{
|
||||
self::runTarget($path, $target, false);
|
||||
}
|
||||
|
||||
public static function rollbackTo(string $path, int $target): void
|
||||
{
|
||||
self::runTarget($path, $target, true);
|
||||
}
|
||||
|
||||
private static function runTarget(string $path, int $target, bool $down): void
|
||||
{
|
||||
$config = self::$configs[$path] ?? throw new \LogicException('Migrate this isolated path first.');
|
||||
$manager = new Manager($config, new ArrayInput([]), new NullOutput());
|
||||
$pdo = $config->getEnvironment('test')['connection'];
|
||||
if ($pdo->inTransaction()) {
|
||||
throw new \LogicException('Migration helpers require no active caller transaction.');
|
||||
}
|
||||
try {
|
||||
if ($down) {
|
||||
$manager->rollback('test', $target);
|
||||
} else {
|
||||
$manager->migrate('test', $target);
|
||||
}
|
||||
} catch (\Throwable $error) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
throw $error;
|
||||
} finally {
|
||||
if (isset(self::$schemas[$path])) {
|
||||
$pdo->exec('SET search_path TO "' . self::$schemas[$path]['schema'] . '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function postgresConfigured(): bool
|
||||
{
|
||||
$dsn = getenv('MESHVAULT_TEST_PG_DSN');
|
||||
@@ -23,9 +62,9 @@ final class RepositoryDatabase
|
||||
}
|
||||
|
||||
/** Never a hand-maintained test schema: drift must fail the suite. */
|
||||
public static function migrate(string $path): PDO
|
||||
public static function migrate(string $path, ?int $target = null): PDO
|
||||
{
|
||||
if (isset(self::$schemas[$path])) {
|
||||
if (isset(self::$configs[$path]) || isset(self::$schemas[$path])) {
|
||||
throw new \LogicException('Clean up the previous database before migrating this path again.');
|
||||
}
|
||||
$environment = ['adapter' => 'sqlite'];
|
||||
@@ -48,7 +87,8 @@ final class RepositoryDatabase
|
||||
'test' => $environment + ['connection' => $pdo],
|
||||
],
|
||||
]);
|
||||
(new Manager($config, new ArrayInput([]), new NullOutput()))->migrate('test');
|
||||
self::$configs[$path] = $config;
|
||||
(new Manager($config, new ArrayInput([]), new NullOutput()))->migrate('test', $target);
|
||||
if (isset(self::$schemas[$path])) {
|
||||
// Phinx may add public to search_path; repository queries must remain isolated.
|
||||
$pdo->exec('SET search_path TO "' . self::$schemas[$path]['schema'] . '"');
|
||||
@@ -78,6 +118,7 @@ final class RepositoryDatabase
|
||||
|
||||
public static function cleanup(string $path): void
|
||||
{
|
||||
unset(self::$configs[$path]);
|
||||
if (isset(self::$schemas[$path])) {
|
||||
['schema' => $schema, 'connection' => $pdo] = self::$schemas[$path];
|
||||
if ($pdo->inTransaction()) {
|
||||
|
||||
Reference in new issue
Block a user