Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistency between documentation and implementation on fields filter #3

Closed
githistory opened this issue Jan 25, 2016 · 17 comments
Closed

Comments

@githistory
Copy link

The fields filter in this library accepts array of field names where as the documentation says

{ fields: {id: true, make: true, model: true} }
@superkhau
Copy link
Contributor

@crandmck ^

@crandmck
Copy link

@superkhau Did this change when loopback-filters was added? It was almost certainly originally the way it's documented.

Does the Node API only accept the array form and not the {propertyName: <true|false>, propertyName: <true|false>, ... } form?

So, IIUC, this example should be:
{ fields: [{id: true}, {make: true}, {model: true}] }
Is that right?

@superkhau
Copy link
Contributor

I believe it takes both, gotta verify though:

function selectFields(fields) {
.

@githistory Can you provide a sample repo for me to verify with?

@FraserChapman
Copy link

@crandmck @superkhau

FWIW I'm using [email protected] and the only thing that works for me is an inclusive array of property names. e.g. To use the example given.

{ fields: ["id", "make", "model"] }

Anything other format supplied to fields results in empty objects being returned from the call to applyFilter.

Puzzled me for about half and hour.

@crandmck
Copy link

crandmck commented May 8, 2017

@FraserChapman Could you please provide a sample repo, so we can reproduce? I know that's what @superkhau will ask! :-)

@ewrayjohnson
Copy link

ewrayjohnson commented May 16, 2017

No offense, but IMHO, a sample repo is unnecessary as any data will do. This is a obvious bug and very easy to fix. I wonder if this code is being maintained since this bug report is so old. The documentation says the pattern is { fields: {id: true, make: true, model: true} } but only something like { fields : [ 'id', 'make', 'model' ] } will ever work. The code should "normalize" the filter.fields object by converting it from a map of fields to include/exclude, to an array of strings of fields to include. I recommend the following fix. Replace the if (filter.fields) {... } on or about line 29 of loopback-filters/lib/index.js with this:

 // field selection
    if (filter.fields) {
       var fieldMap = filter.fields;
       var fieldSet = [];
       for(var key in fieldMap) {
        if (fieldMap.hasOwnProperty(key)) {
          if (fieldMap[key]) {
            fieldSet.push(key);
          }
        }
      }

loopback-filters/test/filter.test.js should also be updated to provide a regression test of this capability.

An ultimate fix would cache this fieldSet for reuse and would also use the declared properties (and relations) of a model and would consider the strict property - but I digress. See loopback=datasource-juggler\lib\utils.js\fieldsToArray(..) for a full implementation.

On this page LoopBack 3.0 Querying data
It states: "Note: We plan to convert all modules to use loopback-filter[s], so it will become LoopBack’s common “built-in” filtering mechanism."
However that all such efforts seems to have been abandoned as the code (Copyright IBM) has not been updated since Dec 9, 2016 and this was reported on way back in Jan 25, 2016, with no one taking it seriously.

@crandmck
Copy link

@Amir-61
@superkhau
@loay

crandmck added a commit to loopbackio/loopback.io that referenced this issue May 17, 2017
@crandmck
Copy link

OK @ewrayjohnson I updated the docs. However, it's not clear to me how you exclude fields with the syntax you indicate. Do you know?

@ewrayjohnson
Copy link

ewrayjohnson commented May 17, 2017 via email

@crandmck
Copy link

crandmck commented May 17, 2017

You said:

The documentation says the pattern is { fields: {id: true, make: true, model: true} } but only something like { fields : [ 'id', 'make', 'model' ] } will ever work.

So I changed fields filter accordingly to have (in the example) { fields: ["id", "make", "model"] }.

Now you're saying that it WAS correct but now is not. So which is correct? The doc should of course state what actually works, not what should work.

@ewrayjohnson
Copy link

ewrayjohnson commented May 18, 2017

Now I see how I confused you. THIS thread is for strongloop/loopback-filters NOT strongloop/loopback (the real LoopBack). The documentation I referred to was for LoopBack, which WAS correct for the real LoopBack. However in "loopback-filters" filter.fields does NOT work the same as in the real LoopBack. I provided the code fix for loopback-filters so that IT would work like the thousands of existing "real" LoopBack projects since the LoopBack documnation states "Note: We plan to convert all modules to use loopback-filter[s], so it will become LoopBack’s common “built-in” filtering mechanism." So changing the documentation in LoopBack will cause lots of people problems. Hope this helps.

So what I mean to say in my ealier post is:
The real LoopBack documentation says the pattern is { fields: {id: true, make: true, model: true} } but for loopback-filters, only something like { fields : [ 'id', 'make', 'model' ] } will ever work.

@ewrayjohnson
Copy link

ewrayjohnson commented May 18, 2017

Here is a snippet of code from the real LoopBack. Note the excludeUnknown param which is mapped to the "model.strict" property and the properties param, which is a list of the names of properties explicitly defined on the model:

/**
 * Normalize fields to an array of included properties
 * @param {String|String[]|Object} fields Fields filter
 * @param {String[]} properties Property names
 * @param {Boolean} excludeUnknown To exclude fields that are unknown properties
 * @returns {String[]} An array of included property names
 */
function fieldsToArray(fields, properties, excludeUnknown) {
  if (!fields) return;

  // include all properties by default
  var result = properties;
  var i, n;

  if (typeof fields === 'string') {
    result = [fields];
  } else if (Array.isArray(fields) && fields.length > 0) {
    // No empty array, including all the fields
    result = fields;
  } else if ('object' === typeof fields) {
    // { field1: boolean, field2: boolean ... }
    var included = [];
    var excluded = [];
    var keys = Object.keys(fields);
    if (!keys.length) return;

    for (i = 0, n = keys.length; i < n; i++) {
      var k = keys[i];
      if (fields[k]) {
        included.push(k);
      } else if ((k in fields) && !fields[k]) {
        excluded.push(k);
      }
    }
    if (included.length > 0) {
      result = included;
    } else if (excluded.length > 0) {
      for (i = 0, n = excluded.length; i < n; i++) {
        var index = result.indexOf(excluded[i]);
        result.splice(index, 1);
      }
    }
  }

  var fieldArray = [];
  if (excludeUnknown) {
    for (i = 0, n = result.length; i < n; i++) {
      if (properties.indexOf(result[i]) !== -1) {
        fieldArray.push(result[i]);
      }
    }
  } else {
    fieldArray = result;
  }
  return fieldArray;
}

@crandmck
Copy link

Oh! Thanks for the clarification @ewrayjohnson. I certainly was confused :-)
I'll back out my change to the LB docs.

crandmck added a commit to loopbackio/loopback.io that referenced this issue May 18, 2017
@crandmck crandmck removed their assignment Nov 7, 2017
@bestvow
Copy link

bestvow commented Dec 9, 2017

image
image
image
Do not add everything if some fields you don't want to see even a flase ?

@bajtos
Copy link
Member

bajtos commented Dec 14, 2017

Hello @ewrayjohnson, sorry for joining this discussion late. You offered a code snippet to change the behavior of loopback-filters and make it consistent with "regular" loopback. Could you please turn it into a pull request that we can land? (Assuming this issue is still relevant.)

@stale
Copy link

stale bot commented Nov 12, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Nov 12, 2019
@stale
Copy link

stale bot commented Nov 26, 2019

This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.

@stale stale bot closed this as completed Nov 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants