import { Request, Response } from 'express'; import { prisma, __path, log } from '../../../index.js'; import { itemStatus } from '@prisma/client'; import { parseIntRelation, parseIntOrUndefined, parseDynamicSortBy } from '../../../assets/helper.js'; // Get item. async function get(req: Request, res: Response) { // Set sane defaults if undefined. if (req.query.sort === undefined) { req.query.sort = 'id'; } if (req.query.order === undefined) { req.query.order = 'asc'; } if (req.query.search === undefined) { req.query.search = ''; } if (req.query.id) { // Check if number is a valid integer if (!Number.isInteger(parseInt(req.query.id.toString()))) { res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'One or more required fields are missing' }); return; } prisma.item .findUnique({ where: { id: parseInt(req.query.id.toString()) }, // Get contactInfo, category, storageLocation( storageUnit ) from relations include: { contactInfo: true, category: true, storageLocation: { include: { storageUnit: { include: { contactInfo: true } } } } } }) .then((items) => { if (items) { res.status(200).json(items); } else { res.status(410).json({ status: 'ERROR', errorcode: 'NOT_EXISTING', message: 'Item does not exist' }); } }) .catch((err) => { log.db.error(err); res.status(500).json({ status: 'ERROR', errorcode: 'DB_ERROR', error: err, message: 'An error occurred during the database operation' }); }); } else { // Get all items const itemCountNotFiltered = await prisma.item.count({}); // Get all items (filtered) const itemCountFiltered = await prisma.item.count({ where: { OR: [ { SKU: { // Probably use prisma's Full-text search if it's out of beta // @ts-ignore contains: req.query.search.length > 0 ? req.query.search : '' } }, { name: { // @ts-ignore contains: req.query.search.length > 0 ? req.query.search : '' } } ] }, orderBy: parseDynamicSortBy(req.query.sort.toString(), req.query.order.toString()) }); // log.core.debug('Dynamic relation:', parseDynamicSortBy(req.query.sort.toString(), req.query.order.toString())); prisma.item .findMany({ take: parseIntOrUndefined(req.query.limit), skip: parseIntOrUndefined(req.query.offset), where: { OR: [ { SKU: { // @ts-ignore contains: req.query.search.length > 0 ? req.query.search : '' } }, { name: { // @ts-ignore contains: req.query.search.length > 0 ? req.query.search : '' } } ] }, orderBy: parseDynamicSortBy(req.query.sort.toString(), req.query.order.toString()), // Get contactInfo, category, storageLocation( storageUnit ) from relations. include: { contactInfo: true, category: true, storageLocation: { include: { storageUnit: { include: { contactInfo: true } } } } } }) .then((items) => { if (items) { res.status(200).json({ total: itemCountFiltered, totalNotFiltered: itemCountNotFiltered, items: items }); } else { res.status(410).json({ status: 'ERROR', errorcode: 'NOT_EXISTING', message: 'Item does not exist' }); } }) .catch((err) => { log.db.error(err); res.status(500).json({ status: 'ERROR', errorcode: 'DB_ERROR', error: err, message: 'An error occurred during the database operation' }); }); } } // Create item. function post(req: Request, res: Response) { // Check if required fields are present. if (!req.body.name) { res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'One or more required fields are missing' }); return; } // Check if status is valid. if (req.body.status !== undefined && !Object.keys(itemStatus).includes(req.body.status)) { res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: `Status is not valid, valid values are: ${Object.keys(itemStatus).join(', ')}` }); return; } prisma.item .create({ data: { SKU: req.body.sku, amount: parseIntOrUndefined(req.body.amount), // FIXME: This is silently failing if NaN.. name: req.body.name, comment: req.body.comment, status: req.body.status, // Only enum(itemStatus) values are valid // Relations contactInfo: parseIntRelation(req.body.contactInfoId, undefined, true), category: parseIntRelation(req.body.categoryId, undefined, true), storageLocation: parseIntRelation(req.body.storageLocationId, undefined, true), manufacturer: req.body.manufacturer, //contents: { // connect: [{ id: 1 }, { id: 2 }, { id: 3 }] //}, //baseItem: { // connect: { // id: req.body.baseitemId // } //}, createdBy: req.body.createdBy } }) .then((data) => { res.status(201).json({ status: 'CREATED', message: 'Successfully created item', id: data.id }); }) .catch((err) => { // Check if an entry already exists. if (err.code === 'P2002') { // P2002 -> "Unique constraint failed on the {constraint}" // https://www.prisma.io/docs/reference/api-reference/error-reference res.status(409).json({ status: 'ERROR', errorcode: 'EXISTING', message: 'Item already exists' }); } else if (err.code == 'P2003') { // P2003 -> "Foreign key constraint failed on the field: {field_name}" // https://www.prisma.io/docs/reference/api-reference/error-reference // FIXME: Is this errormessage right? res.status(404).json({ status: 'ERROR', errorcode: 'NOT_EXISTING', message: 'Item does not exist' }); } else if (err.code == 'P2000') { // P2000 -> "The provided value for the column is too long for the column's type. Column: {column_name}" // https://www.prisma.io/docs/reference/api-reference/error-reference res.status(404).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'One or more fields exceed the maximum length restriction' }); } else { log.db.error(err); res.status(500).json({ status: 'ERROR', errorcode: 'DB_ERROR', error: err, message: 'An error occurred during the database operation' }); } }); } // Update storageLocation. -> Only existing contactInfo. async function patch(req: Request, res: Response) { // Check if required fields are present. if (!req.body.id) { res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'One or more required fields are missing' }); return; } // Check if number is a valid integer if (!Number.isInteger(parseInt(req.body.id.toString()))) { res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'id field must be an integer' }); return; } // Check if status is valid. if (req.body.status !== undefined && !Object.keys(itemStatus).includes(req.body.status)) { res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: `Status is not valid, valid values are: ${Object.keys(itemStatus).join(', ')}` }); return; } prisma.item .update({ where: { id: parseInt(req.body.id) }, data: { SKU: req.body.sku, amount: parseIntOrUndefined(req.body.amount), // FIXME: This is silently failing if NaN.. name: req.body.name, comment: req.body.comment, status: req.body.status, // Only enum(itemStatus) values are valid // Relations contactInfo: parseIntRelation(req.body.contactInfoId), category: parseIntRelation(req.body.categoryId), storageLocation: parseIntRelation(req.body.storageLocationId), manufacturer: req.body.manufacturer, //contents: { // connect: [{ id: 1 }, { id: 2 }, { id: 3 }] //}, //baseItem: { // connect: { // id: req.body.baseitemId // } //}, createdBy: req.body.createdBy }, select: { id: true } }) .then((data) => { res.status(201).json({ status: 'UPDATED', message: 'Successfully updated item', id: data.id }); }) .catch((err) => { // Check if an entry already exists. if (err.code === 'P2002') { // P2002 -> "Unique constraint failed on the {constraint}" // https://www.prisma.io/docs/reference/api-reference/error-reference res.status(409).json({ status: 'ERROR', errorcode: 'EXISTING', message: 'Item already exists' }); } else if (err.code == 'P2003') { // P2003 -> "Foreign key constraint failed on the field: {field_name}" // https://www.prisma.io/docs/reference/api-reference/error-reference res.status(404).json({ status: 'ERROR', errorcode: 'NOT_EXISTING', message: 'Item does not exist' }); } else if (err.code == 'P2000') { // P2000 -> "The provided value for the column is too long for the column's type. Column: {column_name}" // https://www.prisma.io/docs/reference/api-reference/error-reference res.status(404).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'One or more fields exceed the maximum length restriction' }); } else { log.db.error(err); res.status(500).json({ status: 'ERROR', errorcode: 'DB_ERROR', error: err, message: 'An error occurred during the database operation' }); } }); } // Delete item. async function del(req: Request, res: Response) { // Check if required fields are present. if (!req.body.id) { res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'One or more required fields are missing' }); return; } // Does the id exist? If not return 410 Gone. try { const result = await prisma.item.findUnique({ where: { id: parseInt(req.body.id) } }); if (result === null) { res.status(410).json({ status: 'ERROR', errorcode: 'NOT_EXISTING', message: 'Item does not exist' }); return; } } catch (err) { log.db.error(err); res.status(500).json({ status: 'ERROR', errorcode: 'DB_ERROR', error: err, message: 'An error occurred during the database operation' }); } prisma.item .delete({ where: { id: parseInt(req.body.id) } }) .then(() => { res.status(200).json({ status: 'DELETED', message: 'Successfully deleted item' }); }) .catch((err) => { log.db.error(err); res.status(500).json({ status: 'ERROR', errorcode: 'DB_ERROR', error: err, message: 'An error occurred during the database operation' }); }); } export default { get, post, patch, del };