mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-19 10:41:22 +02:00
style: auto-format codebase with Prettier
Applied formatting to 1487+ files using pnpm format:write - TypeScript/JavaScript files - Svelte components - Astro pages - JSON configs - Markdown docs 13 files still need manual review (Astro JSX comments)
This commit is contained in:
parent
0241f5554c
commit
d36b321d9d
3952 changed files with 661498 additions and 739751 deletions
|
|
@ -1,62 +1,53 @@
|
|||
import {
|
||||
pgTable,
|
||||
uuid,
|
||||
varchar,
|
||||
text,
|
||||
timestamp,
|
||||
jsonb,
|
||||
index,
|
||||
pgEnum,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { pgTable, uuid, varchar, text, timestamp, jsonb, index, pgEnum } from 'drizzle-orm/pg-core';
|
||||
import { relations } from 'drizzle-orm';
|
||||
import { decks } from './decks.js';
|
||||
|
||||
// AI generation status enum
|
||||
export const aiGenerationStatusEnum = pgEnum('ai_generation_status', [
|
||||
'pending',
|
||||
'processing',
|
||||
'completed',
|
||||
'failed',
|
||||
'pending',
|
||||
'processing',
|
||||
'completed',
|
||||
'failed',
|
||||
]);
|
||||
|
||||
// AI generation metadata structure
|
||||
export interface AIGenerationMetadata {
|
||||
inputTokens?: number;
|
||||
outputTokens?: number;
|
||||
totalTokens?: number;
|
||||
duration?: number;
|
||||
error?: string;
|
||||
cardCount?: number;
|
||||
[key: string]: unknown;
|
||||
inputTokens?: number;
|
||||
outputTokens?: number;
|
||||
totalTokens?: number;
|
||||
duration?: number;
|
||||
error?: string;
|
||||
cardCount?: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export const aiGenerations = pgTable(
|
||||
'ai_generations',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
deckId: uuid('deck_id').references(() => decks.id, { onDelete: 'set null' }),
|
||||
functionName: varchar('function_name', { length: 100 }).notNull(),
|
||||
prompt: text('prompt').notNull(),
|
||||
model: varchar('model', { length: 100 }),
|
||||
status: aiGenerationStatusEnum('status').default('pending').notNull(),
|
||||
metadata: jsonb('metadata').default({}).$type<AIGenerationMetadata>(),
|
||||
completedAt: timestamp('completed_at', { withTimezone: true }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_ai_generations_user_id').on(table.userId),
|
||||
index('idx_ai_generations_deck_id').on(table.deckId),
|
||||
index('idx_ai_generations_status').on(table.status),
|
||||
index('idx_ai_generations_created_at').on(table.createdAt),
|
||||
]
|
||||
'ai_generations',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
deckId: uuid('deck_id').references(() => decks.id, { onDelete: 'set null' }),
|
||||
functionName: varchar('function_name', { length: 100 }).notNull(),
|
||||
prompt: text('prompt').notNull(),
|
||||
model: varchar('model', { length: 100 }),
|
||||
status: aiGenerationStatusEnum('status').default('pending').notNull(),
|
||||
metadata: jsonb('metadata').default({}).$type<AIGenerationMetadata>(),
|
||||
completedAt: timestamp('completed_at', { withTimezone: true }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_ai_generations_user_id').on(table.userId),
|
||||
index('idx_ai_generations_deck_id').on(table.deckId),
|
||||
index('idx_ai_generations_status').on(table.status),
|
||||
index('idx_ai_generations_created_at').on(table.createdAt),
|
||||
]
|
||||
);
|
||||
|
||||
export const aiGenerationsRelations = relations(aiGenerations, ({ one }) => ({
|
||||
deck: one(decks, {
|
||||
fields: [aiGenerations.deckId],
|
||||
references: [decks.id],
|
||||
}),
|
||||
deck: one(decks, {
|
||||
fields: [aiGenerations.deckId],
|
||||
references: [decks.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export type AIGeneration = typeof aiGenerations.$inferSelect;
|
||||
|
|
|
|||
|
|
@ -1,56 +1,56 @@
|
|||
import {
|
||||
pgTable,
|
||||
uuid,
|
||||
integer,
|
||||
timestamp,
|
||||
index,
|
||||
pgEnum,
|
||||
decimal,
|
||||
unique,
|
||||
pgTable,
|
||||
uuid,
|
||||
integer,
|
||||
timestamp,
|
||||
index,
|
||||
pgEnum,
|
||||
decimal,
|
||||
unique,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { relations } from 'drizzle-orm';
|
||||
import { cards } from './cards.js';
|
||||
|
||||
// Progress status enum (SM-2 algorithm states)
|
||||
export const progressStatusEnum = pgEnum('progress_status', [
|
||||
'new',
|
||||
'learning',
|
||||
'review',
|
||||
'relearning',
|
||||
'new',
|
||||
'learning',
|
||||
'review',
|
||||
'relearning',
|
||||
]);
|
||||
|
||||
export const cardProgress = pgTable(
|
||||
'card_progress',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
cardId: uuid('card_id')
|
||||
.notNull()
|
||||
.references(() => cards.id, { onDelete: 'cascade' }),
|
||||
// SM-2 algorithm fields
|
||||
easeFactor: decimal('ease_factor', { precision: 4, scale: 2 }).default('2.5').notNull(),
|
||||
interval: integer('interval').default(0).notNull(), // Days until next review
|
||||
repetitions: integer('repetitions').default(0).notNull(),
|
||||
lastReviewed: timestamp('last_reviewed', { withTimezone: true }),
|
||||
nextReview: timestamp('next_review', { withTimezone: true }),
|
||||
status: progressStatusEnum('status').default('new').notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_card_progress_user_id').on(table.userId),
|
||||
index('idx_card_progress_card_id').on(table.cardId),
|
||||
index('idx_card_progress_next_review').on(table.nextReview),
|
||||
index('idx_card_progress_status').on(table.status),
|
||||
unique('unique_user_card').on(table.userId, table.cardId),
|
||||
]
|
||||
'card_progress',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
cardId: uuid('card_id')
|
||||
.notNull()
|
||||
.references(() => cards.id, { onDelete: 'cascade' }),
|
||||
// SM-2 algorithm fields
|
||||
easeFactor: decimal('ease_factor', { precision: 4, scale: 2 }).default('2.5').notNull(),
|
||||
interval: integer('interval').default(0).notNull(), // Days until next review
|
||||
repetitions: integer('repetitions').default(0).notNull(),
|
||||
lastReviewed: timestamp('last_reviewed', { withTimezone: true }),
|
||||
nextReview: timestamp('next_review', { withTimezone: true }),
|
||||
status: progressStatusEnum('status').default('new').notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_card_progress_user_id').on(table.userId),
|
||||
index('idx_card_progress_card_id').on(table.cardId),
|
||||
index('idx_card_progress_next_review').on(table.nextReview),
|
||||
index('idx_card_progress_status').on(table.status),
|
||||
unique('unique_user_card').on(table.userId, table.cardId),
|
||||
]
|
||||
);
|
||||
|
||||
export const cardProgressRelations = relations(cardProgress, ({ one }) => ({
|
||||
card: one(cards, {
|
||||
fields: [cardProgress.cardId],
|
||||
references: [cards.id],
|
||||
}),
|
||||
card: one(cards, {
|
||||
fields: [cardProgress.cardId],
|
||||
references: [cards.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export type CardProgress = typeof cardProgress.$inferSelect;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import {
|
||||
pgTable,
|
||||
uuid,
|
||||
varchar,
|
||||
text,
|
||||
integer,
|
||||
boolean,
|
||||
timestamp,
|
||||
jsonb,
|
||||
index,
|
||||
pgEnum,
|
||||
pgTable,
|
||||
uuid,
|
||||
varchar,
|
||||
text,
|
||||
integer,
|
||||
boolean,
|
||||
timestamp,
|
||||
jsonb,
|
||||
index,
|
||||
pgEnum,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { relations } from 'drizzle-orm';
|
||||
import { decks } from './decks.js';
|
||||
|
|
@ -19,63 +19,63 @@ export const cardTypeEnum = pgEnum('card_type', ['text', 'flashcard', 'quiz', 'm
|
|||
|
||||
// Card content types
|
||||
export interface TextContent {
|
||||
text: string;
|
||||
formatting?: {
|
||||
bold?: boolean;
|
||||
italic?: boolean;
|
||||
underline?: boolean;
|
||||
};
|
||||
text: string;
|
||||
formatting?: {
|
||||
bold?: boolean;
|
||||
italic?: boolean;
|
||||
underline?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface FlashcardContent {
|
||||
front: string;
|
||||
back: string;
|
||||
hint?: string;
|
||||
front: string;
|
||||
back: string;
|
||||
hint?: string;
|
||||
}
|
||||
|
||||
export interface QuizContent {
|
||||
question: string;
|
||||
options: string[];
|
||||
correctAnswer: number;
|
||||
explanation?: string;
|
||||
question: string;
|
||||
options: string[];
|
||||
correctAnswer: number;
|
||||
explanation?: string;
|
||||
}
|
||||
|
||||
export interface MixedContent {
|
||||
sections: Array<TextContent | FlashcardContent | QuizContent>;
|
||||
sections: Array<TextContent | FlashcardContent | QuizContent>;
|
||||
}
|
||||
|
||||
export type CardContent = TextContent | FlashcardContent | QuizContent | MixedContent;
|
||||
|
||||
export const cards = pgTable(
|
||||
'cards',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
deckId: uuid('deck_id')
|
||||
.notNull()
|
||||
.references(() => decks.id, { onDelete: 'cascade' }),
|
||||
position: integer('position').notNull().default(0),
|
||||
title: varchar('title', { length: 255 }),
|
||||
content: jsonb('content').notNull().$type<CardContent>(),
|
||||
cardType: cardTypeEnum('card_type').notNull(),
|
||||
aiModel: varchar('ai_model', { length: 100 }),
|
||||
aiPrompt: text('ai_prompt'),
|
||||
version: integer('version').default(1).notNull(),
|
||||
isFavorite: boolean('is_favorite').default(false).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_cards_deck_id').on(table.deckId),
|
||||
index('idx_cards_position').on(table.deckId, table.position),
|
||||
]
|
||||
'cards',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
deckId: uuid('deck_id')
|
||||
.notNull()
|
||||
.references(() => decks.id, { onDelete: 'cascade' }),
|
||||
position: integer('position').notNull().default(0),
|
||||
title: varchar('title', { length: 255 }),
|
||||
content: jsonb('content').notNull().$type<CardContent>(),
|
||||
cardType: cardTypeEnum('card_type').notNull(),
|
||||
aiModel: varchar('ai_model', { length: 100 }),
|
||||
aiPrompt: text('ai_prompt'),
|
||||
version: integer('version').default(1).notNull(),
|
||||
isFavorite: boolean('is_favorite').default(false).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_cards_deck_id').on(table.deckId),
|
||||
index('idx_cards_position').on(table.deckId, table.position),
|
||||
]
|
||||
);
|
||||
|
||||
export const cardsRelations = relations(cards, ({ one, many }) => ({
|
||||
deck: one(decks, {
|
||||
fields: [cards.deckId],
|
||||
references: [decks.id],
|
||||
}),
|
||||
progress: many(cardProgress),
|
||||
deck: one(decks, {
|
||||
fields: [cards.deckId],
|
||||
references: [decks.id],
|
||||
}),
|
||||
progress: many(cardProgress),
|
||||
}));
|
||||
|
||||
export type Card = typeof cards.$inferSelect;
|
||||
|
|
|
|||
|
|
@ -1,34 +1,36 @@
|
|||
import {
|
||||
pgTable,
|
||||
uuid,
|
||||
date,
|
||||
integer,
|
||||
decimal,
|
||||
text,
|
||||
timestamp,
|
||||
index,
|
||||
unique,
|
||||
pgTable,
|
||||
uuid,
|
||||
date,
|
||||
integer,
|
||||
decimal,
|
||||
text,
|
||||
timestamp,
|
||||
index,
|
||||
unique,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
|
||||
export const dailyProgress = pgTable(
|
||||
'daily_progress',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
date: date('date').notNull(),
|
||||
cardsStudied: integer('cards_studied').default(0).notNull(),
|
||||
timeSpentMinutes: integer('time_spent_minutes').default(0).notNull(),
|
||||
accuracyPercentage: decimal('accuracy_percentage', { precision: 5, scale: 2 }).default('0').notNull(),
|
||||
decksStudied: text('decks_studied').array().default([]),
|
||||
sessionsCompleted: integer('sessions_completed').default(0).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_daily_progress_user_id').on(table.userId),
|
||||
index('idx_daily_progress_date').on(table.date),
|
||||
unique('unique_user_date').on(table.userId, table.date),
|
||||
]
|
||||
'daily_progress',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
date: date('date').notNull(),
|
||||
cardsStudied: integer('cards_studied').default(0).notNull(),
|
||||
timeSpentMinutes: integer('time_spent_minutes').default(0).notNull(),
|
||||
accuracyPercentage: decimal('accuracy_percentage', { precision: 5, scale: 2 })
|
||||
.default('0')
|
||||
.notNull(),
|
||||
decksStudied: text('decks_studied').array().default([]),
|
||||
sessionsCompleted: integer('sessions_completed').default(0).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_daily_progress_user_id').on(table.userId),
|
||||
index('idx_daily_progress_date').on(table.date),
|
||||
unique('unique_user_date').on(table.userId, table.date),
|
||||
]
|
||||
);
|
||||
|
||||
export type DailyProgress = typeof dailyProgress.$inferSelect;
|
||||
|
|
|
|||
|
|
@ -1,45 +1,45 @@
|
|||
import {
|
||||
pgTable,
|
||||
uuid,
|
||||
varchar,
|
||||
text,
|
||||
boolean,
|
||||
integer,
|
||||
timestamp,
|
||||
jsonb,
|
||||
index,
|
||||
pgTable,
|
||||
uuid,
|
||||
varchar,
|
||||
text,
|
||||
boolean,
|
||||
integer,
|
||||
timestamp,
|
||||
jsonb,
|
||||
index,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
|
||||
// Template data structure
|
||||
export interface DeckTemplateData {
|
||||
cards: Array<{
|
||||
title?: string;
|
||||
content: Record<string, unknown>;
|
||||
cardType: 'text' | 'flashcard' | 'quiz' | 'mixed';
|
||||
}>;
|
||||
settings?: Record<string, unknown>;
|
||||
tags?: string[];
|
||||
cards: Array<{
|
||||
title?: string;
|
||||
content: Record<string, unknown>;
|
||||
cardType: 'text' | 'flashcard' | 'quiz' | 'mixed';
|
||||
}>;
|
||||
settings?: Record<string, unknown>;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export const deckTemplates = pgTable(
|
||||
'deck_templates',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
title: varchar('title', { length: 255 }).notNull(),
|
||||
description: text('description'),
|
||||
category: varchar('category', { length: 100 }),
|
||||
templateData: jsonb('template_data').notNull().$type<DeckTemplateData>(),
|
||||
isActive: boolean('is_active').default(true).notNull(),
|
||||
isPublic: boolean('is_public').default(true).notNull(),
|
||||
popularity: integer('popularity').default(0).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_deck_templates_category').on(table.category),
|
||||
index('idx_deck_templates_is_active').on(table.isActive),
|
||||
index('idx_deck_templates_popularity').on(table.popularity),
|
||||
]
|
||||
'deck_templates',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
title: varchar('title', { length: 255 }).notNull(),
|
||||
description: text('description'),
|
||||
category: varchar('category', { length: 100 }),
|
||||
templateData: jsonb('template_data').notNull().$type<DeckTemplateData>(),
|
||||
isActive: boolean('is_active').default(true).notNull(),
|
||||
isPublic: boolean('is_public').default(true).notNull(),
|
||||
popularity: integer('popularity').default(0).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_deck_templates_category').on(table.category),
|
||||
index('idx_deck_templates_is_active').on(table.isActive),
|
||||
index('idx_deck_templates_popularity').on(table.popularity),
|
||||
]
|
||||
);
|
||||
|
||||
export type DeckTemplate = typeof deckTemplates.$inferSelect;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import {
|
||||
pgTable,
|
||||
uuid,
|
||||
varchar,
|
||||
text,
|
||||
boolean,
|
||||
timestamp,
|
||||
jsonb,
|
||||
index,
|
||||
pgTable,
|
||||
uuid,
|
||||
varchar,
|
||||
text,
|
||||
boolean,
|
||||
timestamp,
|
||||
jsonb,
|
||||
index,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { relations } from 'drizzle-orm';
|
||||
import { cards } from './cards.js';
|
||||
|
|
@ -14,34 +14,34 @@ import { studySessions } from './studySessions.js';
|
|||
import { aiGenerations } from './aiGenerations.js';
|
||||
|
||||
export const decks = pgTable(
|
||||
'decks',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
title: varchar('title', { length: 255 }).notNull(),
|
||||
description: text('description'),
|
||||
coverImageUrl: text('cover_image_url'),
|
||||
isPublic: boolean('is_public').default(false).notNull(),
|
||||
isFeatured: boolean('is_featured').default(false).notNull(),
|
||||
featuredAt: timestamp('featured_at', { withTimezone: true }),
|
||||
settings: jsonb('settings').default({}).$type<Record<string, unknown>>(),
|
||||
tags: text('tags').array().default([]),
|
||||
metadata: jsonb('metadata').default({}).$type<Record<string, unknown>>(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_decks_user_id').on(table.userId),
|
||||
index('idx_decks_is_public').on(table.isPublic),
|
||||
index('idx_decks_is_featured').on(table.isFeatured),
|
||||
index('idx_decks_updated_at').on(table.updatedAt),
|
||||
]
|
||||
'decks',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id').notNull(),
|
||||
title: varchar('title', { length: 255 }).notNull(),
|
||||
description: text('description'),
|
||||
coverImageUrl: text('cover_image_url'),
|
||||
isPublic: boolean('is_public').default(false).notNull(),
|
||||
isFeatured: boolean('is_featured').default(false).notNull(),
|
||||
featuredAt: timestamp('featured_at', { withTimezone: true }),
|
||||
settings: jsonb('settings').default({}).$type<Record<string, unknown>>(),
|
||||
tags: text('tags').array().default([]),
|
||||
metadata: jsonb('metadata').default({}).$type<Record<string, unknown>>(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_decks_user_id').on(table.userId),
|
||||
index('idx_decks_is_public').on(table.isPublic),
|
||||
index('idx_decks_is_featured').on(table.isFeatured),
|
||||
index('idx_decks_updated_at').on(table.updatedAt),
|
||||
]
|
||||
);
|
||||
|
||||
export const decksRelations = relations(decks, ({ many }) => ({
|
||||
cards: many(cards),
|
||||
studySessions: many(studySessions),
|
||||
aiGenerations: many(aiGenerations),
|
||||
cards: many(cards),
|
||||
studySessions: many(studySessions),
|
||||
aiGenerations: many(aiGenerations),
|
||||
}));
|
||||
|
||||
export type Deck = typeof decks.$inferSelect;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,4 @@
|
|||
import {
|
||||
pgTable,
|
||||
uuid,
|
||||
varchar,
|
||||
integer,
|
||||
timestamp,
|
||||
index,
|
||||
pgEnum,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { pgTable, uuid, varchar, integer, timestamp, index, pgEnum } from 'drizzle-orm/pg-core';
|
||||
import { relations } from 'drizzle-orm';
|
||||
import { decks } from './decks.js';
|
||||
|
||||
|
|
@ -14,33 +6,33 @@ import { decks } from './decks.js';
|
|||
export const studyModeEnum = pgEnum('study_mode', ['all', 'new', 'review', 'favorites', 'random']);
|
||||
|
||||
export const studySessions = pgTable(
|
||||
'study_sessions',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
deckId: uuid('deck_id')
|
||||
.notNull()
|
||||
.references(() => decks.id, { onDelete: 'cascade' }),
|
||||
userId: uuid('user_id').notNull(),
|
||||
mode: studyModeEnum('mode').notNull(),
|
||||
totalCards: integer('total_cards').notNull().default(0),
|
||||
completedCards: integer('completed_cards').notNull().default(0),
|
||||
correctCards: integer('correct_cards').notNull().default(0),
|
||||
startedAt: timestamp('started_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
completedAt: timestamp('completed_at', { withTimezone: true }),
|
||||
timeSpentSeconds: integer('time_spent_seconds').default(0).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_study_sessions_user_id').on(table.userId),
|
||||
index('idx_study_sessions_deck_id').on(table.deckId),
|
||||
index('idx_study_sessions_started_at').on(table.startedAt),
|
||||
]
|
||||
'study_sessions',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
deckId: uuid('deck_id')
|
||||
.notNull()
|
||||
.references(() => decks.id, { onDelete: 'cascade' }),
|
||||
userId: uuid('user_id').notNull(),
|
||||
mode: studyModeEnum('mode').notNull(),
|
||||
totalCards: integer('total_cards').notNull().default(0),
|
||||
completedCards: integer('completed_cards').notNull().default(0),
|
||||
correctCards: integer('correct_cards').notNull().default(0),
|
||||
startedAt: timestamp('started_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
completedAt: timestamp('completed_at', { withTimezone: true }),
|
||||
timeSpentSeconds: integer('time_spent_seconds').default(0).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_study_sessions_user_id').on(table.userId),
|
||||
index('idx_study_sessions_deck_id').on(table.deckId),
|
||||
index('idx_study_sessions_started_at').on(table.startedAt),
|
||||
]
|
||||
);
|
||||
|
||||
export const studySessionsRelations = relations(studySessions, ({ one }) => ({
|
||||
deck: one(decks, {
|
||||
fields: [studySessions.deckId],
|
||||
references: [decks.id],
|
||||
}),
|
||||
deck: one(decks, {
|
||||
fields: [studySessions.deckId],
|
||||
references: [decks.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export type StudySession = typeof studySessions.$inferSelect;
|
||||
|
|
|
|||
|
|
@ -1,32 +1,24 @@
|
|||
import {
|
||||
pgTable,
|
||||
uuid,
|
||||
integer,
|
||||
decimal,
|
||||
date,
|
||||
timestamp,
|
||||
index,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { pgTable, uuid, integer, decimal, date, timestamp, index } from 'drizzle-orm/pg-core';
|
||||
|
||||
export const userStats = pgTable(
|
||||
'user_stats',
|
||||
{
|
||||
userId: uuid('user_id').primaryKey(),
|
||||
totalWins: integer('total_wins').default(0).notNull(),
|
||||
totalSessions: integer('total_sessions').default(0).notNull(),
|
||||
totalCardsStudied: integer('total_cards_studied').default(0).notNull(),
|
||||
totalTimeSeconds: integer('total_time_seconds').default(0).notNull(),
|
||||
averageAccuracy: decimal('average_accuracy', { precision: 5, scale: 2 }).default('0').notNull(),
|
||||
streakDays: integer('streak_days').default(0).notNull(),
|
||||
longestStreak: integer('longest_streak').default(0).notNull(),
|
||||
lastStudyDate: date('last_study_date'),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_user_stats_total_wins').on(table.totalWins),
|
||||
index('idx_user_stats_streak_days').on(table.streakDays),
|
||||
]
|
||||
'user_stats',
|
||||
{
|
||||
userId: uuid('user_id').primaryKey(),
|
||||
totalWins: integer('total_wins').default(0).notNull(),
|
||||
totalSessions: integer('total_sessions').default(0).notNull(),
|
||||
totalCardsStudied: integer('total_cards_studied').default(0).notNull(),
|
||||
totalTimeSeconds: integer('total_time_seconds').default(0).notNull(),
|
||||
averageAccuracy: decimal('average_accuracy', { precision: 5, scale: 2 }).default('0').notNull(),
|
||||
streakDays: integer('streak_days').default(0).notNull(),
|
||||
longestStreak: integer('longest_streak').default(0).notNull(),
|
||||
lastStudyDate: date('last_study_date'),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('idx_user_stats_total_wins').on(table.totalWins),
|
||||
index('idx_user_stats_streak_days').on(table.streakDays),
|
||||
]
|
||||
);
|
||||
|
||||
export type UserStats = typeof userStats.$inferSelect;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue