diff --git a/src/datasources/product-api.ts b/src/datasources/product-api.ts index 22f2aee..766457b 100644 --- a/src/datasources/product-api.ts +++ b/src/datasources/product-api.ts @@ -20,7 +20,12 @@ import { Batch, } from '../types/product-types'; import { Maybe } from '../types/types'; -import { booleanStringField, nullOrNumber, roundOrDefaultTo } from './utils'; +import { + booleanStringField, + isInt, + nullOrNumber, + roundOrDefaultTo, +} from './utils'; import { UserInputError } from 'apollo-server'; const MINUTE = 60; @@ -279,65 +284,67 @@ export class ProductAPI extends BaseSQLDataSource { ); } - async getUniqueProductSlug( - slug: string, + async getUniqueProductPath( + path: string, productId?: number, ): Promise { - // If productId is set then check if slug is already + // If productId is set then check if path is already // set on that product. if (productId) { const productPath = await this.knex.raw( `SELECT path FROM "product-products" WHERE productid = ?`, [productId], ); - if (productPath.rows[0].path === slug) { - return slug; + if (productPath.rows[0].path === path) { + return path; } } - // Check for unique-slug + // Check for unique-path // Get paths from product-products + const basePath = slug(path, { remove: /(\d+)(?!.*\d)/ }); // Remove last number adf-1-asdf-123 = adf-1-asdf- const pathResponse = await this.knex.raw( `SELECT path FROM "product-products" WHERE path LIKE ?`, - [slug + '%'], + [basePath + '%'], ); const paths = pathResponse.rows.map((item) => item.path); - // Evaluate new pathname - let newSlug = ''; + let newPath = ''; // If the exact match of the slug is not listed // in the paths queried from db. Then use the // tested slug. - if (!paths.includes(slug)) { - newSlug = slug; + if (!paths.includes(path)) { + newPath = path; } else { // Try to find any numbers in the pathname const numbers = paths - .map((path) => { - return parseInt(path.replace(slug + '-', '')); + .map((p) => { + const numStr = p.replace(basePath + '-', ''); + return isInt(numStr) ? parseInt(numStr) : null; }) .filter(Boolean); // Remove falsy + if (numbers.length === 0) { // No numbers found, add 1. - newSlug = slug + '-1'; + newPath = path + '-1'; } else { // Get highest number + 1 const next = Math.max(...numbers) + 1; - newSlug = slug + '-' + next; + newPath = basePath + '-' + next; } } - return newSlug; + return newPath; } async addProduct(name: string, batch: string): Promise { const path = batch ? batch + ' ' + name : name; - const productSlug = slug(path); - const safeSlug = await this.getUniqueProductSlug(productSlug, null); + const productPath = slug(path); + const safePath = await this.getUniqueProductPath(productPath, null); const idres = await this.knex .table('product-products') .insert({ - path: slug(safeSlug), + path: slug(safePath), browsable: 0, visible: 0, }) @@ -354,7 +361,7 @@ export class ProductAPI extends BaseSQLDataSource { info: ProductInfoInput, ): Promise { // Check path and insert new unique path if taken - const uniquePath = await this.getUniqueProductSlug(info.path, productId); + const uniquePath = await this.getUniqueProductPath(info.path, productId); const promises = []; promises.push( diff --git a/src/datasources/utils.ts b/src/datasources/utils.ts index 9c575f8..2688122 100644 --- a/src/datasources/utils.ts +++ b/src/datasources/utils.ts @@ -4,6 +4,10 @@ function isNumeric(n: InputType) { return !isNaN(parseFloat(n)); } +export function isInt(str: InputType) { + return !isNaN(parseFloat(str)) && Number.isInteger(parseFloat(str)); +} + function isBoolean(n: InputType | boolean) { if (typeof n === 'boolean') { return true;