Rational
It is a common design to store in a cache field the result of a computation to increase the performance (ex: the sale/purchase amounts, the internal quantity of stock move, etc.)
For now the pattern is to extend the ModelStorage.create
and ModelStorage.write
methods to compute the value of the field and add a second ModelStorage.write
call if needed.
This is complex and not always performent if there are multiple modules extending this way or if there are many instances to update.
Also developers have to deal with access right as they are extending RPC methods (for now).
Proposal
A new attribute compute
is added to Field
s with sql_type
to store the name of a method with the same signature as the on_change_with
(so those method can be also reused).
ModelStorage.create
and ModelStorage.write
call a method ModelStorage.__compute_fields
with the modified records and the names of the modified fields (like ModelStorage._validate
). This method checks all the fields with a compute
argument and call it if the modified fields are in the depends. The result is stored to be written back on the instance. So as only stored fields are written back, ModelStorage.__compute_fields
should not trigger any new write the second times.
In order to be more efficient, ModelStorage._save_values
is also modified to compute in advance the cached fields using the instance if any of the modified fields are in the depends of the compute method.
There will be some limitations to this computed fields:
- the compute method can only depend on direct fields (or the design must ensure that foreign data are stable like lines on confirmed sale or UoM rate).
- the compute method is always an instance method, so it can be be optimized with SQL query.
But there will be also some counterpart feature:
- it can replace a
Function
field withon_change_with
getter by a stored field (with eventually index).