diff --git a/src/controllers/producers.ts b/src/controllers/producers.ts index a04ef3d..2f3130f 100644 --- a/src/controllers/producers.ts +++ b/src/controllers/producers.ts @@ -283,7 +283,8 @@ export class ProducersController { }), query: Joi.object({ page: Joi.number().min(1).optional(), - pageSize: Joi.number().min(1).optional() + pageSize: Joi.number().min(1).optional(), + orderBy: Joi.string().valid('currentPrice', 'name').optional() }) }) ]) @@ -294,7 +295,8 @@ export class ProducersController { const options: ProducerProductOptions = { page: Number(req.query.page) || -1, size: Number(req.query.pageSize) || -1, - populate: ['producerProduct.productSpec', 'producerProduct.productionUnit', 'producerProduct_productSpec.images'] + populate: ['producerProduct.productSpec', 'producerProduct.productionUnit', 'producerProduct_productSpec.images'], + orderBy: req.query.orderBy as any // as any is fine here because Joi validates the value }; const producerProducts = await container.producerProductGateway.findAll({ producerId }, options); diff --git a/src/gateways/AddressGateway.ts b/src/gateways/AddressGateway.ts index f51f733..1550812 100644 --- a/src/gateways/AddressGateway.ts +++ b/src/gateways/AddressGateway.ts @@ -31,8 +31,8 @@ export class AddressGateway { const totalItemsQb = qb.clone(); - // Paginate - void qb.offset(pagination.offset).limit(pagination.limit); + // Order & Paginate + void qb.orderBy({ id: 'DESC' }).offset(pagination.offset).limit(pagination.limit); // Fetch results and map them const [totalItems, addresses] = await Promise.all([totalItemsQb.getCount(), qb.getResultList()]); diff --git a/src/gateways/CarrierGateway.ts b/src/gateways/CarrierGateway.ts index 47a1241..e2703b0 100644 --- a/src/gateways/CarrierGateway.ts +++ b/src/gateways/CarrierGateway.ts @@ -26,8 +26,8 @@ export class CarrierGateway { const totalItemsQb = qb.clone(); - // Paginate - void qb.offset(paginataion.offset).limit(paginataion.limit); + // Order & Paginate + void qb.orderBy({ licensePlate: 'ASC' }).offset(paginataion.offset).limit(paginataion.limit); // Fetch results and map them const [totalResults, carriers] = await Promise.all([totalItemsQb.getCount(), qb.getResultList()]); @@ -49,7 +49,8 @@ export class CarrierGateway { { populate: ['productionUnit'], limit: paginataion.limit, - offset: paginataion.offset + offset: paginataion.offset, + orderBy: { licensePlate: 'ASC' } } ), this.repository.count({ productionUnit: { producer: { user: producerId } }, deletedAt: null }) diff --git a/src/gateways/CartItemGateway.ts b/src/gateways/CartItemGateway.ts index 2259e49..699bd6c 100644 --- a/src/gateways/CartItemGateway.ts +++ b/src/gateways/CartItemGateway.ts @@ -19,7 +19,8 @@ export class CartItemGateway { { populate: ['producerProduct', 'producerProduct.producer', 'producerProduct.productionUnit', 'producerProduct.productSpec'], limit: pagination.limit, - offset: pagination.offset + offset: pagination.offset, + orderBy: { producerProduct: { productSpec: { name: 'ASC' } } } } ), this.repository.count({ consumer: { user: consumerId } }) diff --git a/src/gateways/CategoryGateway.ts b/src/gateways/CategoryGateway.ts index c92956c..95cd25d 100644 --- a/src/gateways/CategoryGateway.ts +++ b/src/gateways/CategoryGateway.ts @@ -69,7 +69,8 @@ export class CategoryGateway { const totalResultsQb = qb.clone(); - void qb.leftJoinAndSelect('category.image', 'image').limit(pagination.limit).offset(pagination.offset); + // Order and Pagination + void qb.leftJoinAndSelect('category.image', 'image').orderBy({ name: 'ASC' }).limit(pagination.limit).offset(pagination.offset); const [categories, totalResults] = await Promise.all([qb.getResult(), totalResultsQb.count()]); return { diff --git a/src/gateways/ConsumerGateway.ts b/src/gateways/ConsumerGateway.ts index 32e4e11..3511a12 100644 --- a/src/gateways/ConsumerGateway.ts +++ b/src/gateways/ConsumerGateway.ts @@ -32,7 +32,7 @@ export class ConsumerGateway { public async findAll(options: PaginatedOptions): Promise> { const pagination = paginate(options); const [consumers, totalResults] = await Promise.all([ - this.repository.find({}, { limit: pagination.limit, offset: pagination.offset }), + this.repository.find({}, { limit: pagination.limit, offset: pagination.offset, orderBy: { user: { name: 'ASC' } } }), this.repository.count() ]); @@ -77,7 +77,15 @@ export class ConsumerGateway { public async findAllWithDeletedAt(options: PaginatedOptions): Promise> { const pagination = paginate(options); const [consumers, totalResults] = await Promise.all([ - this.repository.find({}, { filters: { [SOFT_DELETABLE_FILTER]: false }, limit: pagination.limit, offset: pagination.offset }), + this.repository.find( + {}, + { + filters: { [SOFT_DELETABLE_FILTER]: false }, + limit: pagination.limit, + offset: pagination.offset, + orderBy: { user: { name: 'ASC' } } + } + ), this.repository.count({}, { filters: { [SOFT_DELETABLE_FILTER]: false } }) ]); diff --git a/src/gateways/FieldGateway.ts b/src/gateways/FieldGateway.ts index 697d985..edea993 100644 --- a/src/gateways/FieldGateway.ts +++ b/src/gateways/FieldGateway.ts @@ -20,7 +20,7 @@ export class FieldGateway { const pagination = paginate(options); const [fields, totalResults] = await Promise.all([ - this.repository.find({ categories: categoryId }, { limit: pagination.limit, offset: pagination.offset }), + this.repository.find({ categories: categoryId }, { limit: pagination.limit, offset: pagination.offset, orderBy: { name: 'ASC' } }), this.repository.count({ categories: categoryId }) ]); diff --git a/src/gateways/OrderGateway.ts b/src/gateways/OrderGateway.ts index 97d7dfb..3f66092 100644 --- a/src/gateways/OrderGateway.ts +++ b/src/gateways/OrderGateway.ts @@ -33,7 +33,8 @@ export class OrderGateway { fields: ['shippingAddress'], limit: pagination.limit, offset: pagination.offset, - populate: ['items', 'items.shipment.events.status', 'shippingAddress', 'items.producerProduct.producer'] + populate: ['items', 'items.shipment.events.status', 'shippingAddress', 'items.producerProduct.producer'], + orderBy: { id: 'DESC' } } ), this.repository.count({ id: { $in: orderIds } }) @@ -57,7 +58,8 @@ export class OrderGateway { populate: ['items', 'items.shipment.events.status', 'shippingAddress'], fields: ['shippingAddress'], limit: pagination.limit, - offset: pagination.offset + offset: pagination.offset, + orderBy: { id: 'DESC' } } ), this.repository.count({ consumer: { user: consumerId } }) @@ -85,7 +87,8 @@ export class OrderGateway { 'items.producerProduct.productSpec', 'items.producerProduct.producer', 'shippingAddress' - ] + ], + orderBy: { id: 'DESC' } } ); return orders; @@ -94,7 +97,7 @@ export class OrderGateway { public async findByConsumerAndOrder(consumerId: number, orderId: number): Promise { const order = await this.repository.findOne( { consumer: { user: consumerId }, id: orderId }, - { populate: ['items', 'items.shipment.events.status', 'shippingAddress'] } + { populate: ['items', 'items.shipment.events.status', 'shippingAddress'], orderBy: { id: 'DESC' } } ); return order; } @@ -124,7 +127,8 @@ export class OrderGateway { 'items.producerProduct', 'items.producerProduct.productionUnit', 'items.producerProduct.productionUnit.address' - ] + ], + orderBy: { id: 'DESC' } }); return order; } @@ -133,7 +137,8 @@ export class OrderGateway { const orders = await this.repository.find( { consumer: { user: consumerId } }, { - populate: ['items', 'items.shipment', 'items.shipment.events', 'items.shipment.events.status'] + populate: ['items', 'items.shipment', 'items.shipment.events', 'items.shipment.events.status'], + orderBy: { id: 'DESC' } } ); return orders; diff --git a/src/gateways/OrderItemGateway.ts b/src/gateways/OrderItemGateway.ts index 16cda5b..e94d9f8 100644 --- a/src/gateways/OrderItemGateway.ts +++ b/src/gateways/OrderItemGateway.ts @@ -18,6 +18,7 @@ export class OrderItemGateway { .select('oi.order_id', true) .leftJoin('oi.producerProduct', 'pp') .where(`oi.producer_product_id = pp.id and pp.producer_id = '${producerId}'`) + .orderBy({ order: { id: 'DESC' } }) .getResult(); return orderIds; @@ -38,7 +39,8 @@ export class OrderItemGateway { 'order.consumer', 'order.consumer.user', 'order.items.shipment.events.status' - ] + ], + orderBy: { order: { id: 'DESC' } } } ); @@ -65,7 +67,8 @@ export class OrderItemGateway { 'shipment.events.status' ], limit: pagination.limit, - offset: pagination.offset + offset: pagination.offset, + orderBy: { producerProduct: { productSpec: { name: 'ASC' } } } } ), this.repository.count({ order: orderId, producerProduct: { producer: { user: producerId } } }) @@ -83,7 +86,8 @@ export class OrderItemGateway { const orderItem = await this.repository.findOne( { order: orderId, producerProduct: { producer: { user: producerId }, id: producerProductId } }, { - populate: ['producerProduct', 'producerProduct.producer', 'producerProduct.productionUnit', 'producerProduct.productSpec'] + populate: ['producerProduct', 'producerProduct.producer', 'producerProduct.productionUnit', 'producerProduct.productSpec'], + orderBy: { order: { id: 'DESC' } } } ); return orderItem; @@ -96,7 +100,7 @@ export class OrderItemGateway { ): Promise { const orderItem = await this.repository.findOne( { order: orderId, producerProduct: { producer: { user: producerId }, id: producerProductId } }, - { populate: ['shipment', 'shipment.carrier', 'shipment.events.address'] } + { populate: ['shipment', 'shipment.carrier', 'shipment.events.address'], orderBy: { order: { id: 'DESC' } } } ); return orderItem; } @@ -116,7 +120,8 @@ export class OrderItemGateway { ], limit: pagination.limit, offset: pagination.offset, - filters: { [SOFT_DELETABLE_FILTER]: false } + filters: { [SOFT_DELETABLE_FILTER]: false }, + orderBy: { producerProduct: { productSpec: { name: 'ASC' } } } } ), this.repository.count({ order: { id: orderId, consumer: { user: consumerId } } }) @@ -136,7 +141,8 @@ export class OrderItemGateway { { order: { id: orderId, consumer: { user: consumerId } }, producerProduct: { id: producerProductId } }, { populate: ['producerProduct', 'producerProduct.producer', 'producerProduct.productionUnit', 'producerProduct.productSpec'], - filters: { [SOFT_DELETABLE_FILTER]: false } + filters: { [SOFT_DELETABLE_FILTER]: false }, + orderBy: { order: { id: 'DESC' } } } ); return q2; @@ -146,7 +152,8 @@ export class OrderItemGateway { const products = await this.repository.find( { producerProduct: { producer: { user: producerId } } }, { - populate: ['shipment', 'shipment.events', 'shipment.events.status'] + populate: ['shipment', 'shipment.events', 'shipment.events.status'], + orderBy: { order: { id: 'DESC' } } } ); return products; @@ -165,7 +172,8 @@ export class OrderItemGateway { 'shipment.events.status', 'order.items', 'order.items.shipment.events.status' - ] + ], + orderBy: { order: { id: 'DESC' } } } ); return orderItems; diff --git a/src/gateways/ProducerGateway.ts b/src/gateways/ProducerGateway.ts index 3d94968..53dd30e 100644 --- a/src/gateways/ProducerGateway.ts +++ b/src/gateways/ProducerGateway.ts @@ -16,7 +16,7 @@ export class ProducerGateway { public async findAll(options: PaginatedOptions): Promise> { const pagination = paginate(options); const [producers, totalResults] = await Promise.all([ - this.repository.find({}, { limit: pagination.limit, offset: pagination.offset }), + this.repository.find({}, { limit: pagination.limit, offset: pagination.offset, orderBy: { user: { name: 'ASC' } } }), this.repository.count() ]); @@ -59,7 +59,8 @@ export class ProducerGateway { { populate: ['productionUnits'], limit: pagination.limit, - offset: pagination.offset + offset: pagination.offset, + orderBy: { user: { name: 'ASC' } } } ), this.repository.count({ @@ -89,7 +90,8 @@ export class ProducerGateway { { user: id }, { populate: ['productionUnits', 'producerProducts'], - filters: { [SOFT_DELETABLE_FILTER]: false } + filters: { [SOFT_DELETABLE_FILTER]: false }, + orderBy: { user: { name: 'ASC' } } } ); return producer; @@ -103,7 +105,15 @@ export class ProducerGateway { public async findAllWithDeletedAt(options: PaginatedOptions): Promise> { const pagination = paginate(options); const [producers, totalResults] = await Promise.all([ - this.repository.find({}, { filters: { [SOFT_DELETABLE_FILTER]: false }, limit: pagination.limit, offset: pagination.offset }), + this.repository.find( + {}, + { + filters: { [SOFT_DELETABLE_FILTER]: false }, + limit: pagination.limit, + offset: pagination.offset, + orderBy: { user: { name: 'ASC' } } + } + ), this.repository.count({}, { filters: { [SOFT_DELETABLE_FILTER]: false } }) ]); diff --git a/src/gateways/ProducerProductGateway.ts b/src/gateways/ProducerProductGateway.ts index 8a88a8a..7871a3d 100644 --- a/src/gateways/ProducerProductGateway.ts +++ b/src/gateways/ProducerProductGateway.ts @@ -68,8 +68,8 @@ export class ProducerProductGateway { const totalItemsQb = qb.clone(); - // Paginate - void qb.offset(pagination.offset).limit(pagination.limit); + // Order & Paginate + void qb.orderBy({ currentPrice: 'ASC' }).offset(pagination.offset).limit(pagination.limit); // Fetch results and map them const [totalResults, products] = await Promise.all([totalItemsQb.getCount(), qb.getResultList()]); @@ -102,8 +102,11 @@ export class ProducerProductGateway { const totalItemsQb = qb.clone(); - // Paginate - void qb.offset(pagination.offset).limit(pagination.limit); + // Order & Paginate + void qb + .orderBy({ productSpec: { name: 'ASC' } }) + .offset(pagination.offset) + .limit(pagination.limit); // Populate if (options?.populate) { @@ -151,10 +154,10 @@ export class ProducerProductGateway { } if (filter?.search) { - void qb.leftJoin('producerProduct.specification', 'spec').andWhere({ + void qb.andWhere({ $or: [ - { 'lower(spec.name)': { $like: stringSearchType(filter.search) } }, - { 'lower(spec.description)': { $like: stringSearchType(filter.search) } } + { 'lower(producerProduct_productSpec.name)': { $like: stringSearchType(filter.search) } }, + { 'lower(producerProduct_productSpec.description)': { $like: stringSearchType(filter.search) } } ] }); } @@ -162,6 +165,16 @@ export class ProducerProductGateway { // Calculate items count before grouping and paginating const totalItemsQb = qb.clone(); + // Order + switch (options?.orderBy) { + case 'currentPrice': + void qb.orderBy({ currentPrice: 'ASC' }); + break; + case 'name': + default: + void qb.orderBy({ 'producerProduct_productSpec.name': 'ASC' }); + } + // Paginate void qb.offset(pagination.offset).limit(pagination.limit); diff --git a/src/gateways/ProductSpecCategoryGateway.ts b/src/gateways/ProductSpecCategoryGateway.ts index 8e9b24f..676c436 100644 --- a/src/gateways/ProductSpecCategoryGateway.ts +++ b/src/gateways/ProductSpecCategoryGateway.ts @@ -29,6 +29,7 @@ export class ProductSpecCategoryGateway { .leftJoinAndSelect('category.parent', 'parent') .limit(pagination.limit) .offset(pagination.offset) + .orderBy({ category: { name: 'ASC' } }) .getResult(), this.repository .createQueryBuilder('productSpecCategory') diff --git a/src/gateways/ProductSpecFieldGateway.ts b/src/gateways/ProductSpecFieldGateway.ts index d8b4e3e..757007c 100644 --- a/src/gateways/ProductSpecFieldGateway.ts +++ b/src/gateways/ProductSpecFieldGateway.ts @@ -28,7 +28,12 @@ export class ProductSpecFieldGateway { const [productSpecField, totalResults] = await Promise.all([ this.repository.find( { productSpecCategory: { productSpec: productSpecId, category: categoryId } }, - { fields: ['field', 'value'], limit: pagination.limit, offset: pagination.offset } + { + fields: ['field', 'value'], + limit: pagination.limit, + offset: pagination.offset, + orderBy: { productSpecCategory: { category: { name: 'ASC' } }, field: { name: 'ASC' } } + } ), this.repository.count({ productSpecCategory: { productSpec: productSpecId, category: categoryId } }) ]); diff --git a/src/gateways/ProductSpecGateway.ts b/src/gateways/ProductSpecGateway.ts index 3cdad3e..cd72a97 100644 --- a/src/gateways/ProductSpecGateway.ts +++ b/src/gateways/ProductSpecGateway.ts @@ -96,12 +96,11 @@ export class ProductSpecGateway { .addSelect('MIN(producerProduct.current_price) as minPrice') .addSelect('MAX(producerProduct.current_price) as maxPrice'); - // Paginate - void qb.offset(pagination.offset).limit(pagination.limit); + // Order & Paginate + void qb.orderBy({ name: 'ASC' }).offset(pagination.offset).limit(pagination.limit); // Fetch results and map them const [miscData, productSpecs] = await Promise.all([miscQb.execute('get'), qb.getResultList()]); - console.log('\n\n\n\n\n\n', qb.getQuery(), '\n\n\n\n\n\n'); const totalPages = Math.ceil(miscData.totalItems / pagination.limit); const page = Math.ceil(pagination.offset / pagination.limit) + 1; diff --git a/src/gateways/ProductionUnitGateway.ts b/src/gateways/ProductionUnitGateway.ts index 454be63..c17fc8e 100644 --- a/src/gateways/ProductionUnitGateway.ts +++ b/src/gateways/ProductionUnitGateway.ts @@ -50,8 +50,8 @@ export class ProductionUnitGateway { const totalItemsQb = qb.clone(); - // Paginate - void qb.offset(pagination.offset).limit(pagination.limit); + // Order & Paginate + void qb.orderBy({ name: 'ASC' }).offset(pagination.offset).limit(pagination.limit); // Fetch results and map them const [totalItems, productionUnits] = await Promise.all([totalItemsQb.getCount(), qb.getResultList()]); @@ -88,7 +88,7 @@ export class ProductionUnitGateway { products: { productSpec: specId }, producer: { user: producerId } }, - { populate: ['address'] } + { populate: ['address'], orderBy: { name: 'ASC' } } ); return productionUnits; } diff --git a/src/interfaces/ProducerProductOptions.ts b/src/interfaces/ProducerProductOptions.ts index 2012ce2..101ddba 100644 --- a/src/interfaces/ProducerProductOptions.ts +++ b/src/interfaces/ProducerProductOptions.ts @@ -1,4 +1,6 @@ import type { PaginatedOptions } from './PaginationOptions'; import type { PopulateOptions } from './PopulateOptions'; -export interface ProducerProductOptions extends PaginatedOptions, PopulateOptions {} +export interface ProducerProductOptions extends PaginatedOptions, PopulateOptions { + orderBy?: 'name' | 'currentPrice'; +}