Lazy data processing using Undercut

Photo by Lenny Kuhne on Unsplash

Undercut is a JavaScript library for processing data in a lazy or deferred manner by building pipelines.

The focus of the library is on leveraging existing JavaScript features like Iterators/Generators while having balanced API: not being Java/C# influenced or heavily functional. Undercut also aims to avoid prototype extension and a situation, where you need to name a method as “flat” instead of “flatten”. You may also use it as an alternative to Lodash’s “chain” functionality with support for lazy execution, tree shaking, etc.

Imagine a conveyor on a car factory: a chain of operations from welding body parts and painting doors to gluing a logo and inflating wheels. Every operation is independent and is based only on a protocol: a car comes from this side and goes to that side after the operation is complete.

In JavaScript we may represent this as an array of functions:

Of course, those operations have some input data: this car should have 17" wheels, that car should have 16" wheels. We can do this too:

Calling “skip(1)” creates a function (operation) that knows how to skip exactly 1 item (car).

Sometimes you need to make a new model with additional equipment package. It may be as simple as adding a couple of steps to the conveyor:

Or replacing some steps in existing:

Arrays give you this flexibility to concatenate, merge, copy, and modify existing pipelines.

To finish the conveyor there should be some mechanism like moving belt that will transport a car from one operation from another. This is where Undercut tries to help (not mentioning a pack of 40+ prebuilt common operations like filter/map/skip/etc).

Core pull functions allow you to quickly run a pipeline and acquire the result or combine it into something self-contained and reusable like an Iterable.

Having a list of numbers called “source”:

And a “pipeline” of operations:

We could `pull` items out of the `source` through the `pipeline` and get an array of result items:

In our case “result” will be:

All is done lazily, so “map” won’t run for the skipped item. There’re also “pullValue”, if your result is a single value (not a sequence). Or more generic “pull”, where you pass “target” function getting result items and converting it into whatever you want.

As “pull” is built around Iterables, and many native objects are Iterable out of the box (arrays, strings, maps, sets, etc), you can easily transform a Map of Usernames-by-Id into an Object of Ids-by-Username.

Moreover, you may create a reusable “view” of this data:

The “pullLine” function binds together a “pipeline” and a “source” into an Iterable. Every time you iterate over it, the pipeline will be executed again, giving you a fresh view on processed data.

Every operation is just a function, so you can create your own. Or even create a whole library of your own operations and reuse in different projects. The protocol, operations rely on, is similar to “car-in/car-out”, but instead of cars there’re Iterables. An operation get an Iterable of items to process and return an Iterable of processed items. Returning an Iterable sounds complicated, but it isn’t with JavaScript Generators.

Let’s build a “pow” operation:

Get an Iterable, go by its items, calculate new values, put them into another iterable with “yield”.

If you aren’t familiar with generators (functions marked with “*” asterisk). Basically, the return value of such function will be not what you return, but an implicit Iterable you can put items into with the “yield” keyword. Please read MDN for more detailed description. I also recommend reading an awesome book Exploring ES6 by Dr. Axel Rauschmayer.

Actually, one important aspect is missing. The “exponent” value isn’t defined and should be assigned in a pipeline like those 17" wheels. To fix this just add another function around:

And this “pow” we can actually use:

It was only a brief review of the Undercut, but should be enough for basic use cases. If you want to learn more, please with for documentation and tutorials.

A /dev/null developer and entrepreneur.