-
Notifications
You must be signed in to change notification settings - Fork 126
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
QueryMap encoding does not bracket collections of maps or other collections #584
Comments
@techouse see the above. |
@diegotori that is some convoluted query 🙈 haha 😂 Looks like something that's ripe for a I'll take a look. |
Yeah, if it were that easy. However, my company uses Strapi to expose content, and this is how you filter data when making requests to it. |
@diegotori do you mind testing #585 dependency_overrides:
chopper:
git:
url: https://github.com/lejard-h/chopper
ref: fix/issue-584
path: chopper I used an elegant solution which will probably work Iterable<_Pair<String, String>> _iterableToQuery(
String name,
Iterable values, {
bool useBrackets = false,
bool includeNullQueryVars = false,
}) =>
[
for (final dynamic value in values)
if (value?.toString().isNotEmpty ?? false)
if (value is Iterable)
..._iterableToQuery(
name,
value,
useBrackets: useBrackets,
includeNullQueryVars: includeNullQueryVars,
)
else if (value is Map<String, dynamic>)
..._mapToQuery(
value,
prefix: name,
useBrackets: useBrackets,
includeNullQueryVars: includeNullQueryVars,
)
else
_Pair(
name,
_normalizeValue(value),
useBrackets: useBrackets,
)
]; Check the test example which takes a map like {
'filters': {
r'$or': [
{
'date': {
r'$eq': '2020-01-01',
}
},
{
'date': {
r'$eq': '2020-01-02',
}
}
],
'author': {
'name': {
r'$eq': 'Kai doe',
},
}
}
} and produces
and
|
@techouse Shouldn't it add a bracket as part of the collection being created? In other words, shouldn't it do: filters[$or][][date][$eq]=2020-01-01&filters[$or][][date][$eq]=2020-01-02&filters[author][name][$eq]=Kai doe I'll take a look at the PR either tonight or tomorrow. |
@techouse Maybe it can do: Iterable<_Pair<String, String>> _iterableToQuery(
String name,
Iterable values, {
bool useBrackets = false,
bool includeNullQueryVars = false,
}) =>
[
for (final dynamic value in values)
if (value?.toString().isNotEmpty ?? false)
if (value is Iterable)
..._iterableToQuery(
useBrackets ? '$name[] : name,
value,
useBrackets: useBrackets,
includeNullQueryVars: includeNullQueryVars,
)
else if (value is Map<String, dynamic>)
..._mapToQuery(
value,
prefix: name,
useBrackets: useBrackets,
includeNullQueryVars: includeNullQueryVars,
)
else
_Pair(
name,
_normalizeValue(value),
useBrackets: useBrackets,
)
]; |
qs, which Strapi uses on its server, parses either {
'one' {
'two': [1, 2, 3]
}
} Which produced filters[one][two][]=1&filters[one][two][]=2&filters[one][two][]=3 The problem is, because it never handled anything beyond primitives, there were no examples where it would try to inject something other than simple. The case that needs to be solved is:
|
Yeah, looks like a more involved problem + solution. I'll see when I'll have time to tackle this. Hopefully over the Easter break. |
Nah, that won't work because at that stage it's already a single item. |
@diegotori I started slowly porting qs to Dart. Needless to say that it's quite the ordeal as it's old school non-typed JavaScript 😭 |
@techouse I think I may have fixed it. Long story short, we have to add bracket suffixes to all collection types (map and list) when encoding. In other words, this ended up working and passing the existing tests: Iterable<_Pair<String, String>> _iterableToQuery(
String name,
Iterable values, {
bool useBrackets = false,
bool includeNullQueryVars = false,
}) {
final bracketedName =
'$name${useBrackets ? Uri.encodeQueryComponent('[]') : ''}';
return [
for (final dynamic value in values)
if (value?.toString().isNotEmpty ?? false)
if (value is Iterable)
..._iterableToQuery(
bracketedName,
value,
useBrackets: useBrackets,
includeNullQueryVars: includeNullQueryVars,
)
else if (value is Map<String, dynamic>)
..._mapToQuery(
value,
prefix: bracketedName,
useBrackets: useBrackets,
includeNullQueryVars: includeNullQueryVars,
)
else
_Pair(
name,
_normalizeValue(value),
useBrackets: useBrackets,
)
];
} Given the following query map: {
'filters': {
r'$or': [
{
'date': {
r'$eq': '2020-01-01',
}
},
{
'date': {
r'$eq': '2020-01-02',
}
}
],
'author': {
'name': {
r'$eq': 'Kai doe',
},
}
}
} It ended up producing the following encoded value:
Hopefully, this might suffice. I might end up submitting a PR to this effect shortly. |
…ns and with brackets.
Nice work, however, I have already finished porting the |
@techouse in that case, you may want to retain the test cases that I wrote for it. That way, you can use those to verify that your |
Nothing will go to waste, my friend. 💪 |
@diegotori yesterday I releaded my Dart port of qs to the public. I'll make a PR using it to fix this issue. P.S.: Here's your test case being put to good use ✅ |
@diegotori would you mind playing around with #592 and reporting back any findings / bugs? 🐛 |
Steps to Reproduce
@QueryMap
parameter and its CRUD annotation'suseBrackets
property set totrue
.Expected results:
Actual results:
Looks like this line in
utils.dart
is the culprit, since it's not recursively checking whether the item in the collection is either a map or another collection.If I modify both
_mapToQuery
and_iterableToQuery
to the below, it ends up producing the expected result:I dunno if there's a better way to handle this edge case, but this was my effort thus far.
This is a breaking issue when attempting to use Chopper to communicate with a Strapi server, since it uses
qs
based query formats when requesting filtered data.The text was updated successfully, but these errors were encountered: