BarBar288's picture
Upload 122 files
27127dd verified
import {
type Message,
type InsertMessage,
type Conversation,
type InsertConversation,
type User,
PersonalityType,
messageRoleSchema,
messages,
conversations,
users
} from "@shared/schema";
import { db } from "./db";
import { eq, desc, asc } from "drizzle-orm";
import { nanoid } from "nanoid";
import session from 'express-session';
import connectPgSimple from 'connect-pg-simple';
import { pool } from './db';
export interface IStorage {
// Message operations
getMessages(conversationId: string): Promise<Message[]>;
createMessage(message: InsertMessage): Promise<Message>;
deleteMessages(conversationId: string): Promise<void>;
// Conversation operations
getConversation(id: string): Promise<Conversation | undefined>;
getConversations(): Promise<Conversation[]>;
getUserConversations(userId: number): Promise<Conversation[]>;
createConversation(conversation: InsertConversation): Promise<Conversation>;
deleteConversation(id: string): Promise<boolean>;
updateConversationPersonality(id: string, personality: PersonalityType): Promise<Conversation | undefined>;
updateConversationTitle(id: string, title: string): Promise<Conversation | undefined>;
// User profile operations
getUserProfile(id: number): Promise<User | undefined>;
getUserByUsername(username: string): Promise<User | undefined>;
createUser(userData: any): Promise<User>;
updateUserProfile(id: number, profile: Partial<User>): Promise<User | undefined>;
// Session operations
sessionStore: session.Store;
}
export class DatabaseStorage implements IStorage {
sessionStore: session.Store;
constructor() {
// Initialize PostgreSQL session store
const PgStore = connectPgSimple(session);
this.sessionStore = new PgStore({
pool,
createTableIfMissing: true,
});
// Initialize default conversation if it doesn't exist
this.initializeDefaultConversation();
}
private async initializeDefaultConversation() {
try {
const defaultConversation = await this.getConversation("default");
if (!defaultConversation) {
await this.createConversation({
id: "default",
title: "New Conversation",
personality: "general"
});
}
} catch (error) {
console.error("Error initializing default conversation:", error);
}
}
// Message operations
async getMessages(conversationId: string): Promise<Message[]> {
return db
.select()
.from(messages)
.where(eq(messages.conversationId, conversationId))
.orderBy(asc(messages.createdAt));
}
async createMessage(insertMessage: InsertMessage): Promise<Message> {
const [newMessage] = await db
.insert(messages)
.values({
...insertMessage,
createdAt: new Date()
})
.returning();
return newMessage;
}
async deleteMessages(conversationId: string): Promise<void> {
await db
.delete(messages)
.where(eq(messages.conversationId, conversationId));
}
// Conversation operations
async getConversation(id: string): Promise<Conversation | undefined> {
const [conversation] = await db
.select()
.from(conversations)
.where(eq(conversations.id, id));
return conversation;
}
async getConversations(): Promise<Conversation[]> {
return db
.select()
.from(conversations)
.orderBy(desc(conversations.createdAt));
}
async createConversation(conversation: InsertConversation): Promise<Conversation> {
// If the conversation already exists, update it
if (conversation.id) {
const existingConversation = await this.getConversation(conversation.id);
if (existingConversation) {
const [updatedConversation] = await db
.update(conversations)
.set({
title: conversation.title,
personality: conversation.personality || "general",
// Only update userId if provided
...(conversation.userId && { userId: conversation.userId })
})
.where(eq(conversations.id, conversation.id))
.returning();
return updatedConversation;
}
}
// Otherwise, create a new conversation
const [newConversation] = await db
.insert(conversations)
.values({
id: conversation.id || nanoid(),
title: conversation.title,
personality: conversation.personality || "general",
userId: conversation.userId, // Include the user ID (can be null for unassociated conversations)
createdAt: new Date()
})
.returning();
return newConversation;
}
async deleteConversation(id: string): Promise<boolean> {
// Don't allow deleting the default conversation
if (id === "default") {
return false;
}
try {
// Delete associated messages first
await this.deleteMessages(id);
// Then delete the conversation
const [deletedConversation] = await db
.delete(conversations)
.where(eq(conversations.id, id))
.returning();
return !!deletedConversation;
} catch (error) {
console.error("Error deleting conversation:", error);
return false;
}
}
async updateConversationPersonality(id: string, personality: PersonalityType): Promise<Conversation | undefined> {
const [updatedConversation] = await db
.update(conversations)
.set({ personality })
.where(eq(conversations.id, id))
.returning();
return updatedConversation;
}
async updateConversationTitle(id: string, title: string): Promise<Conversation | undefined> {
const [updatedConversation] = await db
.update(conversations)
.set({ title })
.where(eq(conversations.id, id))
.returning();
return updatedConversation;
}
// User operations
async getUserProfile(id: number): Promise<User | undefined> {
const [user] = await db
.select()
.from(users)
.where(eq(users.id, id));
return user;
}
async getUserByUsername(username: string): Promise<User | undefined> {
const [user] = await db
.select()
.from(users)
.where(eq(users.username, username));
return user;
}
async createUser(userData: any): Promise<User> {
const [user] = await db
.insert(users)
.values(userData)
.returning();
return user;
}
async updateUserProfile(id: number, profile: Partial<User>): Promise<User | undefined> {
// Remove sensitive information that shouldn't be updated this way
const { password, ...updateData } = profile;
const [updatedUser] = await db
.update(users)
.set(updateData as any)
.where(eq(users.id, id))
.returning();
return updatedUser;
}
// Filter conversations by user ID
async getUserConversations(userId: number): Promise<Conversation[]> {
return db
.select()
.from(conversations)
.where(eq(conversations.userId, userId))
.orderBy(desc(conversations.createdAt));
}
}
// Use the database storage for production
export const storage = new DatabaseStorage();