## tl; dr
- Formalism used for domains and states is subpar.
- They are unnecessary difficult for newcomers and error-prone.
- I suggest to use prefix notation to improve the situation and shows
than it may also be helpful for safe-eval.
---
## Domains
Domains are used to define a subest of records lines on an arbitrary
model.
warehouses = cls.search([
('type', '=', 'warehouse'),
['OR',
('storage_location', 'in', ids),
('input_location', 'in', ids),
('output_location', 'in', ids),
]])
---
## Origin
It's one of the few still untouched code from TinyERP
---
## AND and OR
... are boolean operators, but we cannot to use them with boolean
fields. For example,
active and posted
Must be written
[('active', '=', True), ('posted', '=', True)]
---
## Test Equality
Other boolean operator are only allowed on the field themselves.
(first_name = 'john') = (last_name = 'Doe')
Must be expressed like ...
---
## Test Equality
['OR', [
('first_name'', '=', 'John'),
('last_name', '=', Doe'),
], [
('first_name', '!=', 'John'),
('last_name', '!=', Doe'),
]
]
And `not` is only used inside other operators, like `not like`, `not
child_of`, etc.
---
## Position matters
We can do
('last_name', '!=', Doe')
But not
('Doe', '!=', 'last_name')
---
## Fields States
We often need to express fields properties wrt to some context.
Before 1.6, it was dead simple, we where using strings containing
python code.
---
## Example
customer = fields.Many2One('party.party',
'Customer', required=True,
states={
'readonly': "state != 'draft' "\
"or bool(outgoing_moves)",
}, on_change=['customer'])
---
## Pros & Cons
- easy to read
But
- Bug-prone
- "Black-magic"
- Python-centric
---
## Enters PYSON
customer = fields.Many2One('party.party',
'Customer', required=True,
states={
'readonly': Or(
Not(
Equal(Eval('state'),
'draft')),
Bool(
Eval('outgoing_moves'))
),
}, on_change=['customer'])
---
## PYSON Pros & Cons
- Standardised
- "Type checked"
- Can be implemented in any langage
But
- Difficult to read
- Verbose
---
## By the way, what is the PYSON definition?
*PYSON is the PYthon Statement and Object Notation.*
See [http://doc.tryton.org/2.6/trytond/doc/ref/pyson.html](http://doc.tryton.org/2.6/trytond/doc/ref/pyson.html)
---
## And what are domains?
Also statements! (More on that later).
---
## Domain on fields
field = fields.Many2One('ir.model.field',
'Field',
domain=[
('model', '=', Eval(
'_parent_rule_group', {}
).get('model'))
],
select=True, required=True)
Fields domains can be expressed wrt to a context:
- current record and parent_record
- date, current user, parent record, etc
---
# Whe can do better
---
## S-expressions to the rescue!
Simple prefix notation used by the LISP familly.
(defun factorial (x)
(if (zerop x)
1
(* x (factorial (- x 1)))))
---
# S-expressions everywhere!
---
## The first example:
This
warehouses = cls.search([
('type', '=', 'warehouse'),
['OR',
('storage_location', 'in', ids),
('input_location', 'in', ids),
('output_location', 'in', ids),
]])
---
## The first example:
Becomes
warehouses = cls.search(['and',
['=', 'type', 'warehouse'],
['or',
['in', 'storage_location', ids],
['in', 'input_location', ids],
['in', 'output_location', ids),
]])
---
## No operators separation
active and posted
Becomes
['and', 'active', 'posted']
Or even better
"[and active posted]"
---
## Also
[=
[= first_name 'John']
[= 'Doe' last_name]
]
---
## Fields States
'readonly': Or(
Not(Equal(Eval('state'), 'draft')),
Bool(Eval('outgoing_moves'))
),
Becomes
'readonly': "[or [!= state 'draft'] "\
"[bool outgoing_moves]]"
---
## Interlude: Namespace
context and record field are mixed in the same namespace.
What happend if a model contains a field `time` or `context` ?
> Namespaces are one honking great idea, let's do more of those!
>
> -- Zen of Python
---
## Interlude: Namespace
**Several solutions**
- Introduce namespace "ctx" and forbid to have a ctx field on model.
- Introduce a namespace "this" and consider it as part of the eval
context, just like time, active_id, etc.
---
## Prefix Notation: Discussion
- More readble than PYSON, but less than Python code.
- Safer than Python code, equivalent to PYSON wrt to security.
- Easy to implement in virtually all langage, so on par with PYSON.
- Like the evaluated Python string it is far cleaner than mixing PYSON
and domains.
---
## A complete langage
Once we use s-expression, the next logical step is to use several of
them.
A full programm is mainly a list of expression that shares the same
namespace.
---
## Safe-Eval
S-expression may provide a way to implement safe evaluation
without messing with Python internals
But at the cost of a less natural syntax
---
# Thanks for watching