initial commit

Change-Id: Ifa2442bb2e786af351ef5f575ca69828870c8b6e
This commit is contained in:
Scaffolder
2026-08-03 21:12:35 +00:00
commit 8053e114cf
76 changed files with 14013 additions and 0 deletions

View File

@@ -0,0 +1,114 @@
-- CreateTable
CREATE TABLE "Article" (
"id" SERIAL NOT NULL,
"slug" TEXT NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"body" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"authorId" INTEGER NOT NULL,
PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ArticleTags" (
"articleId" INTEGER NOT NULL,
"tagId" INTEGER NOT NULL,
PRIMARY KEY ("articleId","tagId")
);
-- CreateTable
CREATE TABLE "Comment" (
"id" SERIAL NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"body" TEXT NOT NULL,
"articleId" INTEGER NOT NULL,
"authorId" INTEGER NOT NULL,
PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Tag" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "User" (
"id" SERIAL NOT NULL,
"email" TEXT NOT NULL,
"username" TEXT NOT NULL,
"password" TEXT NOT NULL,
"image" TEXT DEFAULT E'https://realworld-temp-api.herokuapp.com/images/smiley-cyrus.jpeg',
"bio" TEXT,
"demo" BOOLEAN NOT NULL DEFAULT false,
PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "_UserFavorites" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL
);
-- CreateTable
CREATE TABLE "_UserFollows" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "Article.slug_unique" ON "Article"("slug");
-- CreateIndex
CREATE UNIQUE INDEX "User.email_unique" ON "User"("email");
-- CreateIndex
CREATE UNIQUE INDEX "User.username_unique" ON "User"("username");
-- CreateIndex
CREATE UNIQUE INDEX "_UserFavorites_AB_unique" ON "_UserFavorites"("A", "B");
-- CreateIndex
CREATE INDEX "_UserFavorites_B_index" ON "_UserFavorites"("B");
-- CreateIndex
CREATE UNIQUE INDEX "_UserFollows_AB_unique" ON "_UserFollows"("A", "B");
-- CreateIndex
CREATE INDEX "_UserFollows_B_index" ON "_UserFollows"("B");
-- AddForeignKey
ALTER TABLE "Article" ADD FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ArticleTags" ADD FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ArticleTags" ADD FOREIGN KEY ("tagId") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Comment" ADD FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Comment" ADD FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_UserFavorites" ADD FOREIGN KEY ("A") REFERENCES "Article"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_UserFavorites" ADD FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_UserFollows" ADD FOREIGN KEY ("A") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_UserFollows" ADD FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,36 @@
/*
Warnings:
- You are about to drop the `ArticleTags` table. If the table is not empty, all the data it contains will be lost.
- A unique constraint covering the columns `[name]` on the table `Tag` will be added. If there are existing duplicate values, this will fail.
*/
-- DropForeignKey
ALTER TABLE "ArticleTags" DROP CONSTRAINT "ArticleTags_articleId_fkey";
-- DropForeignKey
ALTER TABLE "ArticleTags" DROP CONSTRAINT "ArticleTags_tagId_fkey";
-- DropTable
DROP TABLE "ArticleTags";
-- CreateTable
CREATE TABLE "_ArticleToTag" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "_ArticleToTag_AB_unique" ON "_ArticleToTag"("A", "B");
-- CreateIndex
CREATE INDEX "_ArticleToTag_B_index" ON "_ArticleToTag"("B");
-- CreateIndex
CREATE UNIQUE INDEX "Tag.name_unique" ON "Tag"("name");
-- AddForeignKey
ALTER TABLE "_ArticleToTag" ADD FOREIGN KEY ("A") REFERENCES "Article"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_ArticleToTag" ADD FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "User" ALTER COLUMN "image" SET DEFAULT E'https://api.realworld.io/images/smiley-cyrus.jpeg';

View File

@@ -0,0 +1,11 @@
-- RenameIndex
ALTER INDEX "Article.slug_unique" RENAME TO "Article_slug_key";
-- RenameIndex
ALTER INDEX "Tag.name_unique" RENAME TO "Tag_name_key";
-- RenameIndex
ALTER INDEX "User.email_unique" RENAME TO "User_email_key";
-- RenameIndex
ALTER INDEX "User.username_unique" RENAME TO "User_username_key";

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"

View File

@@ -0,0 +1,23 @@
import { PrismaClient } from '@prisma/client';
declare global {
namespace NodeJS {
interface Global {}
}
}
// add prisma to the NodeJS global type
interface CustomNodeJsGlobal extends NodeJS.Global {
prisma: PrismaClient;
}
// Prevent multiple instances of Prisma Client in development
declare const global: CustomNodeJsGlobal;
const prisma = global.prisma || new PrismaClient();
if (process.env.NODE_ENV === 'development') {
global.prisma = prisma;
}
export default prisma;

56
src/prisma/schema.prisma Normal file
View File

@@ -0,0 +1,56 @@
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
previewFeatures = []
}
model Article {
id Int @id @default(autoincrement())
slug String @unique
title String
description String
body String
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
tagList Tag[]
author User @relation("UserArticles", fields: [authorId], onDelete: Cascade, references: [id])
authorId Int
favoritedBy User[] @relation("UserFavorites")
comments Comment[]
}
model Comment {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
body String
article Article @relation(fields: [articleId], references: [id], onDelete: Cascade)
articleId Int
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
authorId Int
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
articles Article[]
}
model User {
id Int @id @default(autoincrement())
email String @unique
username String @unique
password String
image String? @default("https://api.realworld.io/images/smiley-cyrus.jpeg")
bio String?
articles Article[] @relation("UserArticles")
favorites Article[] @relation("UserFavorites")
followedBy User[] @relation("UserFollows")
following User[] @relation("UserFollows")
comments Comment[]
demo Boolean @default(false)
}

66
src/prisma/seed.ts Normal file
View File

@@ -0,0 +1,66 @@
import {
randEmail,
randFullName,
randLines,
randParagraph,
randPassword, randPhrase,
randWord
} from '@ngneat/falso';
import { PrismaClient } from '@prisma/client';
import { RegisteredUser } from '../app/routes/auth/registered-user.model';
import { createUser } from '../app/routes/auth/auth.service';
import { addComment, createArticle } from '../app/routes/article/article.service';
const prisma = new PrismaClient();
export const generateUser = async (): Promise<RegisteredUser> =>
createUser({
username: randFullName(),
email: randEmail(),
password: randPassword(),
image: 'https://api.realworld.io/images/demo-avatar.png',
demo: true,
});
export const generateArticle = async (id: number) =>
createArticle(
{
title: randPhrase(),
description: randParagraph(),
body: randLines({ length: 10 }).join(' '),
tagList: randWord({ length: 4 }),
},
id,
);
export const generateComment = async (id: number, slug: string) =>
addComment(randParagraph(), slug, id);
const main = async () => {
try {
const users = await Promise.all(Array.from({length: 12}, () => generateUser()));
users?.map(user => user);
// eslint-disable-next-line no-restricted-syntax
for await (const user of users) {
const articles = await Promise.all(Array.from({length: 12}, () => generateArticle(user.id)));
// eslint-disable-next-line no-restricted-syntax
for await (const article of articles) {
await Promise.all(users.map(userItem => generateComment(userItem.id, article.slug)));
}
}
} catch (e) {
console.error(e);
}
};
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async () => {
await prisma.$disconnect();
process.exit(1);
});