[FIX] web: keep positional args for search_read

The previous code used to create its own args array
for the search_read method, replacing the one that
was originally given to it.

This lead to silent errors since positional arguments
to this function were completely ignored in the case
of search_read.

I took this commit as an opportunity to improve a
bit on the current state of these rpc helpers.
Namely, the basic args/kwargs priority is the following (top-to-bottom):
- kwargs defined in the rpc call
- kwargs defined in the kwargs key of the params kwarg of the rpc call
- positional arguments are passed as is

For read_group and search_read methods, the priority is the following:
- kwargs defined in the rpc call
- kwargs defined in the params kwarg to the rpc call
- kwargs defined in the kwargs key of the params kwarg of the rpc call
- positional arguments are passed as is

For the /web/dataset/search_read controller, only the params kwarg is
supported, resulting in the following priority:
- kwargs defined in the rpc call
- kwargs defined in the params kwarg to the rpc call
- positional arguments are passed as is

If both a kwargs and a positional arg is given for the same parameter,
it will be sent as is to the server which will crash with a typical
"got multiple values for keyword argument" TypeError. However, in the
MockServer however, we give priority to kwargs over args in this case.

Please note that I also chose to remove unnecessary default values so
that the ones actually used are the ones from the server, not the ones
that were duplicating those in the rpc js file.
This commit is contained in:
David Monjoie
2017-05-02 15:24:56 +02:00
parent 642fe9b9c1
commit d99ae3fd87
4 changed files with 97 additions and 33 deletions
+25 -19
View File
@@ -46,38 +46,44 @@ return {
params.args = options.args || [];
params.model = options.model;
params.method = options.method;
params.kwargs = options.kwargs || {};
params.kwargs.context = options.context || params.kwargs.context;
params.kwargs = _.extend(params.kwargs || {}, options.kwargs);
params.kwargs.context = options.context || params.context || params.kwargs.context;
}
if (options.method === 'read_group') {
params.kwargs.groupby = options.groupBy || params.kwargs.groupby || [];
params.kwargs.domain = options.domain || params.kwargs.domain || [];
params.kwargs.fields = options.fields || params.kwargs.fields || [];
params.kwargs.lazy = 'lazy' in options ? options.lazy : params.kwargs.lazy;
var orderBy = options.orderBy || params.orderBy;
params.kwargs.orderby = orderBy ? this._serializeSort(orderBy) : false;
params.kwargs.domain = options.domain || params.domain || params.kwargs.domain || [];
params.kwargs.fields = options.fields || params.fields || params.kwargs.fields || [];
params.kwargs.groupby = options.groupBy || params.groupBy || params.kwargs.groupby || [];
params.kwargs.offset = options.offset || params.offset || params.kwargs.offset;
params.kwargs.limit = options.limit || params.limit || params.kwargs.limit;
// In kwargs, we look for "orderby" rather than "orderBy" (note the absence of capital B),
// since the Python argument to the actual function is "orderby".
var orderBy = options.orderBy || params.orderBy || params.kwargs.orderby;
params.kwargs.orderby = orderBy ? this._serializeSort(orderBy) : orderBy;
params.kwargs.lazy = 'lazy' in options ? options.lazy : params.lazy;
}
if (options.method === 'search_read') {
// call the model method
params.args = [
options.domain || [],
options.fields || false,
options.offset || 0,
options.limit || false,
this._serializeSort(options.orderBy || params.orderBy || []),
];
params.kwargs.domain = options.domain || params.domain || params.kwargs.domain;
params.kwargs.fields = options.fields || params.fields || params.kwargs.fields;
params.kwargs.offset = options.offset || params.offset || params.kwargs.offset;
params.kwargs.limit = options.limit || params.limit || params.kwargs.limit;
// In kwargs, we look for "order" rather than "orderBy" since the Python
// argument to the actual function is "order".
var orderBy = options.orderBy || params.orderBy || params.kwargs.order;
params.kwargs.order = orderBy ? this._serializeSort(orderBy) : orderBy;
}
if (options.route === '/web/dataset/search_read') {
// specifically call the controller
params.model = options.model || params.model;
params.domain = options.domain || params.domain || [];
params.fields = options.fields || params.fields || false;
params.domain = options.domain || params.domain;
params.fields = options.fields || params.fields;
params.limit = options.limit || params.limit;
params.offset = options.offset || params.offset ;
params.sort = this._serializeSort(options.orderBy || params.orderBy || []);
params.offset = options.offset || params.offset;
var orderBy = options.orderBy || params.orderBy;
params.sort = orderBy ? this._serializeSort(orderBy) : orderBy;
params.context = options.context || params.context || {};
}
+64 -6
View File
@@ -136,6 +136,33 @@ QUnit.module('core', {}, function () {
offset: 2,
orderBy: [{name: 'yop', asc: true}, {name: 'aa', asc: false}],
});
assert.deepEqual(query.params, {
args: [],
kwargs: {
domain: ['a', '=', 1],
fields: ['name'],
offset: 2,
limit: 32,
order: 'yop ASC, aa DESC'
},
method: 'search_read',
model: 'partner'
}, "should have correct kwargs");
});
QUnit.test('search_read with args', function (assert) {
assert.expect(1);
var query = rpc.buildQuery({
model: 'partner',
method: 'search_read',
args: [
['a', '=', 1],
['name'],
2,
32,
'yop ASC, aa DESC',
]
});
assert.deepEqual(query.params, {
args: [['a', '=', 1], ['name'], 2, 32, 'yop ASC, aa DESC'],
kwargs: {},
@@ -165,7 +192,6 @@ QUnit.module('core', {}, function () {
fields: ['name'],
groupby: ['product_id'],
lazy: true,
orderby: false,
},
method: 'read_group',
model: 'partner',
@@ -195,23 +221,55 @@ QUnit.module('core', {}, function () {
fields: ['name'],
groupby: ['product_id'],
lazy: false,
orderby: false,
},
method: 'read_group',
model: 'partner',
}, "should have correct args");
});
QUnit.test('read_group with no domain, nor fields', function (assert) {
assert.expect(7);
var query = rpc.buildQuery({
model: 'partner',
method: 'read_group',
});
assert.deepEqual(query.params.kwargs.domain, [], "should have [] as default domain");
assert.deepEqual(query.params.kwargs.fields, [], "should have false as default fields");
assert.deepEqual(query.params.kwargs.groupby, [], "should have false as default groupby");
assert.deepEqual(query.params.kwargs.offset, undefined, "should not enforce a default value for offst");
assert.deepEqual(query.params.kwargs.limit, undefined, "should not enforce a default value for limit");
assert.deepEqual(query.params.kwargs.orderby, undefined, "should not enforce a default value for orderby");
assert.deepEqual(query.params.kwargs.lazy, undefined, "should not enforce a default value for lazy");
});
QUnit.test('search_read with no domain, nor fields', function (assert) {
assert.expect(2);
assert.expect(5);
var query = rpc.buildQuery({
model: 'partner',
method: 'search_read',
});
assert.deepEqual(query.params.kwargs.domain, undefined, "should not enforce a default value for domain");
assert.deepEqual(query.params.kwargs.fields, undefined, "should not enforce a default value for fields");
assert.deepEqual(query.params.kwargs.offset, undefined, "should not enforce a default value for offset");
assert.deepEqual(query.params.kwargs.limit, undefined, "should not enforce a default value for limit");
assert.deepEqual(query.params.kwargs.order, undefined, "should not enforce a default value for orderby");
});
QUnit.test('search_read controller with no domain, nor fields', function (assert) {
assert.expect(5);
var query = rpc.buildQuery({
model: 'partner',
route: '/web/dataset/search_read',
});
assert.deepEqual(query.params.domain, [], "should have [] as default domain");
assert.strictEqual(query.params.fields, false, "should have false as default fields");
assert.deepEqual(query.params.domain, undefined, "should not enforce a default value for domain");
assert.deepEqual(query.params.fields, undefined, "should not enforce a default value for fields");
assert.deepEqual(query.params.offset, undefined, "should not enforce a default value for groupby");
assert.deepEqual(query.params.limit, undefined, "should not enforce a default value for limit");
assert.deepEqual(query.params.sort, undefined, "should not enforce a default value for order");
});
});
});
});
@@ -3361,7 +3361,7 @@ QUnit.module('relational_fields', {
mockRPC: function (route, args) {
if (args.method === 'search_read') {
count++;
nb_fields_fetched = args.args[1].length;
nb_fields_fetched = args.kwargs.fields.length;
}
return this._super.apply(this, arguments);
},
@@ -3394,7 +3394,7 @@ QUnit.module('relational_fields', {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'search_read') {
assert.deepEqual(args.args[0], ['|', ['id', '=', 4], ['user_id', '=', 17]],
assert.deepEqual(args.kwargs.domain, ['|', ['id', '=', 4], ['user_id', '=', 17]],
"search_read should sent the correct domain");
}
return this._super.apply(this, arguments);
@@ -718,11 +718,11 @@ var MockServer = Class.extend({
_mockSearchRead: function (model, args, kwargs) {
var result = this._mockSearchReadController({
model: model,
domain: args[0],
fields: args[1],
offset: args[2],
limit: args[3],
sort: args[4],
domain: kwargs.domain || args[0],
fields: kwargs.fields || args[1],
offset: kwargs.offset || args[2],
limit: kwargs.limit || args[3],
order: kwargs.order || args[4],
context: kwargs.context,
});
return result.records;
@@ -743,7 +743,7 @@ var MockServer = Class.extend({
*/
_mockSearchReadController: function (args) {
var self = this;
var records = this._getRecords(args.model, args.domain);
var records = this._getRecords(args.model, args.domain || []);
var fields = args.fields || _.keys(this.data[args.model].fields);
var nbRecords = records.length;
var offset = args.offset || 0;