From 01335c4e158f4ba79da0a53b8285e32df5ca35f4 Mon Sep 17 00:00:00 2001 From: "Mike P. Sinn" <m@crowdsourcingcures.org> Date: Thu, 5 Sep 2024 16:05:48 -0500 Subject: [PATCH] Add comprehensive article management schema This migration introduces a new schema for managing articles, categories, tags, sources, search results, generation options, and comments. It includes enums for status, visibility, and comment status, along with necessary foreign key constraints and indexes for efficient querying. --- .env.example | 4 +- .../20240905205856_articles/migration.sql | 176 ++++++++++++++++++ prisma/schema.prisma | 127 +++++++++++++ 3 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/20240905205856_articles/migration.sql diff --git a/.env.example b/.env.example index 1cd945fa..db66cb92 100644 --- a/.env.example +++ b/.env.example @@ -44,4 +44,6 @@ LANGCHAIN_API_KEY=<your-api-key> LANGCHAIN_CALLBACKS_BACKGROUND=true # Get key from https://www.perplexity.ai/settings/api -PERPLEXITY_API_KEY="KEY_HERE" \ No newline at end of file +PERPLEXITY_API_KEY="KEY_HERE" +# Get key from https://dashboard.exa.ai/api-keys +EXASEARCH_API_KEY="KEY_HERE" \ No newline at end of file diff --git a/prisma/migrations/20240905205856_articles/migration.sql b/prisma/migrations/20240905205856_articles/migration.sql new file mode 100644 index 00000000..2b71f5ce --- /dev/null +++ b/prisma/migrations/20240905205856_articles/migration.sql @@ -0,0 +1,176 @@ +-- CreateEnum +CREATE TYPE "ArticleStatus" AS ENUM ('DRAFT', 'PENDING', 'PRIVATE', 'PUBLISH'); + +-- CreateEnum +CREATE TYPE "ArticleVisibility" AS ENUM ('PUBLIC', 'PASSWORD_PROTECTED', 'PRIVATE'); + +-- CreateEnum +CREATE TYPE "ArticleCommentStatus" AS ENUM ('OPEN', 'CLOSED'); + +-- CreateTable +CREATE TABLE "Article" ( + "id" SERIAL NOT NULL, + "title" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "description" TEXT NOT NULL, + "content" TEXT NOT NULL, + "status" "ArticleStatus" NOT NULL DEFAULT 'DRAFT', + "visibility" "ArticleVisibility" NOT NULL DEFAULT 'PUBLIC', + "password" TEXT, + "publishedAt" TIMESTAMP(3), + "updatedAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedAt" TIMESTAMP(3), + "commentStatus" "ArticleCommentStatus" NOT NULL DEFAULT 'OPEN', + "sticky" BOOLEAN NOT NULL DEFAULT false, + "featuredImage" TEXT, + "promptedTopic" TEXT, + "userId" TEXT NOT NULL, + "categoryId" TEXT NOT NULL, + + CONSTRAINT "Article_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ArticleCategory" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "description" TEXT, + "updatedAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "ArticleCategory_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ArticleTag" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "ArticleTag_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ArticleSource" ( + "id" TEXT NOT NULL, + "url" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "articleId" INTEGER NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "ArticleSource_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ArticleSearchResult" ( + "id" TEXT NOT NULL, + "score" DOUBLE PRECISION NOT NULL, + "title" TEXT NOT NULL, + "url" TEXT NOT NULL, + "publishedDate" TIMESTAMP(3), + "author" TEXT, + "text" TEXT NOT NULL, + "articleId" INTEGER NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "ArticleSearchResult_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ArticleGenerationOptions" ( + "id" TEXT NOT NULL, + "numberOfSearchQueryVariations" INTEGER NOT NULL, + "numberOfWebResultsToInclude" INTEGER NOT NULL, + "audience" TEXT NOT NULL, + "purpose" TEXT NOT NULL, + "maxCharactersOfSearchContentToUse" INTEGER NOT NULL, + "tone" TEXT NOT NULL, + "format" TEXT NOT NULL, + "articleId" INTEGER NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "ArticleGenerationOptions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ArticleComment" ( + "id" TEXT NOT NULL, + "content" TEXT NOT NULL, + "articleId" INTEGER NOT NULL, + "userId" TEXT NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "ArticleComment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "_ArticleToArticleTag" ( + "A" INTEGER NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "Article_slug_key" ON "Article"("slug"); + +-- CreateIndex +CREATE UNIQUE INDEX "ArticleCategory_name_key" ON "ArticleCategory"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "ArticleCategory_slug_key" ON "ArticleCategory"("slug"); + +-- CreateIndex +CREATE UNIQUE INDEX "ArticleTag_name_key" ON "ArticleTag"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "ArticleTag_slug_key" ON "ArticleTag"("slug"); + +-- CreateIndex +CREATE UNIQUE INDEX "ArticleGenerationOptions_articleId_key" ON "ArticleGenerationOptions"("articleId"); + +-- CreateIndex +CREATE UNIQUE INDEX "_ArticleToArticleTag_AB_unique" ON "_ArticleToArticleTag"("A", "B"); + +-- CreateIndex +CREATE INDEX "_ArticleToArticleTag_B_index" ON "_ArticleToArticleTag"("B"); + +-- AddForeignKey +ALTER TABLE "Article" ADD CONSTRAINT "Article_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Article" ADD CONSTRAINT "Article_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "ArticleCategory"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ArticleSource" ADD CONSTRAINT "ArticleSource_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ArticleSearchResult" ADD CONSTRAINT "ArticleSearchResult_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ArticleGenerationOptions" ADD CONSTRAINT "ArticleGenerationOptions_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ArticleComment" ADD CONSTRAINT "ArticleComment_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ArticleComment" ADD CONSTRAINT "ArticleComment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_ArticleToArticleTag" ADD CONSTRAINT "_ArticleToArticleTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Article"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_ArticleToArticleTag" ADD CONSTRAINT "_ArticleToArticleTag_B_fkey" FOREIGN KEY ("B") REFERENCES "ArticleTag"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 875cdffe..9dc45c3f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -150,6 +150,8 @@ model User { symptomReports DfdaUserSymptomReport[] treatmentReports DfdaUserTreatmentReport[] sideEffectReports DfdaUserSideEffectReport[] + Article Article[] + ArticleComment ArticleComment[] } model Education { @@ -1407,3 +1409,128 @@ enum Effectiveness { MODERATE_IMPROVEMENT MAJOR_IMPROVEMENT } + +model Article { + id Int @id @default(autoincrement()) + title String + slug String @unique + description String + content String @db.Text + status ArticleStatus @default(DRAFT) + visibility ArticleVisibility @default(PUBLIC) + password String? + publishedAt DateTime? + updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + deletedAt DateTime? + commentStatus ArticleCommentStatus @default(OPEN) + sticky Boolean @default(false) + featuredImage String? + promptedTopic String? + + userId String + user User @relation(fields: [userId], references: [id]) + + categoryId String + category ArticleCategory @relation(fields: [categoryId], references: [id]) + + tags ArticleTag[] + sources ArticleSource[] + searchResults ArticleSearchResult[] + generationOptions ArticleGenerationOptions? + comments ArticleComment[] +} + +enum ArticleStatus { + DRAFT + PENDING + PRIVATE + PUBLISH +} + +enum ArticleVisibility { + PUBLIC + PASSWORD_PROTECTED + PRIVATE +} + +enum ArticleCommentStatus { + OPEN + CLOSED +} + +model ArticleCategory { + id String @id @default(cuid()) + name String @unique + slug String @unique + description String? + articles Article[] + updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + deletedAt DateTime? +} + +model ArticleTag { + id String @id @default(cuid()) + name String @unique + slug String @unique + articles Article[] + updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + deletedAt DateTime? +} + +model ArticleSource { + id String @id @default(cuid()) + url String + title String + description String? + articleId Int + article Article @relation(fields: [articleId], references: [id]) + updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + deletedAt DateTime? +} + +model ArticleSearchResult { + id String @id @default(cuid()) + score Float + title String + url String + publishedDate DateTime? + author String? + text String @db.Text + articleId Int + article Article @relation(fields: [articleId], references: [id]) + updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + deletedAt DateTime? +} + +model ArticleGenerationOptions { + id String @id @default(cuid()) + numberOfSearchQueryVariations Int + numberOfWebResultsToInclude Int + audience String + purpose String + maxCharactersOfSearchContentToUse Int + tone String + format String + articleId Int @unique + article Article @relation(fields: [articleId], references: [id]) + updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + deletedAt DateTime? +} + +model ArticleComment { + id String @id @default(cuid()) + content String @db.Text + articleId Int + article Article @relation(fields: [articleId], references: [id]) + userId String + user User @relation(fields: [userId], references: [id]) + updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + deletedAt DateTime? +}