Skip to content

Comparison with periods in name breaks param naming #184

@jhanggi

Description

@jhanggi

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)}`;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions