apom.js

Build Status via Travis CI NPM version Coverage Status

Asynchronous Partial Object Match provides asynchronous functions to determine if chosen properties between javascript object literals match. A match between properties can be equal value and type (default), a regular expression test, a missing property, a custom match function or a combination of those for different properties.

Install with npm install apom.

Tested with node versions of 4.2, 5.5, 0.10, 0.12.

Examples

Determine if properties are equal value and type between 2 objects.

// test if fido's tail color is gray
var apom = require('apom');

var fido ={ 
    paws: {color: 'grey', count: 3}, 
    tail: {color: 'gray', count: 1},
    body: {color: 'black'},
    housetrained: true};

var pObj = {tail: {color: 'gray'}};

apom.matches(pObj, fido, function(doesMatch){
  console.log(doesMatch);  //true
})

Or build the match function first to include match options and for better performance.

// test if fido has a gray tail regardless if grey or gray
var apom = require('apom');

var fido ={ 
    paws: {color: 'grey', count: 3}, 
    tail: {color: 'gray', count: 1},
    body: {color: 'black'},
    housetrained: true};

// select the properties to be tested and the options
var propsToTest = ['tail.color']; 
var options = {regExpMatch:true}; 

// include the regular expression in the 'pattern object'
var pObj = {tail:{color: /gr.y/}};  

// create the match function
var matchFn = apom.makeMatchFn(propsToTest, options);

// test it
matchFn(pObj, fido, function(doesMatch){
  console.log(doesMatch);  // true
})

Filter an array of objects:

// find which pets have 4 paws

var apom = require('apom');

var pets = [
  { name: 'fido',
    paws: {color: 'gray', count: 3}, 
  },
  { name: 'rover',
    paws: {color: 'white', count: 4}, 
  },
  ];

// create the pattern object
var pObj = {paws:{count: 4}};  

// select properties to test
var propsToTest = ['paws.count'];

// create the filter function
var filter = apom.makeFilterTargetObjectsFn(propsToTest);

// filter
filter(pObj, pets, function(matchedPets){
  console.log(matchedPets);  //matchedPets = {name: 'rover'...}; 
})

See test/test.js for an extensive list of examples.

Documentation

Match and Filter Functions

Options

matches(pObj, tObj, callback)

Returns true as result of callback if properties identified to be tested between pObj and tObj match; otherwise returns false.

Which properties are tested and if they match is determined by whether matches is called directly or created via the makeMatchFn.

If matches is created via makeMatchFn then the propsToTest and options parameters determine which properties are tested for match and how the properties are tested for match. Calling the resulting matches function created via makeMatchFn also provides better performance than calling matches directly.

If matches function is called directly without creating it via makeMatchFn, every property in the pObj object is tested for a match and all options values are default. Options cannot be modified if calling matches directly.

Arguments

Examples

// test if fido's tail color is gray
var apom = require('apom');

var fido ={ 
    tail: {color: 'gray', count: 1},
    body: {color: 'black'},
    housetrained: true};

var pObj = {tail: {color: 'gray'}};

apom.matches(pObj, fido, function(doesMatch){
  console.log(doesMatch);  //true
});

// Or, create the matches function to include option 
//      such as regular expression matches. 

// select the properties to be tested and the options
var propsToTest = ['tail.color']; 
var options = {regExpMatch:true}; 

// create the custom match function
var matchFn = apom.makeMatchFn(propsToTest, options);

// include the regular expression in the 'pattern object'
var pObj = {tail:{color: /gr.y/}};  

// test it
matchFn(pObj, fido, function(doesMatch){
  console.log(doesMatch);  // true
})

makeMatchFn(propsToTest, options)

Creates and returns a matches function that is configured to test the properties included in propsToTest and options to determine how properties are tested for a match. This created function will run faster than calling the matches function directly and allows for greater control, via propsToTest and options, of which properties are tested and how.

Arguments

Examples

// test if fido has a gray tail regardless if grey or gray
var apom = require('apom');

var fido ={ tail: {color: 'gray', count: 1}};

// select the properties to be tested and the options
var propsToTest = ['tail.color']; 
var options = {regExpMatch:true}; 

// create the match function
var matchFn = apom.makeMatchFn(propsToTest, options);

// include the regular expression in the 'pattern object'
var pObj = {tail:{color: /gr.y/}};  

// test it
matchFn(pObj, fido, function(doesMatch){
  console.log(doesMatch);  // true
});

It would give the same result to set the options in propsToTest

