grapher icon indicating copy to clipboard operation
grapher copied to clipboard

Allow params to work for Global Exposure

Open jthomaschewski opened this issue 7 years ago • 18 comments

In 1.3 resolver-links where removed. According to the migration guide "reducers" are recommended as a replacement. Unfortunately the reducer function has only access to the plain object and it doesn't seem possible to get access to the filters of the query or to define filters for the sub query.

E.g. this was possible with links

MyCollection.createQuery({
  some: 1,
  other: {
    $filter({filters, params}) {
      filters.searchTerm = params.searchTerm
    }
  }
})

The filters where passed through to the links resolver function (second parameter).

And chance to get the possibility of accessing filters or passing through parameters in any way down to reducer functions?

Thanks!

jthomaschewski avatar Dec 19 '17 02:12 jthomaschewski

@jbbr I thought about this before and it was implemented since 1.3 release.

Look at the docs: https://github.com/cult-of-coders/grapher/blob/master/docs/reducers.md#params-aware-reducers

Let me know if everything works as you expect it to.

theodorDiaconu avatar Dec 20 '17 08:12 theodorDiaconu

@theodorDiaconu thanks for pointing to the docs. Unfortunately the second parameter of the reduce function is always undefined in my case. I had a look at the code and it seems as only the object (first parameter) is passed through, to the defined function:

return this.reduceFunction.call(null, object); https://github.com/cult-of-coders/grapher/blob/master/lib/query/nodes/reducerNode.js#L13

jthomaschewski avatar Dec 20 '17 10:12 jthomaschewski

@jbbr something is very odd.... I could have swore I tested this function and adapted it properly. You are right. I will fix this ASAP!

theodorDiaconu avatar Dec 20 '17 10:12 theodorDiaconu

Thank you! It's really nice to see that you keep maintaining this package as promised :)

jthomaschewski avatar Dec 20 '17 13:12 jthomaschewski

@theodorDiaconu Unfortunately this doesn't seem to work on the client.

It seems, as if the method prepareForProcess consumes the params on the client-side and the server call does only include the body object with the resulting filters and options but without the raw params.

I think that the exposure-meteor method has to be modified to pass-through the params.

Code to reproduce:

// reducer on server
    paramBasedReducer: {
        body: {
            _id: 1,
        },
        reduce(object, params) {
            return params.element;
        }
    }
// query on client
const query = createQuery({
            authors: {
                $options: {limit: 1},
                paramBasedReducer: 1,
            }
        });

        query.setParams({
            element: 'TEST_STRING'
        });

        const data = await query.fetchSync();
        data.forEach(author => {
            assert.equal(author.paramBasedReducer, 'TEST_STRING');
        })

=> assert author.paramBasedReducer => undefined params in reducer function is {}

jthomaschewski avatar Mar 14 '18 00:03 jthomaschewski

Workaround (not pretty):

  • add the params to the options object
const query = createQuery({
    $filter({filters, options, params}) {
       options.params = params
    }),
    paramBasedReducer: 1
})
  • get params from reducer:
    paramBasedReducer: {
        body: {
            _id: 1,
        },
        reduce(object) {
            const params = this.parent.body.$options.params;
            // params available here
            return params.element;
        }
    }

jthomaschewski avatar Mar 14 '18 12:03 jthomaschewski

Ugh, very ugly indeed. Will take care of this

theodorDiaconu avatar Mar 14 '18 12:03 theodorDiaconu

@jbbr I identified the issue, it's because you need to use a namedQuery for params to work. Params aren't passed to server if you're using Global Exposure, with a named query things will work. This is not a bug but a design flaw.

theodorDiaconu avatar Mar 20 '18 13:03 theodorDiaconu

Is this somehow still present, even for named queries? I have a named query, living in its own file and using export default, which is also using a reducer (defined in another file).

The reducer itself works, but my reduce() function always only receives the object itself, no params, no options, no nothing. 😢 What am I doing wrong?

Items.addLinks({
  'openOrderItems': {
    collection: OpenOrdersBody,
    inversedBy: 'item'
  },
  'category': {
    type: 'one',
    collection: Categories,
    field: 'categoryId'
  },
  'specialPrices': {
    collection: Prices,
    inversedBy: 'item'
  }
});

Items.addReducers({
  'specialPrice': { 
    body: {
      specialPrices: {
        itemId: 1,
        userId: 1,
        groupId: 1,
        priceInfo: 1
      }
    },
    reduce(item) { // no more params :(
      console.log(arguments); // array of 2 items, but the second one (params) is always undefined
      return item.specialPrices[0] || null;
    }
  }
});

Twisterking avatar Jul 16 '18 15:07 Twisterking

@Twisterking how are you calling the query ?

theodorDiaconu avatar Jul 16 '18 15:07 theodorDiaconu

Like so: (client)

withQuery((props) => createQuery({ myNamedQuery: { ...myParams } }), { reactive: true }) 

Twisterking avatar Jul 16 '18 15:07 Twisterking

@Twisterking I think something may not be good. Can you try using query.clone() from the query that you expose

theodorDiaconu avatar Jul 16 '18 15:07 theodorDiaconu

Hmm where exactly? In my expose.js, where also my named itemsQuery query is imported and then .expose()d, I tried .clone().expose() but nothing changed. .expose().clone() throws an errors. Or maybe I am misunderstanding you?

Twisterking avatar Jul 16 '18 15:07 Twisterking

import query from 'xxx';

withQuery(() => query.clone());

theodorDiaconu avatar Jul 16 '18 15:07 theodorDiaconu

Okay. I tied:

import itemsQuery from '/imports/db/items/queries/itemsQuery';

and

withQuery((props) => itemsQuery.clone(myParams))

nothing changed. params is still undefined in my reducer.

Twisterking avatar Jul 16 '18 15:07 Twisterking

I understand I will look into this.

theodorDiaconu avatar Jul 16 '18 15:07 theodorDiaconu

thanks a bunch!

Twisterking avatar Jul 16 '18 15:07 Twisterking

Sidenote: this bug is also present for the $postFilter() function. According to docs: $postFilter(results, params) { ... return results }, but for me params is always undefined, just like in the reducers as stated above.

Twisterking avatar Aug 03 '18 08:08 Twisterking