From bedce02bb7f4bcb03da4025974457b86be52706f Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Mon, 29 Aug 2022 13:48:03 +0000 Subject: [PATCH] [REF] web,mail,account: orm service: move context in kwargs This commit standardizes the API of orm service functions by adding a "kwargs" parameter, s.t. one can always use those functions even if the target model overrides the corresponding method to add the support of a given kwargs. Furthermore, to simplify those function API, and to close the gap between the js and python APIs, we moved the "context" argument inside the kwargs. closes odoo/odoo#99018 Related: odoo/enterprise#30830 Signed-off-by: Samuel Degueldre --- .../components/bills_upload/bills_upload.js | 2 +- addons/mail/static/src/models/messaging.js | 16 ++-- addons/web/static/src/core/orm_service.js | 43 +++++----- .../web/static/src/views/graph/graph_model.js | 6 +- .../web/static/src/views/pivot/pivot_model.js | 7 +- .../web/static/src/views/relational_model.js | 81 +++++++++---------- .../views/view_dialogs/export_data_dialog.js | 4 +- .../static/tests/core/orm_service_tests.js | 18 ++--- .../tests/views/form/form_view_tests.js | 2 +- 9 files changed, 85 insertions(+), 94 deletions(-) diff --git a/addons/account/static/src/components/bills_upload/bills_upload.js b/addons/account/static/src/components/bills_upload/bills_upload.js index 0db2516cb21..a35e8d4ee53 100644 --- a/addons/account/static/src/components/bills_upload/bills_upload.js +++ b/addons/account/static/src/components/bills_upload/bills_upload.js @@ -27,7 +27,7 @@ export class AccountFileUploader extends Component { datas: file.data, }; const att_id = await this.orm.create("ir.attachment", [att_data], { - ...this.props.extraContext, ...this.env.searchModel.context, + context: { ...this.props.extraContext, ...this.env.searchModel.context }, }); this.attachmentIdsToProcess.push(att_id); } diff --git a/addons/mail/static/src/models/messaging.js b/addons/mail/static/src/models/messaging.js index 368cfce2b98..8047354f869 100644 --- a/addons/mail/static/src/models/messaging.js +++ b/addons/mail/static/src/models/messaging.js @@ -171,24 +171,24 @@ registerModel({ return this.env.services.rpc(route, rpcParameters, { silent, ...rpcSettings }); } else { const { args, method, model, kwargs = {} } = params; - const { context, domain, fields, groupBy, ...ormOptions } = kwargs; + const { domain, fields, groupBy } = kwargs; const ormService = 'shadow' in options ? this.env.services.orm.silent : this.env.services.orm; switch (method) { case 'create': - return ormService.create(model, args[0], context); + return ormService.create(model, args[0], kwargs); case 'read': - return ormService.read(model, args[0], args.length > 1 ? args[1] : undefined, {}, context); + return ormService.read(model, args[0], args.length > 1 ? args[1] : undefined, kwargs); case 'read_group': - return ormService.readGroup(model, domain, fields, groupBy, ormOptions, context); + return ormService.readGroup(model, domain, fields, groupBy, kwargs); case 'search': - return ormService.search(model, args[0], ormOptions, context); + return ormService.search(model, args[0], kwargs); case 'search_read': - return ormService.searchRead(model, domain, fields, ormOptions, context); + return ormService.searchRead(model, domain, fields, kwargs); case 'unlink': - return ormService.unlink(model, args[0], context); + return ormService.unlink(model, args[0], kwargs); case 'write': - return ormService.write(model, args[0], args[1], context); + return ormService.write(model, args[0], args[1], kwargs); default: return ormService.call(model, method, args, kwargs); } diff --git a/addons/web/static/src/core/orm_service.js b/addons/web/static/src/core/orm_service.js index 9b96dd21f2e..920d5a0cf72 100644 --- a/addons/web/static/src/core/orm_service.js +++ b/addons/web/static/src/core/orm_service.js @@ -109,23 +109,23 @@ export class ORM { return this.rpc(url, params, { silent: this._silent }); } - create(model, records, context) { + create(model, records, kwargs = {}) { validateArray("records", records); for (const record of records) { validateObject("record", record); } - return this.call(model, "create", records, { context }); + return this.call(model, "create", records, kwargs); } - nameGet(model, ids, context) { + nameGet(model, ids, kwargs = {}) { validatePrimitiveList("ids", "number", ids); if (!ids.length) { return Promise.resolve([]); } - return this.call(model, "name_get", [ids], { context }); + return this.call(model, "name_get", [ids], kwargs); } - read(model, ids, fields, kwargs = {}, context = {}) { + read(model, ids, fields, kwargs = {}) { validatePrimitiveList("ids", "number", ids); if (fields) { validatePrimitiveList("fields", "string", fields); @@ -133,43 +133,43 @@ export class ORM { if (!ids.length) { return Promise.resolve([]); } - return this.call(model, "read", [ids, fields], { ...kwargs, context }); + return this.call(model, "read", [ids, fields], kwargs); } - readGroup(model, domain, fields, groupby, kwargs = {}, context = {}) { + readGroup(model, domain, fields, groupby, kwargs = {}) { validateArray("domain", domain); validatePrimitiveList("fields", "string", fields); validatePrimitiveList("groupby", "string", groupby); - return this.call(model, "read_group", [], { ...kwargs, domain, fields, groupby, context }); + return this.call(model, "read_group", [], { ...kwargs, domain, fields, groupby }); } - search(model, domain, kwargs = {}, context = {}) { + search(model, domain, kwargs = {}) { validateArray("domain", domain); - return this.call(model, "search", [domain], { ...kwargs, context }); + return this.call(model, "search", [domain], kwargs); } - searchRead(model, domain, fields, kwargs = {}, context = {}) { + searchRead(model, domain, fields, kwargs = {}) { validateArray("domain", domain); if (fields) { validatePrimitiveList("fields", "string", fields); } - return this.call(model, "search_read", [], { ...kwargs, context, domain, fields }); + return this.call(model, "search_read", [], { ...kwargs, domain, fields }); } - searchCount(model, domain, context = {}) { + searchCount(model, domain, kwargs = {}) { validateArray("domain", domain); - return this.call(model, "search_count", [domain], { context }); + return this.call(model, "search_count", [domain], kwargs); } - unlink(model, ids, context) { + unlink(model, ids, kwargs = {}) { validatePrimitiveList("ids", "number", ids); if (!ids.length) { return true; } - return this.call(model, "unlink", [ids], { context }); + return this.call(model, "unlink", [ids], kwargs); } - webReadGroup(model, domain, fields, groupby, kwargs = {}, context = {}) { + webReadGroup(model, domain, fields, groupby, kwargs = {}) { validateArray("domain", domain); validatePrimitiveList("fields", "string", fields); validatePrimitiveList("groupby", "string", groupby); @@ -178,20 +178,19 @@ export class ORM { groupby, domain, fields, - context, }); } - webSearchRead(model, domain, fields, kwargs = {}, context = {}) { + webSearchRead(model, domain, fields, kwargs = {}) { validateArray("domain", domain); validatePrimitiveList("fields", "string", fields); - return this.call(model, "web_search_read", [], { ...kwargs, domain, fields, context }); + return this.call(model, "web_search_read", [], { ...kwargs, domain, fields }); } - write(model, ids, data, context) { + write(model, ids, data, kwargs = {}) { validatePrimitiveList("ids", "number", ids); validateObject("data", data); - return this.call(model, "write", [ids, data], { context }); + return this.call(model, "write", [ids, data], kwargs); } } diff --git a/addons/web/static/src/views/graph/graph_model.js b/addons/web/static/src/views/graph/graph_model.js index a5103051f1e..ce4d6180d30 100644 --- a/addons/web/static/src/views/graph/graph_model.js +++ b/addons/web/static/src/views/graph/graph_model.js @@ -413,8 +413,10 @@ export class GraphModel extends Model { domain.arrayRepr, measures, groupBy.map((gb) => gb.spec), - { lazy: false }, // what is this thing??? - { fill_temporal: true, ...this.searchParams.context } + { + lazy: false, // what is this thing??? + context: { fill_temporal: true, ...this.searchParams.context }, + } ) .then((data) => { const dataPoints = []; diff --git a/addons/web/static/src/views/pivot/pivot_model.js b/addons/web/static/src/views/pivot/pivot_model.js index f77c3402c3f..a29675194e1 100644 --- a/addons/web/static/src/views/pivot/pivot_model.js +++ b/addons/web/static/src/views/pivot/pivot_model.js @@ -752,7 +752,7 @@ export class PivotModel extends Model { this.metaData = metaData; } else { metaData.activeMeasures.push(fieldName); - let config = { metaData, data: this.data }; + const config = { metaData, data: this.data }; await this._loadData(config); } this.nextActiveMeasures = null; @@ -955,14 +955,13 @@ export class PivotModel extends Model { const groupDomain = this._getGroupDomain(group, config); const measureSpecs = this._getMeasureSpecs(config); const groupBy = rowGroupBy.concat(colGroupBy); - const options = { lazy: false }; + const kwargs = { lazy: false, context: this.searchParams.context }; const subGroups = await this.orm.readGroup( config.metaData.resModel, groupDomain, measureSpecs, groupBy, - options, - this.searchParams.context + kwargs ); return { group: group, diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js index ae98bbd9972..33cbbe0b493 100644 --- a/addons/web/static/src/views/relational_model.js +++ b/addons/web/static/src/views/relational_model.js @@ -160,9 +160,9 @@ class RequestBatcherORM extends ORM { * @param {object} context * @returns {Promise<[number, string][]>} */ - async nameGet(resModel, resIds, context) { - const pairs = await this.batch(resIds, ["name_get", resModel, context], (resIds) => - super.nameGet(resModel, resIds, context) + async nameGet(resModel, resIds, kwargs) { + const pairs = await this.batch(resIds, ["name_get", resModel, kwargs], (resIds) => + super.nameGet(resModel, resIds, kwargs) ); return pairs.filter(([id]) => resIds.includes(id)); } @@ -179,9 +179,9 @@ class RequestBatcherORM extends ORM { * @param {string[]} fields * @returns {Promise} */ - async read(resModel, resIds, fields, kwargs, context) { - const records = await this.batch(resIds, ["read", resModel, fields, context], (resIds) => - super.read(resModel, resIds, fields, {}, context) + async read(resModel, resIds, fields, kwargs) { + const records = await this.batch(resIds, ["read", resModel, fields, kwargs], (resIds) => + super.read(resModel, resIds, fields, kwargs) ); return records.filter((r) => resIds.includes(r.id)); } @@ -195,9 +195,9 @@ class RequestBatcherORM extends ORM { * @param {number[]} resIds * @returns {Promise} */ - async unlink(resModel, resIds, context) { - return this.batch(resIds, ["unlink", resModel, context], (resIds) => - super.unlink(resModel, resIds, context) + async unlink(resModel, resIds, kwargs) { + return this.batch(resIds, ["unlink", resModel, kwargs], (resIds) => + super.unlink(resModel, resIds, kwargs) ); } @@ -1202,16 +1202,12 @@ export class Record extends DataPoint { if (!fieldNames.length) { return {}; } - const [serverValues] = await this.model.orm.read( - this.resModel, - [this.resId], - fieldNames, - {}, - { + const [serverValues] = await this.model.orm.read(this.resModel, [this.resId], fieldNames, { + context: { bin_size: true, ...this.context, - } - ); + }, + }); return this._parseServerValues(serverValues); } @@ -1259,6 +1255,7 @@ export class Record extends DataPoint { const keys = Object.keys(changes); const hasChanges = this.isVirtual || keys.length; const shouldReload = hasChanges ? !options.noReload : false; + const context = this.context; if (this.isVirtual) { if (keys.length === 1 && keys[0] === "display_name") { @@ -1270,7 +1267,7 @@ export class Record extends DataPoint { ); this.resId = resId; } else { - this.resId = await this.model.orm.create(this.resModel, [changes], this.context); + this.resId = await this.model.orm.create(this.resModel, [changes], { context }); } delete this.virtualId; this.data.id = this.resId; @@ -1278,7 +1275,7 @@ export class Record extends DataPoint { this.invalidateCache(); } else if (keys.length > 0) { try { - await this.model.orm.write(this.resModel, [this.resId], changes, this.context); + await this.model.orm.write(this.resModel, [this.resId], changes, { context }); } catch (e) { if (!this.isInEdition) { await Promise.all([this.model.reloadRecords(this.resId), this.load()]); @@ -1481,14 +1478,10 @@ class DynamicList extends DataPoint { let resIds; if (isSelected) { if (this.isDomainSelected) { - resIds = await this.model.orm.search( - this.resModel, - this.domain, - { - limit: session.active_ids_limit, - }, - this.context - ); + resIds = await this.model.orm.search(this.resModel, this.domain, { + limit: session.active_ids_limit, + context: this.context, + }); } else { resIds = this.selection.map((r) => r.resId); } @@ -1574,7 +1567,8 @@ class DynamicList extends DataPoint { confirm: async () => { const resIds = validSelection.map((r) => r.resId); try { - await this.model.orm.write(this.resModel, resIds, changes, this.context); + const context = this.context; + await this.model.orm.write(this.resModel, resIds, changes, { context }); this.invalidateCache(); validSelection.forEach((record) => { record.selected = false; @@ -1706,7 +1700,7 @@ class DynamicList extends DataPoint { // Read the actual values set by the server and update the records const result = await this.model.keepLast.add( - this.model.orm.read(resModel, ids, [handleField], {}, this.context) + this.model.orm.read(resModel, ids, [handleField], { context: this.context }) ); for (const recordData of result) { const record = records.find((r) => r.resId === recordData.id); @@ -1924,18 +1918,22 @@ export class DynamicRecordList extends DynamicList { * @returns {Promise} */ async _loadRecords() { - const options = { + const kwargs = { limit: this.limit, offset: this.offset, order: orderByToString(this.orderBy), count_limit: this.countLimit + 1, + context: { + bin_size: true, + ...this.context, + }, }; if (this.loadedCount > this.limit) { // This condition means that we are reloading a list of records // that has been manually extended: we need to load exactly the // same amount of records. - options.limit = this.loadedCount; - options.offset = 0; + kwargs.limit = this.loadedCount; + kwargs.offset = 0; } const { records: rawRecords, length } = this.data || @@ -1943,11 +1941,7 @@ export class DynamicRecordList extends DynamicList { this.resModel, this.domain, this.fieldNames, - options, - { - bin_size: true, - ...this.context, - } + kwargs )); const records = await Promise.all( @@ -2243,8 +2237,8 @@ export class DynamicGroupList extends DynamicList { expand: this.expand, offset: this.offset, limit: this.limit, - }, - this.context + context: this.context, + } ); this.count = length; @@ -2788,12 +2782,9 @@ export class StaticList extends DataPoint { } // 2) fetch values for non loaded records if (resIds.length) { - const result = await this.model.orm.read( - this.resModel, - resIds, - orderFieldNames, - this.context - ); + const result = await this.model.orm.read(this.resModel, resIds, orderFieldNames, { + context: this.context, + }); for (const values of result) { const resId = values.id; recordValues[resId] = {}; diff --git a/addons/web/static/src/views/view_dialogs/export_data_dialog.js b/addons/web/static/src/views/view_dialogs/export_data_dialog.js index 0d6973b82fb..ebfbd0834ce 100644 --- a/addons/web/static/src/views/view_dialogs/export_data_dialog.js +++ b/addons/web/static/src/views/view_dialogs/export_data_dialog.js @@ -279,7 +279,7 @@ export class ExportDataDialog extends Component { resource: this.props.root.resModel, }, ], - this.props.context + { context: this.props.context } ); this.state.isEditingTemplate = false; this.state.templateId = id; @@ -316,7 +316,7 @@ export class ExportDataDialog extends Component { text: this.env._t("Do you really want to delete this export template?"), delete: async () => { const id = Number(this.state.templateId); - await this.orm.unlink("ir.exports", [id], this.props.context); + await this.orm.unlink("ir.exports", [id], { context: this.props.context }); this.templates.splice( this.templates.findIndex((i) => i.id === id), 1 diff --git a/addons/web/static/tests/core/orm_service_tests.js b/addons/web/static/tests/core/orm_service_tests.js index 75e0b4bf188..5f981c1301f 100644 --- a/addons/web/static/tests/core/orm_service_tests.js +++ b/addons/web/static/tests/core/orm_service_tests.js @@ -52,7 +52,8 @@ QUnit.test("context is combined with user context in read request", async (asser const [query, rpc] = makeFakeRPC(); serviceRegistry.add("rpc", rpc); const env = await makeTestEnv(); - await env.services.orm.read("my.model", [3], ["id", "descr"], {}, { earth: "isfucked" }); + const context = { earth: "isfucked" }; + await env.services.orm.read("my.model", [3], ["id", "descr"], { context }); assert.strictEqual(query.route, "/web/dataset/call_kw/my.model/read"); assert.deepEqual(query.params, { args: [[3], ["id", "descr"]], @@ -118,7 +119,8 @@ QUnit.test("nameGet method", async (assert) => { const [query, rpc] = makeFakeRPC(); serviceRegistry.add("rpc", rpc); const env = await makeTestEnv(); - await env.services.orm.nameGet("sale.order", [2, 5], { complete: true }); + const context = { complete: true }; + await env.services.orm.nameGet("sale.order", [2, 5], { context }); assert.strictEqual(query.route, "/web/dataset/call_kw/sale.order/name_get"); assert.deepEqual(query.params, { args: [[2, 5]], @@ -139,13 +141,11 @@ QUnit.test("read method", async (assert) => { const [query, rpc] = makeFakeRPC(); serviceRegistry.add("rpc", rpc); const env = await makeTestEnv(); - await env.services.orm.read( - "sale.order", - [2, 5], - ["name", "amount"], - { load: "none" }, - { abc: 3 } - ); + const context = { abc: 3 }; + await env.services.orm.read("sale.order", [2, 5], ["name", "amount"], { + load: "none", + context, + }); assert.strictEqual(query.route, "/web/dataset/call_kw/sale.order/read"); assert.deepEqual(query.params, { args: [ diff --git a/addons/web/static/tests/views/form/form_view_tests.js b/addons/web/static/tests/views/form/form_view_tests.js index 1d24a28cf6c..6caef2a6dde 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -8278,7 +8278,7 @@ QUnit.module("Views", (hooks) => { assert.verifySteps([ `translate args ["partner",1,"foo"]`, `translate context {"lang":"en","uid":7,"tz":"taht"}`, - `search_read translations args: [] ; kwargs: {"context":{"lang":"en","uid":7,"tz":"taht"},"domain":[["res_id","=",1],["name","=","partner_type,foo"],["lang","in",["CUST","CUST2"]]],"fields":["lang","src","value"]}`, + `search_read translations args: [] ; kwargs: {"domain":[["res_id","=",1],["name","=","partner_type,foo"],["lang","in",["CUST","CUST2"]]],"fields":["lang","src","value"],"context":{"lang":"en","uid":7,"tz":"taht"}}`, ]); assert.containsOnce(target, ".modal");