3
\$\begingroup\$

I made this AngularJS 1.x filter, to search using a the same SQL LIKE syntax. Right now only the percentage symbol (%) is supported, the underscore symbol (_) is not.

Under the hood I'm simply building a RegExp from a format string passed as a parameter (ie. the search string), then I'm looping over all the object properties inside an input array (first parameter).

I'm looking for some feedback about performance, and in particular about any possible "edge cases" in which it would perform bad or could possibly break.

Here's the code (ES6/ES2015 syntax):

"use strict";

export default function likeFilter() {
  return (input, format) => {
    if (!(input instanceof Array && "string" === typeof format && format.length)) {
      return input;
    }

    const like = format.indexOf("%") >= 0;
    const startLike = like && format.charAt(0) === "%";
    const endLike = like && format.charAt(format.length - 1) === "%";
    const split = [];

    split.splice(0, 0, ...format.split("%"));

    if (startLike) {
      split.shift();
    }

    if (endLike) {
      split.pop();
    }

    let regexp = split.join(".*");

    if (!startLike) {
      regexp = "^" + regexp;
    }

    if (!endLike) {
      regexp += "$";
    }

    regexp = new RegExp(regexp, "mi");

    return input.filter(el => {
      for (let key in el) {
        if (el.hasOwnProperty(key)) {
          if (regexp.test(el[key])) {
            return true;
          }
        }
      }

      return false;
    });
  }
};

Example usage:

JS code (angular filters module):

"use strict";
import likeFilter from "./like";
filtersModule.filter("like", likeFilter);

HTML code (angular template):

<input type="text" ng-model="data.searchstring" />
<div ng-repeat="obj in data.objs | like : data.searchstring"><!-- [...] --></div>
\$\endgroup\$
  • \$\begingroup\$ I just noticed: maybe I should not split and join, but simply replace the percentage symbol with ".*" instead \$\endgroup\$ – Zorgatone Nov 28 '16 at 17:12
3
\$\begingroup\$

I think you inverted startLike with endLike.

const like = format.indexOf("%") >= 0;
const startLike = like && format.charAt(0) === "%";
const endLike = like && format.charAt(format.length - 1) === "%";

When I read startLike I could misunderstand with startWith, that is the popular term used in APIs.

So it's complicated to read the code, as you work with an inverted logic.

I will use startWith(== endLike) and endWith (== startLike), instead.

Another point about naming is:

const split = [];

I think it is meaningless and a very bad choice for an array name.

Consider the case in a future time if you need to use Array.split():

split.split(...);

Not so good in readability.

Consider the code:

const split = [];

split.splice(0, 0, ...format.split("%"));

Not sure why you want to do all this work to just assign an array.

You could just use:

const split = format.split("%");
\$\endgroup\$
  • \$\begingroup\$ About the split declaration and then the next instruction (splice): that's what I ended with when I removed some code within those two instructions: they can be merged into one, now :) \$\endgroup\$ – Zorgatone Nov 28 '16 at 17:24
  • \$\begingroup\$ @Zorgatone I supposed that, as your code should be used if you have an array with some elements, and you want to add in a specific index (in this case at the beginning) a new element. \$\endgroup\$ – Mario Santini Nov 28 '16 at 17:28
2
\$\begingroup\$

In your return

return input.filter(el => {
  for (let key in el) {
    if (el.hasOwnProperty(key)) {
      if (regexp.test(el[key])) {
        return true;
      }
    }
  }

  return false;
});

I would personally merge the 2 if statements like this

return input.filter(el => {
  for (let key in el) {
    if (el.hasOwnProperty(key) && regexp.test(el[key])) {
        return true;
    }
  }
  return false;
});

reduce the amount of nesting that is going on here.

\$\endgroup\$
  • 1
    \$\begingroup\$ Oh you're right. I totally missed that.. I used to have more code that I removed there.. \$\endgroup\$ – Zorgatone Nov 28 '16 at 17:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.