*/ final class Version20251019151441 extends AbstractMigration { public function getDescription(): string { return 'initial postgresql schema'; } public function up(Schema $schema): void { $this->addSql("CREATE EXTENSION IF NOT EXISTS pg_trgm;"); // for trigram indexes (links, titles, etc.) $this->addSql("SET SESSION TIME ZONE 'UTC';"); // -- ---------- TABLE: article ---------- $this->addSql(<<>'image')) STORED, excerpt VARCHAR(255) GENERATED ALWAYS AS ((LEFT(body, 200) || '...')) STORED, published_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, crawled_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, link VARCHAR(1024) NOT NULL, bias VARCHAR(30) DEFAULT 'neutral' NOT NULL, reliability VARCHAR(30) DEFAULT 'reliable' NOT NULL, transparency VARCHAR(30) DEFAULT 'medium' NOT NULL, reading_time INT DEFAULT 1, CONSTRAINT CHK_ARTICLE_READING_TIME CHECK (reading_time >= 0), CONSTRAINT CHK_ARTICLE_SENTIMENT CHECK (sentiment IN ('positive','neutral','negative')), CONSTRAINT CHK_ARTICLE_METADATA_JSON CHECK (metadata IS NULL OR JSONB_TYPEOF(metadata) IN ('object','array')), PRIMARY KEY (id) ) SQL ); $this->addSql('CREATE INDEX IDX_23A0E66953C1C61 ON article (source_id)'); $this->addSql('CREATE INDEX IDX_ARTICLE_PUBLISHED_AT ON article (published_at DESC)'); $this->addSql('CREATE INDEX IDX_ARTICLE_PUBLISHED_ID ON article (published_at DESC, id DESC)'); $this->addSql('CREATE UNIQUE INDEX UNQ_ARTICLE_HASH ON article (hash)'); $this->addSql(<<addSql('CREATE INDEX GIN_ARTICLE_TSV ON article USING GIN(tsv)'); $this->addSql('CREATE INDEX GIN_ARTICLE_LINK_TRGM ON article USING GIN (link gin_trgm_ops)'); $this->addSql('CREATE INDEX GIN_ARTICLE_TITLE_TRGM ON article USING GIN (title gin_trgm_ops)'); $this->addSql('CREATE INDEX GIN_ARTICLE_CATEGORIES ON article USING GIN (categories)'); $this->addSql("COMMENT ON COLUMN article.id IS '(DC2Type:article_id)';"); $this->addSql("COMMENT ON COLUMN article.source_id IS '(DC2Type:source_id)';"); $this->addSql("COMMENT ON COLUMN article.published_at IS '(DC2Type:datetime_immutable)'"); $this->addSql("COMMENT ON COLUMN article.crawled_at IS '(DC2Type:datetime_immutable)'"); $this->addSql("COMMENT ON COLUMN article.updated_at IS '(DC2Type:datetime_immutable)'"); // -- ---------- TABLE: bookmark ---------- $this->addSql(<<addSql('CREATE INDEX IDX_DA62921DA76ED395 ON bookmark (user_id)'); $this->addSql('CREATE INDEX IDX_BOOKMARK_USER_CREATED ON bookmark (user_id, created_at DESC)'); $this->addSql("COMMENT ON COLUMN bookmark.id IS '(DC2Type:bookmark_id)'"); $this->addSql("COMMENT ON COLUMN bookmark.user_id IS '(DC2Type:user_id)'"); $this->addSql("COMMENT ON COLUMN bookmark.created_at IS '(DC2Type:datetime_immutable)'"); $this->addSql("COMMENT ON COLUMN bookmark.updated_at IS '(DC2Type:datetime_immutable)'"); // -- ---------- TABLE: bookmark_article ---------- $this->addSql(<<addSql('CREATE INDEX IDX_6FE2655D92741D25 ON bookmark_article (bookmark_id)'); $this->addSql('CREATE INDEX IDX_6FE2655D7294869C ON bookmark_article (article_id)'); $this->addSql("COMMENT ON COLUMN bookmark_article.bookmark_id IS '(DC2Type:bookmark_id)'"); $this->addSql("COMMENT ON COLUMN bookmark_article.article_id IS '(DC2Type:article_id)'"); // -- ---------- TABLE: comment ---------- $this->addSql(<<addSql('CREATE INDEX IDX_9474526CA76ED395 ON comment (user_id)'); $this->addSql('CREATE INDEX IDX_9474526C7294869C ON comment (article_id)'); $this->addSql('CREATE INDEX IDX_COMMENT_ARTICLE_CREATED ON comment (article_id, created_at DESC)'); $this->addSql("COMMENT ON COLUMN comment.id IS '(DC2Type:comment_id)'"); $this->addSql("COMMENT ON COLUMN comment.user_id IS '(DC2Type:user_id)'"); $this->addSql("COMMENT ON COLUMN comment.article_id IS '(DC2Type:article_id)'"); $this->addSql("COMMENT ON COLUMN comment.created_at IS '(DC2Type:datetime_immutable)'"); // -- ---------- TABLE: followed_source ---------- $this->addSql(<<addSql('CREATE INDEX IDX_7A763A3EAC24F853 ON followed_source (follower_id)'); $this->addSql('CREATE INDEX IDX_7A763A3E953C1C61 ON followed_source (source_id)'); $this->addSql('CREATE INDEX IDX_FOLLOWED_SOURCE_FOLLOWER_CREATED ON followed_source (follower_id, created_at DESC)'); $this->addSql("COMMENT ON COLUMN followed_source.id IS '(DC2Type:followed_source_id)'"); $this->addSql("COMMENT ON COLUMN followed_source.follower_id IS '(DC2Type:user_id)'"); $this->addSql("COMMENT ON COLUMN followed_source.source_id IS '(DC2Type:source_id)'"); $this->addSql("COMMENT ON COLUMN followed_source.created_at IS '(DC2Type:datetime_immutable)'"); // -- ---------- TABLE: login_attempt ---------- $this->addSql(<<addSql('CREATE INDEX IDX_8C11C1BA76ED395 ON login_attempt (user_id)'); $this->addSql('CREATE INDEX IDX_LOGIN_ATTEMPT_CREATED_AT ON login_attempt (created_at DESC)'); $this->addSql("COMMENT ON COLUMN login_attempt.id IS '(DC2Type:login_attempt_id)'"); $this->addSql("COMMENT ON COLUMN login_attempt.user_id IS '(DC2Type:user_id)'"); $this->addSql("COMMENT ON COLUMN login_attempt.created_at IS '(DC2Type:datetime_immutable)'"); // -- ---------- TABLE: login_history ---------- $this->addSql(<<addSql('CREATE INDEX IDX_37976E36A76ED395 ON login_history (user_id)'); $this->addSql('CREATE INDEX IDX_LOGIN_HISTORY_CREATED_AT ON login_history (user_id, created_at DESC)'); $this->addSql('CREATE INDEX IDX_LOGIN_HISTORY_IP_ADDRESS ON login_history (ip_address)'); $this->addSql("COMMENT ON COLUMN login_history.id IS '(DC2Type:login_history_id)'"); $this->addSql("COMMENT ON COLUMN login_history.user_id IS '(DC2Type:user_id)'"); $this->addSql("COMMENT ON COLUMN login_history.created_at IS '(DC2Type:datetime_immutable)'"); // -- ---------- TABLE: refresh_tokens ---------- $this->addSql('CREATE SEQUENCE refresh_tokens_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql(<<addSql('CREATE UNIQUE INDEX UNIQ_9BACE7E1C74F2195 ON refresh_tokens (refresh_token)'); // -- ---------- TABLE: source ---------- $this->addSql(<<addSql('CREATE UNIQUE INDEX UNQ_SOURCE_NAME ON source (LOWER(name))'); $this->addSql('CREATE UNIQUE INDEX UNQ_SOURCE_URL ON source (LOWER(url))'); $this->addSql("COMMENT ON COLUMN source.id IS '(DC2Type:source_id)'"); $this->addSql("COMMENT ON COLUMN source.updated_at IS '(DC2Type:datetime_immutable)'"); // -- ---------- TABLE: user ---------- $this->addSql(<<addSql(<<addSql("COMMENT ON COLUMN \"user\".id IS '(DC2Type:user_id)'"); $this->addSql("COMMENT ON COLUMN \"user\".created_at IS '(DC2Type:datetime_immutable)'"); $this->addSql("COMMENT ON COLUMN \"user\".updated_at IS '(DC2Type:datetime_immutable)'"); // -- ---------- TABLE: verification_token ---------- $this->addSql(<<addSql('CREATE INDEX IDX_C1CC006BA76ED395 ON verification_token (user_id)'); $this->addSql('CREATE INDEX IDX_VERIF_TOKEN_CREATED_AT ON verification_token (created_at DESC)'); $this->addSql('CREATE UNIQUE INDEX UNQ_VERIF_USER_PURPOSE_TOKEN ON verification_token (user_id, purpose) WHERE token IS NOT NULL'); $this->addSql("COMMENT ON COLUMN verification_token.id IS '(DC2Type:verification_token_id)'"); $this->addSql("COMMENT ON COLUMN verification_token.user_id IS '(DC2Type:user_id)'"); $this->addSql("COMMENT ON COLUMN verification_token.created_at IS '(DC2Type:datetime_immutable)'"); // -- ---------- FOREIGN KEY CONSTRAINTS ---------- $this->addSql('ALTER TABLE article ADD CONSTRAINT FK_23A0E66953C1C61 FOREIGN KEY (source_id) REFERENCES source (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE bookmark ADD CONSTRAINT FK_DA62921DA76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE bookmark_article ADD CONSTRAINT FK_6FE2655D92741D25 FOREIGN KEY (bookmark_id) REFERENCES bookmark (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE bookmark_article ADD CONSTRAINT FK_6FE2655D7294869C FOREIGN KEY (article_id) REFERENCES article (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526CA76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526C7294869C FOREIGN KEY (article_id) REFERENCES article (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE followed_source ADD CONSTRAINT FK_7A763A3EAC24F853 FOREIGN KEY (follower_id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE followed_source ADD CONSTRAINT FK_7A763A3E953C1C61 FOREIGN KEY (source_id) REFERENCES source (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE login_attempt ADD CONSTRAINT FK_8C11C1BA76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE login_history ADD CONSTRAINT FK_37976E36A76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE verification_token ADD CONSTRAINT FK_C1CC006BA76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } public function down(Schema $schema): void { throw new IrreversibleMigration('Sometimes in life you have to accept that you can\'t go back.'); } }