Пример #1
0
    def _copy_object_to_dump(self, src_obj: object) -> None:
        """
        Copy the SQLAlchemy ORM object to the dump.
        """
        # noinspection PyUnresolvedReferences
        src_table = src_obj.__table__  # type: Table

        # 1. Insert row for this object, potentially adding and removing
        #    columns.
        tablename = src_table.name
        dst_table = self.dst_tables[tablename]
        assert dst_table.name == tablename
        row = {}  # type: Dict[str, Any]
        # Copy columns, skipping any we don't want
        for attrname, column in gen_columns(src_obj):
            if self._dump_skip_column(tablename, column.name):
                continue
            row[column.name] = getattr(src_obj, attrname)
        # Any other columns to add for this table?
        if isinstance(src_obj, GenericTabletRecordMixin):
            for summary_element in src_obj.get_summaries(self.req):
                row[summary_element.name] = summary_element.value
        self.dst_session.execute(dst_table.insert(row))

        # 2. If required, add extra tables/rows that this task wants to
        #    offer (usually tables whose rows don't have a 1:1 correspondence
        #    to the task or its ancillary objects).
        if isinstance(src_obj, Task):
            estables = src_obj.get_all_summary_tables(self.req)
            # ... includes SNOMED
            for est in estables:
                dst_summary_table = self._get_or_insert_summary_table(est)
                for row in est.rows:
                    self.dst_session.execute(dst_summary_table.insert(row))
Пример #2
0
def make_xml_branches_from_columns(obj,
                                   skip_fields: List[str] = None
                                   ) -> List[XmlElement]:
    """
    Returns a list of XML branches, each an
    :class:`camcops_server.cc_modules.cc_xml.XmlElement`, from an SQLAlchemy
    ORM object, using the list of SQLAlchemy Column objects that
    define/describe its fields.

    Args:
        obj: the SQLAlchemy ORM object
        skip_fields: database column names to skip
    """
    skip_fields = skip_fields or []  # type: List[str]
    branches = []  # type: List[XmlElement]
    for attrname, column in gen_columns(obj):
        # log.debug("make_xml_branches_from_columns: {!r}", attrname)
        colname = column.name
        if colname in skip_fields:
            continue
        branches.append(
            XmlElement(
                name=colname,
                value=getattr(obj, attrname),
                datatype=get_xml_datatype_from_sqla_column(column),
                comment=column.comment,
            ))
    return branches
Пример #3
0
 def get_attrnames(self) -> List[str]:
     """
     Returns all relevant attribute names.
     """
     attrnames = set([attrname for attrname, _ in gen_columns(self)])
     attrnames.update(key for key in self.__dict__ if not key.startswith('_'))  # noqa
     return sorted(attrnames)
Пример #4
0
 def _get_core_tsv_page(self,
                        req: "CamcopsRequest",
                        heading_prefix: str = "") -> TsvPage:
     """
     Returns a single-row :class:`camcops_server.cc_modules.cc_tsv.TsvPage`,
     like an Excel "sheet", representing this record. (It may be combined
     with others later to produce a multi-row spreadsheet.)
     """
     row = OrderedDict()
     for attrname, column in gen_columns(self):
         row[heading_prefix + attrname] = getattr(self, attrname)
     for s in self.get_summaries(req):
         row[heading_prefix + s.name] = s.value
     return TsvPage(name=self.__tablename__, rows=[row])
Пример #5
0
 def _get_core_spreadsheet_schema(
         self,
         table_name: str = "",
         column_name_prefix: str = "") -> Set[SummarySchemaInfo]:
     """
     Returns schema information compatible with
     :func:`_get_core_spreadsheet_page`.
     """
     return set(
         SummarySchemaInfo.from_column(
             column,
             table_name=table_name,
             column_name_prefix=column_name_prefix,
         ) for _, column in gen_columns(self))
Пример #6
0
    def manually_erase_with_dependants(self, req: "CamcopsRequest") -> None:
        """
        Manually erases a standard record and marks it so erased. Iterates
        through any dependants and does likewise to them.

        The object remains ``_current`` (if it was), as a placeholder, but its
        contents are wiped.

        WRITES TO THE DATABASE.
        """
        if self._manually_erased or self._pk is None or self._era == ERA_NOW:
            # ... _manually_erased: don't do it twice
            # ... _pk: basic sanity check
            # ... _era: don't erase things that are current on the tablet
            return
        # 1. "Erase my dependants"
        for ancillary in self.gen_ancillary_instances_even_noncurrent():
            ancillary.manually_erase_with_dependants(req)
        for blob in self.gen_blobs_even_noncurrent():
            blob.manually_erase_with_dependants(req)
        # 2. "Erase me"
        erasure_attrs = []  # type: List[str]
        for attrname, column in gen_columns(self):
            if attrname.startswith("_"):  # system field
                continue
            if not column.nullable:  # this should cover FKs
                continue
            if column.foreign_keys:  # ... but to be sure...
                continue
            erasure_attrs.append(attrname)
        for attrname in erasure_attrs:
            setattr(self, attrname, None)
        self._current = False
        self._manually_erased = True
        self._manually_erased_at = req.now
        self._manually_erasing_user_id = req.user_id
Пример #7
0
 def __repr__(self) -> str:
     attrnames = sorted(attrname for attrname, _ in gen_columns(self))
     return simple_repr(self, attrnames)
Пример #8
0
    def _copy_object_to_dump(self, src_obj: object) -> None:
        """
        Copy the SQLAlchemy ORM object to the dump.
        """
        # noinspection PyUnresolvedReferences
        src_table = src_obj.__table__  # type: Table
        adding_extra_ids = False
        patient = None  # type: Optional[Patient]
        if self.export_options.db_patient_id_in_each_row:
            adding_extra_ids, patient = self._merits_extra_id_num_columns(
                src_obj)

        # 1. Insert row for this object, potentially adding and removing
        #    columns.
        tablename = src_table.name
        dst_table = self.dst_tables[tablename]
        assert dst_table.name == tablename
        row = {}  # type: Dict[str, Any]
        # Copy columns, skipping any we don't want
        for attrname, column in gen_columns(src_obj):
            if self._dump_skip_column(tablename, column.name):
                continue
            row[column.name] = getattr(src_obj, attrname)
        # Any other columns to add for this table?
        if isinstance(src_obj, GenericTabletRecordMixin):
            if self.export_options.db_include_summaries:
                for summary_element in src_obj.get_summaries(self.req):
                    row[summary_element.name] = summary_element.value
            if adding_extra_ids:
                if patient:
                    patient.add_extra_idnum_info_to_row(row)
                if isinstance(src_obj, TaskDescendant):
                    src_obj.add_extra_task_xref_info_to_row(row)
        try:
            self.dst_session.execute(dst_table.insert(row))
        except CompileError:
            log.critical("\ndst_table:\n{}\nrow:\n{}", dst_table, row)
            raise

        # 2. If required, add extra tables/rows that this task wants to
        #    offer (usually tables whose rows don't have a 1:1 correspondence
        #    to the task or its ancillary objects).
        if isinstance(src_obj, Task):
            estables = src_obj.get_all_summary_tables(self.req)
            # ... includes SNOMED
            for est in estables:
                dst_summary_table = self._get_or_insert_summary_table(
                    est, add_extra_id_cols=adding_extra_ids)
                for row in est.rows:
                    if patient:
                        patient.add_extra_idnum_info_to_row(row)
                    if adding_extra_ids:
                        est.add_extra_task_xref_info_to_row(row)
                    try:
                        self.dst_session.execute(dst_summary_table.insert(row))
                    except CompileError:
                        log.critical(
                            "\ndst_summary_table:\n{}\nrow:\n{}",
                            dst_table,
                            row,
                        )
                        raise