mirror of
https://github.com/OCA/reporting-engine.git
synced 2025-02-16 16:30:38 +02:00
@@ -98,6 +98,19 @@ class BveView(models.Model):
|
||||
compute='_compute_users',
|
||||
store=True)
|
||||
query = fields.Text(compute='_compute_sql_query')
|
||||
over_condition = fields.Text(
|
||||
states={
|
||||
'draft': [
|
||||
('readonly', False),
|
||||
],
|
||||
},
|
||||
readonly=True,
|
||||
help="Condition to be inserted in the OVER part "
|
||||
"of the ID's row_number function.\n"
|
||||
"For instance, 'ORDER BY t1.id' would create "
|
||||
"IDs ordered in the same way as t1's IDs; otherwise "
|
||||
"IDs are assigned with no specific order.",
|
||||
)
|
||||
er_diagram_image = fields.Binary(compute='_compute_er_diagram_image')
|
||||
|
||||
_sql_constraints = [
|
||||
@@ -282,14 +295,23 @@ class BveView(models.Model):
|
||||
self._cr.execute('DROP TABLE IF EXISTS %s', (AsIs(view_name), ))
|
||||
|
||||
# create postgres view
|
||||
self.env.cr.execute('CREATE or REPLACE VIEW %s as (%s)', (
|
||||
AsIs(view_name), AsIs(query), ))
|
||||
try:
|
||||
with self.env.cr.savepoint():
|
||||
self.env.cr.execute('CREATE or REPLACE VIEW %s as (%s)', (
|
||||
AsIs(view_name), AsIs(query), ))
|
||||
except Exception as e:
|
||||
raise UserError(
|
||||
_("Error creating the view '{query}':\n{error}")
|
||||
.format(
|
||||
query=query,
|
||||
error=e))
|
||||
|
||||
@api.depends('line_ids', 'state')
|
||||
@api.depends('line_ids', 'state', 'over_condition')
|
||||
def _compute_sql_query(self):
|
||||
for bve_view in self:
|
||||
tables_map = {}
|
||||
select_str = '\n CAST(row_number() OVER () as integer) AS id'
|
||||
select_str = '\n CAST(row_number() OVER ({}) as integer) AS id' \
|
||||
.format(bve_view.over_condition or '')
|
||||
for line in bve_view.field_ids:
|
||||
table = line.table_alias
|
||||
select = line.field_id.name
|
||||
|
||||
@@ -21,3 +21,6 @@ To access the created BI View with a dedicated menu:
|
||||
A more advanced UI is also available under the "Details" tab. It provides extra
|
||||
possibilities for more advanced users, like to use LEFT JOIN instead of the
|
||||
default INNER JOIN.
|
||||
|
||||
It also possible to improve the IDs generation for new views by adding an `Over Condition` in the "SQL" tab, see https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS for further details.
|
||||
For instance, an ORDER BY clause helps preventing unreliable behavior when filtering the generated views.
|
||||
|
||||
@@ -5,6 +5,7 @@ import json
|
||||
|
||||
import odoo
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools import mute_logger
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from ..hooks import post_load, uninstall_hook
|
||||
|
||||
@@ -407,3 +408,24 @@ class TestBiViewEditor(TransactionCase):
|
||||
bi_view1 = self.env['bve.view'].create(vals)
|
||||
bi_view1.action_create()
|
||||
self.assertEqual(len(bi_view1.line_ids), 4)
|
||||
|
||||
@mute_logger('odoo.sql_db')
|
||||
def test_20_broken_view(self):
|
||||
"""
|
||||
Create a broken query, a nice UserError should be raised.
|
||||
odoo.sql_db logger is muted to avoid the
|
||||
ERROR: bad_query line in the logs.
|
||||
"""
|
||||
vals = self.bi_view1_vals
|
||||
vals.update({
|
||||
'name': 'Test View broken',
|
||||
'over_condition': 'bad SQL code',
|
||||
})
|
||||
bi_view = self.env['bve.view'].create(vals)
|
||||
with self.assertRaises(UserError) as ue:
|
||||
bi_view.action_create()
|
||||
|
||||
self.assertEqual(bi_view.state, 'draft')
|
||||
self.assertIn(bi_view.over_condition, str(ue.exception))
|
||||
# remove view
|
||||
bi_view.unlink()
|
||||
|
||||
@@ -85,8 +85,9 @@
|
||||
</group>
|
||||
</page>
|
||||
<page string="SQL" groups="base.group_no_one">
|
||||
<field name="query"/>
|
||||
<group>
|
||||
<field name="query" nolabel="1" />
|
||||
<field name="over_condition"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Security">
|
||||
|
||||
Reference in New Issue
Block a user