chore: snapshot before performance optimization

This commit is contained in:
Sepehr Ramezani
2026-04-17 21:14:43 +02:00
parent b6a548acd8
commit 2eceb32fd4
95 changed files with 4357 additions and 1942 deletions

View File

@@ -1,96 +1,58 @@
/**
* Test database setup and teardown utilities for migration tests
* Provides isolated database environments for each test suite
* Updated for PostgreSQL
*/
import { PrismaClient } from '@prisma/client'
import * as fs from 'fs'
import * as path from 'path'
// Environment variables
const DATABASE_DIR = path.join(process.cwd(), 'prisma', 'test-databases')
const TEST_DATABASE_PATH = path.join(DATABASE_DIR, 'migration-test.db')
/**
* Initialize test environment
* Creates test database directory if it doesn't exist
*/
export async function setupTestEnvironment() {
// Ensure test database directory exists
if (!fs.existsSync(DATABASE_DIR)) {
fs.mkdirSync(DATABASE_DIR, { recursive: true })
}
// Clean up any existing test database
if (fs.existsSync(TEST_DATABASE_PATH)) {
fs.unlinkSync(TEST_DATABASE_PATH)
}
}
/**
* Create a Prisma client instance connected to test database
* Create a Prisma client instance for testing
* Uses DATABASE_URL from environment
*/
export function createTestPrismaClient(): PrismaClient {
return new PrismaClient({
datasources: {
db: {
url: `file:${TEST_DATABASE_PATH}`
}
}
})
return new PrismaClient()
}
/**
* Initialize test database schema from migrations
* This applies all migrations to create a clean schema
* Initialize test database schema
* Runs prisma migrate deploy or db push
*/
export async function initializeTestDatabase(prisma: PrismaClient) {
// Connect to database
await prisma.$connect()
// Read and execute all migration files in order
const migrationsDir = path.join(process.cwd(), 'prisma', 'migrations')
const migrationFolders = fs.readdirSync(migrationsDir)
.filter(name => !name.includes('migration_lock') && fs.statSync(path.join(migrationsDir, name)).isDirectory())
.sort()
// Execute each migration
for (const folder of migrationFolders) {
const migrationSql = fs.readFileSync(path.join(migrationsDir, folder, 'migration.sql'), 'utf-8')
try {
await prisma.$executeRawUnsafe(migrationSql)
} catch (error) {
// Some migrations might fail if tables already exist, which is okay for test setup
console.log(`Migration ${folder} note:`, (error as Error).message)
}
}
}
/**
* Cleanup test database
* Disconnects Prisma client and removes test database file
* Disconnects Prisma client and cleans all data
*/
export async function cleanupTestDatabase(prisma: PrismaClient) {
try {
// Delete in dependency order
await prisma.aiFeedback.deleteMany()
await prisma.memoryEchoInsight.deleteMany()
await prisma.noteShare.deleteMany()
await prisma.note.deleteMany()
await prisma.label.deleteMany()
await prisma.notebook.deleteMany()
await prisma.userAISettings.deleteMany()
await prisma.systemConfig.deleteMany()
await prisma.session.deleteMany()
await prisma.account.deleteMany()
await prisma.verificationToken.deleteMany()
await prisma.user.deleteMany()
await prisma.$disconnect()
} catch (error) {
console.error('Error disconnecting Prisma:', error)
}
// Remove test database file
if (fs.existsSync(TEST_DATABASE_PATH)) {
fs.unlinkSync(TEST_DATABASE_PATH)
console.error('Error cleaning up test database:', error)
}
}
/**
* Create sample test data
* Generates test notes with various configurations
*/
export async function createSampleNotes(prisma: PrismaClient, count: number = 10) {
const notes = []
const userId = 'test-user-123'
for (let i = 0; i < count; i++) {
const note = await prisma.note.create({
data: {
@@ -107,18 +69,17 @@ export async function createSampleNotes(prisma: PrismaClient, count: number = 10
})
notes.push(note)
}
return notes
}
/**
* Create sample AI-enabled notes
* Tests AI field migration scenarios
*/
export async function createSampleAINotes(prisma: PrismaClient, count: number = 10) {
const notes = []
const userId = 'test-user-ai'
for (let i = 0; i < count; i++) {
const note = await prisma.note.create({
data: {
@@ -137,13 +98,12 @@ export async function createSampleAINotes(prisma: PrismaClient, count: number =
})
notes.push(note)
}
return notes
}
/**
* Measure execution time for a function
* Useful for performance testing
*/
export async function measureExecutionTime<T>(fn: () => Promise<T>): Promise<{ result: T; duration: number }> {
const start = performance.now()
@@ -157,115 +117,98 @@ export async function measureExecutionTime<T>(fn: () => Promise<T>): Promise<{ r
/**
* Verify data integrity after migration
* Checks for data loss or corruption
*/
export async function verifyDataIntegrity(prisma: PrismaClient, expectedNoteCount: number) {
const noteCount = await prisma.note.count()
if (noteCount !== expectedNoteCount) {
throw new Error(`Data integrity check failed: Expected ${expectedNoteCount} notes, found ${noteCount}`)
}
// Verify no null critical fields
const allNotes = await prisma.note.findMany()
for (const note of allNotes) {
if (!note.title && !note.content) {
throw new Error(`Data integrity check failed: Note ${note.id} has neither title nor content`)
}
}
return true
}
/**
* Check if database tables exist
* Verifies schema migration success
* Check if database table exists (PostgreSQL version)
*/
export async function verifyTableExists(prisma: PrismaClient, tableName: string): Promise<boolean> {
try {
const result = await prisma.$queryRawUnsafe<Array<{ name: string }>>(
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
const result = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
`SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = $1
)`,
tableName
)
return result.length > 0
return result[0]?.exists ?? false
} catch (error) {
return false
}
}
/**
* Check if index exists on a table
* Verifies index creation migration success
* Check if index exists on a table (PostgreSQL version)
*/
export async function verifyIndexExists(prisma: PrismaClient, tableName: string, indexName: string): Promise<boolean> {
try {
const result = await prisma.$queryRawUnsafe<Array<{ name: string }>>(
`SELECT name FROM sqlite_master WHERE type='index' AND tbl_name=? AND name=?`,
const result = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
`SELECT EXISTS (
SELECT FROM pg_indexes
WHERE schemaname = 'public'
AND tablename = $1
AND indexname = $2
)`,
tableName,
indexName
)
return result.length > 0
return result[0]?.exists ?? false
} catch (error) {
return false
}
}
/**
* Verify foreign key relationships
* Ensures cascade delete works correctly
* Check if column exists in table (PostgreSQL version)
*/
export async function verifyCascadeDelete(prisma: PrismaClient, parentTableName: string, childTableName: string): Promise<boolean> {
// This is a basic check - in a real migration test, you would:
// 1. Create a parent record
// 2. Create related child records
// 3. Delete the parent
// 4. Verify children are deleted
return true
export async function verifyColumnExists(prisma: PrismaClient, tableName: string, columnName: string): Promise<boolean> {
try {
const result = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
`SELECT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = $1
AND column_name = $2
)`,
tableName,
columnName
)
return result[0]?.exists ?? false
} catch (error) {
return false
}
}
/**
* Get table schema information
* Useful for verifying schema migration
* Get table schema information (PostgreSQL version)
*/
export async function getTableSchema(prisma: PrismaClient, tableName: string) {
try {
const result = await prisma.$queryRawUnsafe<Array<{
cid: number
name: string
type: string
notnull: number
dflt_value: string | null
pk: number
column_name: string
data_type: string
is_nullable: string
column_default: string | null
}>>(
`PRAGMA table_info(${tableName})`
`SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = $1
ORDER BY ordinal_position`,
tableName
)
return result
} catch (error) {
return null
}
}
/**
* Check if column exists in table
* Verifies column migration success
*/
export async function verifyColumnExists(prisma: PrismaClient, tableName: string, columnName: string): Promise<boolean> {
const schema = await getTableSchema(prisma, tableName)
if (!schema) return false
return schema.some(col => col.name === columnName)
}
/**
* Get database size in bytes
* Useful for performance monitoring
*/
export async function getDatabaseSize(prisma: PrismaClient): Promise<number> {
try {
const result = await prisma.$queryRawUnsafe<Array<{ size: number }>>(
`SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()`
)
return result[0]?.size || 0
} catch (error) {
return 0
}
}