var propsToTest = {'tail.color':{regExpMatch:true}}; 

var matchFn = apom.makeMatchFn(propsToTest);  // options not included here

matchFn(pObj, fido, function(doesMatch){
  console.log(doesMatch);  // true
});

makeFilterTargetObjectsFn(propsToTest, options)

Creates and returns a filterTargetObjects function that is configured to test the properties included in propsToTest using options to determine how properties are tested for a match between pObj and tObjs.

Arguments

Examples See filterTargetObjects.

filterTargetObjects(pObj, tObjs, callback)

Returns an array of tObjs that match the pObj based on the propsToTest and options parameters that were used to create this function with makeFilterTargetObjectsFn.

This function is created by calling makeFilterTargetObjectsFn.

Arguments

Examples

// find which pets have gray paws regardeless if 'gray' or 'grey'

var apom = require('apom');

var pets = [
  { name: 'fido',
    paws: {color: 'gray', count: 3}, 
  },
  { name: 'rover',
    paws: {color: 'white', count: 4}, 
  },
  ];

// create the pattern object
var pObj = {paws:{color: /gr[a,e]y/}};  

// select properties and options to test
var propsToTest = ['paws.color'];
var options = {regExpMatch: true}; 

// create the filter function
var filter = apom.makeFilterTargetObjectsFn(propsToTest, options);

// filter
filter(pObj, pets, function(matchedPets){
  console.log(matchedPets);  
  // [ { name: 'fido', paws: { color: 'gray', count: 3 } } ] 
});

makeFilterPatternObjectsFn(propsToTest, options)

Creates and returns a filterPatternObjects function that is configured to test the properties included in propsToTest using options to determine how properties are tested for a match between pObjs and tObj.

Arguments

Examples See filterPatternObjects.

filterPatternObjects(pObjs, tObj, callback)

Returns an array of pObjs that match the tObjbased on the propsToTest and options parameters that were used to create this function with makeFilterPatternObjectsFn.

This function is created by calling makeFilterPatternObjectsFn.

filterPatternObjects allows an array of objects with regular expressions to be filtered on those regular expressions unlike filterTargetObjects.

Arguments

Examples

// find which pets match a request with a role of guarddog

var apom = require('apom');

// pets are the `pObjs` in this case to match on their regular expressions
var pets = [
  {name: 'growler',
   path: /.*role=guarddog.*/},
  {name: 'fido',
   path: /.*role=pet.*/},
]

// request is the tObj 
var request = {path: '/pets?role=guarddog'}

// select properties and options to test
var propsToTest = ['path'];
var options = {regExpMatch: true}; 

// create the filter function
var filter = apom.makeFilterPatternObjectsFn(propsToTest, options);

// filter
filter(pets, request, function(matchedPets){
  console.log(matchedPets);  
  // [ { name: 'growler', path: /.*role=guarddog.*/ } ]
});

pObj

"pattern object". Any object that is passed into a matches, filterPatternObjects or filterTargetObjects function as the first parameter. It is used to test if it matches the target object(tObj). Considered a 'pattern' object because, unlike the tObj, it has characteristics such as :

var apom = require('apom');

// the target object here is fido
var fido ={ 
    paws: {color: 'grey', count: 3}, 
    tail: {color: 'gray', count: 1},
    body: {color: 'black'},
    housetrained: true};

// the pattern object
var pObj = {tail: {color: 'gray'}};

apom.matches(pObj, fido, function(doesMatch){
  console.log(doesMatch);  //true
})

tObj

"target object". Any object that is passed into a matches, filterPatternObjects or filterTargetObjects function as the second parameter. The target object is the object that is being tested against the pattern object to determine if it matches. See notes and example under pObj.

propsToTest

An array or object that contains property names and their assigned options values, if any. Property names are strings and are in dot notation if nested; eg "tail.color" to identify the property in {tail: {color: black}}.

Can take one of the following forms:

options

An object used to set the option values for match and filter functions.

//options properties & their default values
var options = {
  regExpMatch: false,        // match on regular expression in `pObj` 
  regExpIgnoreCase: false,   // ignore case on reg exp match (str only) 
  regExpAnchorStart: false,  // append "^" to beg of str for reg exp (str only)
  regExpAnchorEnd: false,    // append "$" to end of str for reg exp (str only)

  matchIfPObjPropMissing: false,  // matches if `pObj` property doesn't exist
  matchIfTObjPropMissing: false,  // matches if `tObj` property doesn't exist

  variablesAllowed: false,  // replace var names with var values in `pObj` props 
  getVariables: undefined,  // function to call to get object of var names/vals
  variablesStartStr: '~',   // beg str in pObj prop value to find the var name  
  variablesEndStr: null,    // end str in pObj prop value to find the var name

  propMatchFn: null         // function to call instead of std match function
}; 
regExpMatch

