An InRiver iPMC instance typically imports raw data from various data sources into fields. It happens by automated import (using an inbound connector) or from manual upload or data entry. Some of these fields, might have raw values that cannot be used directly by destination systems, and so they need to be transformed into other values.
In this blog post, I demonstrate how to implement an extension that transforms a color value into a color group value.
Scenario
For the rest of this blog posts, let's say I work for an online fashion retailer that uses the InRiver iPMC platform. Because of that, their iPMC instance contains clothes, shoes, accessories. Everything you would expect from such an online retailer.
To make it easy to search and filter products, they need a color picker on our product listing page. It should be one that makes it easy to select one of, let’s say, 20 main colors (e.g. red, blue, white, black, grey, green etc.). The color picker should NOT show every possible color that manufacturers can come up with (that would be way too many to show).
In short: each item needs a field with the main color (I call it a color group) of the item. This is something that should be automated, since no one would like to manually fill in.
The main question in this blog post is:
How can InRiver iPMC be extended, so that it will translate a specific color code or color name into a predefined color group (a CVL value), whenever an entity is updated by automated import, bulk upload or manual edits?
Solution outline
In order to support transformation of field values in automated import, bulk upload and manual editing, I have implemented an entity listener extension. This provides a single and generic implementation. Whenever an original value is saved (by a connector or by the portal), this entity listener will be executed just after.
Since my extension is looking up a color group value, based on a brand name (product specific) and a color ID (item specific), it relies on both entity types. If an item entity is updated, the product entity is also looked up, and vice versa.
I also implemented a link extension, because a link between a product and an item can be added or updated. In that case, the color group value should be transformed again.
Now, whenever an item, a product or a link between those is updated, these steps get executed:
- Load both the product and item entities.
- Get the product brand and the item color ID from the two entities.
- Find the color group CVL key in a table, by brand name and color ID.
- Store the CVL key in the color group field.
That’s it. Sounds easy? To some extend it is.
Implementation notes
There is just one problem: we cannot create our own data tables in iPMC.
I considered compiling an XML or JSON document as a resource file in the binary assembly. However, that is not really flexible. Whenever a new brand name or color ID needs to be added, a developer would need to recompile the solution and deploy a new package. Also, the extension is stateless and we cannot count on the data being cached between each event invocation.
Another possibility could be to simply store that data document as an extension setting. Extension settings get injected into a dictionary in the extension class, and we can read the document from there. That would be a flexible solution as this setting can be changed at runtime. However, this solution is not really scalable. Just think about how large an XML document with 10.000+ entries can be.
For my solution I did something else and created a table in Azure Table Storage.
In short, Azure Table Storage is a simple schema-less NoSQL database, that is very scalable at a low cost. It does not support SQL features such as relations, joins or custom indices, and generally promotes denormalization and flat tables.
In Azure Table Storage, each table entity always has exactly two index fields (a partition key and a row key) that make up a primary key, along with a read-only timestamp field. Then comes our own custom fields.
In my solution I need to store entities that consists of just three fields: BrandName, ColorID and CvlKey. It just so happens that the first two of my fields make up a unique combination that qualifies as a primary key. Since my extension can look up the color group by both key fields, the extension can query entities in the most efficient way (point queries).
This is how a list of entities looks like.
For an updated entity, the full transformation process looks like this. For an added entity, or an added or updated link, there are only minor differences.
You will find the source code to my solution here. If you decide to take it for a spin, see the extension settings you need to configure in the table below.
Settings key | Default value | Notes |
---|---|---|
ITEM_ENTITY_TYPE_ID | Item | Name of item entity. |
PRODUCT_ENTITY_TYPE_ID | Product | Name of product entity. |
PRODUCTITEM_LINK_TYPE_ID | ProductItem | Name of product to item link. |
BRAND_FIELD_TYPE_ID | ProductBrand | Name of brand field on product entity. |
COLORID_FIELD_TYPE_ID | ItemColorId | Name of color id field on item entity. |
COLORGROUP_FIELD_TYPE_ID | ItemColorGroup | Name of color group field on item entity. The field needs to be a CVL field, and the CVL keys must match those in the Azure table. |
TABLE_CONNECTION_STRING | N/A | Connection string taken from Azure. |
TABLE_NAME | N/A | Name of the Azure table. |
Summary
For this blog post I came up with a way in which InRiver iPMC can transform imported values into other values based on data in a custom table in the Azure cloud. You will find my source code here.
In my solution and description, I demonstrated how to transform a specific color into a color group value. However, this method can be used for a range of other applications. Maybe your client needs to convert weight or dimensions between metric and imperial units, or something else that I cannot think of.
I know that I skipped over the details of setting up and working with a table in Azure Table Storage. But here you can read about how to design a table or how to get started developing against the tables.
You are also welcome to leave a comment, if you have questions about the solution or about working with the table storage.