chore: commit all changes
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import { Pool } from 'pg';
|
||||
import { authSchema } from './schema';
|
||||
import { schema } from './schema';
|
||||
|
||||
type AuthDrizzleDb = ReturnType<typeof createDb>;
|
||||
type AppDrizzleDb = ReturnType<typeof createDb>;
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line no-var
|
||||
var __fiscalAuthPgPool: Pool | undefined;
|
||||
var __fiscalPgPool: Pool | undefined;
|
||||
// eslint-disable-next-line no-var
|
||||
var __fiscalAuthDrizzleDb: AuthDrizzleDb | undefined;
|
||||
var __fiscalDrizzleDb: AppDrizzleDb | undefined;
|
||||
}
|
||||
|
||||
function getConnectionString() {
|
||||
@@ -21,21 +21,21 @@ function getConnectionString() {
|
||||
}
|
||||
|
||||
export function getPool() {
|
||||
if (!globalThis.__fiscalAuthPgPool) {
|
||||
globalThis.__fiscalAuthPgPool = new Pool({
|
||||
if (!globalThis.__fiscalPgPool) {
|
||||
globalThis.__fiscalPgPool = new Pool({
|
||||
connectionString: getConnectionString()
|
||||
});
|
||||
}
|
||||
|
||||
return globalThis.__fiscalAuthPgPool;
|
||||
return globalThis.__fiscalPgPool;
|
||||
}
|
||||
|
||||
function createDb() {
|
||||
return drizzle(getPool(), { schema: authSchema });
|
||||
return drizzle(getPool(), { schema });
|
||||
}
|
||||
|
||||
export const db = globalThis.__fiscalAuthDrizzleDb ?? createDb();
|
||||
export const db = globalThis.__fiscalDrizzleDb ?? createDb();
|
||||
|
||||
if (!globalThis.__fiscalAuthDrizzleDb) {
|
||||
globalThis.__fiscalAuthDrizzleDb = db;
|
||||
if (!globalThis.__fiscalDrizzleDb) {
|
||||
globalThis.__fiscalDrizzleDb = db;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,52 @@
|
||||
import { boolean, index, pgTable, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core';
|
||||
import {
|
||||
boolean,
|
||||
index,
|
||||
integer,
|
||||
jsonb,
|
||||
numeric,
|
||||
pgTable,
|
||||
text,
|
||||
timestamp,
|
||||
uniqueIndex
|
||||
} from 'drizzle-orm/pg-core';
|
||||
|
||||
const dateColumn = {
|
||||
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 = {
|
||||
withTimezone: true,
|
||||
mode: 'date'
|
||||
} as const;
|
||||
|
||||
const appDateColumn = {
|
||||
withTimezone: true,
|
||||
mode: 'string'
|
||||
} as const;
|
||||
|
||||
export const user = pgTable('user', {
|
||||
id: text('id').primaryKey().notNull(),
|
||||
name: text('name').notNull(),
|
||||
email: text('email').notNull(),
|
||||
emailVerified: boolean('emailVerified').notNull().default(false),
|
||||
image: text('image'),
|
||||
createdAt: timestamp('createdAt', dateColumn).notNull(),
|
||||
updatedAt: timestamp('updatedAt', dateColumn).notNull(),
|
||||
createdAt: timestamp('createdAt', authDateColumn).notNull(),
|
||||
updatedAt: timestamp('updatedAt', authDateColumn).notNull(),
|
||||
role: text('role'),
|
||||
banned: boolean('banned').default(false),
|
||||
banReason: text('banReason'),
|
||||
banExpires: timestamp('banExpires', dateColumn)
|
||||
banExpires: timestamp('banExpires', authDateColumn)
|
||||
}, (table) => ({
|
||||
userEmailUnique: uniqueIndex('user_email_uidx').on(table.email)
|
||||
}));
|
||||
@@ -26,7 +56,7 @@ export const organization = pgTable('organization', {
|
||||
name: text('name').notNull(),
|
||||
slug: text('slug').notNull(),
|
||||
logo: text('logo'),
|
||||
createdAt: timestamp('createdAt', dateColumn).notNull(),
|
||||
createdAt: timestamp('createdAt', authDateColumn).notNull(),
|
||||
metadata: text('metadata')
|
||||
}, (table) => ({
|
||||
organizationSlugUnique: uniqueIndex('organization_slug_uidx').on(table.slug)
|
||||
@@ -34,10 +64,10 @@ export const organization = pgTable('organization', {
|
||||
|
||||
export const session = pgTable('session', {
|
||||
id: text('id').primaryKey().notNull(),
|
||||
expiresAt: timestamp('expiresAt', dateColumn).notNull(),
|
||||
expiresAt: timestamp('expiresAt', authDateColumn).notNull(),
|
||||
token: text('token').notNull(),
|
||||
createdAt: timestamp('createdAt', dateColumn).notNull(),
|
||||
updatedAt: timestamp('updatedAt', dateColumn).notNull(),
|
||||
createdAt: timestamp('createdAt', authDateColumn).notNull(),
|
||||
updatedAt: timestamp('updatedAt', authDateColumn).notNull(),
|
||||
ipAddress: text('ipAddress'),
|
||||
userAgent: text('userAgent'),
|
||||
userId: text('userId').notNull().references(() => user.id, { onDelete: 'cascade' }),
|
||||
@@ -56,12 +86,12 @@ export const account = pgTable('account', {
|
||||
accessToken: text('accessToken'),
|
||||
refreshToken: text('refreshToken'),
|
||||
idToken: text('idToken'),
|
||||
accessTokenExpiresAt: timestamp('accessTokenExpiresAt', dateColumn),
|
||||
refreshTokenExpiresAt: timestamp('refreshTokenExpiresAt', dateColumn),
|
||||
accessTokenExpiresAt: timestamp('accessTokenExpiresAt', authDateColumn),
|
||||
refreshTokenExpiresAt: timestamp('refreshTokenExpiresAt', authDateColumn),
|
||||
scope: text('scope'),
|
||||
password: text('password'),
|
||||
createdAt: timestamp('createdAt', dateColumn).notNull(),
|
||||
updatedAt: timestamp('updatedAt', dateColumn).notNull()
|
||||
createdAt: timestamp('createdAt', authDateColumn).notNull(),
|
||||
updatedAt: timestamp('updatedAt', authDateColumn).notNull()
|
||||
}, (table) => ({
|
||||
accountUserIdIndex: index('account_userId_idx').on(table.userId)
|
||||
}));
|
||||
@@ -70,9 +100,9 @@ export const verification = pgTable('verification', {
|
||||
id: text('id').primaryKey().notNull(),
|
||||
identifier: text('identifier').notNull(),
|
||||
value: text('value').notNull(),
|
||||
expiresAt: timestamp('expiresAt', dateColumn).notNull(),
|
||||
createdAt: timestamp('createdAt', dateColumn).notNull(),
|
||||
updatedAt: timestamp('updatedAt', dateColumn).notNull()
|
||||
expiresAt: timestamp('expiresAt', authDateColumn).notNull(),
|
||||
createdAt: timestamp('createdAt', authDateColumn).notNull(),
|
||||
updatedAt: timestamp('updatedAt', authDateColumn).notNull()
|
||||
}, (table) => ({
|
||||
verificationIdentifierIndex: index('verification_identifier_idx').on(table.identifier)
|
||||
}));
|
||||
@@ -82,7 +112,7 @@ export const member = pgTable('member', {
|
||||
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: timestamp('createdAt', dateColumn).notNull()
|
||||
createdAt: timestamp('createdAt', authDateColumn).notNull()
|
||||
}, (table) => ({
|
||||
memberOrganizationIdIndex: index('member_organizationId_idx').on(table.organizationId),
|
||||
memberUserIdIndex: index('member_userId_idx').on(table.userId)
|
||||
@@ -94,14 +124,109 @@ export const invitation = pgTable('invitation', {
|
||||
email: text('email').notNull(),
|
||||
role: text('role'),
|
||||
status: text('status').notNull().default('pending'),
|
||||
expiresAt: timestamp('expiresAt', dateColumn).notNull(),
|
||||
createdAt: timestamp('createdAt', dateColumn).notNull(),
|
||||
expiresAt: timestamp('expiresAt', authDateColumn).notNull(),
|
||||
createdAt: timestamp('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 = pgTable('watchlist_item', {
|
||||
id: integer('id').generatedAlwaysAsIdentity().primaryKey(),
|
||||
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: timestamp('created_at', appDateColumn).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 = pgTable('holding', {
|
||||
id: integer('id').generatedAlwaysAsIdentity().primaryKey(),
|
||||
user_id: text('user_id').notNull().references(() => user.id, { onDelete: 'cascade' }),
|
||||
ticker: text('ticker').notNull(),
|
||||
shares: numeric('shares', { precision: 30, scale: 6 }).notNull(),
|
||||
avg_cost: numeric('avg_cost', { precision: 30, scale: 6 }).notNull(),
|
||||
current_price: numeric('current_price', { precision: 30, scale: 6 }),
|
||||
market_value: numeric('market_value', { precision: 30, scale: 2 }).notNull(),
|
||||
gain_loss: numeric('gain_loss', { precision: 30, scale: 2 }).notNull(),
|
||||
gain_loss_pct: numeric('gain_loss_pct', { precision: 30, scale: 2 }).notNull(),
|
||||
last_price_at: timestamp('last_price_at', appDateColumn),
|
||||
created_at: timestamp('created_at', appDateColumn).notNull(),
|
||||
updated_at: timestamp('updated_at', appDateColumn).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 = pgTable('filing', {
|
||||
id: integer('id').generatedAlwaysAsIdentity().primaryKey(),
|
||||
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: jsonb('metrics').$type<FilingMetrics | null>(),
|
||||
analysis: jsonb('analysis').$type<FilingAnalysis | null>(),
|
||||
created_at: timestamp('created_at', appDateColumn).notNull(),
|
||||
updated_at: timestamp('updated_at', appDateColumn).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 = pgTable('filing_link', {
|
||||
id: integer('id').generatedAlwaysAsIdentity().primaryKey(),
|
||||
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: timestamp('created_at', appDateColumn).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 = pgTable('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: jsonb('payload').$type<Record<string, unknown>>().notNull(),
|
||||
result: jsonb('result').$type<Record<string, unknown> | null>(),
|
||||
error: text('error'),
|
||||
attempts: integer('attempts').notNull(),
|
||||
max_attempts: integer('max_attempts').notNull(),
|
||||
workflow_run_id: text('workflow_run_id'),
|
||||
created_at: timestamp('created_at', appDateColumn).notNull(),
|
||||
updated_at: timestamp('updated_at', appDateColumn).notNull(),
|
||||
finished_at: timestamp('finished_at', appDateColumn)
|
||||
}, (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 = pgTable('portfolio_insight', {
|
||||
id: integer('id').generatedAlwaysAsIdentity().primaryKey(),
|
||||
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: timestamp('created_at', appDateColumn).notNull()
|
||||
}, (table) => ({
|
||||
insightUserCreatedIndex: index('insight_user_created_idx').on(table.user_id, table.created_at)
|
||||
}));
|
||||
|
||||
export const authSchema = {
|
||||
user,
|
||||
session,
|
||||
@@ -111,3 +236,17 @@ export const authSchema = {
|
||||
member,
|
||||
invitation
|
||||
};
|
||||
|
||||
export const appSchema = {
|
||||
watchlistItem,
|
||||
holding,
|
||||
filing,
|
||||
filingLink,
|
||||
taskRun,
|
||||
portfolioInsight
|
||||
};
|
||||
|
||||
export const schema = {
|
||||
...authSchema,
|
||||
...appSchema
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user