import { index, integer, numeric, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'; type FilingMetrics = { revenue: number | null; netIncome: number | null; totalAssets: number | null; cash: number | null; debt: number | null; }; type FilingAnalysis = { provider?: string; model?: string; text?: string; legacyInsights?: string; }; const authDateColumn = { mode: 'timestamp_ms' } as const; export const user = sqliteTable('user', { id: text('id').primaryKey().notNull(), name: text('name').notNull(), email: text('email').notNull(), emailVerified: integer('emailVerified', { mode: 'boolean' }).notNull().default(false), image: text('image'), createdAt: integer('createdAt', authDateColumn).notNull(), updatedAt: integer('updatedAt', authDateColumn).notNull(), role: text('role'), banned: integer('banned', { mode: 'boolean' }).default(false), banReason: text('banReason'), banExpires: integer('banExpires', authDateColumn) }, (table) => ({ userEmailUnique: uniqueIndex('user_email_uidx').on(table.email) })); export const organization = sqliteTable('organization', { id: text('id').primaryKey().notNull(), name: text('name').notNull(), slug: text('slug').notNull(), logo: text('logo'), createdAt: integer('createdAt', authDateColumn).notNull(), metadata: text('metadata') }, (table) => ({ organizationSlugUnique: uniqueIndex('organization_slug_uidx').on(table.slug) })); export const session = sqliteTable('session', { id: text('id').primaryKey().notNull(), expiresAt: integer('expiresAt', authDateColumn).notNull(), token: text('token').notNull(), createdAt: integer('createdAt', authDateColumn).notNull(), updatedAt: integer('updatedAt', authDateColumn).notNull(), ipAddress: text('ipAddress'), userAgent: text('userAgent'), userId: text('userId').notNull().references(() => user.id, { onDelete: 'cascade' }), impersonatedBy: text('impersonatedBy'), activeOrganizationId: text('activeOrganizationId') }, (table) => ({ sessionTokenUnique: uniqueIndex('session_token_uidx').on(table.token), sessionUserIdIndex: index('session_userId_idx').on(table.userId) })); export const account = sqliteTable('account', { id: text('id').primaryKey().notNull(), accountId: text('accountId').notNull(), providerId: text('providerId').notNull(), userId: text('userId').notNull().references(() => user.id, { onDelete: 'cascade' }), accessToken: text('accessToken'), refreshToken: text('refreshToken'), idToken: text('idToken'), accessTokenExpiresAt: integer('accessTokenExpiresAt', authDateColumn), refreshTokenExpiresAt: integer('refreshTokenExpiresAt', authDateColumn), scope: text('scope'), password: text('password'), createdAt: integer('createdAt', authDateColumn).notNull(), updatedAt: integer('updatedAt', authDateColumn).notNull() }, (table) => ({ accountUserIdIndex: index('account_userId_idx').on(table.userId) })); export const verification = sqliteTable('verification', { id: text('id').primaryKey().notNull(), identifier: text('identifier').notNull(), value: text('value').notNull(), expiresAt: integer('expiresAt', authDateColumn).notNull(), createdAt: integer('createdAt', authDateColumn).notNull(), updatedAt: integer('updatedAt', authDateColumn).notNull() }, (table) => ({ verificationIdentifierIndex: index('verification_identifier_idx').on(table.identifier) })); export const member = sqliteTable('member', { id: text('id').primaryKey().notNull(), organizationId: text('organizationId').notNull().references(() => organization.id, { onDelete: 'cascade' }), userId: text('userId').notNull().references(() => user.id, { onDelete: 'cascade' }), role: text('role').notNull().default('member'), createdAt: integer('createdAt', authDateColumn).notNull() }, (table) => ({ memberOrganizationIdIndex: index('member_organizationId_idx').on(table.organizationId), memberUserIdIndex: index('member_userId_idx').on(table.userId) })); export const invitation = sqliteTable('invitation', { id: text('id').primaryKey().notNull(), organizationId: text('organizationId').notNull().references(() => organization.id, { onDelete: 'cascade' }), email: text('email').notNull(), role: text('role'), status: text('status').notNull().default('pending'), expiresAt: integer('expiresAt', authDateColumn).notNull(), createdAt: integer('createdAt', authDateColumn).notNull(), inviterId: text('inviterId').notNull().references(() => user.id, { onDelete: 'cascade' }) }, (table) => ({ invitationOrganizationIdIndex: index('invitation_organizationId_idx').on(table.organizationId), invitationEmailIndex: index('invitation_email_idx').on(table.email) })); export const watchlistItem = sqliteTable('watchlist_item', { id: integer('id').primaryKey({ autoIncrement: true }), user_id: text('user_id').notNull().references(() => user.id, { onDelete: 'cascade' }), ticker: text('ticker').notNull(), company_name: text('company_name').notNull(), sector: text('sector'), created_at: text('created_at').notNull() }, (table) => ({ watchlistUserTickerUnique: uniqueIndex('watchlist_user_ticker_uidx').on(table.user_id, table.ticker), watchlistUserCreatedIndex: index('watchlist_user_created_idx').on(table.user_id, table.created_at) })); export const holding = sqliteTable('holding', { id: integer('id').primaryKey({ autoIncrement: true }), user_id: text('user_id').notNull().references(() => user.id, { onDelete: 'cascade' }), ticker: text('ticker').notNull(), shares: numeric('shares').notNull(), avg_cost: numeric('avg_cost').notNull(), current_price: numeric('current_price'), market_value: numeric('market_value').notNull(), gain_loss: numeric('gain_loss').notNull(), gain_loss_pct: numeric('gain_loss_pct').notNull(), last_price_at: text('last_price_at'), created_at: text('created_at').notNull(), updated_at: text('updated_at').notNull() }, (table) => ({ holdingUserTickerUnique: uniqueIndex('holding_user_ticker_uidx').on(table.user_id, table.ticker), holdingUserIndex: index('holding_user_idx').on(table.user_id) })); export const filing = sqliteTable('filing', { id: integer('id').primaryKey({ autoIncrement: true }), ticker: text('ticker').notNull(), filing_type: text('filing_type').$type<'10-K' | '10-Q' | '8-K'>().notNull(), filing_date: text('filing_date').notNull(), accession_number: text('accession_number').notNull(), cik: text('cik').notNull(), company_name: text('company_name').notNull(), filing_url: text('filing_url'), submission_url: text('submission_url'), primary_document: text('primary_document'), metrics: text('metrics', { mode: 'json' }).$type(), analysis: text('analysis', { mode: 'json' }).$type(), created_at: text('created_at').notNull(), updated_at: text('updated_at').notNull() }, (table) => ({ filingAccessionUnique: uniqueIndex('filing_accession_uidx').on(table.accession_number), filingTickerDateIndex: index('filing_ticker_date_idx').on(table.ticker, table.filing_date), filingDateIndex: index('filing_date_idx').on(table.filing_date) })); export const filingLink = sqliteTable('filing_link', { id: integer('id').primaryKey({ autoIncrement: true }), filing_id: integer('filing_id').notNull().references(() => filing.id, { onDelete: 'cascade' }), link_type: text('link_type').notNull(), url: text('url').notNull(), source: text('source').notNull().default('sec'), created_at: text('created_at').notNull() }, (table) => ({ filingLinkUnique: uniqueIndex('filing_link_unique_uidx').on(table.filing_id, table.url), filingLinkFilingIndex: index('filing_link_filing_idx').on(table.filing_id) })); export const taskRun = sqliteTable('task_run', { id: text('id').primaryKey().notNull(), user_id: text('user_id').notNull().references(() => user.id, { onDelete: 'cascade' }), task_type: text('task_type').$type<'sync_filings' | 'refresh_prices' | 'analyze_filing' | 'portfolio_insights'>().notNull(), status: text('status').$type<'queued' | 'running' | 'completed' | 'failed'>().notNull(), priority: integer('priority').notNull(), payload: text('payload', { mode: 'json' }).$type>().notNull(), result: text('result', { mode: 'json' }).$type | null>(), error: text('error'), attempts: integer('attempts').notNull(), max_attempts: integer('max_attempts').notNull(), workflow_run_id: text('workflow_run_id'), created_at: text('created_at').notNull(), updated_at: text('updated_at').notNull(), finished_at: text('finished_at') }, (table) => ({ taskUserCreatedIndex: index('task_user_created_idx').on(table.user_id, table.created_at), taskStatusIndex: index('task_status_idx').on(table.status), taskWorkflowRunUnique: uniqueIndex('task_workflow_run_uidx').on(table.workflow_run_id) })); export const portfolioInsight = sqliteTable('portfolio_insight', { id: integer('id').primaryKey({ autoIncrement: true }), user_id: text('user_id').notNull().references(() => user.id, { onDelete: 'cascade' }), provider: text('provider').notNull(), model: text('model').notNull(), content: text('content').notNull(), created_at: text('created_at').notNull() }, (table) => ({ insightUserCreatedIndex: index('insight_user_created_idx').on(table.user_id, table.created_at) })); export const authSchema = { user, session, account, verification, organization, member, invitation }; export const appSchema = { watchlistItem, holding, filing, filingLink, taskRun, portfolioInsight }; export const schema = { ...authSchema, ...appSchema };