react-querybuilder/react-querybuilder

Using parseNumbers should convert to number only when inputType === 'number'

amiram opened this issue · 2 comments

I'm using this component with MongoDB. Unlike Sql, values should be sent with the correct type.
Consider that I have Zip (string) and Age (number). If I'm not using parseNumbers, Age will be sent as a string which will produce no results. If I'm using parseNumbers, Zip will be converted to number and again I will get no results.

Possible solution: convert to a number only when inputType: 'number'

I'll think about this. There are a lot of ways you can set up an editor to manage numeric values without the inputType being "number", so I need to make sure the implementation is generic and relatively bulletproof.

In the meantime you can meet the requirement with a custom ruleProcessor.

Here's a working sandbox, with the relevant code copied below.

const fields: Field[] = [
  { name: 'age', label: 'Age', inputType: 'number' },
  { name: 'zipcode', label: 'Zip Code' },
];

const initialQuery: RuleGroupType = {
  combinator: 'and',
  rules: [
    { field: 'age', operator: '>', value: '21' },
    { field: 'zipcode', operator: 'beginsWith', value: '8' },
  ],
};

const ruleProcessor: RuleProcessor = (r, opts) => {
  const fieldData = getOption(fields, r.field);
  if (fieldData?.inputType === 'number') {
    // If you use the `getInputType` prop in the query builder,
    // you could also call that function here and "or" it into
    // the condition above like this:
    //   || getInputType(r.field, r.operator) === 'number')
    // FYI in v7 it can look like this:
    //   || getInputType(r.field, r.operator, { fieldData }) === 'number')
    return defaultRuleProcessorMongoDB(r, { ...opts, parseNumbers: true });
  }
  return defaultRuleProcessorMongoDB(r, { ...opts, parseNumbers: false });
};

formatQuery(query, {
  format: 'mongodb',
  fields, // fields are not passed to ruleProcessor from here, but are used for rule validation
  parseNumbers: false, // default to false, set to true when appropriate in ruleProcessor
  ruleProcessor,
});

Result (formatted):

{
  "$and": [
    {
      "age": {
        "$gt": 21
      }
    },
    {
      "zipcode": {
        "$regex": "^8"
      }
    }
  ]
}

@jakeboone02 Thanks a lot for the workaround. It works perfectly. BTW, with the regex it would have been working anyway. The problem was when the query was "zip = 12345". With mongodb, if the zip in db is "12345" then such query {zip: 12345} wouldn't find this document, therefore parseNumbers: true is good only when the input type is number. Anyway, the rule processor solves it.