def delete(self, owner_id, report_id, report_instance_id): ri = self.select(report_id, report_instance_id, None) if not ri: return False diskspace = self._compute_ri_diskspace(ri) tags_powerset = util.powerset(ri['all_tags']) with cursor() as cur: cur.execute( """DELETE FROM report_instance WHERE report_id=? AND tags IN {in_p} AND report_instance_id=?""". format(in_p=in_params(tags_powerset)), [report_id] + tags_powerset + [report_instance_id]) # report counts cur.execute( """UPDATE report SET report_instance_count = report_instance_count - 1 WHERE report_id=?""", [report_id]) cur.execute( """UPDATE report SET report_instance_diskspace = report_instance_diskspace - ? WHERE report_id=?""", [diskspace, report_id]) # owner counts cur.execute( """UPDATE report_data_for_owner SET report_instance_count=report_instance_count-1 WHERE owner_id=?""", [owner_id]) cur.execute( """UPDATE report_data_for_owner SET report_instance_diskspace=report_instance_diskspace-? WHERE owner_id=?""", [diskspace, owner_id]) return True
def _delete_ris(self, owner_id, report_id, tags, ris, update_counters): qs = [] tags_days = set() all_tags_subsets = set() with cursor() as cur: for ri in ris: tags_powerset = util.powerset(ri['all_tags']) cur.execute("""DELETE FROM report_instance WHERE report_id=? AND tags IN {in_p} AND report_instance_id=?""".format(in_p=in_params(tags_powerset)), [report_id] + tags_powerset + [ri['report_instance_id']]) day = util.datetime_from_uuid1(ri['report_instance_id']).date() for tags_subset in tags_powerset: tags_days.add((tuple(tags_subset), day)) all_tags_subsets.add(tuple(tags_subset)) if update_counters: total_diskspace = sum(self._compute_ri_diskspace(ri) for ri in ris) cur.execute("""UPDATE report SET report_instance_count = report_instance_count - ? WHERE report_id=?""", [len(ris), report_id]) cur.execute("""UPDATE report SET report_instance_diskspace = report_instance_diskspace - ? WHERE report_id=?""", [total_diskspace, report_id]) cur.execute("""UPDATE report_data_for_owner SET report_instance_count=report_instance_count - ? WHERE owner_id=?""", [len(ris), owner_id]) cur.execute("""UPDATE report_data_for_owner SET report_instance_diskspace=report_instance_diskspace - ? WHERE owner_id=?""", [total_diskspace, owner_id]) ### Delete days for which report instances no longer exist for day_tags, day in tags_days: cur.execute("""SELECT report_instance_id FROM report_instance WHERE report_id=? AND tags=? AND report_instance_id > ? AND report_instance_id < ? LIMIT 1""", [report_id, list(day_tags), util.min_uuid_with_dt(datetime.datetime.combine(day, datetime.datetime.min.time())), util.max_uuid_with_dt(datetime.datetime.combine(day, datetime.datetime.max.time()))]) if not cur.fetchall(): cur.execute("""DELETE FROM report_instance_day WHERE report_id=? AND tags=? AND day=?""", [report_id, list(day_tags), day]) ### Delete tags for which report instances no longer exist tags_present = set() for tags, _ in tags_days: for tag in tags: tags_present.add(tag) for tag in tags_present: cur.execute("""SELECT report_id FROM report_instance_day WHERE report_id=? AND tags=? LIMIT 1""", [report_id, [tag]]) if cur.fetchall(): continue cur.execute("""DELETE FROM report_tag WHERE report_id=? AND tag=?""", [report_id, tag]) return len(ris), [list(ts) for ts in all_tags_subsets]
def insert(self, owner_id, report_id, report_instance_id, tags, ri_data, input_string, extra_ri_data, custom_created): created = util.datetime_from_uuid1(report_instance_id) with cursor() as cur: first_row = None tags_powerset = util.powerset(tags[:mqeconfig.MAX_TAGS]) for tags_subset in tags_powerset: row = dict(report_id=report_id, tags=tags_subset, report_instance_id=report_instance_id, ri_data=ri_data, input_string=input_string, all_tags=tags, extra_ri_data=extra_ri_data) if first_row is None: first_row = row cur.execute(*insert('report_instance', row)) cur.execute( """INSERT OR IGNORE INTO report_instance_day (report_id, tags, day) VALUES (?, ?, ?)""", [report_id, tags_subset, created.date()]) if first_row: # report counts cur.execute( """UPDATE report SET report_instance_count = report_instance_count + 1 WHERE report_id=?""", [report_id]) diskspace = self._compute_ri_diskspace(first_row) cur.execute( """UPDATE report SET report_instance_diskspace = report_instance_diskspace + ? WHERE report_id=?""", [diskspace, report_id]) # owner counts cur.execute( """SELECT 1 FROM report_data_for_owner WHERE owner_id=?""", [owner_id]) if not cur.fetchone(): try: cur.execute( """INSERT INTO report_data_for_owner (owner_id) VALUES (?)""", [owner_id]) except sqlite3.IntegrityError: pass cur.execute( """UPDATE report_data_for_owner SET report_instance_count=report_instance_count+1 WHERE owner_id=?""", [owner_id]) cur.execute( """UPDATE report_data_for_owner SET report_instance_diskspace=report_instance_diskspace+? WHERE owner_id=?""", [diskspace, owner_id]) for tag in tags: cur.execute( """INSERT OR IGNORE INTO report_tag (report_id, tag) VALUES (?, ?)""", [report_id, tag]) return first_row
def process_input(self, input_string, tags=None, created=None, input_type='any', ip_options={}, force_header=None, extra_ri_data=None, handle_tpcreator=True, handle_sscreator=True): """Process an input string - parse it into a table and create a report instance belonging to the report. :param str|unicode input_string: the input string :param list tags: a list of string tags attached to the report instance :param ~datetime.datetime created: an explicit creation datetime of the report instance ( default: the current datetime) :param str input_type: input type (see :func:`mqetables.parseany.parse_input`) :param dict ip_options: extra parser options (see :func:`mqetables.parsing.InputParser`) :param force_header: a list of header rows indexes to set as a header (defaults to auto-detection) :param extra_ri_data: a custom JSON-serializable document attached to the report instance :param handle_tpcreator: whether to handle TPCreator for the created report instance by calling :func:`~mqe.tpcreator.handle_tpcreator` :param handle_sscreator: whether to handle SSCS by calling :func:`~mqe.sscreator.handle_sscreator` :return: an :class:`InputProcessingResult` """ assert isinstance(input_string, (str, unicode)) # disallow 'created' in the future now = datetime.datetime.utcnow() if created is not None and created.tzinfo: created = util.make_tz_naive(created) if created is not None and created.year < 2000: raise ValueError('created cannot be before the year 2000') if created is not None and created < now: report_instance_id = util.uuid_with_dt(created) custom_created = True else: custom_created = False report_instance_id = gen_timeuuid() created = util.datetime_from_uuid1(report_instance_id) if tags is None: tags = [] parsing_result = parseany.parse_input(input_string, input_type, ip_options) table = mqeconfig.get_table_from_parsing_result(parsing_result) if table is None: return InputProcessingResult(None, parsing_result) if force_header is not None: log.debug('Overwriting header detection due to force_header') table.header_idxs = [ i for i in force_header if util.valid_index(table.num_rows, i) ] table.header_idxs_source = parsing.HEADER_IDXS_SOURCE_USER ri_data_dict = { 'table': table, } result_desc = self._get_result_desc(parsing_result) if result_desc: ri_data_dict['result_desc'] = result_desc report_instance_row = c.dao.ReportInstanceDAO.insert( owner_id=self.owner_id, report_id=self.report_id, report_instance_id=report_instance_id, tags=tags, ri_data=serialize.mjson(ri_data_dict), input_string=parsing_result.input_string, extra_ri_data=serialize.mjson(extra_ri_data) if extra_ri_data else None, custom_created=custom_created) report_instance = ReportInstance(report_instance_row) log.info( 'Created new report instance report_id=%s report_name=%r tags=%s ' 'report_instance_id=%s created=%s', self.report_id, self.report_name, tags, report_instance_id, report_instance.created) if tags and handle_tpcreator: from mqe import tpcreator tpcreator.handle_tpcreator(self.owner_id, self.report_id, report_instance) if handle_sscreator: from mqe import sscreator sscreator.handle_sscreator(self.owner_id, self.report_id, report_instance) if custom_created: from mqe import dataseries dataseries.clear_series_defs(self.report_id, util.powerset(tags)) return InputProcessingResult(report_instance, parsing_result)