loopbackio / loopbackio/loopback-connector-mssql

Like operator not working when trying to fetch stringify array of objects or object

Open
#248 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
JavaScript
Stars
52
Forks
80
PR merge metrics
No merged PRs in 30d

Description

Have tried to search for similar issue, but could not find any.

Basically, I am trying to use like operator in loopback4 filter for columns that store stringified array of objects or just an object.

Because array of objects and object are stored as a string, you would normally use the like operator to find value in the string.

I am not sure if its a bug, can someone please help me on this?

Also, I am not sure if this happens on other SQL database as well.

Steps to reproduce

Here are the steps to reproduce.

  1. Create a Loopback 4 Model as following or any but have one field with property array of objects.
@model({settings: {'strict': true}})
export class LocationLog extends Entity {

    @property({
        type: 'string',
        id: true,
        defaultFn: 'guid'
    })
    id?: string


    @property.array(Object, {
        mssql: {
            dataType: 'nvarchar',
            dataLength: 'max'
        }

    })
    sentTo?: Object[]

    constructor(data?: Partial<Approval>) {
        super(data)
    }
}
  1. Fetch the data using Loopback 4 filter like so.

const filter = {
      
    where: {
         sentTo: {  like: '&anystringyouwanttofindusinglikeoperator&'  }
   }
}

// use the find method to fetch data
this.find(filter)

Basically, only two steps, of course you definitely need the controller and repository created as well, I won't be covering that.
Use loopback-cli to quickly generate the repository and controller for the model.

Current Behavior

When you try to fetch the data through .find() with the filter above, nothing will be returned even though there are data in the database.

I tried to track the problem and I found that in the file loopback-connector-mssql/lib/mssql.js, line 509 where the codes try to build the expression related to like operator.

If you console.log the operatorValue, you will find the the value has double quotations. Like so.

MsSQL.prototype.buildExpression = function(columnName, operator, operatorValue,
  propertyDefinition) {
  
  // console.log the parameters
 console.log(columnName, 'columnName')
console.log(operator, 'operator')
console.log(operatorValue, 'operatorValue')
console.log(propertyDefinition, 'propertyDefinition')

  switch (operator) {
    case 'like':
      return new ParameterizedSQL(columnName + " LIKE ? ESCAPE '\\'",
        [operatorValue]);
    case 'nlike':
      return new ParameterizedSQL(columnName + " NOT LIKE ? ESCAPE '\\'",
        [operatorValue]);
    case 'regexp':
      g.warn('{{Microsoft SQL Server}} does not support the regular ' +
          'expression operator');
    default:
      // invoke the base implementation of `buildExpression`
      return this.invokeSuper('buildExpression', columnName, operator,
        operatorValue, propertyDefinition);
  }
};

//result of console.log

[sentTo] columnName
like operator
"&anystringyouwanttofindusinglikeoperator&" operatorValue
{ ... } propertyDefinition

The operatorValue has double quotation which then will just be treated as a string in the like statement.

Because I am using MSSQL database, I understand that an array of objects or object will be stringified before being stored in the database.

Expected Behavior

The operatorValue should not have a double quotation.
It should be something like this.

[sentTo] columnName
like operator
&anystringyouwanttofindusinglikeoperator& operatorValue
{ ... } propertyDefinition

Additional information

Please note this will only happen if you have a model with field that is an array of objects or if that field is an object itself.
If you have an array of string, it works just fine.

I guess its probably because of how the code treats object which will always get stringified.

To fix this problem for my application, I modified the code like so,

MsSQL.prototype.buildExpression = function(columnName, operator, operatorValue,
  propertyDefinition) {

  // check for propertyDefinition first, only checks for object
  if(propertyDefinition.type.name === 'Object' || typeof(propertyDefinition.type) === 'object'){
    
    // only if operator is `like`
    if(operator === 'like'){

      // check if double quotation is present as the first and last char
      if(operatorValue[0] === '"' && operatorValue[operatorValue.length - 1] === '"'){
        // remove the double quotations
        operatorValue = operatorValue.slice(1, -1)
      }
    }
  }

  switch (operator) {
    case 'like':
      return new ParameterizedSQL(columnName + " LIKE ? ESCAPE '\\'",
        [operatorValue]);
    case 'nlike':
      return new ParameterizedSQL(columnName + " NOT LIKE ? ESCAPE '\\'",
        [operatorValue]);
    case 'regexp':
      g.warn('{{Microsoft SQL Server}} does not support the regular ' +
          'expression operator');
    default:
      // invoke the base implementation of `buildExpression`
      return this.invokeSuper('buildExpression', columnName, operator,
        operatorValue, propertyDefinition);
  }
};

The above code checks if the column is an object and remove the double quotations if present

node -e 'console.log(process.platform, process.arch, process.versions.node)';

win32 x64 16.14.2

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in loopback-connector-mssql/lib/mssql.js at MsSQL.prototype.buildExpression, around the reported line 509, and reproduce the like query with an object or array-of-objects property in MSSQL. Compare it with the working array-of-strings case and verify that the generated parameter preserves the intended pattern. Done means the query finds matching stringified object data without breaking other like operators.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nodejs, sql
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.