import { sqliteTable, integer, text, blob, real } from 'drizzle-orm/sqlite-core'; import { isNull } from 'drizzle-orm'; export const user = sqliteTable('user', { id: text('id').primaryKey(), age: integer('age'), username: text('username').notNull().unique(), passwordHash: text('password_hash').notNull() }); export const session = sqliteTable('session', { id: text('id').primaryKey(), userId: text('user_id') .notNull() .references(() => user.id), expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull() }); export const audioFile = sqliteTable('audio_file', { id: text('id').primaryKey(), filename: text('filename').notNull(), contentType: text('content_type').notNull(), data: blob('data').default(null), // Temporarily keep for migration s3Key: text('s3_key'), // Temporarily optional for migration duration: real('duration'), fileSize: integer('file_size'), createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), deletedAt: integer('deleted_at', { mode: 'timestamp' }) // Soft delete for audio files }); export const inviteLink = sqliteTable('invite_link', { id: text('id').primaryKey(), token: text('token').notNull().unique(), participantName: text('participant_name'), isUsed: integer('is_used', { mode: 'boolean' }).notNull().default(false), createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), usedAt: integer('used_at', { mode: 'timestamp' }), deletedAt: integer('deleted_at', { mode: 'timestamp' }) }); export const participant = sqliteTable('participant', { id: text('id').primaryKey(), inviteToken: text('invite_token') .notNull() .references(() => inviteLink.token), sessionId: text('session_id'), createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), deletedAt: integer('deleted_at', { mode: 'timestamp' }) }); export const rating = sqliteTable('rating', { id: text('id').primaryKey(), participantId: text('participant_id') .notNull() .references(() => participant.id), audioFileId: text('audio_file_id') .notNull() .references(() => audioFile.id), timestamp: real('timestamp').notNull(), value: real('value').notNull(), isCompleted: integer('is_completed', { mode: 'boolean' }).notNull().default(false), timeseriesData: text('timeseries_data'), // JSON string of all rating changes (for completed ratings) createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), deletedAt: integer('deleted_at', { mode: 'timestamp' }) // Soft delete for redos }); export const participantProgress = sqliteTable('participant_progress', { id: text('id').primaryKey(), participantId: text('participant_id') .notNull() .references(() => participant.id), audioFileId: text('audio_file_id') .notNull() .references(() => audioFile.id), isCompleted: integer('is_completed', { mode: 'boolean' }).notNull().default(false), lastPosition: real('last_position').default(0), maxReachedTime: real('max_reached_time').default(0), updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull() }); export const overallRating = sqliteTable('overall_rating', { id: text('id').primaryKey(), participantId: text('participant_id') .notNull() .references(() => participant.id), audioFileId: text('audio_file_id') .notNull() .references(() => audioFile.id), value: real('value').notNull(), // 0-100 rating value createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(), deletedAt: integer('deleted_at', { mode: 'timestamp' }) // Soft delete for potential redos });