Refactor drizzle and db folder

This commit is contained in:
Jared Palmer 2024-11-15 10:13:21 -05:00
parent e96dfb2d74
commit c493ac342b
31 changed files with 22 additions and 23 deletions

32
lib/db/migrate.ts Normal file
View file

@ -0,0 +1,32 @@
import { config } from 'dotenv';
import { drizzle } from 'drizzle-orm/postgres-js';
import { migrate } from 'drizzle-orm/postgres-js/migrator';
import postgres from 'postgres';
config({
path: '.env.local',
});
const runMigrate = async () => {
if (!process.env.POSTGRES_URL) {
throw new Error('POSTGRES_URL is not defined');
}
const connection = postgres(process.env.POSTGRES_URL, { max: 1 });
const db = drizzle(connection);
console.log('⏳ Running migrations...');
const start = Date.now();
await migrate(db, { migrationsFolder: './lib/drizzle' });
const end = Date.now();
console.log('✅ Migrations completed in', end - start, 'ms');
process.exit(0);
};
runMigrate().catch((err) => {
console.error('❌ Migration failed');
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,18 @@
CREATE TABLE IF NOT EXISTS "Chat" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"createdAt" timestamp NOT NULL,
"messages" json NOT NULL,
"userId" uuid NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "User" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"email" varchar(64) NOT NULL,
"password" varchar(64)
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Chat" ADD CONSTRAINT "Chat_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View file

@ -0,0 +1,39 @@
CREATE TABLE IF NOT EXISTS "Suggestion" (
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"documentId" uuid NOT NULL,
"documentCreatedAt" timestamp NOT NULL,
"originalText" text NOT NULL,
"suggestedText" text NOT NULL,
"description" text,
"isResolved" boolean DEFAULT false NOT NULL,
"userId" uuid NOT NULL,
"createdAt" timestamp NOT NULL,
CONSTRAINT "Suggestion_id_pk" PRIMARY KEY("id")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "Document" (
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"createdAt" timestamp NOT NULL,
"title" text NOT NULL,
"content" text,
"userId" uuid NOT NULL,
CONSTRAINT "Document_id_createdAt_pk" PRIMARY KEY("id","createdAt")
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Suggestion" ADD CONSTRAINT "Suggestion_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Suggestion" ADD CONSTRAINT "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk" FOREIGN KEY ("documentId","documentCreatedAt") REFERENCES "public"."Document"("id","createdAt") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Document" ADD CONSTRAINT "Document_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View file

@ -0,0 +1,35 @@
CREATE TABLE IF NOT EXISTS "Message" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"chatId" uuid NOT NULL,
"role" varchar NOT NULL,
"content" json NOT NULL,
"createdAt" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "Vote" (
"chatId" uuid NOT NULL,
"messageId" uuid NOT NULL,
"isUpvoted" boolean NOT NULL,
CONSTRAINT "Vote_chatId_messageId_pk" PRIMARY KEY("chatId","messageId")
);
--> statement-breakpoint
ALTER TABLE "Chat" ADD COLUMN "title" text NOT NULL;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Message" ADD CONSTRAINT "Message_chatId_Chat_id_fk" FOREIGN KEY ("chatId") REFERENCES "public"."Chat"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Vote" ADD CONSTRAINT "Vote_chatId_Chat_id_fk" FOREIGN KEY ("chatId") REFERENCES "public"."Chat"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Vote" ADD CONSTRAINT "Vote_messageId_Message_id_fk" FOREIGN KEY ("messageId") REFERENCES "public"."Message"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "Chat" DROP COLUMN IF EXISTS "messages";

View file

@ -0,0 +1,94 @@
{
"id": "715ec9ec-6715-4d0f-9f6c-9b5c7f09827c",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"messages": {
"name": "messages",
"type": "json",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -0,0 +1,259 @@
{
"id": "f3d3437c-4735-4c91-80af-1014048a904e",
"prevId": "715ec9ec-6715-4d0f-9f6c-9b5c7f09827c",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": [
"documentId",
"documentCreatedAt"
],
"columnsTo": [
"id",
"createdAt"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": [
"id"
]
}
},
"uniqueConstraints": {}
},
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"messages": {
"name": "messages",
"type": "json",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": [
"id",
"createdAt"
]
}
},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -0,0 +1,377 @@
{
"id": "b5d8e862-936f-4419-a50f-97be3e7fe665",
"prevId": "f3d3437c-4735-4c91-80af-1014048a904e",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": [
"documentId",
"documentCreatedAt"
],
"columnsTo": [
"id",
"createdAt"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": [
"id"
]
}
},
"uniqueConstraints": {}
},
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": [
"id",
"createdAt"
]
}
},
"uniqueConstraints": {}
},
"public.Message": {
"name": "Message",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_chatId_Chat_id_fk": {
"name": "Message_chatId_Chat_id_fk",
"tableFrom": "Message",
"tableTo": "Chat",
"columnsFrom": [
"chatId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_chatId_Chat_id_fk": {
"name": "Vote_chatId_Chat_id_fk",
"tableFrom": "Vote",
"tableTo": "Chat",
"columnsFrom": [
"chatId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_messageId_Message_id_fk": {
"name": "Vote_messageId_Message_id_fk",
"tableFrom": "Vote",
"tableTo": "Message",
"columnsFrom": [
"messageId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_chatId_messageId_pk": {
"name": "Vote_chatId_messageId_pk",
"columns": [
"chatId",
"messageId"
]
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -0,0 +1,27 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1728598022383,
"tag": "0000_keen_devos",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1730207363999,
"tag": "0001_sparkling_blue_marvel",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1730725226313,
"tag": "0002_wandering_riptide",
"breakpoints": true
}
]
}

280
lib/db/queries.ts Normal file
View file

@ -0,0 +1,280 @@
'server-only';
import { genSaltSync, hashSync } from 'bcrypt-ts';
import { and, asc, desc, eq, gt } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import {
user,
chat,
User,
document,
Suggestion,
suggestion,
Message,
message,
vote,
} from './schema';
// Optionally, if not using email/pass login, you can
// use the Drizzle adapter for Auth.js / NextAuth
// https://authjs.dev/reference/adapter/drizzle
let client = postgres(`${process.env.POSTGRES_URL!}?sslmode=require`);
let db = drizzle(client);
export async function getUser(email: string): Promise<Array<User>> {
try {
return await db.select().from(user).where(eq(user.email, email));
} catch (error) {
console.error('Failed to get user from database');
throw error;
}
}
export async function createUser(email: string, password: string) {
let salt = genSaltSync(10);
let hash = hashSync(password, salt);
try {
return await db.insert(user).values({ email, password: hash });
} catch (error) {
console.error('Failed to create user in database');
throw error;
}
}
export async function saveChat({
id,
userId,
title,
}: {
id: string;
userId: string;
title: string;
}) {
try {
return await db.insert(chat).values({
id,
createdAt: new Date(),
userId,
title,
});
} catch (error) {
console.error('Failed to save chat in database');
throw error;
}
}
export async function deleteChatById({ id }: { id: string }) {
try {
await db.delete(vote).where(eq(vote.chatId, id));
await db.delete(message).where(eq(message.chatId, id));
return await db.delete(chat).where(eq(chat.id, id));
} catch (error) {
console.error('Failed to delete chat by id from database');
throw error;
}
}
export async function getChatsByUserId({ id }: { id: string }) {
try {
return await db
.select()
.from(chat)
.where(eq(chat.userId, id))
.orderBy(desc(chat.createdAt));
} catch (error) {
console.error('Failed to get chats by user from database');
throw error;
}
}
export async function getChatById({ id }: { id: string }) {
try {
const [selectedChat] = await db.select().from(chat).where(eq(chat.id, id));
return selectedChat;
} catch (error) {
console.error('Failed to get chat by id from database');
throw error;
}
}
export async function saveMessages({ messages }: { messages: Array<Message> }) {
try {
return await db.insert(message).values(messages);
} catch (error) {
console.error('Failed to save messages in database', error);
throw error;
}
}
export async function getMessagesByChatId({ id }: { id: string }) {
try {
return await db
.select()
.from(message)
.where(eq(message.chatId, id))
.orderBy(asc(message.createdAt));
} catch (error) {
console.error('Failed to get messages by chat id from database', error);
throw error;
}
}
export async function voteMessage({
chatId,
messageId,
type,
}: {
chatId: string;
messageId: string;
type: 'up' | 'down';
}) {
try {
const [existingVote] = await db
.select()
.from(vote)
.where(and(eq(vote.messageId, messageId)));
if (existingVote) {
return await db
.update(vote)
.set({ isUpvoted: type === 'up' ? true : false })
.where(and(eq(vote.messageId, messageId), eq(vote.chatId, chatId)));
} else {
return await db.insert(vote).values({
chatId,
messageId,
isUpvoted: type === 'up' ? true : false,
});
}
} catch (error) {
console.error('Failed to upvote message in database', error);
throw error;
}
}
export async function getVotesByChatId({ id }: { id: string }) {
try {
return await db.select().from(vote).where(eq(vote.chatId, id));
} catch (error) {
console.error('Failed to get votes by chat id from database', error);
throw error;
}
}
export async function saveDocument({
id,
title,
content,
userId,
}: {
id: string;
title: string;
content: string;
userId: string;
}) {
try {
return await db.insert(document).values({
id,
title,
content,
userId,
createdAt: new Date(),
});
} catch (error) {
console.error('Failed to save document in database');
throw error;
}
}
export async function getDocumentsById({ id }: { id: string }) {
try {
const documents = await db
.select()
.from(document)
.where(eq(document.id, id))
.orderBy(asc(document.createdAt));
return documents;
} catch (error) {
console.error('Failed to get document by id from database');
throw error;
}
}
export async function getDocumentById({ id }: { id: string }) {
try {
const [selectedDocument] = await db
.select()
.from(document)
.where(eq(document.id, id))
.orderBy(desc(document.createdAt));
return selectedDocument;
} catch (error) {
console.error('Failed to get document by id from database');
throw error;
}
}
export async function deleteDocumentsByIdAfterTimestamp({
id,
timestamp,
}: {
id: string;
timestamp: Date;
}) {
try {
await db
.delete(suggestion)
.where(
and(
eq(suggestion.documentId, id),
gt(suggestion.documentCreatedAt, timestamp)
)
);
return await db
.delete(document)
.where(and(eq(document.id, id), gt(document.createdAt, timestamp)));
} catch (error) {
console.error(
'Failed to delete documents by id after timestamp from database'
);
throw error;
}
}
export async function saveSuggestions({
suggestions,
}: {
suggestions: Array<Suggestion>;
}) {
try {
return await db.insert(suggestion).values(suggestions);
} catch (error) {
console.error('Failed to save suggestions in database');
throw error;
}
}
export async function getSuggestionsByDocumentId({
documentId,
}: {
documentId: string;
}) {
try {
return await db
.select()
.from(suggestion)
.where(and(eq(suggestion.documentId, documentId)));
} catch (error) {
console.error(
'Failed to get suggestions by document version from database'
);
throw error;
}
}

109
lib/db/schema.ts Normal file
View file

@ -0,0 +1,109 @@
import { InferSelectModel } from 'drizzle-orm';
import {
pgTable,
varchar,
timestamp,
json,
uuid,
text,
primaryKey,
foreignKey,
boolean,
} from 'drizzle-orm/pg-core';
export const user = pgTable('User', {
id: uuid('id').primaryKey().notNull().defaultRandom(),
email: varchar('email', { length: 64 }).notNull(),
password: varchar('password', { length: 64 }),
});
export type User = InferSelectModel<typeof user>;
export const chat = pgTable('Chat', {
id: uuid('id').primaryKey().notNull().defaultRandom(),
createdAt: timestamp('createdAt').notNull(),
title: text('title').notNull(),
userId: uuid('userId')
.notNull()
.references(() => user.id),
});
export type Chat = InferSelectModel<typeof chat>;
export const message = pgTable('Message', {
id: uuid('id').primaryKey().notNull().defaultRandom(),
chatId: uuid('chatId')
.notNull()
.references(() => chat.id),
role: varchar('role').notNull(),
content: json('content').notNull(),
createdAt: timestamp('createdAt').notNull(),
});
export type Message = InferSelectModel<typeof message>;
export const vote = pgTable(
'Vote',
{
chatId: uuid('chatId')
.notNull()
.references(() => chat.id),
messageId: uuid('messageId')
.notNull()
.references(() => message.id),
isUpvoted: boolean('isUpvoted').notNull(),
},
(table) => {
return {
pk: primaryKey({ columns: [table.chatId, table.messageId] }),
};
}
);
export type Vote = InferSelectModel<typeof vote>;
export const document = pgTable(
'Document',
{
id: uuid('id').notNull().defaultRandom(),
createdAt: timestamp('createdAt').notNull(),
title: text('title').notNull(),
content: text('content'),
userId: uuid('userId')
.notNull()
.references(() => user.id),
},
(table) => {
return {
pk: primaryKey({ columns: [table.id, table.createdAt] }),
};
}
);
export type Document = InferSelectModel<typeof document>;
export const suggestion = pgTable(
'Suggestion',
{
id: uuid('id').notNull().defaultRandom(),
documentId: uuid('documentId').notNull(),
documentCreatedAt: timestamp('documentCreatedAt').notNull(),
originalText: text('originalText').notNull(),
suggestedText: text('suggestedText').notNull(),
description: text('description'),
isResolved: boolean('isResolved').notNull().default(false),
userId: uuid('userId')
.notNull()
.references(() => user.id),
createdAt: timestamp('createdAt').notNull(),
},
(table) => ({
pk: primaryKey({ columns: [table.id] }),
documentRef: foreignKey({
columns: [table.documentId, table.documentCreatedAt],
foreignColumns: [document.id, document.createdAt],
}),
})
);
export type Suggestion = InferSelectModel<typeof suggestion>;