Skip to content

Commit

Permalink
feat(Where): allow RegExp objects directly in where clause
Browse files Browse the repository at this point in the history
Javascript RegExp objects can now be passed into the regexp comparator and used directly as a value
in Where clauses.

Closes #13
  • Loading branch information
jamesfer committed Aug 8, 2018
1 parent 350bb63 commit 362c7ca
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 7 deletions.
15 changes: 15 additions & 0 deletions src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,21 @@ export abstract class Builder<Q> extends SetBlock<Q> {
* // WHERE (name = 'Alan' OR name = 'Steve' OR name = 'Barry') AND age = 54
* ```
*
* For convenience you can also pass a Javascript RegExp object as a value,
* which will then be converted into a string before it is passed to cypher.
* *However*, beware that, the cypher regexp syntax is inherited from
* [java]{@link
* https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html},
* and may have slight differences to the Javascript syntax. If you would
* prefer, you can use the `regexp` comparator and use strings instead of
* RegExp objects. For example, Javascript RegExp flags will not be
* preserved when sent to cypher.
* ```javascript
* query.where({
* name: /[A-Z].*son/,
* })
* // WHERE age =~ '[A-Z].*son'
*
* For more complex comparisons, you can use the comparator functions such as:
* ```javascript
* query.where({
Expand Down
24 changes: 18 additions & 6 deletions src/clauses/where-comparators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,13 @@ export function inArray(value: any[], variable?: boolean) {
* to true because it will prepend `'(?i)'` which will make your regexp
* malformed.
*
* The regexp syntax is inherited from the
* [java regexp syntax]{@link
* https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html}.
* For convenience you can also pass a Javascript RegExp object into this
* comparator, which will then be converted into a string before it is
* passed to cypher. *However*, beware that the cypher regexp syntax is
* inherited from [java]{@link
* https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html},
* and may have slight differences to the Javascript syntax. For example,
* Javascript RegExp flags will not be preserved when sent to cypher.
*
* If you want to compare against a Neo4j variable you can set `variable` to
* true and the value will be inserted literally into the query.
Expand All @@ -241,16 +245,24 @@ export function inArray(value: any[], variable?: boolean) {
* query.where({ name: regexp('s.*e') })
* // WHERE name =~ 's.*e'
*
* query.where({ name: regexp('clientPattern', true) })
* query.where({ name: regexp('s.*e', true) })
* // WHERE name =~ '(?i)s.*e'
*
* query.where({ name: regexp('clientPattern', false, true) })
* // WHERE name =~ clientPattern
* ```
* @param exp
* @param insensitive
* @param {boolean} variable
* @returns {Comparator}
*/
export function regexp(exp: string, insensitive?: boolean, variable?: boolean) {
return compare('=~', insensitive ? '(?i)' + exp : exp, variable);
export function regexp(exp: string | RegExp, insensitive?: boolean, variable?: boolean) {
let stringExp = exp;
if (exp instanceof RegExp) {
// Convert regular expression to string and strip slashes and trailing flags
stringExp = exp.toString().match(/\/(.*)\/[a-z]*/)[1];
}
return compare('=~', insensitive ? '(?i)' + stringExp : stringExp, variable);
}

/**
Expand Down
6 changes: 5 additions & 1 deletion src/clauses/where-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
last,
keys,
isFunction,
isRegExp,
} from 'lodash';
import { ParameterBag } from '../parameter-bag';
import { WhereOp } from './where-operators';
import { Comparator } from './where-comparators';
import { Comparator, regexp } from './where-comparators';

export type Condition = any | Comparator;
export type Conditions = Dictionary<Many<Condition>>;
Expand Down Expand Up @@ -57,6 +58,9 @@ export function stringCons(
if (conditions instanceof WhereOp) {
return conditions.evaluate(params, precedence, name);
}
if (isRegExp(conditions)) {
return stringifyCondition(params, regexp(conditions), name);
}
return stringifyCondition(params, conditions, name);
}

Expand Down
16 changes: 16 additions & 0 deletions src/clauses/where.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,21 @@ describe('Where', () => {
upperAge: 65,
});
});

it('should compile with a regular expression', () => {
const query = new Where({ name: /[A-Z].*son/ });
expect(query.build()).to.equal('WHERE name =~ $name');
expect(query.getParams()).to.deep.equal({
name: '[A-Z].*son',
});
});

it('should compile with a regular expression with flags', () => {
const query = new Where({ name: /.*son/i });
expect(query.build()).to.equal('WHERE name =~ $name');
expect(query.getParams()).to.deep.equal({
name: '.*son',
});
});
});
});

0 comments on commit 362c7ca

Please sign in to comment.