I'm using Lodash to do some work on our object. So I had a little problem that I can't solve.
I'm trying to add the result of a query, in the _.transform array. But without success.
The return is empty.
I did some tests using the console.log and the value is shown normally.
const result = _.transform(data.items, async (r: any, v: any) => {
let data = await Cliente.query().where('id', '=', v.codiPsv).orderBy('validade', 'asc').first()
if (data){
console.log(data.serialize()) --> Show object
r.push(data.serialize())
console.log(0)
}
})
console.log(result) --> empty
Resolved
const cods = _.map(data.items, 'codiPsv')
const items = await Cliente.query().whereIn('id', cods).orderBy('validade', 'desc')
const itemsSerelialize = items.map((item) => item.serialize())
const result = _.transform(data.items, async (r: any, v: any) => {
const item = _.filter(itemsSerelialize, {'id':v.codiPsv}).slice(-1).pop()
if ( !_.isUndefined( item )) {
r.push(item)
} else {
console.log(v)
r.push({'local': 'Indisponível', ...v})
}
})
var user1 = {
name: 'Nady',
active: true,
cart: [],
purchase: [],
};
var compose = function test1(f, g) {
return function test2(...args) {
return f(g(...args));
};
};
function userPurchase(...fns) {
return fns.reduce(compose);
}
userPurchase(
empty,
addItemToPurchase,
applayTax,
addItemToCart
)(user1, { name: 'laptop', price: 876 });
function addItemToCart(user, item) {
return { ...user, cart: [item] };
}
function applayTax(user) {
var { cart } = user;
var taxRate = 1.3;
var updatedCart = cart.map(function updateCartItem(item) {
return { ...item, price: item.price * taxRate };
});
return { ...user, cart: updatedCart };
}
function addItemToPurchase(user) {
return { ...user, purchase: user.cart };
}
function empty(user) {
return { ...user, cart: [] };
}
I don't understand this example well. I tried stepping through it with the debugger and concluded the following:
When I call function userPurchase the reduce will work and at its end f will be test2 and g will be addItemToCart then test2 is returned as the accumulated. Then we call it passing (user1, { name: 'laptop', price: 876 }) as arguments and g is called in it that is addItemToCart.
I don't understand how g is changed to applayTax, then addItemToPurchase, then empty every time function test2 call itself.
How or why this is happening?
The thing that may have gotten you confused is taking the term accumulator literally. By convention that's the name of the first argument to a reducer. But it's not necessary to use it to accumulate a value. In this case it is used to compose a series of functions.
The real meaning of the first argument to a reducer is previouslyReturnedValue:
function compose(previouslyReturnedValue, g) {
return function (...args) {
return previouslyReturnedValue(g(...args));
};
}
So let's walk through this loop:
[empty, addItemToPurchase, applayTax, addItemToCart].reduce(
(f,g) => {
return (...args) => {
return f(g(...args));
}
}
);
The first round of the loop, f = empty and g = addItemToPurchase. This will cause compose to return:
return (...args) => {
return empty(addItemToPurchase(...args));
}
Leaving the array to become: [applayTax, addItemToCart]
The second round of the loop f = (...args) => {return empty(addItemToPurchase(...args))} and g = applyTax. This will cause compose to return:
return (...args) => {
return empty(addItemToPurchase(applyTax(...args)));
}
We continue with this logic until we finally get compose to return the full chain of functions:
return (...args) => {
return empty(addItemToPurchase(applyTax(addItemToCart(...args))));
}
Alternate view of the same process
If the above is a bit hard to follow then let's name the anonymous function that becomes f in each loop.
In the first round we get:
function f1 (...args) {
return empty(addItemToPurchase(...args));
}
In the second round we get:
function f2 (...args) {
return f1(applyTax(...args));
}
In the final round we get:
function f3 (...args) {
return f2(addItemToCart(...args));
}
It is this function f3 that is returned by reduce(). So when you call the return value of reduce it will try to do:
f2(addItemToCart(...args))
Which will call addItemToCart() and then call f2 which will execute:
f1(applyTax(...args))
Which will call applyTax() and then call f1 which will execute:
empty(addItemToPurchase(...args))
Which will call addItemToPurchase() and then call empty()
TLDR
Basically all this is doing:
let tmp;
tmp = addItemToCart(args);
tmp = applyTax(tmp);
tmp = addItemToPurchase(tmp);
tmp = empty(tmp);
More readable version
There is a way to implement this logic which is more readable and easier to understand if we abandon reduce(). I personally like the functional array methods like map() and reduce() but this is one of those rare situations where a regular for loop may lead to much more readable and debuggable code. Here's a simple alternative implementation that does exactly the same thing:
function userPurchase(...fns) {
return function(...args) {
let result = args;
// The original logic apply the functions in reverse:
for (let i=fns.length-1; i>=0; i--) {
let f = fns[i];
result = f(result);
}
return result;
}
}
Personally I find the implementation of userPurchase using a for loop much more readable than the reduce version. It clearly loops through the functions in reverse order and keep calling the next function with the result of the previous function.
Does this help at all?
var user1 = {
name: 'Nady',
active: true,
cart: [],
purchase: [],
};
function compose(f, g) {
const composition = function(...args) {
console.log('f name', f.name);
console.log('g name', g.name);
return f(g(...args));
};
Object.defineProperty(composition, 'name', {
value: 'composition_of_' + f.name + '_and_' + g.name,
writable: false
});
return composition;
};
function userPurchase(...fns) {
return fns.reduce(compose);
}
function addItemToCart(user, item) {
return { ...user, cart: [item] };
}
function applayTax(user) {
var { cart } = user;
var taxRate = 1.3;
var updatedCart = cart.map(function updateCartItem(item) {
return { ...item, price: item.price * taxRate };
});
return { ...user, cart: updatedCart };
}
function addItemToPurchase(user) {
return { ...user, purchase: user.cart };
}
function empty(user) {
return { ...user, cart: [] };
}
const result = userPurchase(
empty,
addItemToPurchase,
applayTax,
addItemToCart
)(user1, { name: 'laptop', price: 876 });
console.log(result);
Let's say you need to take in a number, add ten to it and then double it. You could write some functions like:
const add_ten = function(num) { return num + 10; };
const double = function(num) { return num * 2; };
const add_ten_and_double = function(num) { return double(add_ten(num)); };
You could also write the same thing as:
function compose(outer_function, inner_function) {
return function(num) {
return outer_function(inner_function(num));
};
};
const add_ten = function(num) { return num + 10; };
const double = function(num) { return num * 2; };
const add_ten_and_double = compose(double, add_ten);
console.log('typeof add_ten_and_double:', typeof add_ten_and_double);
console.log('add_ten_and_double:', add_ten_and_double(4));
Using compose, we've created a function that does the same thing as our original add_ten_and_double function. Does that make sense up to here? (Point A).
If we then decided to add five we could have:
function compose(outer_function, inner_function) {
return function(num) {
return outer_function(inner_function(num));
};
};
const add_ten = function(num) { return num + 10; };
const double = function(num) { return num * 2; };
const add_five = function(num) { return num + 5; };
const add_ten_and_double_and_add_five = compose(compose(add_five, double), add_ten);
console.log('typeof add_ten_and_double_and_add_five :', typeof add_ten_and_double_and_add_five);
console.log('add_ten_and_double_and_add_five :', add_ten_and_double_and_add_five(4));
Now we've run compose using a function and a function that was composed of two other functions, but what we've got back is still just a function that takes a number and returns a number. Does that make sense up to here? (Point B).
If we wanted to add a few more functions then we would end up with a lot of compose calls in our code, so we could just say "give me the composition of all of these functions", and it might look like:
function compose(outer_function, inner_function) {
return function(num) {
return outer_function(inner_function(num));
};
};
const add_ten = function(num) { return num + 10; };
const double = function(num) { return num * 2; };
const add_five = function(num) { return num + 5; };
functions_to_compose = [add_five, double, add_ten];
let composition;
functions_to_compose.forEach(function(to_compose) {
if(!composition)
composition = to_compose;
else
composition = compose(composition, to_compose);
});
const add_ten_and_double_and_add_five = composition;
console.log('typeof add_ten_and_double_and_add_five:', typeof add_ten_and_double_and_add_five);
console.log('add_ten_and_double_and_add_five:', add_ten_and_double_and_add_five(4));
The fns.reduce(compose); in userPurchase in your code is basically doing the same thing as the forEach loop here, but neater. Does that make sense why add_ten_and_double_and_add_five is a function that you can pass in a number and all of the operations from functions_to_compose are being applied (last to first) to the number? (Point C).
Renaming
Part of the problem is simply in naming. It would help to introduce one more function, and to rename two others.
var composeTwo = function test1(f, g) {
return function test2(...args) {
return f(g(...args));
};
};
function composeMany(...fns) {
return fns.reduce(composeTwo);
}
const userPurchase = composeMany(
empty,
addItemToPurchase,
applyTax,
addItemToCart
)
userPurchase(user1, { name: 'laptop', price: 876 });
//=> {active: true, cart: [], name: "Nady", purchase: [{name: "laptop", price: 1138.8}]}
// other functions elided
composeTwo (originally called compose) is a function that accepts two functions and returns a new one which accepts some input, calls the second function with that input and then calls the first function with the result. This is straightforward mathematical composition of functions.
composeMany (which as originally called -- very confusingly -- userPurchase) extends this composition to work on a list of functions, using reduce to sequentially call each function on the result of the pipeline so far, starting with the arguments passed. Note that it works from the last item in the list to the first one.
We use this to define the new userPurchase, which passes empty, addItemToPurchase, applyTax and addItemToCart to pipeline. This returns a function that will then apply them in sequence, doing something equivalent to function (...args) {return empty1(addItemToPurchase(applyTax(addItemToCart(...args))))}
We can see this in action in this snippet:
var user1 = {
name: 'Nady',
active: true,
cart: [],
purchase: [],
};
var composeTwo = function test1(f, g) {
return function test2(...args) {
return f(g(...args));
};
};
function composeMany (...fns) {
return fns.reduce(composeTwo);
}
const userPurchase = composeMany (
empty,
addItemToPurchase,
applyTax,
addItemToCart
)
console .log (
userPurchase(user1, { name: 'laptop', price: 876 })
)
function addItemToCart(user, item) {
return { ...user, cart: [item] };
}
function applyTax(user) {
var { cart } = user;
var taxRate = 1.3;
var updatedCart = cart.map(function updateCartItem(item) {
return { ...item, price: item.price * taxRate };
});
return { ...user, cart: updatedCart };
}
function addItemToPurchase(user) {
return { ...user, purchase: user.cart };
}
function empty(user) {
return { ...user, cart: [] };
}
.as-console-wrapper {max-height: 100% !important; top: 0}
Modern Syntax
However, I would find this much cleaner with a more modern JS syntax. This is very much equivalent, but cleaner:
const composeTwo = (f, g) => (...args) =>
f (g (...args))
const composeMany = (...fns) =>
fns .reduce (composeTwo)
// .. other functions elided
const userPurchase = composeMany (
empty,
addItemToPurchase,
applyTax,
addItemToCart
)
Here it should be obvious that composeTwo takes two functions and returns a function. And in knowing that and understanding .reduce, it should be clear that composeMany takes a list of functions and returns a new function. This version, which also applies this change to the remaining functions is available in this snippet:
var composeTwo = (f, g) => (...args) =>
f (g (...args))
const composeMany = (...fns) =>
fns .reduce (composeTwo)
const addItemToCart = (user, item) =>
({ ...user, cart: [item] })
const applyTax = (user) => {
var { cart } = user;
var taxRate = 1.3;
var updatedCart = cart .map (item => ({ ...item, price: item .price * taxRate }))
return { ...user, cart: updatedCart };
}
const addItemToPurchase = (user) =>
({ ...user, purchase: user.cart })
const empty = (user) =>
({ ...user, cart: [] })
const userPurchase = composeMany (
empty,
addItemToPurchase,
applyTax,
addItemToCart
)
const user1 = {
name: 'Nady',
active: true,
cart: [],
purchase: [],
};
console .log (
userPurchase (user1, { name: 'laptop', price: 876 })
)
.as-console-wrapper {max-height: 100% !important; top: 0}
How reduce and composeTwo work together
Here we try to demonstrate how reduce works with composeTwo to compose multiple functions into one.
In the first step, the init parameter to reduce is missing, so JS uses the first value in the array as the initial one, and starts iterating with the second one. So reduce first calls composeTwo with empty and addItemToPurchase, yielding a function equivalent to
(...args) => empty (addItemsToPurchase (...args))
Now reduce passes that function and applyTax to compose, yielding a function like
(...args) => ((...args2) => empty (addItemsToPurchase (...args2))) (applyTax (...args))
Now this is structured like the following:
(x) => ((y) => f ( g (y)) (h (x))
where x represents ...args, y represents ...args2, f represents empty, g represents addItems, and h represents applyTax.
but the right-hand side is a function ((y) => f ( g ( y))) with the value h (x) applied to it. This is the same as replacing y in the body with h(x), yielding f (g (h (x))), so that this function is equivalent to (x) => f (g (h (x))), and by replacing our original values, this ends up as
(...args) => empty (addItemsToPurchase (applyTax ( ...args)))
Do note that this application of values to the function does not happen now when the function is being built. It will happen when the resulting function is called. In memory, this is still something like (...args) => ((...args2) => empty (addItems (...args2))) (applyTax (...args)). But this logical version shows how it will work.
Of course we now do it again for addItemToCart:
(...args) => ((...args2) => empty (addItemsToPurchase (applyTax ( ...args2)))) (addItemToCart (...args))
and by the same sort of application, we get the equivalent of
(...args) => empty (addItems (applyTax ( addItemToCart (...args))))
Which is the basic definition of the composition of those functions.
Cleaning up the tax rate
There's something strange about the hard-coded tax rate. We can fix that by making a parameter used in calling userPurchase. This also allows us to clean up the applyTax function:
const applyTax = (taxRate) => ({cart, ...rest}) => ({
... rest,
cart: cart .map (item => ({ ...item, price: item .price * taxRate }))
})
const userPurchase = (taxRate) => composeMany (
empty,
addItemToPurchase,
applyTax(taxRate),
addItemToCart
)
// ...
userPurchase (1.3) (user1, { name: 'laptop', price: 876 })
Note that the curried nature of this parameter lets us choose to apply just this value to get back a tax-rate specific function:
const someDistrictPurchase = userPurchase (1.12) // 12% tax
someDistrictPurchase(user, item)
Which we can see in one more snippet:
var composeTwo = (f, g) => (...args) =>
f (g (...args))
const composeMany = (...fns) =>
fns .reduce (composeTwo)
const addItemToCart = (user, item) =>
({ ...user, cart: [item] })
const applyTax = (taxRate) => ({cart, ...rest}) => ({
... rest,
cart: cart .map (item => ({ ...item, price: item .price * taxRate }))
})
const addItemToPurchase = (user) =>
({ ...user, purchase: user.cart })
const empty = (user) =>
({ ...user, cart: [] })
const userPurchase = (taxRate) => composeMany (
empty,
addItemToPurchase,
applyTax(taxRate),
addItemToCart
)
var user1 = { name: 'Nady', active: true, cart: [], purchase: []}
console .log (
userPurchase (1.3) (user1, { name: 'laptop', price: 876 })
)
.as-console-wrapper {max-height: 100% !important; top: 0}
Lessons
Function composition is an essential part of functional programming (FP). While it helps to have functions like composeTwo and composeMany, it is much better if they have understandable names. (Note that compose is a perfectly legitimate name for the first one. My change here was just to make the distinction with composeMany clearer.) The biggest problem, to my mind was the original name of userPurchase as a composition function. That confuses a lot of things.
Modern JS (arrow functions, rest/spread, and destructuring) makes for code that is not only more succinct but generally easier to understand.
I want the result of activeCustomers array inside the last then but I keep getting an error saying arrow function expects a return. Not sure how I can get activeCustomers?
const CreateCustomer = (storeData) => {
let activeOrganization = null;
storeData.Org
.getOrganization()
.then(function createCustomer(organization) {
activeOrganization = organization[0];
const dataArray= storeData.attributes;
activeOrganization
.createAttributes(
attributeType[0],
getSomeData(dimensions)
)
.then(function Properties(createdAttribute) {
updateCustomerProperty(createdAttribute, attributeType[0]);
});
activeOrganization
.createAttributes(
attributeType[1],
getSomeData(dimensions)
)
.then(function Properties(createdAttribute) {
updateCustomerProperty(createdAttribute, attributeType[1]);
});
}).then(() => {
activeOrganization
.getCustomers()
.then((cusomters) => {
const activeCustomers = [];
cusomters.map((customer) => {
activeCustomers.push(customer);
});
return activeCustomers;
})
.then((activeCustomers) => {
console.log(activeCustomers);
});
});
};
//Now I want the result of activeCustomers array inside the last then but I keep getting an error saying arrow function expects a return. Not sure how I can get activeCustomers?
I want the result of activeCustomers array inside the last then but I keep getting an error saying arrow function expects a return. Not sure how I can get activeCustomers?
In your example i think you received a warning. But still how to access to activeCustomers it depends on how you want to use it there are you storing it.
If you want to store it globally then you can store it like that
let activeCustomers;
....
.then((cusomters) => {
activeCustomers = [];
cusomters.map((customer) => {
activeCustomers.push(customer);
});
return activeCustomers;
})
But i think it's better to rewrite to async/await.
const CreateCustomer = async (storeData) => {
let activeOrganization = null;
const [activeOrganization] = await storeData.Org
.getOrganization();
const activeOrgPrs = attributeType.map(x => activeOrganization
.createAttributes(
x,
getSomeData(dimensions)
)));
const attrs = await Promise.all(activeOrgPrs);
attrs.forEach((attr, i) => {
updateCustomerProperty(attr, attributeType[i]);
})
const cusomters = await activeOrganization
.getCustomers();
return cusomters;
};
And you can use it like const customers = await CreateCustomer(someData);
or like CreateCustomer(someData).then((cusomters) => { activeCustomers = cusomters; return null;(if it keeps to return errors)});
I have a function which returns an object with properties only which are defined.
How to refactor the function so that I don't need to make if clauses for every parameter value? There must be more elegant way to do this.
const getQuery = ({ foo, bar, zoo }) => {
const query = {};
if (foo) {
query.foo = foo;
}
if (bar) {
query.bar = bar;
}
if (zoo) {
query.zoo = zoo;
}
return query;
}
I would do something like
function getQuery(obj){
// filter the accepted keys
var filtered = Object.keys(obj).filter((k) => ~["foo", "bar", "baz"].indexOf(k))
// construct new object with filtered keys
var query = {}
filtered.forEach((k) => query[k] = obj[k])
return query
}
Here's a basic function that will copy only properties provided in the wantedProps array. It will not mutate the original object.
let filterProperties = (originalObject = {}, wantedProps = []) =>
{
let filteredObject = {};
wantedProps.forEach( val => filteredObject[val] = originalObject[val] );
return filteredObject;
}
If you're just trying to filter out undefined vals then you could do:
obj => {
let newObject = {}
Object.keys(obj).forEach(key => {
if(obj[key] !== undefined) newObject[key] = obj[key];
})
return newObject;
}
Can someone provide an example on how to use the beforeEach? http://www.node-tap.org/api/
Ideally, an example of the promise version, but a callback version example would also be nice.
Here is a test I created which works fine:
'use strict';
const t = require('tap');
const tp = require('tapromise');
const app = require('../../../server/server');
const Team = app.models.Team;
t.test('crupdate', t => {
t = tp(t);
const existingId = '123';
const existingData = {externalId: existingId, botId: 'b123'};
const existingTeam = Team.create(existingData);
return existingTeam.then(() => {
stubCreate();
const newId = 'not 123'
const newData = {externalId: newId, whatever: 'value'};
const newResult = Team.crupdate({externalId: newId}, newData);
const existingResult = Team.crupdate({externalId: existingId}, existingData);
return Promise.all([
t.equal(newResult, newData, 'Creates new Team when the external ID is different'),
t.match(existingResult, existingTeam, 'Finds existing Team when the external ID exists')
]);
});
})
.then(() => {
process.exit();
})
.catch(t.threw);
function stubCreate() {
Team.create = data => Promise.resolve(data);
}
Before I do anything, I want to persist existingTeam. After it's saved, I want to stub Team.create. After these two things, I want to start actually testing. I think it would be cleaner if instead of using a Promise.all or perhaps duplicating the test code, I could use beforeEach.
How would I convert this to use beforeEach? Or what is an example of its usage?
Simple, just return promise from callback function
const t = require('tap');
const tp = require('tapromise');
const app = require('../../../server/server');
const Team = app.models.Team;
const existingId = '123';
const existingData = {
externalId: existingId,
botId: 'b123'
};
t.beforeEach(() => {
return Team.create(existingData).then(() => stubCreate());
});
t.test('crupdate', t => {
t = tp(t);
const newId = 'not 123'
const newData = {
externalId: newId,
whatever: 'value'
};
const newResult = Team.crupdate({
externalId: newId
}, newData);
const existingResult = Team.crupdate({
externalId: existingId
}, existingData);
return Promise.all([
t.equal(newResult, newData, 'Creates new Team when the external ID is different'),
t.match(existingResult, existingTeam, 'Finds existing Team when the external ID exists')
]);
}).then(() => {
process.exit();
}).catch(t.threw);
function stubCreate() {
Team.create = data => Promise.resolve(data);
}