Property on the options object that if equal to true, apom filter and matches functions will use the pObj property value as a regular expression to test against the tObj property. If the pattern object property value is a string, the string will be converted to a javascript regular expression.

Example:

// test if fido has a gray tail regardless if grey or gray
var apom = require('apom');

var fido ={ 
    paws: {color: 'grey', count: 3}, 
    tail: {color: 'gray', count: 1},
    body: {color: 'black'},
    housetrained: true};

// select the properties to be tested and the options
var propsToTest = ['tail.color']; 
var options = {regExpMatch:true}; 

// include the regular expression in the 'pattern object'
var pObj = {tail:{color: /gr[a,e]y/}};  

// create the match function
var matchFn = apom.makeMatchFn(propsToTest, options);

// test it
matchFn(pObj, fido, function(doesMatch){
  console.log(doesMatch);  // true
});
regExpIgnoreCase

Property on the options object that if equal to true and regExpMatch===true and the pObj property value is a string, then when the pObj value is converted from a string to a regular expression object in apom matches and filter functions, the regular expression is included with the 'i' flag to ignore case on the regular expression match. This option value is only considered where the pObj property value is a string. If the pObj value is a regular expression object, then the ignore case flag can be included on that object; eg "/gray/i".

Example:

// test if fido has a gray tail regardless if grey or Gray
var apom = require('apom');

var fido ={ 
    paws: {color: 'grey', count: 3}, 
    tail: {color: 'Gray', count: 1},
    body: {color: 'black'},
    housetrained: true};

// select the properties to be tested and the options
var propsToTest = ['tail.color']; 
var options = {regExpMatch:true, regExpIgnoreCase: true}; 

// include the regular expression as a string in the pattern object
var pObj = {tail:{color: 'gr[a,e]y'}};  

// create the match function
var matchFn = apom.makeMatchFn(propsToTest, options);

// test it
matchFn(pObj, fido, function(doesMatch){
  console.log(doesMatch);  // true
});

// regExpIgnoreCase does not apply if pObj property is a regular expression

var pObj = {tail:{color: /gr[a,e]y/}};  

matchFn(pObj, fido, function(doesMatch){
  console.log(doesMatch);  // false
});

// use the 'i' flag on the regular expression object instead 
var pObj = {tail:{color: /gr[a,e]y/i}};  

matchFn(pObj, fido, function(doesMatch){
  console.log(doesMatch);  // true
});
regExpAnchorStart

Property on the options object that if equal to true and regExpMatch===true and the pObj property value is a string, then when the pObj value is converted from a string to a regular expression object in apom matches and filter functions, it includes a '^' prepended to pObj string value. This option value is only considered where the pObj is a string. If the pObj property value is a regular expression object, then the ^ can be included in the regular expression; eg, /^gray/.

regExpAnchorEnd

Property on the options object that if equal to true and regExpMatch===true and the pObj property value is a string, then when the pObj value is converted from a string to a regular expression object in apom matches and filter functions, it includes a '$' appended to the end of the pObj string value. This option value is only considered where the pObj is a string. If the pObj property value is a regular expression object, then the $ can be included in the regular expression; eg, /gray$/.

matchIfTObjPropMissing

Property on the options object that if equal to true, apom filter and matches functions will return true for the given property's match test if the property being tested does not exist on tObj.

Example:

// find which pets have a role of guarddog and (the breed is chihuahua or 
//     breed is not defined)  

var apom = require('apom');

var pets = [
  {name: 'growler',
   breed: 'chihuahua',
   role: 'guarddog'},
  {name: 'fido',
   breed: 'lab',
   role: 'pet'},
  {name: 'duchy',
   role: 'guarddog'},
  {name: 'bruiser',
   breed: 'chihuahua',
   role: 'cuddler'},
]

// request is the tObj 
var pObj = {role:'guarddog', breed: 'chihuahua'};

// select properties to test; role with default options
var propsToTest = 
    {role: {}, breed: {matchIfTObjPropMissing: true}};

// create the filter function
var filter = apom.makeFilterTargetObjectsFn(propsToTest);

// filter
filter(pObj, pets, function(matchedPets){
  console.log(matchedPets);  
  // [ { name: 'growler'...},{name: 'duchy'...} ]
});
matchIfPObjPropMissing

