From 84214c42bea9dda7f2ee947915c56ca1efeac1b3 Mon Sep 17 00:00:00 2001 From: Tara Aqeel Date: Tue, 6 Oct 2026 18:37:40 +0200 Subject: [PATCH 1/4] Jeg har lagt til GraphQL-typer og mutasjoner for handleliste --- backend/src/index.ts | 176 +++++++++++++++++++++++++++++++++++++++++-- package-lock.json | 6 ++ 2 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 package-lock.json diff --git a/backend/src/index.ts b/backend/src/index.ts index d2f2e4c..95bd2d6 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,22 +1,188 @@ import 'dotenv/config'; import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; +import { pool } from './db.js'; -// Midlertidig skjema for å sjekke at serveren kjører. -// Erstattes av det ekte skjemaet når databasen er på plass. const typeDefs = `#graphql + type Category { + id: ID! + parentId: ID + name: String! + } + + type Price { + storeCode: String! + price: Float! + unitPrice: Float + url: String + } + + type Product { + ean: String! + name: String! + brand: String + imageUrl: String + categoryId: ID + category: Category + prices: [Price!]! + } + type Query { - hello: String! + products( + search: String + category: ID + limit: Int = 20 + offset: Int = 0 + ): [Product!]! + + product(ean: String!): Product + + categories: [Category!]! + + shoppingList(id: ID!): ShoppingList + } + + type ShoppingListItem { + id: ID! + ean: String! + quantity: Int! + note: String + checked: Boolean! + } + + type ShoppingList { + id: ID! + name: String! + status: String! + inUse: Boolean! + items: [ShoppingListItem!]! + } + + type Mutation { + createShoppingList(name: String!): ShoppingList! + + addItemToList( + listId: ID! + ean: String! + quantity: Int = 1 + ): ShoppingList! } `; const resolvers = { Query: { - hello: () => 'Hei fra Handlelappen-backend!', + categories: async () => { + const result = await pool.query(` + SELECT + id, + parent_id AS "parentId", + name + FROM categories + ORDER BY name + `); + + return result.rows; + }, + + product: async (_parent: unknown, args: { ean: string }) => { + const result = await pool.query( + ` + SELECT + ean, + name, + brand, + image_url AS "imageUrl", + category_id AS "categoryId" + FROM products + WHERE ean = $1 + `, + [args.ean], + ); + + return result.rows[0] ?? null; + }, + + products: async ( + _parent: unknown, + args: { + search?: string; + category?: string; + limit?: number; + offset?: number; + }, + ) => { + const search = args.search ?? null; + const category = args.category ?? null; + const limit = args.limit ?? 20; + const offset = args.offset ?? 0; + + const result = await pool.query( + ` + SELECT + ean, + name, + brand, + image_url AS "imageUrl", + category_id AS "categoryId" + FROM products + WHERE + ($1::text IS NULL OR name ILIKE '%' || $1 || '%') + AND + ($2::integer IS NULL OR category_id = $2) + ORDER BY name + LIMIT $3 + OFFSET $4 + `, + [search, category, limit, offset], + ); + + return result.rows; + }, + }, + + Product: { + category: async (product: { categoryId?: number | null }) => { + if (!product.categoryId) { + return null; + } + + const result = await pool.query( + ` + SELECT + id, + parent_id AS "parentId", + name + FROM categories + WHERE id = $1 + `, + [product.categoryId], + ); + + return result.rows[0] ?? null; + }, + + prices: async (product: { ean: string }) => { + const result = await pool.query( + ` + SELECT + store_code AS "storeCode", + price, + unit_price AS "unitPrice", + url + FROM prices + WHERE ean = $1 + ORDER BY price + `, + [product.ean], + ); + + return result.rows; + }, }, }; -const server = new ApolloServer({ typeDefs, resolvers }); + +const server = new ApolloServer({ typeDefs, resolvers, introspection: true, }); // Port 3001 er kravet i oppgaven, men kan overstyres i .env const port = Number(process.env.PORT ?? 3001); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..749f7fc --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "T27-Project-2", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From 1f0fe3755efc2d941daca3ee3f3b18ea6f71d268 Mon Sep 17 00:00:00 2001 From: Tara Aqeel Date: Tue, 6 Oct 2026 18:45:30 +0200 Subject: [PATCH 2/4] =?UTF-8?q?Mutatiion=20for=20handlelist=20s=C3=A5=20ha?= =?UTF-8?q?ndleliste=20faktisk=20blir=20laget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/index.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/backend/src/index.ts b/backend/src/index.ts index 95bd2d6..3b4665e 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -102,6 +102,28 @@ const resolvers = { return result.rows[0] ?? null; }, + Mutation: { + createShoppingList: async ( + _parent: unknown, + args: { name: string }, + ) => { + const result = await pool.query( + ` + INSERT INTO shopping_lists (owner_id, name) + VALUES ($1, $2) + RETURNING + id, + name, + status, + in_use AS "inUse" + `, + ['anonymous', args.name], + ); + + return result.rows[0]; + }, + }, + products: async ( _parent: unknown, args: { @@ -182,6 +204,8 @@ const resolvers = { }; + + const server = new ApolloServer({ typeDefs, resolvers, introspection: true, }); // Port 3001 er kravet i oppgaven, men kan overstyres i .env From c3a31d973180b1cbb737f6112b31c031ecc1ee24 Mon Sep 17 00:00:00 2001 From: Tara Aqeel Date: Tue, 6 Oct 2026 18:53:34 +0200 Subject: [PATCH 3/4] Rettet opp i feil ved plassering av mutation-kode --- backend/src/index.ts | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/backend/src/index.ts b/backend/src/index.ts index 3b4665e..77dbe84 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -102,27 +102,6 @@ const resolvers = { return result.rows[0] ?? null; }, - Mutation: { - createShoppingList: async ( - _parent: unknown, - args: { name: string }, - ) => { - const result = await pool.query( - ` - INSERT INTO shopping_lists (owner_id, name) - VALUES ($1, $2) - RETURNING - id, - name, - status, - in_use AS "inUse" - `, - ['anonymous', args.name], - ); - - return result.rows[0]; - }, - }, products: async ( _parent: unknown, @@ -162,6 +141,28 @@ const resolvers = { }, }, + Mutation: { + createShoppingList: async ( + _parent: unknown, + args: { name: string }, + ) => { + const result = await pool.query( + ` + INSERT INTO shopping_lists (owner_id, name) + VALUES ($1, $2) + RETURNING + id, + name, + status, + in_use AS "inUse" + `, + ['anonymous', args.name], + ); + + return result.rows[0]; + }, + }, + Product: { category: async (product: { categoryId?: number | null }) => { if (!product.categoryId) { From 99927e18529c5cc922be6e20c48b77d27314df39 Mon Sep 17 00:00:00 2001 From: Tara Aqeel Date: Thu, 8 Oct 2026 13:06:22 +0200 Subject: [PATCH 4/4] finpussing av kode --- backend/src/index.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/backend/src/index.ts b/backend/src/index.ts index 2917ae4..e6972be 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -139,6 +139,26 @@ const resolvers = { return result.rows; }, + + shoppingList: async ( + _parent: unknown, + args: { id: string }, + ) => { + const result = await pool.query( + ` + SELECT + id, + name, + status, + in_use AS "inUse" + FROM shopping_lists + WHERE id = $1 + `, + [args.id], + ); + + return result.rows[0] ?? null; + }, }, Mutation: {