cypher-query-builder
cypher-query-builder copied to clipboard
Comparison with periods in name breaks param naming
This was a tricky one. I'm not sure if it's intended usage, but we've taken advantage of a neat little quirk, using the keys of where clause objects to do computations in the left side of the comparator.
const lastName = 'FromInput';
new Query().matchNode('n', 'Node')
.where({
'split(n.name, " ")': myVariable,
})
However, this breaks if we try to split by periods because of the split('.')
in compare()
. It gets added to the bag as an empty string. Then we get a syntax error when we run the query because the $
param prefix is just hanging there.
Here is a failing test case:
it("can perform a comparision when there is a dot in the key", () => {
const clause = equals("value")(bag, "split(node.ID, '.')[0]");
expect(clause).to.equal(`split(node.ID, '.')[0] = $something`);
expect(bag.getParams()).to.have.property("something").that.equals("value");
});
---
AssertionError: expected 'split(node.ID, \'.\')[0] = $' to equal 'split(node.ID, \'.\')[0] = $something'
+ expected - actual
-split(node.ID, '.')[0] = $
+split(node.ID, '.')[0] = $something
The ')[0]
goes into the bag and gets sent through uniqueString
where it gets slimmed down to just 0
, then because it's a trailing number, it gets stripped off leaving us with an empty string.
One option might be to provide a fallback name if the given string gets stripped down to the empty string. Another might be to allow another argument in some of the comparisons, e.g. equals(value, false, 'myParamName')
.
I'm not sure if the usage of keys like this was ever intended, but it works really nicely for us. We've worked around this particular issue by creating a custom comparator, but it would be nice if the library could handle it.
I'd be happy to put together a PR, but I don't know what the best solution would be. A fallback might be the simplest, or make it so that if you have empty strings, they get incremented $0
, $1
, etc (assuming that's valid in cypher).
export function equalsForceParamName(
value: any,
paramName: string,
): Comparator {
return (params, name) => `${name} = ${params.addParam(value, paramName)}`;
}