Skip to content

janis-commerce/lambda-model-wrapper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

32 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Lambda Model Wrapper

Build Status Coverage Status npm version

A package to simplify wrapper model lambda functions in Janis Services

๐Ÿ“ฅ Installation

npm install @janiscommerce/lambda-model-wrapper

๐Ÿ“ƒ Usage

LambdaGet

LambdaGet is used to wrap the get() and getPaged() method from models.

Configuration

  • The getter modelClass should return the Model for our entity.
  • You can use mustHaveClient to defines if the function will be used for Client models. default true.
  • You can use mustHavePayload to make payload mandatory or not. default false.

โ„น๏ธ The payload is used to apply params to the get() method, this will be explained below.

Parameters

All parameters are optional

  • fields. String Array to reduce response. For more information see @janiscommerce/model.
  • excludeFields. String Array to reduce response. Since 2.1.0. For more information see @janiscommerce/model.
  • allItems. Boolean to obtain all items, using getPaged() method. default false. Since 2.0.0
  • calculateTotals. Boolean to calculate totals with getTotals() method. default false. Since 2.0.0
  • filters, page, limit, order, changeKeys. Classic get() parameters. For more information see @janiscommerce/model.
  • formatParams. Object to pass parameters to format() method. Since 2.1.0. See Formatting results below.
  • onlyTotals. Boolean to only calculate totals with optional filters. Since 4.0.0.

Formatting results

The optional method async format(items, formatParams) allows you to format every item. The formatParams can be used give different behaviors to the function.

Totals

To obtain the totals object is required to

Response

The response of the lambda functions is explained in the @janiscommerce/lambda package.

Examples

First you need to create your lambda function.

'use strict';

const { Handler } = require('@janiscommerce/lambda');
const { LambdaGet } = require('@janiscommerce/lambda-wrapper-model');

const ProductModel = require('../../models/product');

class GetProduct extends LambdaGet {

	get modelClass() {
		return ProductModel;
	}

	async format(items, { countImages }) {
		return items.map(item => ({
			...item,
			...countImages && { imagesCount: item?.images.length || 0 }
		}));
	}
}

module.exports.handler = (...args) => Handler.handle(GetProduct, ...args);

For using the lambda you need to invoke with the @janiscommerce/lambda package.

'use strict';

const { Invoker } = require('@janiscommerce/lambda');

async () => {

	const response = await Invoker.clientCall('GetProduct', 'my-client-code');

	/**
	 *	response.payload: {
		 	items: [
				{ id: 1, referenceId: 'coke-2lt', name: 'Coke lts', stock: 100, images: ['coke-2lt.jpg'] },
				{ id: 2, referenceId: 'pepsi-2lt', name: 'Pepsi 2lts', stock: 100 },
				{ id: 3, referenceId: 'fanta-2lt', name: 'Fanta 2lts', stock: 95 }
			]
	 	}
	 */

	const filteredResponse = await Invoker.clientCall('GetProduct', 'my-client-code', {
		filters: { stock: 100 },
		fields: ['referenceId', 'images'],
		calculateTotals: true,
		formatParams: { countImages: true }
	});

	/**
	 *	filteredResponse.payload: {
		 	items: [
				{ id: 1, referenceId: 'coke-2lt', images: ['coke-2lt.jpg'], imagesCount: 1 },
				{ id: 2, referenceId: 'pepsi-2lt', imagesCount: 0 }
			],
			totals: { total: 2, page: 1 }
	 	}
	 */

};

๐Ÿงฎ LambdaGroupAggregate

The LambdaGroupAggregate wrapper allows you to easily create a Lambda that performs a MongoDB aggregate() with a simple $group by a specific field.

This wrapper is designed for one Lambda per service, and supports grouping for multiple entities using a common pattern.

โœ… When to use

Use LambdaGroupAggregate if you want to expose a Lambda that groups documents by a specific field and returns a count for each group.

๐Ÿ“ฆ Usage

Extend the LambdaGroupAggregate class and define the entities getter with the available entities for this service.

Each entity must be mapped to its corresponding model class.

'use strict';

const { Handler } = require('@janiscommerce/lambda');
const { LambdaGroupAggregate } = require('@janiscommerce/lambda-model-wrapper');

const ProductModel = require('./models/product');
const ProductImageModel = require('./models/product-image');
const BrandModel = require('./models/brand');

class GroupAggregate extends LambdaGroupAggregate {

	get entities() {
		return {
			product: ProductModel
			'product-image': ProductImageModel,
			brand: BrandModel
		};
	}
};

module.exports.handler = (...args) => Handler.handle(GroupAggregate, ...args);

๐Ÿ“ค Expected Input

The request body should include the following:

{
	"entity": "product",
	"field": "status"
}
  • entity: The key defined in the entities getter (e.g. 'product')
  • field: The field in the model to group by (e.g. 'status')

๐Ÿ“ฅ Response

The Lambda will respond with an object containing the group values and the corresponding counts:

{
	"active": 450,
	"inactive": 20,
	"error": 1
}

โš ๏ธ Field Index Requirement

Important: The field provided in the request body must have an index defined in the corresponding MongoDB collection.

Internally, the aggregation uses a hint to force index usage:

If the specified field is not indexed with { [field]: 1 }, the lambda will fail with an error like:

MongoServerError: hint provided does not correspond to an existing index

โœ… Make sure to create the appropriate index in your model or migration before using this lambda.

๐Ÿงช Example Aggregation

Internally, the Lambda will run a simple $group aggregation on the selected model:

await model.aggregate([
	$group: {
		_id: `$${field}`,
		count: { $sum: 1 }
	},
], {
	allowDiskUse: true,
	hint: { [${field}]: 1 }
});

๐Ÿ“ก How to invoke

To call a Lambda using LambdaGroupAggregate, use the @janiscommerce/lambda package from another service.

'use strict';

const { Invoker } = require('@janiscommerce/lambda');

const result = await Invoker.clientCall('your-service-name', 'your-lambda-name', {
	entity: 'product',
	field: 'status'
});

โœ… Result

The result will be an object mapping the grouped field values to their count:

{
	active: 450,
	inactive: 20,
	error: 1
}
  • If the entity or field is missing or invalid, the Lambda will respond with a 400 error.
  • If the model returns no data, an empty object will be returned.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published