Establishes multi-tenant database layer with vector similarity search for AI-powered memory features. Includes Docker infrastructure, Prisma ORM integration, NestJS services, and shared types across the monorepo. Key changes: - Docker: PostgreSQL 17 + pgvector v0.7.4, Valkey cache - Schema: 8 models (User, Workspace, Task, Event, Project, ActivityLog, MemoryEmbedding) with RLS preparation - NestJS: PrismaModule, DatabaseModule, EmbeddingsService - Shared: Type-safe enums, constants, and database types Fixes #2 Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
96 lines
2.3 KiB
TypeScript
96 lines
2.3 KiB
TypeScript
import {
|
|
Injectable,
|
|
Logger,
|
|
OnModuleDestroy,
|
|
OnModuleInit,
|
|
} from "@nestjs/common";
|
|
import { PrismaClient } from "@prisma/client";
|
|
|
|
/**
|
|
* Prisma service that manages database connection lifecycle
|
|
* Extends PrismaClient to provide connection management and health checks
|
|
*/
|
|
@Injectable()
|
|
export class PrismaService
|
|
extends PrismaClient
|
|
implements OnModuleInit, OnModuleDestroy
|
|
{
|
|
private readonly logger = new Logger(PrismaService.name);
|
|
|
|
constructor() {
|
|
super({
|
|
log:
|
|
process.env.NODE_ENV === "development"
|
|
? ["query", "info", "warn", "error"]
|
|
: ["error"],
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Connect to database when NestJS module initializes
|
|
*/
|
|
async onModuleInit() {
|
|
try {
|
|
await this.$connect();
|
|
this.logger.log("Database connection established");
|
|
} catch (error) {
|
|
this.logger.error("Failed to connect to database", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disconnect from database when NestJS module is destroyed
|
|
*/
|
|
async onModuleDestroy() {
|
|
await this.$disconnect();
|
|
this.logger.log("Database connection closed");
|
|
}
|
|
|
|
/**
|
|
* Health check for database connectivity
|
|
* @returns true if database is accessible, false otherwise
|
|
*/
|
|
async isHealthy(): Promise<boolean> {
|
|
try {
|
|
await this.$queryRaw`SELECT 1`;
|
|
return true;
|
|
} catch (error) {
|
|
this.logger.error("Database health check failed", error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get database connection info for debugging
|
|
* @returns Connection status and basic info
|
|
*/
|
|
async getConnectionInfo(): Promise<{
|
|
connected: boolean;
|
|
database?: string;
|
|
version?: string;
|
|
}> {
|
|
try {
|
|
const result = await this.$queryRaw<
|
|
Array<{ current_database: string; version: string }>
|
|
>`
|
|
SELECT current_database(), version()
|
|
`;
|
|
|
|
if (result && result.length > 0 && result[0]) {
|
|
const dbVersion = result[0].version?.split(" ")[0];
|
|
return {
|
|
connected: true,
|
|
database: result[0].current_database,
|
|
...(dbVersion && { version: dbVersion }),
|
|
};
|
|
}
|
|
|
|
return { connected: false };
|
|
} catch (error) {
|
|
this.logger.error("Failed to get connection info", error);
|
|
return { connected: false };
|
|
}
|
|
}
|
|
}
|