OpenBookPrices / country-data

Country related data such as ISO codes, currencies etc
MIT License
513 stars 165 forks source link

Add search helpers #6

Closed bebraw closed 10 years ago

bebraw commented 11 years ago

It would be extremely useful to have some common lookups in the library. For instance I needed to get a alpha3 based on country name. I ended up writing something like this:

 function findAlpha3(name) {
      for(var code in countries) {
          var country = countries[code];

          if(country.name == name && code) return country.alpha3;
      }

      if(name == 'United Kingdom') return 'GBR';
  }

I would much rather write something like countries.find({name: 'Germany'}).alpha3.

evdb commented 11 years ago

I agree that some helpers would be good, but I think that they should go into a separate module, something like:

var lookup  = require('country-data').lookup;

var countries = lookup.countries({ currencies: 'GBP' });

var country = lookup.country({ name: 'United Kingdom' });

In the above I've got two methods depending on if you expect back a single result, or several. Perhaps that is over complicating things? Also I think returning the whole country (or currency) result would make sense, then from that you can extract the particular bit that is of interest.

Would this work for you?

evdb commented 11 years ago

PS I'll be offline for this coming week, I'll follow up with this once I'm back on.

bebraw commented 11 years ago

In the above I've got two methods depending on if you expect back a single result, or several. Perhaps that is over complicating things? Also I think returning the whole country (or currency) result would make sense, then from that you can extract the particular bit that is of interest.

That country/countries thing could be either eliminated either by returning always an array of objects or by documenting that it may return an object or an array. I would prefer to return an array always as that makes it easier on the "customer" side.

I would propose an API such as follows:

var lookup = require('country-data').lookup;

var countries = lookup.countries({currencies: 'GBP'});
var gb = lookup.countries({name: 'United Kingdom'})[0];
var aud = lookup.currencies({code: 'AUD'})[0];

Of course more often than not the API would return an array with either zero or one item. I think the advantage of this scheme is that it is unambiguous what a EUR lookup should return (not just first country but all). Same goes for other plural queries.

Now that I think of it, what if this whole query thing belongs to a separate, generic module of its own? The idea is so simple that it's definitely possible to implement this way. I could whip up something. The it would look like this:

var cd = require('country-data');
var lookup = require('lookup');

var countryLookup = lookup.bind(null, cd.countries);
var currencyLookup = lookup.bind(null, cd.currencies);

var countries = countryLookup({currencies: 'GBP'});
var gb = countryLookup({name: 'United Kingdom'})[0];
var aud = currencyLookup({code: 'AUD'})[0];

Yes, there's some extra wiring but not that much! What does this sound to you?

evdb commented 10 years ago

This sounds like it would be very similar to underscore's where and findWhere. The only bit that would differ is that searching countries for a currency would need the search to understand that the currencies is an array, and any match in the array should be enough for a hit.

With this special case behaviour having it built in to the country-data package sounds like it would be best, a more generic approach might not work easily.

I could whip up something.

Please do, pull requests very welcome. I think that the first set of examples would be exactly the right approach, possibly with .countries(...) returning an array, and .country(...) returning first match, or null (and likewise for currencies/currency). The singular one could just be a wrapper around the plural one.

bebraw commented 10 years ago

Please do, pull requests very welcome. I think that the first set of examples would be exactly the right approach, possibly with .countries(...) returning an array, and .country(...) returning first match, or null (and likewise for currencies/currency). The singular one could just be a wrapper around the plural one.

I made a PR with plurals. You can add singulars later if you want to.

Underscore whereand findWhere were quite close but they did not support partial cases (ie. arrays). As a result I had to implement a custom solution of my own.