refactor: swapped 'topic' with 'lesson' semantically
This commit is contained in:
@@ -4,15 +4,27 @@ import { api } from "~/trpc/server";
|
||||
export default async function Home() {
|
||||
const self = await api.user.getSelf();
|
||||
if (!self?.activeCourseId) redirect("/courses");
|
||||
|
||||
const activeCourse = await api.course.getCourse({
|
||||
courseId: self.activeCourseId,
|
||||
includeTopics: true,
|
||||
});
|
||||
if (!activeCourse) redirect("/courses");
|
||||
|
||||
return (
|
||||
<main className="mx-auto max-w-2xl">
|
||||
<h1 className="text-2xl font-bold">Home</h1>
|
||||
<p>Active Course:</p>
|
||||
<pre>{JSON.stringify(activeCourse, undefined, 2)}</pre>
|
||||
<h2 className="text-lg font-bold">Topics</h2>
|
||||
<ol className="list-inside list-decimal">
|
||||
{activeCourse.topics.map((topic) => (
|
||||
<li>
|
||||
<p className="inline">{topic.name}</p>
|
||||
<p className="ml-5 text-sm">{topic.description}</p>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,11 +51,6 @@ export default function RootLayout({
|
||||
Courses
|
||||
</a>
|
||||
</li>
|
||||
<li className="">
|
||||
<a className="hover:underline" href="/lesson">
|
||||
Lesson
|
||||
</a>
|
||||
</li>
|
||||
<li className="">
|
||||
<a className="hover:underline" href="/practice">
|
||||
Practice
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import Link from "next/link";
|
||||
|
||||
export default async function Landing() {
|
||||
return (
|
||||
<main className="mx-auto max-w-2xl">
|
||||
<h1 className="text-2xl font-bold">Landing</h1>
|
||||
<Link href="/home" className="hover:underline">
|
||||
Get started
|
||||
</Link>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ import { createTRPCRouter } from "~/server/api/trpc";
|
||||
export const appRouter = createTRPCRouter({
|
||||
user: userRouter,
|
||||
course: courseRouter,
|
||||
lesson: lessonRouter,
|
||||
topic: topicRouter,
|
||||
lesson: lessonRouter,
|
||||
exercise: exerciseRouter,
|
||||
});
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ export const courseRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
courseId: z.number(),
|
||||
includeLessons: z.boolean().optional().default(false),
|
||||
includeTopics: z.boolean().optional().default(false),
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
const lessons = input.includeLessons ? true : undefined;
|
||||
const topics = input.includeTopics ? true : undefined;
|
||||
return await ctx.db.query.courses.findFirst({
|
||||
where: eq(courses.courseId, input.courseId),
|
||||
with: { lessons },
|
||||
with: { topics },
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
import { exercises, topicToExercise } from "~/server/db/schema";
|
||||
import { exercises, lessonToExercise } from "~/server/db/schema";
|
||||
|
||||
export const exerciseRouter = createTRPCRouter({
|
||||
getAllTopicExercises: protectedProcedure
|
||||
.input(z.object({ topicId: z.number() }))
|
||||
getAllLessonExercises: protectedProcedure
|
||||
.input(z.object({ lessonId: z.number() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
return await ctx.db.query.topicToExercise.findMany({
|
||||
where: eq(topicToExercise.topicId, input.topicId),
|
||||
return await ctx.db.query.lessonToExercise.findMany({
|
||||
where: eq(lessonToExercise.lessonId, input.lessonId),
|
||||
with: { exercise: true },
|
||||
});
|
||||
}),
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
import { lessons } from "~/server/db/schema";
|
||||
import { lessons, topicToLesson } from "~/server/db/schema";
|
||||
|
||||
export const lessonRouter = createTRPCRouter({
|
||||
getAllCourseLessons: protectedProcedure
|
||||
.input(z.object({ courseId: z.number() }))
|
||||
getAllTopicLessons: protectedProcedure
|
||||
.input(z.object({ topicId: z.number() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
return await ctx.db.query.lessons.findMany({
|
||||
where: eq(lessons.courseId, input.courseId),
|
||||
return await ctx.db.query.topicToLesson.findMany({
|
||||
where: eq(topicToLesson.topicId, input.topicId),
|
||||
with: { lesson: true },
|
||||
});
|
||||
}),
|
||||
getLesson: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
lessonId: z.number(),
|
||||
includeTopics: z.boolean().optional().default(false),
|
||||
includeExercises: z.boolean().optional().default(false),
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
const topics = input.includeTopics ? true : undefined;
|
||||
const exercises = input.includeExercises ? true : undefined;
|
||||
return await ctx.db.query.lessons.findFirst({
|
||||
where: eq(lessons.lessonId, input.lessonId),
|
||||
with: { topics },
|
||||
with: { exercises },
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
import { lessonToTopic, topics } from "~/server/db/schema";
|
||||
import { topics } from "~/server/db/schema";
|
||||
|
||||
export const topicRouter = createTRPCRouter({
|
||||
getAllLessonTopics: protectedProcedure
|
||||
.input(z.object({ lessonId: z.number() }))
|
||||
getAllCourseTopics: protectedProcedure
|
||||
.input(z.object({ courseId: z.number() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
return await ctx.db.query.lessonToTopic.findMany({
|
||||
where: eq(lessonToTopic.lessonId, input.lessonId),
|
||||
with: { topic: true },
|
||||
return await ctx.db.query.topics.findMany({
|
||||
where: eq(topics.courseId, input.courseId),
|
||||
});
|
||||
}),
|
||||
getTopic: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
topicId: z.number(),
|
||||
includeExercises: z.boolean().optional().default(false),
|
||||
includeLessons: z.boolean().optional().default(false),
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
const exercises = input.includeExercises ? true : undefined;
|
||||
const lessons = input.includeLessons ? true : undefined;
|
||||
return await ctx.db.query.topics.findFirst({
|
||||
where: eq(topics.topicId, input.topicId),
|
||||
with: { exercises },
|
||||
// with: { exercises: { with: { exercise: { with: { topics: true } } } } },
|
||||
with: { lessons },
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -32,16 +32,16 @@ export const courses = mysqlTable("course", {
|
||||
guide: json("guide"),
|
||||
});
|
||||
|
||||
export const lessons = mysqlTable("lesson", {
|
||||
lessonId: serial("lesson_id").primaryKey(),
|
||||
export const topics = mysqlTable("topic", {
|
||||
topicId: serial("topic_id").primaryKey(),
|
||||
courseId: bigint("course_id", { mode: "number" }).notNull(),
|
||||
name: varchar("name", { length: 255 }),
|
||||
description: text("description"),
|
||||
guide: json("guide"),
|
||||
});
|
||||
|
||||
export const topics = mysqlTable("topic", {
|
||||
topicId: serial("topic_id").primaryKey(),
|
||||
export const lessons = mysqlTable("lesson", {
|
||||
lessonId: serial("lesson_id").primaryKey(),
|
||||
name: varchar("name", { length: 255 }),
|
||||
description: text("description"),
|
||||
guide: json("guide"),
|
||||
@@ -63,8 +63,8 @@ export const courseHistory = mysqlTable("course_history", {
|
||||
courseHistoryId: serial("course_history_id").primaryKey(),
|
||||
userId: varchar("user_id", { length: 255 }),
|
||||
courseId: bigint("course_id", { mode: "number" }).notNull(),
|
||||
lessonId: bigint("lesson_id", { mode: "number" }).notNull(),
|
||||
topicId: bigint("topic_id", { mode: "number" }).notNull(),
|
||||
lessonId: bigint("lesson_id", { mode: "number" }).notNull(),
|
||||
exerciseId: bigint("exercise_id", { mode: "number" }).notNull(),
|
||||
completionTime: timestamp("completion_time", { mode: "date" }),
|
||||
isCorrect: boolean("is_correct"),
|
||||
@@ -72,22 +72,22 @@ export const courseHistory = mysqlTable("course_history", {
|
||||
|
||||
// === Junctions =========================================================
|
||||
|
||||
export const lessonToTopic = mysqlTable(
|
||||
"lesson_to_topic",
|
||||
export const topicToLesson = mysqlTable(
|
||||
"topic_to_lesson",
|
||||
{
|
||||
lessonId: bigint("lesson_id", { mode: "number" }).notNull(),
|
||||
topicId: bigint("topic_id", { mode: "number" }).notNull(),
|
||||
lessonId: bigint("lesson_id", { mode: "number" }).notNull(),
|
||||
},
|
||||
(t) => ({ pk: primaryKey(t.topicId, t.lessonId) }),
|
||||
);
|
||||
|
||||
export const topicToExercise = mysqlTable(
|
||||
"topic_to_exercise",
|
||||
export const lessonToExercise = mysqlTable(
|
||||
"lesson_to_exercise",
|
||||
{
|
||||
topicId: bigint("topic_id", { mode: "number" }).notNull(),
|
||||
lessonId: bigint("lesson_id", { mode: "number" }).notNull(),
|
||||
exerciseId: bigint("exercise_id", { mode: "number" }).notNull(),
|
||||
},
|
||||
(t) => ({ pk: primaryKey(t.topicId, t.exerciseId) }),
|
||||
(t) => ({ pk: primaryKey(t.lessonId, t.exerciseId) }),
|
||||
);
|
||||
|
||||
// === Relations =========================================================
|
||||
@@ -101,50 +101,50 @@ export const userRelations = relations(users, ({ one, many }) => ({
|
||||
}));
|
||||
|
||||
export const courseRelations = relations(courses, ({ many }) => ({
|
||||
lessons: many(lessons),
|
||||
topics: many(topics),
|
||||
courseHistory: many(courseHistory),
|
||||
}));
|
||||
|
||||
export const lessonRelations = relations(lessons, ({ one, many }) => ({
|
||||
export const topicRelations = relations(topics, ({ one, many }) => ({
|
||||
course: one(courses, {
|
||||
fields: [lessons.courseId],
|
||||
fields: [topics.courseId],
|
||||
references: [courses.courseId],
|
||||
}),
|
||||
topics: many(lessonToTopic),
|
||||
lessons: many(topicToLesson),
|
||||
courseHistory: many(courseHistory),
|
||||
}));
|
||||
|
||||
export const topicRelations = relations(topics, ({ many }) => ({
|
||||
lessons: many(lessonToTopic),
|
||||
exercises: many(topicToExercise),
|
||||
export const lessonRelations = relations(lessons, ({ many }) => ({
|
||||
topics: many(topicToLesson),
|
||||
exercises: many(lessonToExercise),
|
||||
courseHistory: many(courseHistory),
|
||||
}));
|
||||
|
||||
export const exerciseRelations = relations(exercises, ({ many }) => ({
|
||||
topics: many(topicToExercise),
|
||||
lessons: many(lessonToExercise),
|
||||
courseHistory: many(courseHistory),
|
||||
}));
|
||||
|
||||
export const lessonToTopicRelations = relations(lessonToTopic, ({ one }) => ({
|
||||
export const topicToLessonRelations = relations(topicToLesson, ({ one }) => ({
|
||||
lesson: one(lessons, {
|
||||
fields: [lessonToTopic.lessonId],
|
||||
fields: [topicToLesson.lessonId],
|
||||
references: [lessons.lessonId],
|
||||
}),
|
||||
topic: one(topics, {
|
||||
fields: [lessonToTopic.topicId],
|
||||
fields: [topicToLesson.topicId],
|
||||
references: [topics.topicId],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const topicToExerciseRelations = relations(
|
||||
topicToExercise,
|
||||
export const lessonToExerciseRelations = relations(
|
||||
lessonToExercise,
|
||||
({ one }) => ({
|
||||
topic: one(topics, {
|
||||
fields: [topicToExercise.topicId],
|
||||
references: [topics.topicId],
|
||||
lesson: one(lessons, {
|
||||
fields: [lessonToExercise.lessonId],
|
||||
references: [lessons.lessonId],
|
||||
}),
|
||||
exercise: one(exercises, {
|
||||
fields: [topicToExercise.exerciseId],
|
||||
fields: [lessonToExercise.exerciseId],
|
||||
references: [exercises.exerciseId],
|
||||
}),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user