Package Gnumed :: Package business :: Module gmIncomingData |
[frames] | no frames]

# Source Code for Module Gnumed.business.gmIncomingData

      1  # -*- coding: utf-8 -*-
      2  """Handling of <INCOMING> area."""
      3  #============================================================
      4  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
      5  __license__ = "GPL v2 or later"
      6
      7
      8  import sys
      9  import os
     10  import logging
     11
     12
     13  if __name__ == '__main__':
     14          sys.path.insert(0, '../../')
     15
     16  from Gnumed.pycommon import gmI18N
     17  if __name__ == '__main__':
     18          gmI18N.activate_locale()
     19          gmI18N.install_domain()
     20  from Gnumed.pycommon import gmTools
     21  from Gnumed.pycommon import gmBusinessDBObject
     22  from Gnumed.pycommon import gmPG2
     23  from Gnumed.pycommon import gmDateTime
     24
     25
     26  _log = logging.getLogger('gm.import')
     27
     28  #============================================================
     29  # class to handle unmatched incoming clinical data
     30  #------------------------------------------------------------
     31  _SQL_get_incoming_data = """SELECT * FROM clin.v_incoming_data_unmatched WHERE %s"""
     32
     33 -class cIncomingData(gmBusinessDBObject.cBusinessDBObject):
     34          """Represents items of incoming data, say, HL7 snippets."""
     35
     36          _cmd_fetch_payload = _SQL_get_incoming_data % "pk_incoming_data_unmatched = %s"
     37          _cmds_store_payload = [
     38                  """UPDATE clin.incoming_data_unmatched SET
     39                                  fk_patient_candidates = %(pk_patient_candidates)s,
     40                                  fk_identity_disambiguated = %(pk_identity_disambiguated)s,
     41                                  fk_provider_disambiguated = %(pk_provider_disambiguated)s,
     42                                  request_id = gm.nullify_empty_string(%(request_id)s),
     43                                  firstnames = gm.nullify_empty_string(%(firstnames)s),
     44                                  lastnames = gm.nullify_empty_string(%(lastnames)s),
     45                                  dob = %(dob)s,
     46                                  postcode = gm.nullify_empty_string(%(postcode)s),
     47                                  other_info = gm.nullify_empty_string(%(other_info)s),
     48                                  type = gm.nullify_empty_string(%(data_type)s),
     49                                  gender = gm.nullify_empty_string(%(gender)s),
     50                                  requestor = gm.nullify_empty_string(%(requestor)s),
     51                                  external_data_id = gm.nullify_empty_string(%(external_data_id)s),
     52                                  comment = gm.nullify_empty_string(%(comment)s)
     53                          WHERE
     54                                  pk = %(pk_incoming_data_unmatched)s
     55                                          AND
     56                                  xmin = %(xmin_incoming_data_unmatched)s
     57                          RETURNING
     58                                  xmin as xmin_incoming_data_unmatched,
     59                                  octet_length(data) as data_size
     60                  """
     61          ]
     62          # view columns that can be updated:
     63          _updatable_fields = [
     64                  'pk_patient_candidates',
     65                  'request_id',                                           # request ID as found in <data>
     66                  'firstnames',
     67                  'lastnames',
     68                  'dob',
     69                  'postcode',
     70                  'other_info',                                           # other identifying info in .data
     71                  'data_type',
     72                  'gender',
     73                  'requestor',                                            # Requestor of data (e.g. who ordered test results) if available in source data.
     74                  'external_data_id',                             # ID of content of .data in external system (e.g. importer) where appropriate
     75                  'comment',                                                      # a free text comment on this row, eg. why is it here, error logs etc
     76                  'pk_identity_disambiguated',
     77                  'pk_provider_disambiguated'             # The provider the data is relevant to.
     78          ]
     79          #--------------------------------------------------------
     80 -        def format(self):
     81                  return '%s' % self
     82          #--------------------------------------------------------
     83 -        def _format_patient_identification(self):
     84                  tmp = '%s %s %s' % (
     85                          gmTools.coalesce(self._payload[self._idx['lastnames']], '', 'last=%s'),
     86                          gmTools.coalesce(self._payload[self._idx['firstnames']], '', 'first=%s'),
     87                          gmTools.coalesce(self._payload[self._idx['gender']], '', 'gender=%s')
     88                  )
     89                  if self._payload[self._idx['dob']] is not None:
     90                          tmp += ' dob=%s' % gmDateTime.pydt_strftime(self._payload[self._idx['dob']], '%Y %b %d')
     91                  return tmp
     92
     93          patient_identification = property(_format_patient_identification, lambda x:x)
     94
     95          #--------------------------------------------------------
     96 -        def update_data_from_file(self, fname=None):
     97                  # sanity check
     98                  if not (os.access(fname, os.R_OK) and os.path.isfile(fname)):
     99                          _log.error('[%s] is not a readable file' % fname)
    100                          return False
    101
    102                  _log.debug('updating [pk=%s] from [%s]', self.pk_obj, fname)
    103                  gmPG2.file2bytea (
    104                          query = "UPDATE clin.incoming_data_unmatched SET data = %(data)s::bytea WHERE pk = %(pk)s",
    105                          filename = fname,
    106                          args = {'pk': self.pk_obj}
    107                  )
    108
    109                  # must update XMIN now ...
    110                  self.refetch_payload()
    111                  return True
    112
    113          #--------------------------------------------------------
    114 -        def save_to_file(self, aChunkSize=0, filename=None):
    115
    116                  if self._payload[self._idx['data_size']] == 0:
    117                          return None
    118
    119                  if self._payload[self._idx['data_size']] is None:
    120                          return None
    121
    122                  if filename is None:
    123                          filename = gmTools.get_unique_filename(prefix = 'gm-incoming_data_unmatched-')
    124
    125                  success = gmPG2.bytea2file (
    126                          data_query = {
    127                                  'cmd': 'SELECT substring(data from %(start)s for %(size)s) FROM clin.incoming_data_unmatched WHERE pk = %(pk)s',
    128                                  'args': {'pk': self.pk_obj}
    129                          },
    130                          filename = filename,
    131                          chunk_size = aChunkSize,
    132                          data_size = self._payload[self._idx['data_size']]
    133                  )
    134
    135                  if not success:
    136                          return None
    137
    138                  return filename
    139
    140          #--------------------------------------------------------
    141 -        def lock(self, exclusive=False):
    142                  return gmPG2.lock_row(table = 'clin.incoming_data_unmatched', pk = self.pk_obj, exclusive = exclusive)
    143
    144          #--------------------------------------------------------
    145 -        def unlock(self, exclusive=False):
    146                  return gmPG2.unlock_row(table = 'clin.incoming_data_unmatched', pk = self.pk_obj, exclusive = exclusive)
    147
    148  #------------------------------------------------------------
    149 -def get_incoming_data(order_by=None, return_pks=False):
    150          if order_by is None:
    151                  order_by = 'true'
    152          else:
    153                  order_by = 'true ORDER BY %s' % order_by
    154          cmd = _SQL_get_incoming_data % order_by
    155          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
    156          if return_pks:
    157                  return [ r['pk_incoming_data_unmatched'] for r in rows ]
    158          return [ cIncomingData(row = {'data': r, 'idx': idx, 'pk_field': 'pk_incoming_data_unmatched'}) for r in rows ]
    159
    160  #------------------------------------------------------------
    161 -def create_incoming_data(data_type, filename):
    162          args = {'typ': data_type}
    163          cmd = """
    164                  INSERT INTO clin.incoming_data_unmatched (type, data)
    165                  VALUES (%(typ)s, 'new data'::bytea)
    166                  RETURNING pk"""
    167          rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
    168          pk = rows[0]['pk']
    169          incoming = cIncomingData(aPK_obj = pk)
    170          if not incoming.update_data_from_file(fname = filename):
    171                  _log.debug('cannot update newly created incoming_data record from file, deleting stub')
    172                  delete_incoming_data(incoming_data = pk)
    173                  return None
    174          return incoming
    175
    176  #------------------------------------------------------------
    177 -def delete_incoming_data(pk_incoming_data=None):
    178          args = {'pk': pk_incoming_data}
    179          cmd = "DELETE FROM clin.incoming_data_unmatched WHERE pk = %(pk)s"
    180          gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
    181          return True
    182
    183  #============================================================
    184  # main
    185  #------------------------------------------------------------
    186  if __name__ == "__main__":
    187
    188          if len(sys.argv) < 2:
    189                  sys.exit()
    190
    191          if sys.argv[1] != 'test':
    192                  sys.exit()
    193
    194          from Gnumed.pycommon import gmLog2
    195
    196          gmDateTime.init()
    197          gmTools.gmPaths()
    198
    199          #-------------------------------------------------------
    200 -        def test_incoming_data():
    201                  for d in get_incoming_data():
    202                          print(d)
    203
    204          #-------------------------------------------------------
    205          test_incoming_data()
    206