Skip to content

Commit 7780918

Browse files
committed
Fix new Copilot AI review comments
- Fix mock path mismatch in quizRepo.test.ts: mock now targets correct import path (app/repo/db) - Replace hardcoded table names in adminRepo.ts with proper Drizzle SQL query - Fix TypeScript error by replacing 'any' type with proper interface - All 135 unit tests passing - All linting and TypeScript checks passing - Addresses all remaining Copilot AI review comments
1 parent d0022c7 commit 7780918

File tree

3 files changed

+75
-85
lines changed

3 files changed

+75
-85
lines changed

app/repo/adminRepo.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,20 @@ export interface PaginatedTableData {
1010
}
1111

1212
export const getAllTableNames = async (): Promise<string[]> => {
13-
// For now, return a hardcoded list of known tables
14-
// This avoids the raw SQL issue while maintaining functionality
15-
const knownTables = [
16-
'users',
17-
'quiz',
18-
'userLanguageProgress',
19-
'questionFeedback',
20-
'rateLimits',
21-
'translationCache',
22-
'aiApiUsage',
23-
];
13+
try {
14+
const db = await getDb();
15+
16+
// Use Drizzle's sql template to query SQLite system tables
17+
const result = await db.all(sql`
18+
SELECT name FROM sqlite_master
19+
WHERE type='table' AND name NOT LIKE 'sqlite_%'
20+
`);
2421

25-
return Promise.resolve(knownTables);
22+
return result.map((row: { name: string }) => row.name);
23+
} catch (error) {
24+
console.error('[AdminRepository] Error fetching table names:', error);
25+
throw error;
26+
}
2627
};
2728

