Generic support for cache fields

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 Fields 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 with on_change_with getter by a stored field (with eventually index).

Implementation

2 Likes

We can not rely on the depends decorator because it is filling some fields attributes only in ModelView but we want to have this feature for any kind of Model.
Instead I think the signature should be compute_something(self, field_names=None) where field_names is a set containing the names of the modified fields (like validate_fields.
This way it can still be compatible with on_change_with(self).

Indeed I think it is even simpler to not add a new attribute on the fields but just have a method compute_fields(self, field_names) which must return a dictionary with the new values to store for the record.
It will still be possible to reuse on_change_with inside the override of the method.

1 Like

This topic was automatically closed after 8 days. New replies are no longer allowed.