Property on the options object that if equal to true, apom filter and matches functions will return truefor the given property's match test if the property being tested does not exist on pObj.

Example:

This option would typically be used in a makeFilterPatternObjectsFn, like this example, but like all options can also be used in makeFilterPatternObjectsFn and matches.

// find which pets match a request with a role of guarddog and 
//     (the breed is chihuahua or breed is not defined)  

var apom = require('apom');

// pets are the `pObjs` in this case to match on their regular expressions
var pets = [
  {name: 'growler',
   breed: 'chihuahua',
   path: /.*role=guarddog.*/},
  {name: 'fido',
   breed: 'lab',
   path: /.*role=pet.*/},
  {name: 'duchy',
   path: /.*role=guarddog.*/},
  {name: 'bruiser',
   breed: 'chihuahua',
   path: /.*role=cuddler.*/},
]

// request is the tObj 
var request = {path: '/pets?role=guarddog', breed: 'chihuahua'}

// select properties and options to test
var propsToTest = 
    {path: {regExpMatch: true}, breed: {matchIfPObjPropMissing: true}};

// create the filter function
var filter = apom.makeFilterPatternObjectsFn(propsToTest);

// filter
filter(pets, request, function(matchedPets){
  console.log(matchedPets);  
  // [ { name: 'growler'...},{name: 'duchy'...} ]
});
variablesAllowed

Property on the options object that if equal to true, replaces strings that are recognized as variable names in pObj property values with their respective variable values from getVariables. The varible names on the pObj property values is matched based on the variablesStartStr and variablesEndStr.

Example:

// match if fido has a grey tail and paws regardless if grey or gray

var apom = require('apom');

var fido ={ 
    paws: {color: 'grey', count: 3}, 
    tail: {color: 'gray', count: 1},
    body: {color: 'black'},
    housetrained: true};

var options =  
    {regExpMatch: true,
     variablesAllowed:true,
     variablesStartStr:"~",
     variablesEndStr: "#",
     getVariables:  function(cb) {
       return cb(null, {grayColor: /gr[a,e]y/}); 
    }};

// variable name is identified between variablesStartStr(~) and variablesEndStr(#)
//   and replaced with that name from getVariables (grayColor => /gr[a,e]y/)
var pObj = {paws:{color: '~grayColor#'},tail:{color:'~grayColor#'}};  

var propsToTest = ['paws.color', 'tail.color'];

var matchFn = apom.makeMatchFn(propsToTest, options);

matchFn(pObj, fido, function(matches){
  console.log(matches); //true 
  return; 
});
getVariables

Property on the options object that defines a function which, if variablesAllowed is true, takes a callback which is called with an error (null if no error) and an object of the form :

{variable1Name: `variable1Value`,
  variable2Name: `variable2Value`}

See variablesAllowed for an example.

variablesStartStr

Property on the options object that defines a string which, if variablesAllowed === true, determines the starting position of a variable name string in a pObj property value that will be replaced with the variable value string of the respective variable name obtained from getVariables.

See variablesAllowed for an example.

variablesEndStr

Property on the options object that defines a string which, if variablesAllowed === true, determines the ending position of a variable name string in a pObj property value that will be replaced with the variable value string of the respective variable name obtained from getVariables.

See variablesAllowed for an example.

propMatchFn

Property on the options object that defines a function to replace the match function between pObj and tObj properties.

Function is called with 3 parameters for each property being tested:

Example:

// find pets with 3 or more paws

var apom = require('apom');

var pets = [
  { name: 'fido',
    paws: {color: 'gray', count: 3}},
  { name: 'rover',
    paws: {color: 'white', count: 4}},
  { name: 'slither',
    paws: {count: 0}},
  ];

var pObj = {paws:{count: 3}};  

//   propMatchFn is called for each property with the 
//      pattern object property value and the target object property value 
var matchFn = function(pObjProp, tObjProp, cb) {
  var hasAtLeast3Paws = tObjProp.exists === true && 
      pObjProp.exists === true && 
      tObjProp.value >= pObjProp.value;
  return cb(hasAtLeast3Paws);  
}; 

var propsToTest = {'paws.count': {propMatchFn: matchFn}}; 

var filter = apom.makeFilterTargetObjectsFn(propsToTest);

filter(pObj, pets, function(matchedPets){
  console.log(matchedPets);
  //matchedPets = {name: 'fido'..., name:'rover'...}; 
});