diff --git a/src/config.ts b/src/config.ts index ea07084..d8b9bfa 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,6 +12,8 @@ export const dbConfig = { return 'product-products'; } else if (output === 'order_rows_fields') { return 'order-rows_fields'; + } else if (output === 'product_products_products') { + return 'product-products_products'; } return output; }, diff --git a/src/datasources/product-api.ts b/src/datasources/product-api.ts index 31e6933..eb25911 100644 --- a/src/datasources/product-api.ts +++ b/src/datasources/product-api.ts @@ -19,6 +19,7 @@ import { } from '../types/product-types'; import { Maybe } from '../types/types'; import { booleanStringField, nullOrNumber } from './utils'; +import { UserInputError } from 'apollo-server'; const MINUTE = 60; @@ -33,7 +34,10 @@ export class ProductAPI extends BaseSQLDataSource { // } getWallpaperTypes(row: any): Array { - return row.wallpapertypes?.map((t: number) => ProductWallpaperType[t]); + if (!row.wallpapertypes) { + return []; + } + return row.wallpapertypes.map((t: number) => ProductWallpaperType[t]); } getProductTypes(row: any): Array { @@ -185,10 +189,10 @@ export class ProductAPI extends BaseSQLDataSource { } async getRelatedProducts(id: number): Promise> { - const ids = await this.cachedRaw( - `SELECT productid2 FROM "product-products_products" WHERE productid1 = ${id}`, - ) - .cache(MINUTE * 60) + const ids = await this.knex + .raw( + `SELECT productid2 FROM "product-products_products" WHERE productid1 = ${id}`, + ) .then((data) => data.rows.map((r) => r.productid2)); return ids.map(async (id) => this.getProduct(id)); @@ -471,4 +475,65 @@ export class ProductAPI extends BaseSQLDataSource { return Promise.all(promises); } + + async addRelatedProducts( + productId: number, + articleNumbers: Array, + ): Promise[]> { + const whereClause = articleNumbers.map((a) => `'${a}'`).join(','); + const query = /* sql */ ` + SELECT pp.productid, ppf.value FROM "product-products" pp + LEFT JOIN "product-products_fields" ppf + ON ppf.productid = pp.productid AND ppf.fieldid = 1 + WHERE ppf.value IN (${whereClause}); + `; + + const res = await this.cachedRaw(query) + .cache(MINUTE) + .then((data) => data.rows); + + if (!res.length) { + throw new UserInputError('No articles found'); + } + const fieldsToInsert = res.map((item) => ({ + productid1: productId, + productid2: item.productid, + })); + + // Add this productId as related to its friends + res.forEach((item) => { + fieldsToInsert.push({ + productid1: item.productid, + productid2: productId, + }); + }); + + return this.knex.raw(`? ON CONFLICT (productid1, productid2) DO NOTHING;`, [ + this.knex('product-products_products').insert(fieldsToInsert), + ]); + } + + /** + * Removes variant products from productid as well as the sent in + * productid from its variants + */ + async removeRelatedProducts( + productId, + relatedProductIds, + ): Promise[]> { + // remove connection between the friends id and this produdId + const promises = relatedProductIds.map((pId) => { + return this.knex('product-products_products') + .where('productid1', pId) + .where('productid2', productId) + .del(); + }); + // remove connection to friends for this productsid + const query = this.knex('product-products_products') + .where('productid1', productId) + .whereIn('productid2', relatedProductIds) + .del(); + promises.push(query); + return Promise.all(promises); + } } diff --git a/src/resolvers/products-resolver.ts b/src/resolvers/products-resolver.ts index 5f7e744..cd65f2a 100644 --- a/src/resolvers/products-resolver.ts +++ b/src/resolvers/products-resolver.ts @@ -161,4 +161,23 @@ export const productMutationTypeDefs = { ); return (dataSources.productApi).getProduct(productId); }, + async addRelatedProducts(_, { productId, articleNumbers }, { dataSources }) { + await (dataSources.productApi).addRelatedProducts( + productId, + articleNumbers, + ); + return (dataSources.productApi).getProduct(productId); + }, + + async removeRelatedProducts( + _, + { productId, relatedProductIds }, + { dataSources }, + ) { + await (dataSources.productApi).removeRelatedProducts( + productId, + relatedProductIds, + ); + return (dataSources.productApi).getProduct(productId); + }, }; diff --git a/src/schema.graphql b/src/schema.graphql index 556fe1c..1c58151 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -263,7 +263,7 @@ type Product { ref2: String ref3: String related: [Product] - wallpaperTypes: [ProductWallpaperType] + wallpaperTypes: [ProductWallpaperType]! fields: ProductFields orientation: Orientation """ @@ -454,5 +454,9 @@ type Mutation { productId: Int! wallpaperTypes: [ProductWallpaperType]! ): Product + + addRelatedProducts(productId: Int!, articleNumbers: [String]!): Product + removeRelatedProducts(productId: Int!, relatedProductIds: [Int]!): Product + addKeyword(name: String!, type: KeywordType): Keyword }