From b633ef7b70d4cb1359d9c6273cf23cf879b8aeb2 Mon Sep 17 00:00:00 2001 From: Eman Date: Fri, 1 Mar 2024 17:33:37 +0200 Subject: [PATCH 1/9] chore: draft PR --- apps/api/src/suppliers/router.ts | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 apps/api/src/suppliers/router.ts diff --git a/apps/api/src/suppliers/router.ts b/apps/api/src/suppliers/router.ts new file mode 100644 index 00000000..c8f2d2ea --- /dev/null +++ b/apps/api/src/suppliers/router.ts @@ -0,0 +1,3 @@ +import { NextFunction, Response, Router, Request } from "express"; +import { logRequest } from "../middleware/requestLogger"; +import { validate } from "../middleware/zodValidate"; \ No newline at end of file From 7dbda4b5b3c2d816eb36a3497d4e19e77e1ed43a Mon Sep 17 00:00:00 2001 From: Eman Date: Tue, 19 Mar 2024 18:34:21 +0200 Subject: [PATCH 2/9] feat: update orders --- apps/api/src/matcher/setGeofence.ts | 6 +++++ apps/api/src/orders/operations/initOrder.ts | 23 +++++++--------- apps/api/src/orders/operations/updateOrder.ts | 25 ++++++++++++++++++ apps/api/src/orders/router.ts | 26 +++++++++++++++++-- apps/api/src/orders/worker.ts | 2 ++ apps/api/src/queue.ts | 2 +- apps/maps/src/Directions/index.ts | 1 + apps/maps/src/Geolocation/index.ts | 6 +++-- apps/maps/src/Places/index.ts | 9 ++++--- packages/lib/graphql/mutations/orders.ts | 10 +++++++ packages/lib/hooks/businesses.tsx | 2 -- 11 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 apps/api/src/matcher/setGeofence.ts create mode 100644 apps/api/src/orders/operations/updateOrder.ts diff --git a/apps/api/src/matcher/setGeofence.ts b/apps/api/src/matcher/setGeofence.ts new file mode 100644 index 00000000..bade35e4 --- /dev/null +++ b/apps/api/src/matcher/setGeofence.ts @@ -0,0 +1,6 @@ +import { client } from "../lib/graphql-request"; + + +export const setGeofence = async (lat, lng) => { + // const coords = client.request(); +} \ No newline at end of file diff --git a/apps/api/src/orders/operations/initOrder.ts b/apps/api/src/orders/operations/initOrder.ts index bebda8ae..a5608991 100644 --- a/apps/api/src/orders/operations/initOrder.ts +++ b/apps/api/src/orders/operations/initOrder.ts @@ -9,24 +9,19 @@ export const orderSchema = z .refine((value) => value > new Date()) .optional(), customerId: z.any(), - destination: z.string(), origin: z.string(), processedBy: z.string().optional(), - }) - .refine( - ({ destination, origin }) => { - return origin !== destination; - }, - { message: "Destination is the same as origin" } - ); + orderItems: z.any() + }); export type OrderAttributes = z.infer; export const initOrder = async (order: OrderAttributes): Promise => { - const data = await client.request(INSERT_NEW_ORDER, { - object: { - ...order, - }, - }); - return Promise.resolve(data); + // const data = await client.request(INSERT_NEW_ORDER, { + // object: { + // ...order, + // }, + // }); + // return Promise.resolve(data); + return Promise.resolve(order); }; diff --git a/apps/api/src/orders/operations/updateOrder.ts b/apps/api/src/orders/operations/updateOrder.ts new file mode 100644 index 00000000..6e0303a3 --- /dev/null +++ b/apps/api/src/orders/operations/updateOrder.ts @@ -0,0 +1,25 @@ +import { UPDATE_ORDER_STATUS, FETCH_ORDER_BY_PK } from "@sahil/lib/graphql"; +import { z } from "zod"; +import { client } from "../../lib/graphql-request"; + +export const updateOrder = async (orderId: string, data = { + status: "IN-PROGRESS" +}) => { + // check if the order exists + const order = await client.request(FETCH_ORDER_BY_PK, { + id: orderId + }); + + if(!order) { + throw new Error("Order Not Found"); + } + + const updatedOrder = await client.request(UPDATE_ORDER_STATUS, { + object: { + ...order, + status: "IN_PROGRESS" + } + }); + + return updateOrder; +} \ No newline at end of file diff --git a/apps/api/src/orders/router.ts b/apps/api/src/orders/router.ts index c967beae..1105ee63 100644 --- a/apps/api/src/orders/router.ts +++ b/apps/api/src/orders/router.ts @@ -2,6 +2,7 @@ import { NextFunction, Response, Router, Request } from "express"; import { pushIntoOrders } from "../enqueue"; import { logRequest } from "../middleware/requestLogger"; import { validate } from "../middleware/zodValidate"; +import { updateOrder } from "./operations/updateOrder"; import { initOrder, @@ -16,14 +17,35 @@ ordersRouter.use(logRequest); ordersRouter.post( "/", - validate(orderSchema), + + async (req: Request, res: Response, next: NextFunction) => { + try { + const order = await initOrder(req.body); + // push into Queue + await pushIntoOrders(req.body); + res.status(201).send({ + order: { + name: "hello" + } + }); + } catch (error) { + next(error); + } + } +); + +ordersRouter.put( + "/:orderId", + async (req: Request, res: Response, next: NextFunction) => { try { const order = await initOrder(req.body); // push into Queue await pushIntoOrders(req.body); res.status(201).send({ - order, + order: { + name: "hello" + } }); } catch (error) { next(error); diff --git a/apps/api/src/orders/worker.ts b/apps/api/src/orders/worker.ts index e21cfcd9..4fc58cc6 100644 --- a/apps/api/src/orders/worker.ts +++ b/apps/api/src/orders/worker.ts @@ -2,11 +2,13 @@ import { Worker } from "bullmq"; import { logger } from "../lib/winston"; import { connection } from "../lib/ioredis"; import { Queues } from "../queue"; +import { updateOrder } from "./operations/updateOrder"; const worker = new Worker( Queues.Order, async (job) => { console.log("yerrrrr", job.data); + const updatedOrder = await updateOrder(job.data.id); logger.info("Processing Job", { world: "hello 0", }); diff --git a/apps/api/src/queue.ts b/apps/api/src/queue.ts index da9024a9..db352960 100644 --- a/apps/api/src/queue.ts +++ b/apps/api/src/queue.ts @@ -3,7 +3,7 @@ import { connection } from "./lib/ioredis"; import { redisHost, redisPort } from "./config"; export enum Queues { - Auth = "Auth", + Auth = "Auth", Client = "Client", Event = "Event", Mail = "Mail", diff --git a/apps/maps/src/Directions/index.ts b/apps/maps/src/Directions/index.ts index 45b14567..4714ca10 100644 --- a/apps/maps/src/Directions/index.ts +++ b/apps/maps/src/Directions/index.ts @@ -3,6 +3,7 @@ export class GoogleDirectionsAPI { private client; private _key; + // @ts-ignore constructor({ key }) { this.client = new Client({}); this._key = key; diff --git a/apps/maps/src/Geolocation/index.ts b/apps/maps/src/Geolocation/index.ts index e6b70199..3de2f97d 100644 --- a/apps/maps/src/Geolocation/index.ts +++ b/apps/maps/src/Geolocation/index.ts @@ -4,12 +4,12 @@ import type { GeocodeResult } from "@googlemaps/google-maps-services-js"; export class GoogleGeocodingAPI { private client; private _key; - +// @ts-ignore constructor({ key }) { this.client = new Client({}); this._key = key; } - +// @ts-ignore async geocode({ address }): Promise< Pick & { location: Record; @@ -23,6 +23,7 @@ export class GoogleGeocodingAPI { }, }); return { + // @ts-ignore location: { ...data.results[0]?.geometry?.location }, placeId: data.results[0]?.place_id, types: data.results[0]?.types, @@ -33,6 +34,7 @@ export class GoogleGeocodingAPI { const { data } = await this.client.geocode({ params: { key: this._key, + // @ts-ignore latlng: `${lat},${lng}`, }, }); diff --git a/apps/maps/src/Places/index.ts b/apps/maps/src/Places/index.ts index 09fe2060..2f4c6951 100644 --- a/apps/maps/src/Places/index.ts +++ b/apps/maps/src/Places/index.ts @@ -2,7 +2,7 @@ import { Client } from "@googlemaps/google-maps-services-js"; export class GooglePlacesAPI { private client; private _key; - +// @ts-ignore constructor({ key }) { this.client = new Client({}); this._key = key; @@ -20,12 +20,15 @@ export class GooglePlacesAPI { }); console.log("response", response?.data?.results); console.log("************"); + // @ts-ignore console.log("response", response?.data?.results?.geometry); return response?.data?.results?.map((place) => { return { name: place.name, - lat: place.geometry.location.lat, - lng: place.geometry.location.lng, + // @ts-ignore + lat: place?.geometry?.location?.lat, + // @ts-ignore + lng: place?.geometry?.location?.lng, address: "String", location: "String", }; diff --git a/packages/lib/graphql/mutations/orders.ts b/packages/lib/graphql/mutations/orders.ts index 54dddf1d..019c2dc4 100644 --- a/packages/lib/graphql/mutations/orders.ts +++ b/packages/lib/graphql/mutations/orders.ts @@ -8,6 +8,16 @@ export const INSERT_NEW_ORDER = gql` } `; + +export const UPDATE_ORDER_STATUS = gql` + mutation insertBusinessOrder($orderId: uuid!) { + update_order_status(where: {orders: {id: {_eq: $orderId}}}) { + affected_rows + } + } +`; + + export const INIT_ORDER_ACTION = gql` mutation insertBusinessOrderAction( $object: InsertBusinessOrderOrdersInsertInput = {} diff --git a/packages/lib/hooks/businesses.tsx b/packages/lib/hooks/businesses.tsx index 5173864b..50526050 100644 --- a/packages/lib/hooks/businesses.tsx +++ b/packages/lib/hooks/businesses.tsx @@ -4,7 +4,6 @@ import { FETCH_BUSINESSES, FETCH_BUSINESS_BY_PK, FETCH_BUSINESS_ORDERS, - INSERT_NEW_BUSINESS, REGISTER_BUSINESS_ACTION, } from "@sahil/lib/graphql"; @@ -14,7 +13,6 @@ import { BUSINESS_VALIDATED } from "@sahil/lib/graphql/subscriptions/businesses" import { GetBusinessesQuery, GetBusinessesQueryVariables, - GetBusinessesDocument, GetBusinessByPkQuery, GetBusinessByPkQueryVariables, GetBusinessOrdersQuery, From 3547922770d191aae97b2423f1d9f4cc9882aa62 Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 14 Apr 2024 11:42:05 +0200 Subject: [PATCH 3/9] feat: configure kysley query builder --- apps/api/package.json | 2 + apps/api/src/config.ts | 6 ++ apps/api/src/lib/kysley/databse.ts | 33 ++++++++ apps/api/src/lib/kysley/types.ts | 89 ++++++++++++++++++++++ apps/api/src/routers/api.ts | 2 + apps/api/src/suppliers/operations/list.ts | 7 ++ apps/api/src/suppliers/router.ts | 21 ++++- apps/api/src/users/operations/listUsers.ts | 8 ++ apps/api/src/users/router.ts | 9 ++- apps/api/tsconfig.json | 2 +- yarn.lock | 69 +++++++++++++++++ 11 files changed, 243 insertions(+), 5 deletions(-) create mode 100644 apps/api/src/lib/kysley/databse.ts create mode 100644 apps/api/src/lib/kysley/types.ts create mode 100644 apps/api/src/suppliers/operations/list.ts create mode 100644 apps/api/src/users/operations/listUsers.ts diff --git a/apps/api/package.json b/apps/api/package.json index fd7cd040..1bb3f370 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -25,6 +25,7 @@ "helmet": "^7.1.0", "ioredis": "^5.3.2", "jsonwebtoken": "^9.0.2", + "kysely": "^0.27.3", "morgan": "^1.10.0", "nodemon": "^3.0.2", "oslo": "^1.1.1", @@ -40,6 +41,7 @@ "@types/cors": "^2.8.17", "@types/express": "^4.17.21", "@types/node": "^20.10.5", + "@types/pg": "^8.11.5", "chalk": "^5.3.0", "concurrently": "^8.2.2", "typescript": "^5.3.3" diff --git a/apps/api/src/config.ts b/apps/api/src/config.ts index 43290c62..bdec4a2b 100644 --- a/apps/api/src/config.ts +++ b/apps/api/src/config.ts @@ -23,3 +23,9 @@ export const WebPushPrivateVapidKey = export const hasuraEndpoint = process.env.HASURA_GRAPHQL_ENDPOINT || ""; export const hasuraAdminSecret = process.env.HASURA_GRAPHQL_ADMIN_SECRET || ""; + +export const databaseHost = process.env?.DATABASE_HOST ?? "localhost"; +export const databaseUser = process.env?.DATABASE_USER ?? "postgres"; +export const databasePort = process.env?.DATABASE_PORT ?? "5432"; +export const database = process.env?.DATABASE_NAME ?? "postgres"; +export const databasePassword = process?.env?.DATABASE_PASSWORD ?? "password"; \ No newline at end of file diff --git a/apps/api/src/lib/kysley/databse.ts b/apps/api/src/lib/kysley/databse.ts new file mode 100644 index 00000000..947eb8ea --- /dev/null +++ b/apps/api/src/lib/kysley/databse.ts @@ -0,0 +1,33 @@ +import { Database } from "./types"; // this is the Database interface we defined earlier +import { Pool } from "pg"; +import { Kysely, PostgresDialect } from "kysely"; + +import { + database, + databaseHost, + databasePort, + databaseUser, + databasePassword, +} from "../../config"; + +const dialect = new PostgresDialect({ + pool: new Pool({ + database, + host: databaseHost, + user: databaseUser, + port: parseInt(databasePort), + password: databasePassword, + max: 10, + ssl: { + rejectUnauthorized: false, + } + }), +}); + +// Database interface is passed to Kysely's constructor, and from now on, Kysely +// knows your database structure. +// Dialect is passed to Kysely's constructor, and from now on, Kysely knows how +// to communicate with your database. +export const db = new Kysely({ + dialect, +}); diff --git a/apps/api/src/lib/kysley/types.ts b/apps/api/src/lib/kysley/types.ts new file mode 100644 index 00000000..846060d9 --- /dev/null +++ b/apps/api/src/lib/kysley/types.ts @@ -0,0 +1,89 @@ +import { + ColumnType, + Insertable, + Selectable, + Updateable +} from 'kysely'; + +export interface Database { + users: UsersTable; + suppliers: SupplierTable; + businesses: BusinessTable; + couriers: CourierTable; + agents: AgentTable; + order_items: OrderItemTable; + orders: OrderTable; + products: ProductTable; +} + +// users +export interface UsersTable { + created_at: ColumnType; +} + +export type Users = Selectable; +export type NewUsers = Insertable; +export type UsersUpdate = Updateable; + +// suppliers +export interface SupplierTable { + created_at: ColumnType; +} + +export type Supplier = Selectable; +export type NewSupplier = Insertable; +export type SupplierUpdate = Updateable; + +// businesses +export interface BusinessTable { + created_at: ColumnType; +} + +export type Business = Selectable; +export type NewBusiness = Insertable; +export type BusinessUpdate = Updateable; + +// couriers +export interface CourierTable { + created_at: ColumnType; +} + +export type Courier = Selectable; +export type NewCourier = Insertable; +export type CourierUpdate = Updateable; + +// agents +export interface AgentTable { + created_at: ColumnType; +} + +export type Agent = Selectable; +export type NewAgent = Insertable; +export type AgentUpdate = Updateable; + +// order items +export interface OrderItemTable { + created_at: ColumnType; +} + +export type OrderItem = Selectable; +export type NewOrderItem = Insertable; +export type OrderItemUpdate = Updateable; + +// orders +export interface OrderTable { + created_at: ColumnType; +} + +export type Order = Selectable; +export type NewOrder = Insertable; +export type OrderUpdate = Updateable; + +// products +export interface ProductTable { + created_at: ColumnType; +} + +export type Product = Selectable; +export type NewProduct = Insertable; +export type ProductUpdate = Updateable; diff --git a/apps/api/src/routers/api.ts b/apps/api/src/routers/api.ts index faac485e..5d6f4fb1 100644 --- a/apps/api/src/routers/api.ts +++ b/apps/api/src/routers/api.ts @@ -4,6 +4,7 @@ import businesses from "../businesses/router"; import notifications from "../notifications/router"; import orders from "../orders/router"; import users from "../users/router"; +import suppliers from "../suppliers/router"; import auth from "../auth/router"; const router = Router(); @@ -13,5 +14,6 @@ router.use("/businesses", businesses); router.use("/notifications", notifications); router.use("/orders", orders); router.use("/users", users); +router.use("/suppliers", suppliers); export default router; diff --git a/apps/api/src/suppliers/operations/list.ts b/apps/api/src/suppliers/operations/list.ts new file mode 100644 index 00000000..354bd977 --- /dev/null +++ b/apps/api/src/suppliers/operations/list.ts @@ -0,0 +1,7 @@ +import { db } from "../../lib/kysley/databse"; + +export const listRecommendedSuppliers = async () => { + let query = db.selectFrom('suppliers'); + const result = await query.selectAll().execute(); + return result; +} \ No newline at end of file diff --git a/apps/api/src/suppliers/router.ts b/apps/api/src/suppliers/router.ts index c8f2d2ea..e3a73042 100644 --- a/apps/api/src/suppliers/router.ts +++ b/apps/api/src/suppliers/router.ts @@ -1,3 +1,22 @@ import { NextFunction, Response, Router, Request } from "express"; import { logRequest } from "../middleware/requestLogger"; -import { validate } from "../middleware/zodValidate"; \ No newline at end of file +import { validate } from "../middleware/zodValidate"; +import { listRecommendedSuppliers } from "./operations/list"; + +const suppliersRouter = Router(); + +suppliersRouter.get( + "/", + async (req: Request, res: Response, next: NextFunction) => { + try { + const suppliers = await listRecommendedSuppliers(); + res.status(201).json({ + suppliers, + }); + } catch (error) { + next(error); + } + } +); + +export default suppliersRouter; diff --git a/apps/api/src/users/operations/listUsers.ts b/apps/api/src/users/operations/listUsers.ts new file mode 100644 index 00000000..f040fda6 --- /dev/null +++ b/apps/api/src/users/operations/listUsers.ts @@ -0,0 +1,8 @@ +import { db } from "../../lib/kysley/databse"; +import { Users } from "../../lib/kysley/types"; + +export const listUsers = async () => { + let query = db.selectFrom('users'); + const result = await query.selectAll().execute(); + return result; +} \ No newline at end of file diff --git a/apps/api/src/users/router.ts b/apps/api/src/users/router.ts index 514e5957..1534bcf4 100644 --- a/apps/api/src/users/router.ts +++ b/apps/api/src/users/router.ts @@ -1,6 +1,8 @@ import { NextFunction, Response, Router, Request } from "express"; -const userRouter = Router(); import { registerUser } from "./operations/register"; +import { listUsers } from "./operations/listUsers"; + +const userRouter = Router(); userRouter.get( "/:userId", @@ -21,9 +23,10 @@ userRouter.post( } ); -userRouter.get("/", (req: Request, res: Response, next: NextFunction) => { +userRouter.get("/", async (req: Request, res: Response, next: NextFunction) => { + const users = await listUsers(); res.status(200).json({ - hi: "Message", + users }); }); diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index 75dcaeac..83ee9e28 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -49,7 +49,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ diff --git a/yarn.lock b/yarn.lock index ed78f697..76d8494e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2635,6 +2635,15 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190" integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== +"@types/pg@^8.11.5": + version "8.11.5" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.11.5.tgz#a1ffb4dc4a46a83bda096cb298051a5b171de167" + integrity sha512-2xMjVviMxneZHDHX5p5S6tsRRs7TpDHeeK7kTTMe/kAC/mRRNjWHjZg0rkiY+e17jXSZV3zJYDxXV8Cy72/Vuw== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^4.0.1" + "@types/prop-types@*": version "15.7.11" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" @@ -6524,6 +6533,11 @@ kuler@^2.0.0: resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== +kysely@^0.27.3: + version "0.27.3" + resolved "https://registry.yarnpkg.com/kysely/-/kysely-0.27.3.tgz#6cc6c757040500b43c4ac596cdbb12be400ee276" + integrity sha512-lG03Ru+XyOJFsjH3OMY6R/9U38IjDPfnOfDgO3ynhbDr+Dz8fak+X6L62vqu3iybQnj+lG84OttBuU9KY3L9kA== + language-subtag-registry@^0.3.20: version "0.3.22" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" @@ -7408,6 +7422,11 @@ object.values@^1.1.5, object.values@^1.1.6, object.values@^1.1.7: define-properties "^1.2.0" es-abstract "^1.22.1" +obuf@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + oidc-token-hash@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz#9a229f0a1ce9d4fc89bcaee5478c97a889e7b7b6" @@ -7753,11 +7772,21 @@ pg-int8@1.0.1: resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== +pg-numeric@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a" + integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== + pg-pool@^3.6.1: version "3.6.1" resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.1.tgz#5a902eda79a8d7e3c928b77abf776b3cb7d351f7" integrity sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og== +pg-protocol@*: + version "1.6.1" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.1.tgz#21333e6d83b01faaebfe7a33a7ad6bfd9ed38cb3" + integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg== + pg-protocol@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.0.tgz#4c91613c0315349363af2084608db843502f8833" @@ -7774,6 +7803,19 @@ pg-types@^2.1.0: postgres-date "~1.0.4" postgres-interval "^1.1.0" +pg-types@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-4.0.2.tgz#399209a57c326f162461faa870145bb0f918b76d" + integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng== + dependencies: + pg-int8 "1.0.1" + pg-numeric "1.0.2" + postgres-array "~3.0.1" + postgres-bytea "~3.0.0" + postgres-date "~2.1.0" + postgres-interval "^3.0.0" + postgres-range "^1.1.1" + pg@^8.11.3: version "8.11.3" resolved "https://registry.yarnpkg.com/pg/-/pg-8.11.3.tgz#d7db6e3fe268fcedd65b8e4599cda0b8b4bf76cb" @@ -7910,16 +7952,33 @@ postgres-array@~2.0.0: resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== +postgres-array@~3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-3.0.2.tgz#68d6182cb0f7f152a7e60dc6a6889ed74b0a5f98" + integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog== + postgres-bytea@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== +postgres-bytea@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-3.0.0.tgz#9048dc461ac7ba70a6a42d109221619ecd1cb089" + integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw== + dependencies: + obuf "~1.1.2" + postgres-date@~1.0.4: version "1.0.7" resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== +postgres-date@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-2.1.0.tgz#b85d3c1fb6fb3c6c8db1e9942a13a3bf625189d0" + integrity sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA== + postgres-interval@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" @@ -7927,6 +7986,16 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" +postgres-interval@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-3.0.0.tgz#baf7a8b3ebab19b7f38f07566c7aab0962f0c86a" + integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw== + +postgres-range@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" + integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== + preact-render-to-string@^5.1.19: version "5.2.6" resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz#0ff0c86cd118d30affb825193f18e92bd59d0604" From 856c6f00c652c349d1291c214f2d6339f21891e7 Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 14 Apr 2024 13:49:34 +0200 Subject: [PATCH 4/9] feat: add types to matcher --- apps/api/src/matcher/setGeofence.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/src/matcher/setGeofence.ts b/apps/api/src/matcher/setGeofence.ts index bade35e4..9798079a 100644 --- a/apps/api/src/matcher/setGeofence.ts +++ b/apps/api/src/matcher/setGeofence.ts @@ -1,6 +1,6 @@ import { client } from "../lib/graphql-request"; -export const setGeofence = async (lat, lng) => { +export const setGeofence = async (lat: number, lng: number) => { // const coords = client.request(); } \ No newline at end of file From be5efaf6794416eddc32ccf7ce13e0a8cdb9e283 Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 14 Apr 2024 16:23:57 +0200 Subject: [PATCH 5/9] feat: return supplier pairs with quantities that add up to order items --- apps/api/package.json | 8 +- apps/api/src/matcher/sumOrderItems.ts | 24 ++++++ apps/api/src/matcher/supplerCombinations.ts | 13 +++ apps/api/src/suppliers/operations/list.ts | 70 ++++++++++++++++- apps/api/src/suppliers/router.ts | 3 +- apps/api/tsconfig.json | 16 ++-- packages/lib/kysley/database.ts | 2 + yarn.lock | 87 +++++++++++++++++++++ 8 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 apps/api/src/matcher/sumOrderItems.ts create mode 100644 apps/api/src/matcher/supplerCombinations.ts create mode 100644 packages/lib/kysley/database.ts diff --git a/apps/api/package.json b/apps/api/package.json index 1bb3f370..25fd6663 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -4,9 +4,9 @@ "main": "index.js", "license": "MIT", "scripts": { - "build": "tsc --project ./tsconfig.json", + "build": "tsc --project tsconfig.json", "clean": "rm -r dist", - "dev": "nodemon src/server.ts --experimental-global-webcrypto", + "dev": "nodemon src/server.ts", "format": "", "work": "ts-node ./src/workers.ts", "work:order": "ts-node ./src/orders/worker.ts" @@ -24,8 +24,10 @@ "graphql-request": "^6.1.0", "helmet": "^7.1.0", "ioredis": "^5.3.2", + "js-combinatorics": "^2.1.2", "jsonwebtoken": "^9.0.2", "kysely": "^0.27.3", + "libphonenumber-js": "^1.10.60", "morgan": "^1.10.0", "nodemon": "^3.0.2", "oslo": "^1.1.1", @@ -44,6 +46,8 @@ "@types/pg": "^8.11.5", "chalk": "^5.3.0", "concurrently": "^8.2.2", + "otplib": "^12.0.1", + "qrcode": "^1.5.3", "typescript": "^5.3.3" } } diff --git a/apps/api/src/matcher/sumOrderItems.ts b/apps/api/src/matcher/sumOrderItems.ts new file mode 100644 index 00000000..fdb882d7 --- /dev/null +++ b/apps/api/src/matcher/sumOrderItems.ts @@ -0,0 +1,24 @@ +export const sumOrderItems = (suppliersArray: any, target: number) => { + const map = new Map(); + const pairs = []; + + for (let i = 0; i < suppliersArray.length; i++) { + const complement = target - suppliersArray[i].quantity; + + if (map.has(complement)) { + // If the complement is found, add all pairs that include the current supplier + const indices = map.get(complement); + for (const element of indices) { + pairs.push([suppliersArray[element], suppliersArray[i]]); + } + } + + // Update the map with the current supplier's quantity and its index + if (map.has(suppliersArray[i].quantity)) { + map.get(suppliersArray[i].quantity).push(i); + } else { + map.set(suppliersArray[i].quantity, [i]); + } + } + return pairs; +}; diff --git a/apps/api/src/matcher/supplerCombinations.ts b/apps/api/src/matcher/supplerCombinations.ts new file mode 100644 index 00000000..714b60b4 --- /dev/null +++ b/apps/api/src/matcher/supplerCombinations.ts @@ -0,0 +1,13 @@ +import { Combination } from 'js-combinatorics'; + +export const generateCombinations = async (suppliers: { name: string; id: string; quantity: number; }[], target: number) => { + +} + +export const findBestCombination = (suppliers: any, target: number) => { + const combinations = generateCombinations(suppliers, target); + let bestCombination: never[] = []; + let bestCombinationSum = 0; + + return bestCombination; +} \ No newline at end of file diff --git a/apps/api/src/suppliers/operations/list.ts b/apps/api/src/suppliers/operations/list.ts index 354bd977..bf2fbe4b 100644 --- a/apps/api/src/suppliers/operations/list.ts +++ b/apps/api/src/suppliers/operations/list.ts @@ -1,7 +1,69 @@ import { db } from "../../lib/kysley/databse"; +import { + findBestCombination, + generateCombinations, +} from "../../matcher/supplerCombinations"; + +import { sumOrderItems } from "../../matcher/sumOrderItems"; + +const candidates = [ + { + name: "Emmanuel Office Solutions", + id: "514f5a78-9f4c-4cde-b6c0-5f7649a28d60", + quantity: 9, + pricePerKg: 0.8 + }, + { + name: "Twins Construction", + id: "627460d3-7b29-4bc6-b9ff-3958d6d02fe4", + quantity: 14, + pricePerKg: 0.8 + }, + { + name: "Khan Agricultural", + id: "403140dc-1d5d-435f-ba3d-ccc65abb1e5f", + quantity: 7, + pricePerKg: 0.8 + }, + { + name: "Energi Dealers", + id: "6f911d9b-580b-4283-bc8b-fbd381d298be", + quantity: 6, + pricePerKg: 0.8 + }, + { + name: "Brown Safety Solutions", + id: "0c8c5d87-b0a3-4409-95ea-d1134e1d72fd", + quantity: 12, + pricePerKg: 0.8 + }, + { + name: "Ozone Supermarket", + id: "b5f93ced-ba1f-42cb-bb96-e0d388bb111d", + quantity: 8, + pricePerKg: 0.8 + }, + { + name: "Mtn Momo", + id: "64f3bac9-12f7-4821-bd5c-4c48e5afe4fb", + quantity: 10, + pricePerKg: 0.8 + }, +]; export const listRecommendedSuppliers = async () => { - let query = db.selectFrom('suppliers'); - const result = await query.selectAll().execute(); - return result; -} \ No newline at end of file + const combinations = await generateCombinations(candidates, 20); + // Print the combinations + console.log("Combinations of suppliers that add up to 20kgs:"); + + // @ts-ignore + combinations.forEach((combination) => console.log(combination.join(", "))); + + const pairs = sumOrderItems(candidates, 20); + + console.log("pairs", pairs); + + let query = db.selectFrom("suppliers"); + const suppliers = await query.selectAll().execute(); + return { suppliers }; +}; diff --git a/apps/api/src/suppliers/router.ts b/apps/api/src/suppliers/router.ts index e3a73042..4c122b2b 100644 --- a/apps/api/src/suppliers/router.ts +++ b/apps/api/src/suppliers/router.ts @@ -9,7 +9,8 @@ suppliersRouter.get( "/", async (req: Request, res: Response, next: NextFunction) => { try { - const suppliers = await listRecommendedSuppliers(); + console.log("check!"); + const { suppliers } = await listRecommendedSuppliers(); res.status(201).json({ suppliers, }); diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index 83ee9e28..bebb5965 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -14,7 +14,7 @@ "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ @@ -27,7 +27,7 @@ /* Modules */ "module": "commonjs", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ @@ -35,7 +35,12 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ @@ -48,8 +53,9 @@ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./dist", /* Specify an output folder for all emitted files. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ @@ -57,7 +63,6 @@ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ // "newLine": "crlf", /* Set the newline character for emitting files. */ @@ -70,6 +75,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ @@ -100,4 +106,4 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ } -} +} \ No newline at end of file diff --git a/packages/lib/kysley/database.ts b/packages/lib/kysley/database.ts new file mode 100644 index 00000000..9629f26e --- /dev/null +++ b/packages/lib/kysley/database.ts @@ -0,0 +1,2 @@ +import { Pool } from "pg"; +import { Kysely, PostgresDialect } from "kysely"; diff --git a/yarn.lock b/yarn.lock index 76d8494e..f33f9721 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2130,6 +2130,44 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@otplib/core@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/core/-/core-12.0.1.tgz#73720a8cedce211fe5b3f683cd5a9c098eaf0f8d" + integrity sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA== + +"@otplib/plugin-crypto@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz#2b42c624227f4f9303c1c041fca399eddcbae25e" + integrity sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g== + dependencies: + "@otplib/core" "^12.0.1" + +"@otplib/plugin-thirty-two@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz#5cc9b56e6e89f2a1fe4a2b38900ca4e11c87aa9e" + integrity sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA== + dependencies: + "@otplib/core" "^12.0.1" + thirty-two "^1.0.2" + +"@otplib/preset-default@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/preset-default/-/preset-default-12.0.1.tgz#cb596553c08251e71b187ada4a2246ad2a3165ba" + integrity sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ== + dependencies: + "@otplib/core" "^12.0.1" + "@otplib/plugin-crypto" "^12.0.1" + "@otplib/plugin-thirty-two" "^12.0.1" + +"@otplib/preset-v11@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/preset-v11/-/preset-v11-12.0.1.tgz#4c7266712e7230500b421ba89252963c838fc96d" + integrity sha512-9hSetMI7ECqbFiKICrNa4w70deTUfArtwXykPUvSHWOdzOlfa9ajglu7mNCntlvxycTiOAXkQGwjQCzzDEMRMg== + dependencies: + "@otplib/core" "^12.0.1" + "@otplib/plugin-crypto" "^12.0.1" + "@otplib/plugin-thirty-two" "^12.0.1" + "@panva/hkdf@^1.0.2": version "1.1.1" resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.1.1.tgz#ab9cd8755d1976e72fc77a00f7655a64efe6cd5d" @@ -4384,6 +4422,11 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +dijkstrajs@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz#4c8dbdea1f0f6478bff94d9c49c784d623e4fc23" + integrity sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -4502,6 +4545,11 @@ enabled@2.0.x: resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== +encode-utf8@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" + integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -6355,6 +6403,11 @@ jose@^5.0.0: resolved "https://registry.yarnpkg.com/jose/-/jose-5.2.0.tgz#d0ffd7f7e31253f633eefb190a930cd14a916995" integrity sha512-oW3PCnvyrcm1HMvGTzqjxxfnEs9EoFOFWi2HsEGhlFVOXxTE3K9GKWVMFoFw06yPUqwpvEWic1BmtUZBI/tIjw== +js-combinatorics@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/js-combinatorics/-/js-combinatorics-2.1.2.tgz#1434bce70c6e3b46f01c6b214626e95ff7905f81" + integrity sha512-/1AY2bYwxajoaKjPzvgQ80U7lcucU71ubzFPVgZGmzbDGn3R18ZQUZfD69+4Idg4JfNcq6trwD6I+dRfVnr/tg== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -6558,6 +6611,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libphonenumber-js@^1.10.60: + version "1.10.60" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.60.tgz#1160ec5b390d46345032aa52be7ffa7a1950214b" + integrity sha512-Ctgq2lXUpEJo5j1762NOzl2xo7z7pqmVWYai0p07LvAkQ32tbPv3wb+tcUeHEiXhKU5buM4H9MXsXo6OlM6C2g== + lilconfig@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" @@ -7555,6 +7613,15 @@ oslo@^1.1.1: "@node-rs/bcrypt" "1.9.0" auri "1.0.2" +otplib@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/otplib/-/otplib-12.0.1.tgz#c1d3060ab7aadf041ed2960302f27095777d1f73" + integrity sha512-xDGvUOQjop7RDgxTQ+o4pOol0/3xSZzawTiPKRrHnQWAy0WjhNs/5HdIDJCrqC4MBynmjXgULc6YfioaxZeFgg== + dependencies: + "@otplib/core" "^12.0.1" + "@otplib/preset-default" "^12.0.1" + "@otplib/preset-v11" "^12.0.1" + p-limit@3.1.0, p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -7858,6 +7925,11 @@ pirates@^4.0.1: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== +pngjs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" + integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== + postcss-import@^15.1.0: version "15.1.0" resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" @@ -8105,6 +8177,16 @@ pvutils@^1.1.3: resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== +qrcode@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.3.tgz#03afa80912c0dccf12bc93f615a535aad1066170" + integrity sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg== + dependencies: + dijkstrajs "^1.0.1" + encode-utf8 "^1.0.3" + pngjs "^5.0.0" + yargs "^15.3.1" + qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" @@ -9098,6 +9180,11 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" +thirty-two@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" + integrity sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA== + through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" From 0bb8868394533461cccfa6382052100ce539b388 Mon Sep 17 00:00:00 2001 From: Eman Date: Sun, 14 Apr 2024 17:04:12 +0200 Subject: [PATCH 6/9] feat: simulate order process step: find supplier pairs --- apps/api/src/matcher/sumOrderItems.ts | 60 ++++++++++++------- apps/api/src/suppliers/operations/list.ts | 33 +++++++--- .../google-maps/directions/getDirections.ts | 42 +++++++++++++ 3 files changed, 105 insertions(+), 30 deletions(-) create mode 100644 packages/lib/google-maps/directions/getDirections.ts diff --git a/apps/api/src/matcher/sumOrderItems.ts b/apps/api/src/matcher/sumOrderItems.ts index fdb882d7..c95f885c 100644 --- a/apps/api/src/matcher/sumOrderItems.ts +++ b/apps/api/src/matcher/sumOrderItems.ts @@ -1,24 +1,42 @@ export const sumOrderItems = (suppliersArray: any, target: number) => { - const map = new Map(); - const pairs = []; - - for (let i = 0; i < suppliersArray.length; i++) { - const complement = target - suppliersArray[i].quantity; - - if (map.has(complement)) { - // If the complement is found, add all pairs that include the current supplier - const indices = map.get(complement); - for (const element of indices) { - pairs.push([suppliersArray[element], suppliersArray[i]]); - } - } - - // Update the map with the current supplier's quantity and its index - if (map.has(suppliersArray[i].quantity)) { - map.get(suppliersArray[i].quantity).push(i); - } else { - map.set(suppliersArray[i].quantity, [i]); - } + const map = new Map(); + const pairs = []; + + for (let i = 0; i < suppliersArray.length; i++) { + const complement = target - suppliersArray[i].quantity; + + if (map.has(complement)) { + // If the complement is found, add all pairs that include the current supplier + const indices = map.get(complement); + for (const element of indices) { + pairs.push([suppliersArray[element], suppliersArray[i]]); + } } - return pairs; + + // Update the map with the current supplier's quantity and its index + if (map.has(suppliersArray[i].quantity)) { + map.get(suppliersArray[i].quantity).push(i); + } else { + map.set(suppliersArray[i].quantity, [i]); + } + } + return pairs; +}; + +export const calculateSahilScore = (pair: any) => { + const totalQuantity = pair[0].quantity + pair[1].quantity; + const totalDistance = pair[0].distance + pair[1].distance; + const totalPricePerUnit = pair[0].pricePerUnit + pair[1].pricePerUnit; + const distanceCost = totalDistance * 0.5; + const unitCost = totalQuantity * totalPricePerUnit; + return distanceCost + unitCost; }; + + +// Calculate total cost for each pair and rank them +export const rankedSuppliersBasedOnScore = (suppliers: any) => { + return suppliers.map((supplier: any) => ({ + supplier, + totalCost: calculateSahilScore(supplier) + })).sort((a: any, b: any) => a.totalCost - b.totalCost); +} \ No newline at end of file diff --git a/apps/api/src/suppliers/operations/list.ts b/apps/api/src/suppliers/operations/list.ts index bf2fbe4b..2e1ee292 100644 --- a/apps/api/src/suppliers/operations/list.ts +++ b/apps/api/src/suppliers/operations/list.ts @@ -4,6 +4,8 @@ import { generateCombinations, } from "../../matcher/supplerCombinations"; +import { rankedSuppliersBasedOnScore } from "../../matcher/sumOrderItems"; + import { sumOrderItems } from "../../matcher/sumOrderItems"; const candidates = [ @@ -11,58 +13,71 @@ const candidates = [ name: "Emmanuel Office Solutions", id: "514f5a78-9f4c-4cde-b6c0-5f7649a28d60", quantity: 9, - pricePerKg: 0.8 + pricePerUnit: 0.95, + distance: 144 }, { name: "Twins Construction", id: "627460d3-7b29-4bc6-b9ff-3958d6d02fe4", quantity: 14, - pricePerKg: 0.8 + pricePerUnit: 0.9, + distance: 120 }, { name: "Khan Agricultural", id: "403140dc-1d5d-435f-ba3d-ccc65abb1e5f", quantity: 7, - pricePerKg: 0.8 + pricePerUnit: 0.8, + distance: 111 }, { name: "Energi Dealers", id: "6f911d9b-580b-4283-bc8b-fbd381d298be", quantity: 6, - pricePerKg: 0.8 + pricePerUnit: 1, + distance: 97 }, { name: "Brown Safety Solutions", id: "0c8c5d87-b0a3-4409-95ea-d1134e1d72fd", quantity: 12, - pricePerKg: 0.8 + pricePerUnit: 0.85, + distance: 123 }, { name: "Ozone Supermarket", id: "b5f93ced-ba1f-42cb-bb96-e0d388bb111d", quantity: 8, - pricePerKg: 0.8 + pricePerUnit: 0.95, + distance: 109 }, { name: "Mtn Momo", id: "64f3bac9-12f7-4821-bd5c-4c48e5afe4fb", quantity: 10, - pricePerKg: 0.8 + pricePerUnit: 0.9, + distance: 119 }, ]; + + export const listRecommendedSuppliers = async () => { const combinations = await generateCombinations(candidates, 20); // Print the combinations console.log("Combinations of suppliers that add up to 20kgs:"); - // @ts-ignore - combinations.forEach((combination) => console.log(combination.join(", "))); const pairs = sumOrderItems(candidates, 20); console.log("pairs", pairs); + const rankedSuppliers = rankedSuppliersBasedOnScore(pairs); + + console.log("rankedSuppliers", rankedSuppliers[0]); + console.log("*****************"); + console.log("rankedSuppliers", rankedSuppliers[1]); + let query = db.selectFrom("suppliers"); const suppliers = await query.selectAll().execute(); return { suppliers }; diff --git a/packages/lib/google-maps/directions/getDirections.ts b/packages/lib/google-maps/directions/getDirections.ts new file mode 100644 index 00000000..4714ca10 --- /dev/null +++ b/packages/lib/google-maps/directions/getDirections.ts @@ -0,0 +1,42 @@ +import { Client } from "@googlemaps/google-maps-services-js"; +export class GoogleDirectionsAPI { + private client; + private _key; + + // @ts-ignore + constructor({ key }) { + this.client = new Client({}); + this._key = key; + } + async getDirections(origin: string, destination: string): Promise { + const { data } = await this.client.directions({ + params: { + origin, + destination, + key: this._key, + }, + }); + + return { + routes: { + name: "Route", + legs: [ + { + distance: { + ...data.routes?.[0]?.legs[0]?.distance, + }, + duration: { + ...data.routes?.[0]?.legs[0]?.duration, + }, + }, + ], + }, + startLocation: { + ...data.routes?.[0]?.legs[0]?.start_location, + }, + endLocation: { + ...data.routes?.[0]?.legs[0]?.end_location, + }, + }; + } +} From 1756cce34c9ab46c763e331ba41eabcb7fd7f99f Mon Sep 17 00:00:00 2001 From: Eman Date: Wed, 17 Apr 2024 01:16:01 +0200 Subject: [PATCH 7/9] feat; generate partial fulfillment pairs --- apps/api/package.json | 1 + apps/api/src/matcher/sahilScore.ts | 9 +++++++++ apps/api/src/matcher/supplerCombinations.ts | 4 +++- apps/api/src/suppliers/operations/list.ts | 4 ++-- yarn.lock | 9 ++++++++- 5 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 apps/api/src/matcher/sahilScore.ts diff --git a/apps/api/package.json b/apps/api/package.json index 25fd6663..817c64e0 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -42,6 +42,7 @@ "@types/concurrently": "^7.0.0", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", + "@types/js-combinatorics": "^1.2.0", "@types/node": "^20.10.5", "@types/pg": "^8.11.5", "chalk": "^5.3.0", diff --git a/apps/api/src/matcher/sahilScore.ts b/apps/api/src/matcher/sahilScore.ts new file mode 100644 index 00000000..51d1f847 --- /dev/null +++ b/apps/api/src/matcher/sahilScore.ts @@ -0,0 +1,9 @@ +export const calculateSahilScore = (pair: any) => { + const totalQuantity = pair[0].quantity + pair[1].quantity; + const totalDistance = pair[0].distance + pair[1].distance; + const totalPricePerUnit = pair[0].pricePerUnit + pair[1].pricePerUnit; + const distanceCost = totalDistance * 0.5; + const unitCost = totalQuantity * totalPricePerUnit; + return distanceCost + unitCost; + }; + \ No newline at end of file diff --git a/apps/api/src/matcher/supplerCombinations.ts b/apps/api/src/matcher/supplerCombinations.ts index 714b60b4..5342cdc6 100644 --- a/apps/api/src/matcher/supplerCombinations.ts +++ b/apps/api/src/matcher/supplerCombinations.ts @@ -1,7 +1,9 @@ import { Combination } from 'js-combinatorics'; export const generateCombinations = async (suppliers: { name: string; id: string; quantity: number; }[], target: number) => { - + const combinations = new Combination(suppliers, 2); + console.log(combinations); + return [...combinations]; } export const findBestCombination = (suppliers: any, target: number) => { diff --git a/apps/api/src/suppliers/operations/list.ts b/apps/api/src/suppliers/operations/list.ts index 2e1ee292..921911c9 100644 --- a/apps/api/src/suppliers/operations/list.ts +++ b/apps/api/src/suppliers/operations/list.ts @@ -65,12 +65,12 @@ const candidates = [ export const listRecommendedSuppliers = async () => { const combinations = await generateCombinations(candidates, 20); // Print the combinations - console.log("Combinations of suppliers that add up to 20kgs:"); + console.log("Combinations of suppliers that add up to 20kgs:", combinations); const pairs = sumOrderItems(candidates, 20); - console.log("pairs", pairs); + // console.log("pairs", pairs); const rankedSuppliers = rankedSuppliersBasedOnScore(pairs); diff --git a/yarn.lock b/yarn.lock index f33f9721..6b37f8c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2601,6 +2601,13 @@ "@types/through" "*" rxjs "^6.4.0" +"@types/js-combinatorics@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/js-combinatorics/-/js-combinatorics-1.2.0.tgz#81c753702bf9c826297abe85d179f803dc51ada1" + integrity sha512-c8JDKRYrLjJUD77htINkEXTZ4bq5MaJNTRYnFLMoeXviSWQkdHYZ3wUfT2YGuB+pizDmQTsaXCMQOntMdS9kvQ== + dependencies: + js-combinatorics "*" + "@types/js-yaml@^4.0.0": version "4.0.9" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" @@ -6403,7 +6410,7 @@ jose@^5.0.0: resolved "https://registry.yarnpkg.com/jose/-/jose-5.2.0.tgz#d0ffd7f7e31253f633eefb190a930cd14a916995" integrity sha512-oW3PCnvyrcm1HMvGTzqjxxfnEs9EoFOFWi2HsEGhlFVOXxTE3K9GKWVMFoFw06yPUqwpvEWic1BmtUZBI/tIjw== -js-combinatorics@^2.1.2: +js-combinatorics@*, js-combinatorics@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/js-combinatorics/-/js-combinatorics-2.1.2.tgz#1434bce70c6e3b46f01c6b214626e95ff7905f81" integrity sha512-/1AY2bYwxajoaKjPzvgQ80U7lcucU71ubzFPVgZGmzbDGn3R18ZQUZfD69+4Idg4JfNcq6trwD6I+dRfVnr/tg== From 7db3cc082a4a71268d1e5807f1ed53606d76656c Mon Sep 17 00:00:00 2001 From: Eman Date: Wed, 17 Apr 2024 02:14:04 +0200 Subject: [PATCH 8/9] feat: add supplier product info endpoint --- apps/api/src/matcher/supplerCombinations.ts | 15 --------- apps/api/src/matcher/supplierCombinations.ts | 32 +++++++++++++++++++ apps/api/src/suppliers/operations/list.ts | 2 +- .../operations/supplierProductInfo.ts | 16 ++++++++++ 4 files changed, 49 insertions(+), 16 deletions(-) delete mode 100644 apps/api/src/matcher/supplerCombinations.ts create mode 100644 apps/api/src/matcher/supplierCombinations.ts create mode 100644 apps/api/src/suppliers/operations/supplierProductInfo.ts diff --git a/apps/api/src/matcher/supplerCombinations.ts b/apps/api/src/matcher/supplerCombinations.ts deleted file mode 100644 index 5342cdc6..00000000 --- a/apps/api/src/matcher/supplerCombinations.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Combination } from 'js-combinatorics'; - -export const generateCombinations = async (suppliers: { name: string; id: string; quantity: number; }[], target: number) => { - const combinations = new Combination(suppliers, 2); - console.log(combinations); - return [...combinations]; -} - -export const findBestCombination = (suppliers: any, target: number) => { - const combinations = generateCombinations(suppliers, target); - let bestCombination: never[] = []; - let bestCombinationSum = 0; - - return bestCombination; -} \ No newline at end of file diff --git a/apps/api/src/matcher/supplierCombinations.ts b/apps/api/src/matcher/supplierCombinations.ts new file mode 100644 index 00000000..4e55fa83 --- /dev/null +++ b/apps/api/src/matcher/supplierCombinations.ts @@ -0,0 +1,32 @@ +import { Combination } from 'js-combinatorics'; + +export const calculateCombinationSize = (candidates: { name: string, quantity: number }[], targetQuantity: number) : number => { + let remainingQuantity = targetQuantity; + let combinationSize = 0; + for (const candidate of candidates) { + if (remainingQuantity <= 0) { + break; + } + if (candidate.quantity >= remainingQuantity) { + combinationSize++; + break; + } else { + combinationSize++; + remainingQuantity -= candidate.quantity; + } + } + return combinationSize; + } + +export const generateCombinations = async (suppliers: { name: string; id: string; quantity: number; }[], combinationSize: number = 2) => { + const combinations = new Combination(suppliers, combinationSize); + return [...combinations]; +} + +export const findBestCombination = (suppliers: any, target: number) => { + const combinations = generateCombinations(suppliers, target); + let bestCombination: never[] = []; + let bestCombinationSum = 0; + + return bestCombination; +} \ No newline at end of file diff --git a/apps/api/src/suppliers/operations/list.ts b/apps/api/src/suppliers/operations/list.ts index 921911c9..12711ac7 100644 --- a/apps/api/src/suppliers/operations/list.ts +++ b/apps/api/src/suppliers/operations/list.ts @@ -2,7 +2,7 @@ import { db } from "../../lib/kysley/databse"; import { findBestCombination, generateCombinations, -} from "../../matcher/supplerCombinations"; +} from "../../matcher/supplierCombinations"; import { rankedSuppliersBasedOnScore } from "../../matcher/sumOrderItems"; diff --git a/apps/api/src/suppliers/operations/supplierProductInfo.ts b/apps/api/src/suppliers/operations/supplierProductInfo.ts new file mode 100644 index 00000000..fef67382 --- /dev/null +++ b/apps/api/src/suppliers/operations/supplierProductInfo.ts @@ -0,0 +1,16 @@ +import { db } from "../../lib/kysley/databse"; +// given a product label and category, this function returns the supplier as well as the product information +// for instance, suppliers could have milk as a label and diary as a category but a unique brand name for the product which +// we need to get the exact product from each supplier for comparison +export const supplierProductInfo = async (supplierId: string, product: any) => { + // Construct the query + const query = db + .selectFrom("products") + // .where("products.supplier_id", "=", supplierId) + // .andWhere("products.category", "=", product.category) + // .andWhere("products.label", "=", product.label) + + // Execute the query + const result = await query.execute(); + return result; +}; From bd9519d50311ccf822a0a2ad89a2023eab18a024 Mon Sep 17 00:00:00 2001 From: Eman Date: Sat, 20 Apr 2024 14:10:09 +0200 Subject: [PATCH 9/9] feat: generate supplier combinations --- apps/api/src/init.ts | 2 ++ apps/api/src/matcher/supplierCombinations.ts | 2 ++ apps/api/src/suppliers/operations/list.ts | 1 - apps/api/src/suppliers/operations/supplierProductInfo.ts | 6 ++++-- apps/api/src/suppliers/router.ts | 1 - 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/api/src/init.ts b/apps/api/src/init.ts index 1f0db144..bc29b624 100644 --- a/apps/api/src/init.ts +++ b/apps/api/src/init.ts @@ -4,6 +4,7 @@ import cors from "cors"; // import compression from "compression"; import * as helmet from "helmet"; import { catchErrors } from "./middleware/errors"; +import { logRequest } from "./middleware/requestLogger"; export function init(app: any) { app.use(cors()); @@ -16,5 +17,6 @@ export function init(app: any) { // app.use(helmet()); // app.use(morganLogger("dev")); app.use(routers); + app.use(logRequest); app.use(catchErrors); } diff --git a/apps/api/src/matcher/supplierCombinations.ts b/apps/api/src/matcher/supplierCombinations.ts index 4e55fa83..f8fb3b48 100644 --- a/apps/api/src/matcher/supplierCombinations.ts +++ b/apps/api/src/matcher/supplierCombinations.ts @@ -1,5 +1,7 @@ import { Combination } from 'js-combinatorics'; +// we could rank the combinations based on the sum of their quantities +// modulus the number of qunatity to get the combination size export const calculateCombinationSize = (candidates: { name: string, quantity: number }[], targetQuantity: number) : number => { let remainingQuantity = targetQuantity; let combinationSize = 0; diff --git a/apps/api/src/suppliers/operations/list.ts b/apps/api/src/suppliers/operations/list.ts index 12711ac7..cf553516 100644 --- a/apps/api/src/suppliers/operations/list.ts +++ b/apps/api/src/suppliers/operations/list.ts @@ -61,7 +61,6 @@ const candidates = [ ]; - export const listRecommendedSuppliers = async () => { const combinations = await generateCombinations(candidates, 20); // Print the combinations diff --git a/apps/api/src/suppliers/operations/supplierProductInfo.ts b/apps/api/src/suppliers/operations/supplierProductInfo.ts index fef67382..4d084709 100644 --- a/apps/api/src/suppliers/operations/supplierProductInfo.ts +++ b/apps/api/src/suppliers/operations/supplierProductInfo.ts @@ -5,12 +5,14 @@ import { db } from "../../lib/kysley/databse"; export const supplierProductInfo = async (supplierId: string, product: any) => { // Construct the query const query = db - .selectFrom("products") + .selectFrom("products"); // .where("products.supplier_id", "=", supplierId) // .andWhere("products.category", "=", product.category) // .andWhere("products.label", "=", product.label) // Execute the query const result = await query.execute(); + + return result; -}; +}; \ No newline at end of file diff --git a/apps/api/src/suppliers/router.ts b/apps/api/src/suppliers/router.ts index 4c122b2b..f889ed6c 100644 --- a/apps/api/src/suppliers/router.ts +++ b/apps/api/src/suppliers/router.ts @@ -9,7 +9,6 @@ suppliersRouter.get( "/", async (req: Request, res: Response, next: NextFunction) => { try { - console.log("check!"); const { suppliers } = await listRecommendedSuppliers(); res.status(201).json({ suppliers,