Skip to content

Commit 79ee998

Browse files
fix: make a more economic solution with a single container
1 parent 2691976 commit 79ee998

File tree

5 files changed

+94
-64
lines changed

5 files changed

+94
-64
lines changed

lib/graphql/cosmos-client.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,25 @@ export const getDatabase = () => {
99
return client.database(process.env.AZURE_COSMOSDB_DATABASE!);
1010
};
1111

12-
export const getContainer = async (containerName: string) => {
12+
export const getQuestionsContainer = async () => {
1313
const database = getDatabase();
1414

1515
// Try to create container if it doesn't exist
1616
try {
1717
const { container } = await database.containers.createIfNotExists({
18-
id: containerName,
18+
id: "questions",
1919
partitionKey: {
20-
paths: ["/id"],
20+
paths: ["/examId"],
2121
},
2222
});
2323
return container;
2424
} catch (error: any) {
2525
// If container creation fails, try to get the existing container
2626
if (error.code === 409) {
2727
console.log(
28-
`Container ${containerName} already exists, using existing container`,
28+
`Container questions already exists, using existing container`,
2929
);
30-
return database.container(containerName);
30+
return database.container("questions");
3131
} else {
3232
console.error("Error creating container:", error);
3333
throw error;

lib/graphql/questionsDataSource.tsx

Lines changed: 85 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Container } from "@azure/cosmos";
22
import { fetchQuestions } from "./repoQuestions";
3-
import { getContainer } from "./cosmos-client";
3+
import { getQuestionsContainer } from "./cosmos-client";
44

55
export const QuestionsDataSource = (container: Container) => {
66
return {
@@ -68,101 +68,137 @@ export const RepoQuestionsDataSource = (container: any) => {
6868
};
6969
};
7070

71+
// Helper function to extract exam ID from URL
72+
const extractExamId = (link: string): string => {
73+
const segments = link.split("/");
74+
return segments[segments.length - 3].replace(/-/g, "_").toLowerCase();
75+
};
76+
7177
export const CombinedQuestionsDataSource = () => {
7278
return {
7379
async getQuestion(id: string, link: string) {
7480
try {
75-
// Extract exam name from URL and create a safe container name
76-
const segments = link.split("/");
77-
const examName = segments[segments.length - 3]
78-
.replace(/-/g, "_")
79-
.toLowerCase();
80-
const examContainer = await getContainer(examName);
81-
82-
// Try GitHub first
81+
const examId = extractExamId(link);
82+
const questionsContainer = await getQuestionsContainer();
83+
84+
// Try Cosmos DB first (most efficient)
85+
const querySpec = {
86+
query: "SELECT * FROM c WHERE c.id = @id AND c.examId = @examId",
87+
parameters: [
88+
{ name: "@id", value: id },
89+
{ name: "@examId", value: examId },
90+
],
91+
};
92+
const { resources: items } = await questionsContainer.items
93+
.query(querySpec)
94+
.fetchAll();
95+
96+
if (items.length > 0) {
97+
return items[0];
98+
}
99+
100+
// Fallback to GitHub if not found in database
83101
const questions = await fetchQuestions(link);
84102
if (questions) {
85103
const question = questions.find((q: any) => q.id === id);
86104
if (question) {
87-
// Upload to exam-specific container
105+
// Add examId to the question document and upload to database
106+
const questionWithExamId = {
107+
...question,
108+
examId: examId,
109+
};
110+
88111
try {
89-
await examContainer.items.upsert(question);
112+
await questionsContainer.items.upsert(questionWithExamId);
90113
} catch (err) {
91114
console.warn("Failed to upload question to Cosmos DB:", err);
92115
}
93116
return question;
94117
}
95118
}
96119

97-
// Fallback to Cosmos DB
98-
const querySpec = {
99-
query: "SELECT * FROM c WHERE c.id = @id",
100-
parameters: [{ name: "@id", value: id }],
101-
};
102-
const { resources: items } = await examContainer.items
103-
.query(querySpec)
104-
.fetchAll();
105-
return items[0];
120+
return null;
106121
} catch (err) {
107122
throw new Error("Error fetching question: " + err);
108123
}
109124
},
110125

111126
async getQuestions(link: string) {
112127
try {
113-
// Extract exam name from URL and create a safe container name
114-
const segments = link.split("/");
115-
const examName = segments[segments.length - 3]
116-
.replace(/-/g, "_")
117-
.toLowerCase();
118-
const examContainer = await getContainer(examName);
119-
120-
// Try GitHub first
128+
const examId = extractExamId(link);
129+
const questionsContainer = await getQuestionsContainer();
130+
131+
// Try Cosmos DB first
132+
const querySpec = {
133+
query: "SELECT VALUE COUNT(c.id) FROM c WHERE c.examId = @examId",
134+
parameters: [{ name: "@examId", value: examId }],
135+
};
136+
const { resources: items } = await questionsContainer.items
137+
.query(querySpec)
138+
.fetchAll();
139+
140+
if (items[0] > 0) {
141+
return { count: items[0] };
142+
}
143+
144+
// Fallback to GitHub if no questions found in database
121145
const questions = await fetchQuestions(link);
122146
if (questions) {
123-
// Upload all questions to exam-specific container
147+
// Upload all questions to database (only if they don't exist)
124148
try {
125149
for (const question of questions) {
126-
await examContainer.items.upsert(question);
150+
const questionWithExamId = {
151+
...question,
152+
examId: examId,
153+
};
154+
await questionsContainer.items.upsert(questionWithExamId);
127155
}
128156
} catch (err) {
129157
console.warn("Failed to upload questions to Cosmos DB:", err);
130158
}
131159
return { count: questions.length };
132160
}
133161

134-
// Fallback to Cosmos DB
135-
const querySpec = {
136-
query: "SELECT VALUE COUNT(c.id) FROM c",
137-
};
138-
const { resources: items } = await examContainer.items
139-
.query(querySpec)
140-
.fetchAll();
141-
return { count: items[0] };
162+
return { count: 0 };
142163
} catch (err) {
143164
throw new Error("Error fetching questions: " + err);
144165
}
145166
},
146167

147168
async getRandomQuestions(range: number, link: string) {
148169
try {
149-
// Extract exam name from URL and create a safe container name
150-
const segments = link.split("/");
151-
const examName = segments[segments.length - 3]
152-
.replace(/-/g, "_")
153-
.toLowerCase();
154-
const examContainer = await getContainer(examName);
155-
156-
// Try GitHub first
170+
const examId = extractExamId(link);
171+
const questionsContainer = await getQuestionsContainer();
172+
173+
// Try Cosmos DB first
174+
const querySpec = {
175+
query: "SELECT * FROM c WHERE c.examId = @examId",
176+
parameters: [{ name: "@examId", value: examId }],
177+
};
178+
const { resources: items } = await questionsContainer.items
179+
.query(querySpec)
180+
.fetchAll();
181+
182+
if (items.length > 0) {
183+
// Questions exist in database, return random selection
184+
const shuffled = [...items].sort(() => 0.5 - Math.random());
185+
return shuffled.slice(0, range);
186+
}
187+
188+
// Fallback to GitHub if no questions found in database
157189
const questions = await fetchQuestions(link);
158190
if (questions) {
159191
const shuffled = [...questions].sort(() => 0.5 - Math.random());
160192
const selected = shuffled.slice(0, range);
161193

162-
// Upload selected questions to exam-specific container
194+
// Upload selected questions to database (only if they don't exist)
163195
try {
164196
for (const question of selected) {
165-
await examContainer.items.upsert(question);
197+
const questionWithExamId = {
198+
...question,
199+
examId: examId,
200+
};
201+
await questionsContainer.items.upsert(questionWithExamId);
166202
}
167203
} catch (err) {
168204
console.warn("Failed to upload questions to Cosmos DB:", err);
@@ -171,15 +207,7 @@ export const CombinedQuestionsDataSource = () => {
171207
return selected;
172208
}
173209

174-
// Fallback to Cosmos DB
175-
const querySpec = {
176-
query: "SELECT * FROM c",
177-
};
178-
const { resources: items } = await examContainer.items
179-
.query(querySpec)
180-
.fetchAll();
181-
const shuffled = [...items].sort(() => 0.5 - Math.random());
182-
return shuffled.slice(0, range);
210+
return [];
183211
} catch (err) {
184212
throw new Error("Error fetching random questions: " + err);
185213
}

lib/graphql/schemas.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const typeDefs = gql`
1414
question: String
1515
options: [Option]
1616
images: [Images]
17+
examId: String
1718
}
1819
type Questions {
1920
count: Int

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"postcss": "^8.4.21",
6161
"prettier": "^3.0.3",
6262
"tailwindcss": "^3.2.7",
63-
"ts-jest": "^29.1.1"
63+
"ts-jest": "^29.1.1",
64+
"tsx": "^4.7.0"
6465
}
6566
}

public/sw.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)