2829
const validateTableName = async (tableName: string): Promise<void> => {

app/repo/quizRepo.test.ts

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,9 @@
11
import { describe, it, expect, vi, beforeEach } from 'vitest';
22

33
// Mock the database
4-
vi.mock('app/lib/db', () => ({
4+
vi.mock('app/repo/db', () => ({
55
default: vi.fn(),
66
getDb: vi.fn(),
7-
schema: {
8-
quiz: {
9-
id: 'id',
10-
language: 'language',
11-
level: 'level',
12-
content: 'content',
13-
createdAt: 'createdAt',
14-
questionLanguage: 'questionLanguage',
15-
userId: 'userId',
16-
},
17-
questionFeedback: {
18-
id: 'id',
19-
quizId: 'quizId',
20-
userId: 'userId',
21-
isGood: 'isGood',
22-
submittedAt: 'submittedAt',
23-
},
24-
},
257
}));
268

279
describe('quizRepo', () => {
@@ -32,10 +14,10 @@ describe('quizRepo', () => {
3214
describe('getRandomGoodQuestion', () => {
3315
it('should handle database errors gracefully', async () => {
3416
const { getRandomGoodQuestion } = await import('app/repo/quizRepo');
35-
const { getDb } = await import('app/lib/db');
17+
const getDb = await import('app/repo/db');
3618

3719
// Mock database error
38-
vi.mocked(getDb).mockRejectedValue(new Error('Database error'));
20+
vi.mocked(getDb.default).mockRejectedValue(new Error('Database error'));
3921

4022
const result = await getRandomGoodQuestion('es', 'en', 'A1', 1, null);
4123

@@ -44,7 +26,7 @@ describe('quizRepo', () => {
4426

4527
it('should return undefined when no good questions found', async () => {
4628
const { getRandomGoodQuestion } = await import('app/repo/quizRepo');
47-
const { getDb } = await import('app/lib/db');
29+
const getDb = await import('app/repo/db');
4830

4931
// Mock empty result
5032
const mockDb = {
@@ -55,7 +37,7 @@ describe('quizRepo', () => {
5537
orderBy: vi.fn().mockReturnThis(),
5638
limit: vi.fn().mockResolvedValue([]),
5739
};
58-
vi.mocked(getDb).mockResolvedValue(mockDb as unknown);
40+
vi.mocked(getDb.default).mockResolvedValue(mockDb as unknown);
5941

6042
const result = await getRandomGoodQuestion('es', 'en', 'A1', 1, null);
6143

migrations/0001_initial_schema.sql

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,87 @@
11
-- Initial schema migration for Comprehendo D1 database
22
-- This migration creates all the required tables for the application
3-
43
CREATE TABLE IF NOT EXISTS quiz (
5-
id INTEGER PRIMARY KEY AUTOINCREMENT,
6-
language TEXT NOT NULL,
7-
level TEXT NOT NULL,
8-
content TEXT NOT NULL,
9-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
10-
question_language TEXT,
11-
user_id INTEGER,
12-
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
4+
id INTEGER PRIMARY KEY AUTOINCREMENT,
5+
language TEXT NOT NULL,
6+
level TEXT NOT NULL,
7+
content TEXT NOT NULL,
8+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
9+
question_language TEXT,
10+
user_id INTEGER,
11+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE
12+
SET
13+
NULL
1314
);
1415

1516
CREATE TABLE IF NOT EXISTS users (
16-
id INTEGER PRIMARY KEY AUTOINCREMENT,
17-
provider_id TEXT NOT NULL,
18-
provider TEXT NOT NULL,
19-
name TEXT,
20-
email TEXT,
21-
image TEXT,
22-
first_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
23-
last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
24-
language TEXT DEFAULT 'en',
25-
UNIQUE(provider_id, provider)
17+
id INTEGER PRIMARY KEY AUTOINCREMENT,
18+
provider_id TEXT NOT NULL,
19+
provider TEXT NOT NULL,
20+
name TEXT,
21+
email TEXT,
22+
image TEXT,
23+
first_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
24+
last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
25+
language TEXT DEFAULT 'en',
26+
UNIQUE(provider_id, provider)
2627
);
2728

2829
CREATE TABLE IF NOT EXISTS user_language_progress (
29-
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
30-
language_code TEXT NOT NULL,
31-
cefr_level TEXT NOT NULL DEFAULT 'A1',
32-
correct_streak INTEGER NOT NULL DEFAULT 0,
33-
last_practiced TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
34-
PRIMARY KEY (user_id, language_code)
30+
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
31+
language_code TEXT NOT NULL,
32+
cefr_level TEXT NOT NULL DEFAULT 'A1',
33+
correct_streak INTEGER NOT NULL DEFAULT 0,
34+
last_practiced TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
35+
PRIMARY KEY (user_id, language_code)
3536
);
3637

3738
CREATE TABLE IF NOT EXISTS question_feedback (
38-
id INTEGER PRIMARY KEY AUTOINCREMENT,
39-
quiz_id INTEGER NOT NULL,
40-
user_id INTEGER NOT NULL,
41-
is_good INTEGER NOT NULL,
42-
user_answer TEXT,
43-
is_correct INTEGER,
44-
submitted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
45-
FOREIGN KEY (quiz_id) REFERENCES quiz (id) ON DELETE CASCADE,
46-
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
39+
id INTEGER PRIMARY KEY AUTOINCREMENT,
40+
quiz_id INTEGER NOT NULL,
41+
user_id INTEGER NOT NULL,
42+
is_good INTEGER NOT NULL,
43+
user_answer TEXT,
44+
is_correct INTEGER,
45+
submitted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
46+
FOREIGN KEY (quiz_id) REFERENCES quiz (id) ON DELETE CASCADE,
47+
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
4748
);
4849

4950
CREATE TABLE IF NOT EXISTS rate_limits (
50-
ip_address TEXT PRIMARY KEY,
51-
request_count INTEGER NOT NULL DEFAULT 1,
52-
window_start_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
51+
ip_address TEXT PRIMARY KEY,
52+
request_count INTEGER NOT NULL DEFAULT 1,
53+
window_start_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
5354
);
5455

5556
CREATE TABLE IF NOT EXISTS translation_cache (
56-
id INTEGER PRIMARY KEY AUTOINCREMENT,
57-
source_word TEXT NOT NULL,
58-
source_language TEXT NOT NULL,
59-
target_language TEXT NOT NULL,
60-
translated_text TEXT NOT NULL,
61-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
62-
UNIQUE(source_word, source_language, target_language)
57+
id INTEGER PRIMARY KEY AUTOINCREMENT,
58+
source_word TEXT NOT NULL,
59+
source_language TEXT NOT NULL,
60+
target_language TEXT NOT NULL,
61+
translated_text TEXT NOT NULL,
62+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
63+
UNIQUE(source_word, source_language, target_language)
6364
);
6465

6566
CREATE TABLE IF NOT EXISTS ai_api_usage (
66-
id INTEGER PRIMARY KEY AUTOINCREMENT,
67-
date TEXT NOT NULL,
68-
request_count INTEGER NOT NULL DEFAULT 0,
69-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
70-
UNIQUE(date)
67+
id INTEGER PRIMARY KEY AUTOINCREMENT,
68+
date TEXT NOT NULL,
69+
request_count INTEGER NOT NULL DEFAULT 0,
70+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
71+
UNIQUE(date)
7172
);
7273

7374
-- Create indexes for better performance
7475
CREATE INDEX IF NOT EXISTS idx_quiz_created_at ON quiz(created_at DESC);
76+
7577
CREATE INDEX IF NOT EXISTS idx_users_last_login ON users(last_login DESC);
78+
7679
CREATE INDEX IF NOT EXISTS idx_user_language_progress_last_practiced ON user_language_progress(last_practiced DESC);
80+
7781
CREATE INDEX IF NOT EXISTS idx_question_feedback_quiz_id ON question_feedback (quiz_id);
82+
7883
CREATE INDEX IF NOT EXISTS idx_question_feedback_user_id ON question_feedback (user_id);
84+
7985
CREATE INDEX IF NOT EXISTS idx_translation_cache_lookup ON translation_cache(source_word, source_language, target_language);
80-
CREATE INDEX IF NOT EXISTS idx_ai_api_usage_date ON ai_api_usage(date);
86+
87+
CREATE INDEX IF NOT EXISTS idx_ai_api_usage_date ON ai_api_usage(date);

0 commit comments

Comments
 (0)