goodybag / mongo-sql

An extensible SQL generation library for JavaScript with a focus on introspectibility
321 stars 72 forks source link

$not operator #157

Closed PaulGrimshaw closed 7 years ago

PaulGrimshaw commented 7 years ago

Has there been any thought to implementing a $not operator? This would invert the expression in the filter.

Example test to add to conditionals tests (not tested):

/**
 * Querying where helper is $not, parsing to opposite of equal
 * @param column {String}  - Column name either table.column or column
 */
conditionals.add('$not', function(column, value, values, collection, original){
    return 'not ' + column + ' ' + getValueEqualityOperator(value) + ' ' + value;
});

https://docs.mongodb.com/manual/reference/operator/query/not/

jrf0110 commented 7 years ago

I haven't exactly thought about it, but it should be pretty easy to implement (well, if you're brave enough to go into the condition builder source). As it currently stands, the condition builder will see the $not operator and likely ignore other operators, so it might need special treatment. Not sure. Feel free to take a hack at it, otherwise I might check it out this weekend

PaulGrimshaw commented 7 years ago

I started work on this. Got the basic $not working, but don't quite understand how i would do the more complex examples using brackets not (xxxx = y or xxxx = z)

Example tests and implementation here: https://github.com/sennentech/mongo-sql/commit/7e4f0050e85cdd4992f15564a29c0d6bc7671a15

PaulGrimshaw commented 7 years ago

Any thoughts on this? Would be useful and rather fundamental...

jrf0110 commented 7 years ago

@PaulGrimshaw Sorry for forgetting about this!

So, I'm thinking this could be done by specifying the $not helper to be non-cascading (){ cascade: false } as the second arg to conditionals.add(...)) and then using the condition-builder directly in the definition:

conditionals.add('$not', function(column, value, values, collection, original){
  var result = 'not ' + column + ' ';

  // This is the normal case where there are no nested conditionals
  if (typeof value === 'string') {
    result += getValueEqualityOperator(value) + ' ' + value
  } else {
    // Somehow get the conditionBuilder since there would be
    // a circular depdency. We could maybe just pass it as a param
    // to conditional helpers? This stuff really needs a refactor
    result += conditionBuilder(value, collection, values)
  }

  return result
});

Not sure if that works, but I think it might be good direction :)