[TEST] serialization of search domains & contexts by the search view
bzr revid: xmo@openerp.com-20120503125949-2m8euott3xzyivdm
This commit is contained in:
parent
836dfa6aa8
commit
6d12c155a4
|
@ -656,7 +656,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
|
|||
do_search: function () {
|
||||
var domains = [], contexts = [], groupbys = [], errors = [];
|
||||
|
||||
return this.on_search([], [], []);
|
||||
this.query.each(function (facet) {
|
||||
var field = facet.get('field');
|
||||
try {
|
||||
|
@ -902,12 +901,12 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
|
|||
/**
|
||||
* Fetches contexts for all enabled filters in the group
|
||||
*
|
||||
* @param {VS.model.SearchFacet} facet
|
||||
* @param {openerp.web.search.Facet} facet
|
||||
* @return {*} combined contexts of the enabled filters in this group
|
||||
*/
|
||||
get_context: function (facet) {
|
||||
var contexts = _(facet.get('values')).chain()
|
||||
.map(function (filter) { return filter.attrs.context; })
|
||||
var contexts = _(facet.values).chain()
|
||||
.map(function (f) { return f.get('value').attrs.context; })
|
||||
.reject(_.isEmpty)
|
||||
.value();
|
||||
|
||||
|
@ -924,8 +923,8 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
|
|||
* @return {Array} enabled filters in this group
|
||||
*/
|
||||
get_groupby: function (facet) {
|
||||
return _(facet.get('values')).chain()
|
||||
.map(function (filter) { return filter.attrs.context; })
|
||||
return _(facet.values).chain()
|
||||
.map(function (f) { return f.get('value').attrs.context; })
|
||||
.reject(_.isEmpty)
|
||||
.value();
|
||||
},
|
||||
|
@ -936,8 +935,8 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
|
|||
* @return {*} combined domains of the enabled filters in this group
|
||||
*/
|
||||
get_domain: function (facet) {
|
||||
var domains = _(facet.get('values')).chain()
|
||||
.map(function (filter) { return filter.attrs.domain; })
|
||||
var domains = _(facet.values).chain()
|
||||
.map(function (f) { return f.get('value').attrs.domain; })
|
||||
.reject(_.isEmpty)
|
||||
.value();
|
||||
|
||||
|
@ -1014,14 +1013,14 @@ instance.web.search.Field = instance.web.search.Input.extend( /** @lends instanc
|
|||
return facet.value();
|
||||
},
|
||||
get_context: function (facet) {
|
||||
var val = this.get_value(facet);
|
||||
// A field needs a value to be "active", and a context to send when
|
||||
// active
|
||||
var has_value = (val !== null && val !== '');
|
||||
var context = this.attrs.context;
|
||||
if (!(has_value && context)) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
var val = this.get_value(facet);
|
||||
var has_value = (val !== null && val !== '');
|
||||
return new instance.web.CompoundContext(context)
|
||||
.set_eval_context({self: val});
|
||||
},
|
||||
|
|
|
@ -4,6 +4,25 @@ $(document).ready(function () {
|
|||
xhr.send(null);
|
||||
var doc = xhr.responseXML;
|
||||
|
||||
var noop = function () {};
|
||||
/**
|
||||
* Make connection RPC responses mockable by setting keys on the
|
||||
* Connection#responses object (key is the URL, value is the function to
|
||||
* call with the RPC request payload)
|
||||
*
|
||||
* @param {openerp.web.Connection} connection connection instance to mockify
|
||||
* @param {Object} [responses] url:function mapping to seed the mock connection
|
||||
*/
|
||||
var mockifyRPC = function (connection, responses) {
|
||||
connection.responses = responses || {};
|
||||
connection.rpc_function = function (url, payload) {
|
||||
if (!(url.url in this.responses)) {
|
||||
return $.Deferred().reject({}, 'failed', _.str.sprintf("Url %s not found in mock responses", url.url)).promise();
|
||||
}
|
||||
return $.when(this.responses[url.url](payload));
|
||||
};
|
||||
};
|
||||
|
||||
var instance;
|
||||
module('query', {
|
||||
setup: function () {
|
||||
|
@ -157,16 +176,7 @@ $(document).ready(function () {
|
|||
|
||||
instance.web.qweb.add_template(doc);
|
||||
|
||||
instance.connection.responses = {};
|
||||
instance.connection.rpc_function = function (url, payload) {
|
||||
if (!(url.url in this.responses)) {
|
||||
return $.Deferred().reject(
|
||||
{}, 'failed',
|
||||
_.str.sprintf("Url %s not found in mock responses",
|
||||
url.url)).promise();
|
||||
}
|
||||
return $.when(this.responses[url.url](payload));
|
||||
};
|
||||
mockifyRPC(instance.connection);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -220,7 +230,11 @@ $(document).ready(function () {
|
|||
};
|
||||
|
||||
var dataset = {model: 'dummy.model', get_context: function () { return {}; }};
|
||||
return new instance.web.SearchView(null, dataset, false, defaults);
|
||||
var view = new instance.web.SearchView(null, dataset, false, defaults);
|
||||
view.on_invalid.add(function () {
|
||||
ok(false, JSON.stringify([].slice(arguments)));
|
||||
});
|
||||
return view;
|
||||
}
|
||||
asyncTest('calling', 2, function () {
|
||||
var defaults_called = false;
|
||||
|
@ -401,16 +415,7 @@ $(document).ready(function () {
|
|||
|
||||
instance.web.qweb.add_template(doc);
|
||||
|
||||
instance.connection.responses = {};
|
||||
instance.connection.rpc_function = function (url, payload) {
|
||||
if (!(url.url in this.responses)) {
|
||||
return $.Deferred().reject(
|
||||
{}, 'failed',
|
||||
_.str.sprintf("Url %s not found in mock responses",
|
||||
url.url)).promise();
|
||||
}
|
||||
return $.when(this.responses[url.url](payload));
|
||||
};
|
||||
mockifyRPC(instance.connection);
|
||||
}
|
||||
});
|
||||
asyncTest('calling', 4, function () {
|
||||
|
@ -449,7 +454,7 @@ $(document).ready(function () {
|
|||
var completion = {
|
||||
label: "Dummy",
|
||||
facet: {
|
||||
field: {},
|
||||
field: {get_domain: noop, get_context: noop, get_groupby: noop},
|
||||
category: 'Dummy',
|
||||
values: [{label: 'dummy', value: 42}]
|
||||
}
|
||||
|
@ -471,7 +476,7 @@ $(document).ready(function () {
|
|||
});
|
||||
});
|
||||
asyncTest('facet selection: new value existing facet', 3, function () {
|
||||
var field = {};
|
||||
var field = {get_domain: noop, get_context: noop, get_groupby: noop};
|
||||
var completion = {
|
||||
label: "Dummy",
|
||||
facet: {
|
||||
|
@ -656,6 +661,115 @@ $(document).ready(function () {
|
|||
});
|
||||
});
|
||||
|
||||
module('search-serialization', {
|
||||
setup: function () {
|
||||
instance = window.openerp.init([]);
|
||||
window.openerp.web.corelib(instance);
|
||||
window.openerp.web.coresetup(instance);
|
||||
window.openerp.web.chrome(instance);
|
||||
window.openerp.web.data(instance);
|
||||
window.openerp.web.search(instance);
|
||||
|
||||
instance.web.qweb.add_template(doc);
|
||||
|
||||
mockifyRPC(instance.connection);
|
||||
}
|
||||
});
|
||||
asyncTest('No facet, no call', 6, function () {
|
||||
var got_domain = false, got_context = false, got_groupby = false;
|
||||
var $fix = $('#qunit-fixture');
|
||||
var view = makeSearchView({
|
||||
get_domain: function () {
|
||||
got_domain = true;
|
||||
return null;
|
||||
},
|
||||
get_context: function () {
|
||||
got_context = true;
|
||||
return null;
|
||||
},
|
||||
get_groupby: function () {
|
||||
got_groupby = true;
|
||||
return null;
|
||||
}
|
||||
});
|
||||
var ds, cs, gs;
|
||||
view.on_search.add(function (d, c, g) {
|
||||
ds = d, cs = c, gs = g;
|
||||
});
|
||||
view.appendTo($fix)
|
||||
.always(start)
|
||||
.fail(function (error) { ok(false, error.message); })
|
||||
.done(function () {
|
||||
view.do_search();
|
||||
ok(!got_domain, "no facet, should not have fetched domain");
|
||||
ok(_(ds).isEmpty(), "domains list should be empty");
|
||||
|
||||
ok(!got_context, "no facet, should not have fetched context");
|
||||
ok(_(cs).isEmpty(), "contexts list should be empty");
|
||||
|
||||
ok(!got_groupby, "no facet, should not have fetched groupby");
|
||||
ok(_(gs).isEmpty(), "groupby list should be empty");
|
||||
})
|
||||
});
|
||||
asyncTest('London, calling', 8, function () {
|
||||
var got_domain = false, got_context = false, got_groupby = false;
|
||||
var $fix = $('#qunit-fixture');
|
||||
var view = makeSearchView({
|
||||
get_domain: function (facet) {
|
||||
equal(facet.get('category'), "dummy");
|
||||
deepEqual(facet.values.toJSON(), [{label: "42", value: 42}]);
|
||||
got_domain = true;
|
||||
return null;
|
||||
},
|
||||
get_context: function () {
|
||||
got_context = true;
|
||||
return null;
|
||||
},
|
||||
get_groupby: function () {
|
||||
got_groupby = true;
|
||||
return null;
|
||||
}
|
||||
}, {dummy: 42});
|
||||
var ds, cs, gs;
|
||||
view.on_search.add(function (d, c, g) {
|
||||
ds = d, cs = c, gs = g;
|
||||
});
|
||||
view.appendTo($fix)
|
||||
.always(start)
|
||||
.fail(function (error) { ok(false, error.message); })
|
||||
.done(function () {
|
||||
view.do_search();
|
||||
ok(got_domain, "should have fetched domain");
|
||||
ok(_(ds).isEmpty(), "domains list should be empty");
|
||||
|
||||
ok(got_context, "should have fetched context");
|
||||
ok(_(cs).isEmpty(), "contexts list should be empty");
|
||||
|
||||
ok(got_groupby, "should have fetched groupby");
|
||||
ok(_(gs).isEmpty(), "groupby list should be empty");
|
||||
})
|
||||
});
|
||||
asyncTest('Generate domains', 1, function () {
|
||||
var $fix = $('#qunit-fixture');
|
||||
var view = makeSearchView({
|
||||
get_domain: function (facet) {
|
||||
return facet.values.map(function (value) {
|
||||
return ['win', '4', value.get('value')];
|
||||
});
|
||||
}
|
||||
}, {dummy: 42});
|
||||
var ds;
|
||||
view.on_search.add(function (d) { ds = d; });
|
||||
view.appendTo($fix)
|
||||
.always(start)
|
||||
.fail(function (error) { ok(false, error.message); })
|
||||
.done(function () {
|
||||
view.do_search();
|
||||
deepEqual(ds, [[['win', '4', 42]]],
|
||||
"search should yield an array of contexts");
|
||||
});
|
||||
});
|
||||
|
||||
module('drawer', {
|
||||
setup: function () {
|
||||
instance = window.openerp.init([]);
|
||||
|
@ -667,16 +781,7 @@ $(document).ready(function () {
|
|||
|
||||
instance.web.qweb.add_template(doc);
|
||||
|
||||
instance.connection.responses = {};
|
||||
instance.connection.rpc_function = function (url, payload) {
|
||||
if (!(url.url in this.responses)) {
|
||||
return $.Deferred().reject(
|
||||
{}, 'failed',
|
||||
_.str.sprintf("Url %s not found in mock responses",
|
||||
url.url)).promise();
|
||||
}
|
||||
return $.when(this.responses[url.url](payload));
|
||||
};
|
||||
mockifyRPC(instance.connection);
|
||||
}
|
||||
});
|
||||
asyncTest('is-drawn', 2, function () {
|
||||
|
@ -704,43 +809,35 @@ $(document).ready(function () {
|
|||
|
||||
instance.web.qweb.add_template(doc);
|
||||
|
||||
instance.connection.responses = {};
|
||||
instance.connection.rpc_function = function (url, payload) {
|
||||
if (!(url.url in this.responses)) {
|
||||
return $.Deferred().reject(
|
||||
{}, 'failed',
|
||||
_.str.sprintf("Url %s not found in mock responses",
|
||||
url.url)).promise();
|
||||
mockifyRPC(instance.connection, {
|
||||
'/web/searchview/load': function () {
|
||||
// view with a single group of filters
|
||||
return {result: {fields_view: {
|
||||
type: 'search',
|
||||
fields: {},
|
||||
arch: {
|
||||
tag: 'search',
|
||||
attrs: {},
|
||||
children: [{
|
||||
tag: 'filter',
|
||||
attrs: { string: "Foo1", domain: [ ['foo', '=', '1'] ] },
|
||||
children: []
|
||||
}, {
|
||||
tag: 'filter',
|
||||
attrs: {
|
||||
name: 'foo2',
|
||||
string: "Foo2",
|
||||
domain: [ ['foo', '=', '2'] ] },
|
||||
children: []
|
||||
}, {
|
||||
tag: 'filter',
|
||||
attrs: { string: "Foo3", domain: [ ['foo', '=', '3'] ] },
|
||||
children: []
|
||||
}]
|
||||
}
|
||||
}}};
|
||||
}
|
||||
return $.when(this.responses[url.url](payload));
|
||||
};
|
||||
instance.connection.responses['/web/searchview/load'] = function () {
|
||||
// view with a single group of filters
|
||||
return {result: {fields_view: {
|
||||
type: 'search',
|
||||
fields: {},
|
||||
arch: {
|
||||
tag: 'search',
|
||||
attrs: {},
|
||||
children: [{
|
||||
tag: 'filter',
|
||||
attrs: { string: "Foo1", domain: [ ['foo', '=', '1'] ] },
|
||||
children: []
|
||||
}, {
|
||||
tag: 'filter',
|
||||
attrs: {
|
||||
name: 'foo2',
|
||||
string: "Foo2",
|
||||
domain: [ ['foo', '=', '2'] ] },
|
||||
children: []
|
||||
}, {
|
||||
tag: 'filter',
|
||||
attrs: { string: "Foo3", domain: [ ['foo', '=', '3'] ] },
|
||||
children: []
|
||||
}]
|
||||
}
|
||||
}}};
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
asyncTest('drawn', 3, function () {
|
||||
|
|
|
@ -249,21 +249,33 @@ Converting from facet objects
|
|||
Ultimately, the point of the search view is to allow searching. In
|
||||
OpenERP this is done via :ref:`domains <openerpserver:domains>`. On
|
||||
the other hand, the OpenERP Web 7 search view's state is modelled
|
||||
after a collection of :js:class:`~VS.model.SearchFacet`, and each
|
||||
after a collection of :js:class:`~openerp.web.search.Facet`, and each
|
||||
field of a search view may have special requirements when it comes to
|
||||
the domains it produces [#]_.
|
||||
|
||||
So there needs to be some way of mapping
|
||||
:js:class:`~VS.model.SearchFacet` objects to OpenERP search data.
|
||||
:js:class:`~openerp.web.search.Facet` objects to OpenERP search data.
|
||||
|
||||
This is done via an input's
|
||||
:js:func:`~openerp.web.search.Input.get_domain` and
|
||||
:js:func:`~openerp.web.search.Input.get_context`. Each takes a
|
||||
:js:class:`~VS.model.SearchFacet` and returns whatever it's supposed
|
||||
to generate (a domain or a context, respectively). Either can return
|
||||
``null`` if the current value does not map to a domain or context, and
|
||||
can throw an :js:class:`~openerp.web.search.Invalid` exception if the
|
||||
value is not valid at all for the field.
|
||||
:js:class:`~openerp.web.search.Facet` and returns whatever it's
|
||||
supposed to generate (a domain or a context, respectively). Either can
|
||||
return ``null`` if the current value does not map to a domain or
|
||||
context, and can throw an :js:class:`~openerp.web.search.Invalid`
|
||||
exception if the value is not valid at all for the field.
|
||||
|
||||
.. note::
|
||||
|
||||
The :js:class:`~openerp.web.search.Facet` object can have any
|
||||
number of values (from 1 upwards)
|
||||
|
||||
.. note::
|
||||
|
||||
There is a third conversion method,
|
||||
:js:func:`~openerp.web.search.Input.get_groupby`, which returns an
|
||||
``Array`` of groupby domains rather than a single context. At this
|
||||
point, it is only implemented on (and used by) filters.
|
||||
|
||||
Converting to facet objects
|
||||
---------------------------
|
||||
|
|
Loading…
Reference in New Issue