Browse Source
[ADD] allow creating missing indexes and purging properties (#736)
[ADD] allow creating missing indexes and purging properties (#736)
* [ADD] allow creating missing indexes * [FIX] tests; installation * [ADD] allow purging properties * [ADD] missing file * [ADD] test purging properties * [ADD] missing parent_id for menu entry * [FIX] don't delete too many and wrong propertiespull/1009/head
Holger Brunn
8 years ago
No known key found for this signature in database
GPG Key ID: 1C9760FECA3AE18
9 changed files with 329 additions and 2 deletions
-
2database_cleanup/__manifest__.py
-
2database_cleanup/models/__init__.py
-
80database_cleanup/models/create_indexes.py
-
110database_cleanup/models/purge_properties.py
-
15database_cleanup/tests/test_database_cleanup.py
-
52database_cleanup/views/create_indexes.xml
-
14database_cleanup/views/menu.xml
-
49database_cleanup/views/purge_properties.xml
-
7database_cleanup/views/purge_wizard.xml
@ -0,0 +1,80 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from ..identifier_adapter import IdentifierAdapter |
|||
from openerp import api, fields, models |
|||
|
|||
|
|||
class CreateIndexesLine(models.TransientModel): |
|||
_inherit = 'cleanup.purge.line' |
|||
_name = 'cleanup.create_indexes.line' |
|||
|
|||
purged = fields.Boolean('Created') |
|||
wizard_id = fields.Many2one('cleanup.create_indexes.wizard') |
|||
field_id = fields.Many2one('ir.model.fields', required=True) |
|||
|
|||
@api.multi |
|||
def purge(self): |
|||
tables = set() |
|||
for field in self.mapped('field_id'): |
|||
model = self.env[field.model] |
|||
name = '%s_%s_index' % (model._table, field.name) |
|||
self.env.cr.execute( |
|||
'create index %s ON %s (%s)', |
|||
( |
|||
IdentifierAdapter(name, quote=False), |
|||
IdentifierAdapter(model._table), |
|||
IdentifierAdapter(field.name), |
|||
), |
|||
) |
|||
tables.add(model._table) |
|||
for table in tables: |
|||
self.env.cr.execute( |
|||
'analyze %s', (IdentifierAdapter(model._table),) |
|||
) |
|||
self.write({ |
|||
'purged': True, |
|||
}) |
|||
|
|||
|
|||
class CreateIndexesWizard(models.TransientModel): |
|||
_inherit = 'cleanup.purge.wizard' |
|||
_name = 'cleanup.create_indexes.wizard' |
|||
_description = 'Create indexes' |
|||
|
|||
purge_line_ids = fields.One2many( |
|||
'cleanup.create_indexes.line', 'wizard_id', |
|||
) |
|||
|
|||
@api.multi |
|||
def find(self): |
|||
for field in self.env['ir.model.fields'].search([ |
|||
('index', '=', True), |
|||
]): |
|||
if field.model not in self.env.registry: |
|||
continue |
|||
model = self.env[field.model] |
|||
name = '%s_%s_index' % (model._table, field.name) |
|||
self.env.cr.execute( |
|||
'select indexname from pg_indexes ' |
|||
'where indexname=%s and tablename=%s', |
|||
(name, model._table) |
|||
) |
|||
if self.env.cr.rowcount: |
|||
continue |
|||
|
|||
self.env.cr.execute( |
|||
'select a.attname ' |
|||
'from pg_attribute a ' |
|||
'join pg_class c on a.attrelid=c.oid ' |
|||
'join pg_tables t on t.tablename=c.relname ' |
|||
'where attname=%s and c.relname=%s', |
|||
(field.name, model._table,) |
|||
) |
|||
if not self.env.cr.rowcount: |
|||
continue |
|||
|
|||
yield (0, 0, { |
|||
'name': '%s.%s' % (field.model, field.name), |
|||
'field_id': field.id, |
|||
}) |
@ -0,0 +1,110 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2017 Therp BV <http://therp.nl> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from openerp import api, models, fields |
|||
REASON_DUPLICATE = 1 |
|||
REASON_DEFAULT = 2 |
|||
|
|||
|
|||
class CleanupPurgeLineProperty(models.TransientModel): |
|||
_inherit = 'cleanup.purge.line' |
|||
_name = 'cleanup.purge.line.property' |
|||
_description = 'Purge properties' |
|||
|
|||
wizard_id = fields.Many2one( |
|||
'cleanup.purge.wizard.property', 'Purge Wizard', readonly=True) |
|||
property_id = fields.Many2one('ir.property') |
|||
reason = fields.Selection([ |
|||
(REASON_DUPLICATE, 'Duplicated property'), |
|||
(REASON_DEFAULT, 'Same value as default'), |
|||
]) |
|||
|
|||
@api.multi |
|||
def purge(self): |
|||
"""Delete properties""" |
|||
self.write({'purged': True}) |
|||
return self.mapped('property_id').unlink() |
|||
|
|||
|
|||
class CleanupPurgeWizardProperty(models.TransientModel): |
|||
_inherit = 'cleanup.purge.wizard' |
|||
_name = 'cleanup.purge.wizard.property' |
|||
_description = 'Purge properties' |
|||
|
|||
@api.model |
|||
def find(self): |
|||
""" |
|||
Search property records which are duplicated or the same as the default |
|||
""" |
|||
result = [] |
|||
default_properties = self.env['ir.property'].search([ |
|||
('res_id', '=', False), |
|||
]) |
|||
handled_field_ids = [] |
|||
for prop in default_properties: |
|||
if prop.fields_id.id in handled_field_ids: |
|||
continue |
|||
domain = [ |
|||
('id', '!=', prop.id), |
|||
('fields_id', '=', prop.fields_id.id), |
|||
# =? explicitly tests for None or False, not falsyness |
|||
('value_float', '=?', prop.value_float or False), |
|||
('value_integer', '=?', prop.value_integer or False), |
|||
('value_text', '=?', prop.value_text or False), |
|||
('value_binary', '=?', prop.value_binary or False), |
|||
('value_reference', '=?', prop.value_reference or False), |
|||
('value_datetime', '=?', prop.value_datetime or False), |
|||
] |
|||
if prop.company_id: |
|||
domain.append(('company_id', '=', prop.company_id.id)) |
|||
else: |
|||
domain.extend([ |
|||
'|', |
|||
('company_id', '=', False), |
|||
( |
|||
'company_id', 'in', self.env['res.company'].search([ |
|||
( |
|||
'id', 'not in', default_properties.filtered( |
|||
lambda x: x.company_id and |
|||
x.fields_id == prop.fields_id |
|||
).ids, |
|||
) |
|||
]).ids |
|||
), |
|||
]) |
|||
|
|||
for redundant_property in self.env['ir.property'].search(domain): |
|||
result.append({ |
|||
'name': '%s@%s: %s' % ( |
|||
prop.name, prop.res_id, prop.get_by_record(prop) |
|||
), |
|||
'property_id': redundant_property.id, |
|||
'reason': REASON_DEFAULT, |
|||
}) |
|||
handled_field_ids.append(prop.fields_id.id) |
|||
self.env.cr.execute( |
|||
''' |
|||
with grouped_properties(ids, cnt) as ( |
|||
select array_agg(id), count(*) |
|||
from ir_property group by res_id, company_id, fields_id |
|||
) |
|||
select ids from grouped_properties where cnt > 1 |
|||
''' |
|||
) |
|||
for ids, in self.env.cr.fetchall(): |
|||
# odoo uses the first property found by search |
|||
for prop in self.env['ir.property'].search([ |
|||
('id', 'in', ids) |
|||
])[1:]: |
|||
result.append({ |
|||
'name': '%s@%s: %s' % ( |
|||
prop.name, prop.res_id, prop.get_by_record(prop) |
|||
), |
|||
'property_id': prop.id, |
|||
'reason': REASON_DUPLICATE, |
|||
}) |
|||
|
|||
return result |
|||
|
|||
purge_line_ids = fields.One2many( |
|||
'cleanup.purge.line.property', 'wizard_id', 'Properties to purge') |
@ -0,0 +1,52 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo> |
|||
<record id="cleanup_create_indexes_wizard_view_form" model="ir.ui.view"> |
|||
<field name="model">cleanup.create_indexes.wizard</field> |
|||
<field name="inherit_id" ref="form_purge_wizard" /> |
|||
<field name="mode">primary</field> |
|||
<field name="arch" type="xml"> |
|||
<button name="purge_all" position="attributes"> |
|||
<attribute name="string">Create all</attribute> |
|||
</button> |
|||
<button name="purge" position="attributes"> |
|||
<attribute name="string">Create</attribute> |
|||
</button> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="cleanup_create_indexes_wizard_action" model="ir.actions.server"> |
|||
<field name="name">Create missing indexes</field> |
|||
<field name="type">ir.actions.server</field> |
|||
<field name="state">code</field> |
|||
<field name="model_id" ref="database_cleanup.model_cleanup_create_indexes_wizard" /> |
|||
<field name="code">action = self.get_wizard_action(cr, uid, context=context)</field> |
|||
</record> |
|||
|
|||
<record id="cleanup_create_indexes_line_view_tree" model="ir.ui.view"> |
|||
<field name="model">cleanup.create_indexes.line</field> |
|||
<field name="inherit_id" ref="tree_purge_line" /> |
|||
<field name="mode">primary</field> |
|||
<field name="arch" type="xml"> |
|||
<button name="purge" position="attributes"> |
|||
<attribute name="string">Create this index</attribute> |
|||
<attribute name="icon">gtk-add</attribute> |
|||
</button> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="cleanup_create_indexes_line_action" model="ir.actions.server"> |
|||
<field name="name">Create</field> |
|||
<field name="type">ir.actions.server</field> |
|||
<field name="state">code</field> |
|||
<field name="model_id" ref="database_cleanup.model_cleanup_create_indexes_line" /> |
|||
<field name="code">self.purge(cr, uid, context.get('active_ids', []), context)</field> |
|||
</record> |
|||
|
|||
<record id="cleanup_create_indexes_line_action_value" model="ir.values"> |
|||
<field name="name">Create indexes</field> |
|||
<field name="key">action</field> |
|||
<field name="key2">client_action_multi</field> |
|||
<field name="model">cleanup.create_indexes.line</field> |
|||
<field name="value" eval="'ir.actions.server,%d' % ref('database_cleanup.cleanup_create_indexes_line_action')" /> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,49 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<openerp> |
|||
<data> |
|||
<record id="purge_property_view" model="ir.ui.view"> |
|||
<field name="model">cleanup.purge.wizard.property</field> |
|||
<field name="inherit_id" ref="form_purge_wizard" /> |
|||
<field name="mode">primary</field> |
|||
<field name="arch" type="xml"> |
|||
<data /> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="action_purge_property" model="ir.actions.server"> |
|||
<field name="name">Purge properties</field> |
|||
<field name="type">ir.actions.server</field> |
|||
<field name="state">code</field> |
|||
<field name="model_id" ref="database_cleanup.model_cleanup_purge_wizard_property" /> |
|||
<field name="code">action = self.get_wizard_action(cr, uid, context=context)</field> |
|||
</record> |
|||
|
|||
<record id="purge_property_line_tree" model="ir.ui.view"> |
|||
<field name="model">cleanup.purge.line.property</field> |
|||
<field name="inherit_id" ref="tree_purge_line" /> |
|||
<field name="mode">primary</field> |
|||
<field name="arch" type="xml"> |
|||
<field name="name" position="after"> |
|||
<field name="reason" /> |
|||
</field> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="action_purge_property_line" model="ir.actions.server"> |
|||
<field name="name">Purge</field> |
|||
<field name="type">ir.actions.server</field> |
|||
<field name="state">code</field> |
|||
<field name="model_id" ref="database_cleanup.model_cleanup_purge_line_property" /> |
|||
<field name="code">self.purge(cr, uid, context.get('active_ids', []), context)</field> |
|||
</record> |
|||
|
|||
<record id="action_purge_property_line_value" model="ir.values"> |
|||
<field name="name">Purge</field> |
|||
<field name="key">action</field> |
|||
<field name="key2">client_action_multi</field> |
|||
<field name="model">cleanup.purge.line.property</field> |
|||
<field name="value" eval="'ir.actions.server,%d' % ref('database_cleanup.action_purge_property_line')" /> |
|||
</record> |
|||
|
|||
</data> |
|||
</openerp> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue