diff --git a/.gitignore b/.gitignore index 5acca89..f32b471 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ node_modules frontend/dist frontend/node_modules .idea +.vim config.json -pizza-collage \ No newline at end of file +pizza-collage diff --git a/frontend/src/ui/StoccaTreRoot/index.tsx b/frontend/src/ui/StoccaTreRoot/index.tsx index 6877810..55261b3 100644 --- a/frontend/src/ui/StoccaTreRoot/index.tsx +++ b/frontend/src/ui/StoccaTreRoot/index.tsx @@ -1,4 +1,4 @@ -import {Capsule, h, Rung } from "@djledda/ladder"; +import { Capsule, h, Rung } from "@djledda/ladder"; import StoccaTreLogo from "@/assets/stocca-tre-logo.svg"; import "./stocca-tre-root.scss"; import IngredientsPage from "../pages/IngredientsPage"; @@ -78,4 +78,4 @@ export default class StoccaTreRoot extends Rung { ; } -} \ No newline at end of file +} diff --git a/frontend/src/ui/pages/IngredientsPage/index.tsx b/frontend/src/ui/pages/IngredientsPage/index.tsx index 7f23662..0b823a1 100644 --- a/frontend/src/ui/pages/IngredientsPage/index.tsx +++ b/frontend/src/ui/pages/IngredientsPage/index.tsx @@ -57,4 +57,4 @@ export default class IngredientsPage extends Rung { this.getIngredients(); return node; } -} \ No newline at end of file +} diff --git a/server/deno.json b/server/deno.json new file mode 100644 index 0000000..2f4c1c2 --- /dev/null +++ b/server/deno.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "allowJs": true, + "lib": ["deno.window"], + "strict": true + }, + "importMap": "./import_map.json", + "fmt": { + "options": { + "useTabs": true, + "lineWidth": 120, + "indentWidth": 4, + "singleQuote": false, + "proseWrap": "preserve" + } + } +} diff --git a/server/resources/ingredient/IngredientCollection.ts b/server/resources/ingredient/IngredientCollection.ts index 12b689f..59d1379 100644 --- a/server/resources/ingredient/IngredientCollection.ts +++ b/server/resources/ingredient/IngredientCollection.ts @@ -1,10 +1,21 @@ -import { Q, StoccaTreDbConn, WithoutId } from "../../database.ts"; -import { IngredientModel } from "./IngredientModel.ts"; +import { z } from "zod"; +import { JSONObject } from "../../JSON.ts"; +import { Q, StoccaTreDbConn } from "../../database.ts"; import { Result, StoccaTreError } from "../../Result.ts"; -const TABLE_NAME = "main.ingredients"; +export const IngredientSchema = z.object({ + id: z.number(), + name: z.string().nonempty(), + displayName: z.string().nonempty(), + displayNameDE: z.string().nonempty(), +}); + +export const IngredientSchemaWithoutId = IngredientSchema.omit({ id: true }); + +export type IngredientModel = z.infer; export default class IngredientCollection { + static readonly TABLE_NAME = "main.ingredients"; private db: StoccaTreDbConn; private mapById: Map = new Map(); @@ -12,8 +23,15 @@ export default class IngredientCollection { this.db = database; } - async addIngredient(ingredient: WithoutId): Promise> { - const [error, result] = > await this.db.query(`INSERT INTO ${ TABLE_NAME } VALUES (DEFAULT, $name, $displayName, $displayNameDE) RETURNING *;`, ingredient); + async addIngredient(ingredient: JSONObject): Promise> { + const parsed = IngredientSchemaWithoutId.safeParse(ingredient); + if (!ingredient.success) { + return [new StoccaTreError("Ingredient definition was malformed.", 400)]; + } + const [error, result] = > await this.db.query( + `INSERT INTO ${ IngredientCollection.TABLE_NAME } VALUES (DEFAULT, $name, $displayName, $displayNameDE) RETURNING *;`, + parsed + ); if (error) { return [error]; } @@ -28,7 +46,7 @@ export default class IngredientCollection { if (found) { return [, found]; } - const [error, result] = > await this.db.query(`SELECT * FROM ${ TABLE_NAME } WHERE id is $id`, { id }); + const [error, result] = > await this.db.query(`SELECT * FROM ${ IngredientCollection.TABLE_NAME } WHERE id is $id`, { id }); if (error) { return [error]; } @@ -37,13 +55,13 @@ export default class IngredientCollection { return [, ingredient]; } - async getAllIngredients(): Promise>> { - const [error, result] = > await this.db.query(`SELECT * FROM ${ TABLE_NAME }`); + async getAllIngredients(): Promise> { + const [error, result] = > await this.db.query(`SELECT * FROM ${ IngredientCollection.TABLE_NAME }`); if (!error) { result.forEach((ingredient: IngredientModel) => this.mapById.set(ingredient.id, ingredient)); } else { return [error]; } - return [, this.mapById.values()]; + return [, Array.from(this.mapById.values())]; } } diff --git a/server/resources/ingredient/IngredientModel.ts b/server/resources/ingredient/IngredientModel.ts index 844b8e3..e69de29 100644 --- a/server/resources/ingredient/IngredientModel.ts +++ b/server/resources/ingredient/IngredientModel.ts @@ -1,14 +0,0 @@ -import { z } from "zod"; - -export const IngredientSchema = z.object({ - id: z.number(), - name: z.string().nonempty(), - displayName: z.string().nonempty(), - displayNameDE: z.string().nonempty(), -}); - -export const IngredientSchemaWithoutId = IngredientSchema.omit({ id: true }); - - -export type IngredientModel = z.infer; - diff --git a/server/resources/ingredient/IngredientResource.ts b/server/resources/ingredient/IngredientResource.ts index f9e97af..26cccf3 100644 --- a/server/resources/ingredient/IngredientResource.ts +++ b/server/resources/ingredient/IngredientResource.ts @@ -1,12 +1,10 @@ import { StoccaTreDbConn } from "../../database.ts"; import IngredientCollection from "./IngredientCollection.ts"; import StoccaTreRequest, { RouteDefinition } from "../../StoccaTreRequest.ts"; -import {Result, StoccaTreError} from "../../Result.ts"; +import { Result, StoccaTreError } from "../../Result.ts"; import { JSONObject } from "../../JSON.ts"; -import { IngredientModel, IngredientSchemaWithoutId } from "./IngredientModel.ts"; export default class IngredientResource { - private dbConnection: StoccaTreDbConn; private collection: IngredientCollection; private routes: Readonly> = { Add: { @@ -20,44 +18,17 @@ export default class IngredientResource { } as const; constructor(dbConnection: StoccaTreDbConn) { - this.dbConnection = dbConnection; this.collection = new IngredientCollection(dbConnection); } async handleRequest(request: StoccaTreRequest): Promise | null> { - let result; - if (request.match(this.routes.Add)) { - result = await this.addIngredient(request); + let result = null; + if (request.match(this.routes.Add) && request.body) { + result = await this.collection.addIngredient(request.body); } if (request.match(this.routes.GetAll)) { - result = await this.allIngredients(request); + result = await this.collection.getAllIngredients(); } - if (result) { - const [error] = result; - if (error) { - return [error.qualified("Could not fulfill ingredient request: ")]; - } else { - return result; - } - } - return null; - } - - private async addIngredient(request: StoccaTreRequest): Promise> { - const ingredient = IngredientSchemaWithoutId.safeParse(request.body); - if (!ingredient.success) { - return [new StoccaTreError("Ingredient definition was malformed.", 400)]; - } - return await this.collection.addIngredient(ingredient.data); - } - - private async allIngredients(request: StoccaTreRequest): Promise> { - const [error, ingredients] = await this.collection.getAllIngredients(); - if (error) { - return [error]; - } - return [, { - ingredients: Array.from(ingredients), - }]; + return result; } } diff --git a/server/resources/ingredient/main.ts b/server/resources/ingredient/main.ts index cb3f697..1dfb19c 100644 --- a/server/resources/ingredient/main.ts +++ b/server/resources/ingredient/main.ts @@ -1,3 +1,2 @@ -export { type IngredientModel } from "./IngredientModel.ts"; -export { default as IngredientCollection } from "./IngredientCollection.ts"; +export { default as IngredientCollection, type IngredientModel } from "./IngredientCollection.ts"; export { default as IngredientResource } from "./IngredientResource.ts";