Skip to content

Commit

Permalink
Create an endpoint to retrieve classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Dlurak committed Mar 29, 2024
1 parent 1b52d17 commit 83ea381
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/constants/documentation.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ElysiaSwaggerConfig } from "@elysiajs/swagger/dist/types";
import { VERSION } from "./general";

/**
Expand Down Expand Up @@ -25,4 +26,4 @@ export const DOCUMENTATION_OPTIONS = {
{ name: "User", description: "User information endpoints" },
],
},
};
} satisfies ElysiaSwaggerConfig<"/swagger">;
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Elysia } from "elysia";
import { accessTokenRouter } from "routes/auth/accessToken";
import { refreshTokenRouter } from "routes/auth/refreshToken";
import { registerRouter } from "routes/auth/register";
import { classRouter } from "routes/classes";
import { schoolRouter } from "routes/school";
import { userInfoRouter } from "routes/user/info";
import { edgedb } from "../dbschema/edgeql-js/imports";
Expand All @@ -14,6 +15,7 @@ export const client = edgedb.createClient();
const app = new Elysia()
.use(swagger(DOCUMENTATION_OPTIONS))
.use(schoolRouter)
.use(classRouter)
.get(
"/",
() => ({
Expand Down
89 changes: 89 additions & 0 deletions src/routes/classes/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import e from "@edgedb";
import {
DATABASE_READ_FAILED,
DATABASE_WRITE_FAILED,
UNAUTHORIZED,
} from "constants/responses";
import Elysia, { t } from "elysia";
import { HttpStatusCode } from "elysia-http-status-code";
import { client } from "index";
import { auth } from "plugins/auth";
import { promiseResult } from "utils/errors";
import { responseBuilder } from "utils/response";
import { z } from "zod";

const classesSchema = z.object({
classes: z
.array(
z.object({
id: z.string(),
}),
)
.max(1)
.min(1),
});

export const createClass = new Elysia()
.use(auth)
.use(HttpStatusCode())
.post(
"/",
async ({ body, auth, set, httpStatus }) => {
if (!auth.isAuthorized) {
set.status = httpStatus.HTTP_401_UNAUTHORIZED;
return UNAUTHORIZED;
}

const classesQuery = e.select(e.School, (s) => ({
filter_single: e.op(s.name, "=", body.school),
classes: (c) => ({
filter_single: e.op(c.name, "=", body.name),
}),
}));
const result = await promiseResult(() => classesQuery.run(client));
if (result.status === "error") {
set.status = httpStatus.HTTP_500_INTERNAL_SERVER_ERROR;
return DATABASE_READ_FAILED;
}
const classNameIsInUse = classesSchema.safeParse(result.data).success;
if (classNameIsInUse) {
set.status = httpStatus.HTTP_400_BAD_REQUEST;
return responseBuilder("error", {
error: `A class with the name ${body.name} already exists in the school ${body.school}`,
});
}

const createClassQuery = e.update(e.School, (s) => ({
filter_single: e.op(s.name, "=", body.school),
set: {
classes: { "+=": e.insert(e.Class, { name: body.name }) },
},
}));
const createResult = await promiseResult(() =>
createClassQuery.run(client),
);
if (createResult.status === "error") {
set.status = httpStatus.HTTP_500_INTERNAL_SERVER_ERROR;
return DATABASE_WRITE_FAILED;
}

set.status = httpStatus.HTTP_201_CREATED;
return responseBuilder("success", {
message: `Successfully created class ${body.name}`,
data: null,
});
},
{
body: t.Object({
name: t.String({
minLength: 1,
description: "The name of the class",
examples: ["10a", "Dolphins", "Mathe LK", "Latein GK"],
}),
school: t.String({
minLength: 1,
description: "The name of the school the class belongs to",
}),
}),
},
);
70 changes: 70 additions & 0 deletions src/routes/classes/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import e from "@edgedb";
import { DATABASE_READ_FAILED } from "constants/responses";
import Elysia, { t } from "elysia";
import { HttpStatusCode } from "elysia-http-status-code";
import { client } from "index";
import { promiseResult } from "utils/errors";
import { replaceDateWithTimestamp } from "utils/objects/transform";
import { responseBuilder } from "utils/response";

export const getClass = new Elysia().use(HttpStatusCode()).get(
"/",
async ({ query, set, httpStatus }) => {
const classesQuery = e.select(e.School, (s) => ({
filter_single: e.op(s.name, "=", query.school),
classes: (c) => ({
limit: query.limit,
offset: query.offset,
filter: query.query
? e.op(c.name, "like", `%${query.query}%`)
: undefined,

name: true,
created: true,
}),
}));
const result = await promiseResult(() => classesQuery.run(client));

if (result.status === "error") {
set.status = httpStatus.HTTP_500_INTERNAL_SERVER_ERROR;
return DATABASE_READ_FAILED;
}
const { data } = result;
if (!data) {
set.status = httpStatus.HTTP_404_NOT_FOUND;
return responseBuilder("error", {
error: `The school ${query.school} doesn't exist`,
});
}

return responseBuilder("success", {
message: "Successfully retrieved classes",
data: data.classes.map(replaceDateWithTimestamp),
});
},
{
query: t.Object({
school: t.String({
minLength: 1,
description: "The name of the school to get the classes from",
}),
limit: t.Numeric({
minimum: 1,
maximum: 100,
default: 20,
description: "The maximum number of classes to retrieve",
}),
offset: t.Numeric({
minimum: 0,
default: 0,
description: "The number of classes to skip",
}),
query: t.Optional(
t.String({
minLength: 1,
description: "A query to search for classes",
}),
),
}),
},
);
7 changes: 7 additions & 0 deletions src/routes/classes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Elysia from "elysia";
import { createClass } from "./create";
import { getClass } from "./get";

export const classRouter = new Elysia({ prefix: "/classes" })
.use(getClass)
.use(createClass);

0 comments on commit 83ea381

Please sign in to comment.