CRUD Albums + Spotify API requests into DB.
All checks were successful
CI - Build Tonehaus Docker image / tonehaus-ci-build (push) Successful in 2m17s

This commit is contained in:
2025-11-20 19:53:45 +00:00
parent cd13f1478a
commit cd04fa5212
26 changed files with 6180 additions and 66 deletions

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20251114111853 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// Idempotent guard: if table already exists (from previous migration), skip
if ($schema->hasTable('albums')) {
return;
}
$this->addSql('CREATE TABLE albums (id SERIAL NOT NULL, spotify_id VARCHAR(64) NOT NULL, name VARCHAR(255) NOT NULL, artists JSON NOT NULL, release_date VARCHAR(20) DEFAULT NULL, total_tracks INT NOT NULL, cover_url VARCHAR(1024) DEFAULT NULL, external_url VARCHAR(1024) DEFAULT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE UNIQUE INDEX UNIQ_F4E2474FA905FC5C ON albums (spotify_id)');
$this->addSql('COMMENT ON COLUMN albums.created_at IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN albums.updated_at IS \'(DC2Type:datetime_immutable)\'');
}
public function down(Schema $schema): void
{
// Be defensive: only drop the table if it exists
if ($schema->hasTable('albums')) {
$this->addSql('DROP TABLE albums');
}
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20251114112016 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE albums ALTER created_at TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('ALTER TABLE albums ALTER updated_at TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('COMMENT ON COLUMN albums.created_at IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN albums.updated_at IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('ALTER INDEX uniq_album_spotify_id RENAME TO UNIQ_F4E2474FA905FC5C');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE albums ALTER created_at TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('ALTER TABLE albums ALTER updated_at TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('COMMENT ON COLUMN albums.created_at IS NULL');
$this->addSql('COMMENT ON COLUMN albums.updated_at IS NULL');
$this->addSql('ALTER INDEX uniq_f4e2474fa905fc5c RENAME TO uniq_album_spotify_id');
}
}

View File

@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20251114113000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Normalize reviews: add album_id FK, backfill from albums.spotify_id';
}
public function up(Schema $schema): void
{
// Add nullable album_id first
$this->addSql('ALTER TABLE reviews ADD album_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE reviews ADD CONSTRAINT FK_6970EF78E0C31AF9 FOREIGN KEY (album_id) REFERENCES albums (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_6970EF78E0C31AF9 ON reviews (album_id)');
// Backfill using existing spotify_album_id if both columns exist
// Some environments may not have the legacy column; guard with DO blocks
$this->addSql(<<<'SQL'
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name='reviews' AND column_name='spotify_album_id'
) THEN
UPDATE reviews r
SET album_id = a.id
FROM albums a
WHERE a.spotify_id = r.spotify_album_id
AND r.album_id IS NULL;
END IF;
END $$;
SQL);
// Optionally set NOT NULL if all rows are linked
$this->addSql(<<<'SQL'
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM reviews WHERE album_id IS NULL) THEN
ALTER TABLE reviews ALTER COLUMN album_id SET NOT NULL;
END IF;
END $$;
SQL);
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE reviews DROP CONSTRAINT FK_6970EF78E0C31AF9');
$this->addSql('DROP INDEX IF EXISTS IDX_6970EF78E0C31AF9');
$this->addSql('ALTER TABLE reviews DROP COLUMN album_id');
}
}

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20251114114000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Drop legacy duplicated review columns: spotify_album_id, album_name, album_artist';
}
public function up(Schema $schema): void
{
// Guard: drop columns only if they exist
$this->addSql(<<<'SQL'
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='reviews' AND column_name='spotify_album_id') THEN
ALTER TABLE reviews DROP COLUMN spotify_album_id;
END IF;
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='reviews' AND column_name='album_name') THEN
ALTER TABLE reviews DROP COLUMN album_name;
END IF;
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='reviews' AND column_name='album_artist') THEN
ALTER TABLE reviews DROP COLUMN album_artist;
END IF;
END $$;
SQL);
}
public function down(Schema $schema): void
{
// Recreate columns as nullable in down migration
$this->addSql('ALTER TABLE reviews ADD spotify_album_id VARCHAR(64) DEFAULT NULL');
$this->addSql('ALTER TABLE reviews ADD album_name VARCHAR(255) DEFAULT NULL');
$this->addSql('ALTER TABLE reviews ADD album_artist VARCHAR(255) DEFAULT NULL');
}
}

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20251114120500 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add user-created album fields: local_id, source, created_by_id; make spotify_id nullable';
}
public function up(Schema $schema): void
{
$this->addSql("ALTER TABLE albums ADD local_id VARCHAR(64) DEFAULT NULL");
$this->addSql("ALTER TABLE albums ADD source VARCHAR(16) NOT NULL DEFAULT 'spotify'");
$this->addSql("ALTER TABLE albums ADD created_by_id INT DEFAULT NULL");
$this->addSql("ALTER TABLE albums ALTER spotify_id DROP NOT NULL");
$this->addSql("CREATE UNIQUE INDEX uniq_album_local_id ON albums (local_id)");
$this->addSql("ALTER TABLE albums ADD CONSTRAINT FK_F4E2474FB03A8386 FOREIGN KEY (created_by_id) REFERENCES users (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE");
$this->addSql("CREATE INDEX IDX_F4E2474FB03A8386 ON albums (created_by_id)");
$this->addSql("UPDATE albums SET source = 'spotify' WHERE source IS NULL");
}
public function down(Schema $schema): void
{
$this->addSql("ALTER TABLE albums DROP CONSTRAINT FK_F4E2474FB03A8386");
$this->addSql("DROP INDEX IF EXISTS uniq_album_local_id");
$this->addSql("DROP INDEX IF EXISTS IDX_F4E2474FB03A8386");
$this->addSql("ALTER TABLE albums DROP COLUMN local_id");
$this->addSql("ALTER TABLE albums DROP COLUMN source");
$this->addSql("ALTER TABLE albums DROP COLUMN created_by_id");
$this->addSql("ALTER TABLE albums ALTER spotify_id SET NOT NULL");
}
}

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20251120174722 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE reviews ALTER album_id SET NOT NULL');
$this->addSql('ALTER INDEX idx_6970ef78e0c31af9 RENAME TO IDX_6970EB0F1137ABCF');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE reviews ALTER album_id DROP NOT NULL');
$this->addSql('ALTER INDEX idx_6970eb0f1137abcf RENAME TO idx_6970ef78e0c31af9');
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20251120175034 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
}
}