grapher
grapher copied to clipboard
Allow params to work for Global Exposure
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!
@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 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
@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!
Thank you! It's really nice to see that you keep maintaining this package as promised :)
@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 {}
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;
}
}
Ugh, very ugly indeed. Will take care of this
@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.
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 how are you calling the query ?
Like so: (client)
withQuery((props) => createQuery({ myNamedQuery: { ...myParams } }), { reactive: true })
@Twisterking I think something may not be good. Can you try using query.clone()
from the query that you expose
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?
import query from 'xxx';
withQuery(() => query.clone());
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.
I understand I will look into this.
thanks a bunch!
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.