Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coalesce with falsy #52

Open
StreetStrider opened this issue May 18, 2015 · 8 comments
Open

coalesce with falsy #52

StreetStrider opened this issue May 18, 2015 · 8 comments

Comments

@StreetStrider
Copy link
Contributor

Hi. I'm finding myself using coalesce for achieving clean and idiomatic code. But sometimes my data providers return me objects, where some keys I pick present, but falsy (undefined, null, empty string etc). In the mean time coalesce relies on key existing/non-existing.

Is it possible to implement in this module another variant of coalesce which will check not key presence, but its value falsiness? So, it will work like good old object.key || object.key2 || ... but with benefits of deep paths support.

I've looked through opened & closed issues, but found nothing similar. If it is a dulicate, please, forgive me. I think other users of object-path could face this issue as well, and it's not pleasant to return to ||-stuff when you're already using such powerful utility like this.

@pocesar
Copy link
Collaborator

pocesar commented May 18, 2015

in the upcoming version you'll be able to augment object-path to fit your needs. this would require creating a plugin for object-path and adding another parameter to it, would be like this:

objectPath.extend(function(base, options){
   return {
      coalesce: function(obj, paths, defaultValue, falsy){
        falsy = falsy !== undefined ? falsy : false;
        if (falsy === true){
             var value, i, len = paths.length;
             for(i = 0; i < len; i++) {
                if ((value = base.get(obj, paths[i], void 0, options.ownPropertiesOnly))){
                   return value; 
                }
             }
             return defaultValue;
        } 
        return base.coalesce(obj, paths, defaultValue, options.ownPropertiesOnly);
      }
   };
});
// new usage
objectPath.coalesce(obj, ['path','path.2','path.3'], null, true);

as you can see, you don't need to rewrite the coalesce code by hand, only augment it's capabilities :)
the 1.0.0 is right around the corner

@StreetStrider
Copy link
Contributor Author

@pocesar, hm, your snippet does not represent my idea, since it relies on base coalesce. Consider obj.path = null (but present) and obj.path2 = true. Base coalesce will return null since path in in object, and then default will be applied. In my idea it should return true, since there is such a key with non-fasy value in list. The problem is deeper and that is why I've opened the issue.

Your snippet can be effectively reduced to: coalesce(obj, [ paths ]) || defaultValue. That is not what I meant.

@pocesar
Copy link
Collaborator

pocesar commented May 18, 2015

indeed, I've rewritten the snippet. if you want to test the 1.0.0 to see if solves your problem, check the 1.0.0 branch

@StreetStrider
Copy link
Contributor Author

@pocesar, thanks, no testing required, I've looked through your updated version and it's a solution. I think such thing must be in core, since it's a very low-level code and it has complexity comparable to complexity of coalesce itself.

@pocesar
Copy link
Collaborator

pocesar commented May 18, 2015

it makes sense to have a fourth parameter to change the behavior of the function (like set has the internal option doNotReplace), it would not break existing code that relies on coalesce

@StreetStrider
Copy link
Contributor Author

@pocesar, of course it can save compability. This can be done with boolean parameter or predicate for coalese or even distinct function.

@StreetStrider
Copy link
Contributor Author

@pocesar, I have an idea of such design:
.first(object, paths[], predicate = Boolean);

— for every path in paths checks if path is present and the predicate(value, path, object) is true for it. Returns first value for such conditions.

I'm not sure if defaultValue is required, but if so, it should stay before predicate (because predicate will be Boolean most of the time, and for consistency with coalesce):
.first(object, paths[], defaultValue = undefined, predicate = Boolean);

If user do not pass predicate at all, or predicate is Boolean it can be aggressively optimized to short form without running callback at all (like in your snippet above).

@pocesar
Copy link
Collaborator

pocesar commented May 18, 2015

that would definitely be a good plugin to have :)
1.0 is embracing modularity, and we will be able to add awesome things using the base of objectPath. we expect the community to make some nice plugins to use out of the box

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants