15.2.107. camcops_server.cc_modules.cc_db¶
camcops_server/cc_modules/cc_db.py
Copyright (C) 2012, University of Cambridge, Department of Psychiatry. Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
This file is part of CamCOPS.
CamCOPS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
CamCOPS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
Common database code, e.g. mixins for tables that are uploaded from the client.
- class camcops_server.cc_modules.cc_db.GenericTabletRecordMixin[source]¶
Mixin for all tables that are uploaded from the client, representing the fields that the server adds at the point of upload.
From the server’s perspective,
_pk
is the unique primary key.However, records are defined also in their tablet context, for which an individual tablet (defined by the combination of
_device_id
and_era
) sees its own PK,id
.- create_fresh(req: CamcopsRequest, device_id: int, era: str, group_id: int) None [source]¶
Used to create a record from scratch.
- delete_with_dependants(req: CamcopsRequest) None [source]¶
Deletes (completely from the database) this record and any dependant records.
- property device_id: Optional[int]¶
Returns the client device ID of this record.
- property era: Optional[str]¶
Returns the era of this record (a text representation of the date/time of the point of record finalization, or
NOW
if the record is still present on the client device).
- gen_ancillary_instances() Generator[camcops_server.cc_modules.cc_db.GenericTabletRecordMixin, None, None] [source]¶
Generates all
_current
ancillary objects of this object.
- gen_ancillary_instances_even_noncurrent() Generator[camcops_server.cc_modules.cc_db.GenericTabletRecordMixin, None, None] [source]¶
Generates all ancillary objects of this object, even non-current ones.
- gen_attrname_ancillary_pairs() Generator[Tuple[str, camcops_server.cc_modules.cc_db.GenericTabletRecordMixin], None, None] [source]¶
Iterates through and yields all
_current
“ancillary” objects (typically: records of subtables).Yields tuples of
(attrname, related_record)
.
- gen_blobs_even_noncurrent() Generator[Blob, None, None] [source]¶
Generates all BLOBs owned by this object, even non-current ones.
- get_lineage() List[camcops_server.cc_modules.cc_db.GenericTabletRecordMixin] [source]¶
Returns all records that are part of the same “lineage”, that is:
of the same class;
matching on id/device_id/era;
including both current and any historical non-current versions.
Will include the “self” object.
- classmethod get_linked(client_id: Optional[int], other: camcops_server.cc_modules.cc_db.GenericTabletRecordMixin) Optional[camcops_server.cc_modules.cc_db.GenericTabletRecordMixin] [source]¶
Returns a specific linked record, of the class of
self
, whose client-side ID isclient_id
, and which matchesother
in terms of device/era.
- get_summaries(req: CamcopsRequest) List[SummaryElement] [source]¶
Return a list of
SummaryElement
objects, for this database object (not any dependent classes/tables).Note that this is implemented on
GenericTabletRecordMixin
, notcamcops_server.cc_modules.cc_task.Task
, so that ancillary objects can also provide summaries.
- property group_id: Optional[int]¶
Returns the group ID of this record.
- is_finalized() bool [source]¶
Is the record finalized (no longer available to be edited on the client device), and therefore (if required) editable on the server?
- manually_erase_with_dependants(req: CamcopsRequest) None [source]¶
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.
- mark_as_deleted(req: CamcopsRequest) None [source]¶
Ends the history chain and marks this record as non-current.
- property pk: Optional[int]¶
Returns the (server) primary key of this record.
- save_with_next_available_id(req: CamcopsRequest, device_id: int, era: str = 'NOW') None [source]¶
Save a record with the next available client pk in sequence. This is of use when creating patients and ID numbers on the server to ensure uniqueness, or when fixing up a missing ID number for a patient created on a device.
- set_predecessor(req: CamcopsRequest, predecessor: GenericTabletRecordMixin) None [source]¶
Used for some unusual server-side manipulations (e.g. editing patient details).
Amends this object so the “self” object replaces the predecessor, so:
“self” becomes current and refers back to “predecessor”;
“predecessor” becomes non-current and refers forward to “self”.
- class camcops_server.cc_modules.cc_db.TaskDescendant[source]¶
Information mixin for sub-tables that can be traced back to a class. Used to denormalize the database for export in some circumstances.
Not used for the Blob class, which has no reasonable way of tracing itself back to a given task if it is used by a task’s ancillary tables rather than a primary task row.
- add_extra_task_xref_info_to_row(row: Dict[str, Any]) None [source]¶
For the
DB_PATIENT_ID_PER_ROW
export option. Adds additional cross-referencing info to a row.- Parameters
row – future database row, as a dictionary
- classmethod extra_task_xref_columns() List[sqlalchemy.sql.schema.Column] [source]¶
Returns extra columns used to cross-reference this
TaskDescendant
to its ancestor task, in certain export formats (DB_PATIENT_ID_PER_ROW
).
- classmethod task_ancestor_class() Optional[Type[Task]] [source]¶
Returns the class of the ancestral task.
If the descendant can descend from lots of types of task (rare; only applies to
camcops_server.cc_modules.cc_blob.Blob
andcamcops_server.cc_modules.cc_summaryelement.ExtraSummaryTable
), returnsNone
.
- classmethod task_ancestor_might_have_patient() bool [source]¶
Does this object have a single task ancestor, that is not anonymous?
- camcops_server.cc_modules.cc_db.add_multiple_columns(cls: Type, prefix: str, start: int, end: int, coltype=<class 'sqlalchemy.sql.sqltypes.Integer'>, colkwargs: Optional[Dict[str, Any]] = None, comment_fmt: Optional[str] = None, comment_strings: Optional[List[str]] = None, minimum: Optional[Union[float, int]] = None, maximum: Optional[Union[float, int]] = None, pv: Optional[List[Any]] = None, suffix: str = '') None [source]¶
Add a sequence of SQLAlchemy columns to a class.
Called from a metaclass. Used to make task creation a bit easier.
- Parameters
cls – class to which to add columns
prefix – Fieldname will be
prefix + str(n) + suffix
, wheren
is defined as below.suffix – Optional. See
prefix
.start – Start of range.
end – End of range. Thus:
i
will range from0
to(end - start)
inclusive;n
will range fromstart
toend
inclusive.coltype – SQLAlchemy column type, in either of these formats: (a)
Integer
(of general typeType[TypeEngine]
?); (b)Integer()
(of general typeTypeEngine
).colkwargs – SQLAlchemy column arguments, as in
Column(name, coltype, **colkwargs)
comment_fmt –
Format string defining field comments. Substitutable values are:
{n}
: field number (from range).{s}
:comment_strings[i]
, wherei
is a zero-based index as defined as above, or “” if out of range.
comment_strings – see
comment_fmt
minimum – minimum permitted value, or
None
maximum – maximum permitted value, or
None
pv – list of permitted values, or
None
- camcops_server.cc_modules.cc_db.ancillary_relationship(parent_class_name: str, ancillary_class_name: str, ancillary_fk_to_parent_attr_name: str, ancillary_order_by_attr_name: Optional[str] = None, read_only: bool = True) sqlalchemy.orm.relationships.RelationshipProperty [source]¶
Implements a one-to-many relationship, i.e. one parent to many ancillaries.
- camcops_server.cc_modules.cc_db.mysqldb_crash_on_bad_conversion(o: Any, d: Dict[Any, Callable]) NoReturn [source]¶
Reports a bad conversion and crashes. For debugging only (obviously)!
Conversions by mysqlclient (MySQLdb)
As per the help docstring for
MySQLdb/converters.py
,the Python-to-database conversion function has the signature
f(o, d)
whereo
is the thing to be converted (such as a datetime.datetime) andd
is the conversion dictionary; it returns an SQL literal value.The database-to-Python conversion function has the argument
f(s)
wheres
is a string; it returns a Python object.
Both types of functions are stored in
MySQLdb.converters
, which is adict
. The keys namedFIELD_TYPE.*
are the database-to-Python converters; the others are the Python-to-database converters.Conversions by pymysql
Similar (for back compatibility), but not the same.
pymysql.converters.conversions
ispymysql.converters.decoders
and contains database-to-Python converters.pymysql.converters.encoders
contains Python-to-database converters.
- Parameters
o – Python object
d – MySQLdb conversion dictionary
- Returns
SQL literal