Logical and/or conditions

You've seen how we can use maps to execute behavior based on a single value. Where this approach falls apart is when you get into more involved logic and/or conditions. However, you can still use Immutable.js collections to check declaratively for these types of conditions. For example, let's implement a function that will help us look for AND/OR conditions:

const some = (...predicates) => {
const predicateSeq = Seq(predicates);
return (...args) => predicateSeq.some(p => p(...args));
};
const every = (...predicates) => {
const predicateSeq = Seq(predicates);
return (...args) => predicateSeq.every(p => p(...args));
};

The some() function is used to evaluate predicate functions in a logical OR fashion while the every() function evaluates predicate functions in a logical AND fashion. Both functions follow the same approach—they just use different sequence methods to return the result.

The idea is to construct a sequence (predicateSeq) from the predicate function arguments (predicates). Then we use the some()/every() method to call each predicate function with the given behavior arguments. The some() method returns true the first time that a predicate function returns true. The every() method returns true only if every predicate returns true. Let's use these functions to compose some behavior:

const hasEnough = some(
v => v.get('source1') > 5,
v => v.get('source2') > 5,
v => v.get('source3') > 5
);
const hasEverything = every(
v => v.get('enabled'),
v => v.get('hasPermission'),
v => v.get('oldEnough')
);

Now we have two functions that we can call to test logical AND/OR conditions. In the hasEnough() function, we have three predicates that test the values of different map properties. If any of these return true, hasEnough() will return true. The hasEverything() function also has three predicates, but will only return true if every predicate returns true.

Now let's compose some behavior to execute side-effects based on the result of calling hasEnough() and hasEverything():

const logHasEnough = behavior(Map.of(
true, () => console.log('yep, has enough'),
false, () => console.log('sorry, not enough')
));
const logHasEverything = behavior(Map.of(
true, () => console.log('yep, has everything'),
false, () => console.log('sorry, not everything')
));

Once again, we have functions that map Boolean input values to behavior. In this case, we're executing logging side-effects. Let's test out what we have:

const myMap1 = Map.of(
'source1', 5,
'source2', 6,
'source3', 7
);
const myMap2 = Map.of(
'source1', 6
);
const myMap3 = Map.of(
'source1', 1,
'source2', 2,
'source3', 3
);
const myMap4 = Map.of(
'enabled', true,
'hasPermission', true,
'oldEnough', true
);
const myMap5 = Map.of(
'enabled', true,
'hasPermission', true
);

console.log('myMap1', myMap1.toJS());
logHasEnough(hasEnough(myMap1));
// -> myMap1 { source1: 5, source2: 6, source3: 7 }
// -> yep, has enough
console.log('myMap2', myMap2.toJS());
logHasEnough(hasEnough(myMap2));
// -> myMap2 { source1: 6 }
// -> yep, has enough
console.log('myMap3', myMap3.toJS());
logHasEnough(hasEnough(myMap3));
// -> myMap3 { source1: 1, source2: 2, source3: 3 }
// -> sorry, not enough
console.log('myMap4', myMap4.toJS());
logHasEverything(hasEverything(myMap4));
// -> myMap4 { enabled: true, hasPermission: true, oldEnough: true }
// -> yep, has everything
console.log('myMap5', myMap5.toJS());
logHasEverything(hasEverything(myMap5));
// -> myMap5 { enabled: true, hasPermission: true }
// -> sorry, not everything

We've managed to distill our logic, and the code that runs as a result, into two function calls. We have a function that evaluates to Boolean result, and a function executes based on this result. As your application grows and more conditions become necessary, it's easier to expand this declarative code than it would be to hunt down if statements.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.153.69