Commit 3658862d authored by sarsonl's avatar sarsonl
Browse files

Change attr names to match with 'm_'+column key

It was decided that it would be sensible if the column key
closely matched to the attribute name. Previously this
was deeply nested and made very long and confusing attribute
names. Have also added the ability to give a different column
name to the attribute name.
parent d93ca708
This diff is collapsed.
......@@ -13,7 +13,7 @@ from hydws.db.base import (ORMBase, CreationInfoMixin, RealQuantityMixin,
TimeQuantityMixin, EpochMixin,
LiteratureSourceMixin, PublicIDMixin)
KEY_PREFIX = 'm_'
PREFIX = 'm_'
# XXX(damb): The implementation of the entities below is based on the QuakeML
# and the SC3 DB model naming conventions. As a consequence,
......@@ -24,16 +24,16 @@ KEY_PREFIX = 'm_'
class Borehole(CreationInfoMixin('CreationInfo',
column_prefix='creationinfo_',
key_prefix=KEY_PREFIX),
parent_prefix='creationinfo_',
global_column_prefix=PREFIX),
LiteratureSourceMixin('LiteratureSource',
column_prefix='literaturesource_',
key_prefix=KEY_PREFIX),
RealQuantityMixin('longitude', key_prefix=KEY_PREFIX),
RealQuantityMixin('latitude', key_prefix=KEY_PREFIX),
RealQuantityMixin('depth', key_prefix=KEY_PREFIX),
RealQuantityMixin('bedrockdepth', key_prefix=KEY_PREFIX),
PublicIDMixin(column_prefix=KEY_PREFIX),
parent_prefix='literaturesource_',
global_column_prefix=PREFIX),
RealQuantityMixin('longitude', global_column_prefix=PREFIX),
RealQuantityMixin('latitude', global_column_prefix=PREFIX),
RealQuantityMixin('depth', global_column_prefix=PREFIX),
RealQuantityMixin('bedrockdepth', global_column_prefix=PREFIX),
PublicIDMixin(global_column_prefix=PREFIX),
ORMBase):
"""
ORM representation of a borehole. The attributes are in accordance with
......@@ -51,15 +51,15 @@ class Borehole(CreationInfoMixin('CreationInfo',
class BoreholeSection(EpochMixin('Epoch', epoch_type='open',
column_prefix='m_'),
RealQuantityMixin('toplongitude', key_prefix=KEY_PREFIX),
RealQuantityMixin('toplatitude', key_prefix=KEY_PREFIX),
RealQuantityMixin('topdepth', key_prefix=KEY_PREFIX),
RealQuantityMixin('bottomlongitude', key_prefix=KEY_PREFIX),
RealQuantityMixin('bottomlatitude', key_prefix=KEY_PREFIX),
RealQuantityMixin('bottomdepth', key_prefix=KEY_PREFIX),
RealQuantityMixin('holediameter', key_prefix=KEY_PREFIX),
RealQuantityMixin('casingdiameter', key_prefix=KEY_PREFIX),
PublicIDMixin(column_prefix=KEY_PREFIX),
RealQuantityMixin('toplongitude', global_column_prefix=PREFIX),
RealQuantityMixin('toplatitude', global_column_prefix=PREFIX),
RealQuantityMixin('topdepth', global_column_prefix=PREFIX),
RealQuantityMixin('bottomlongitude', global_column_prefix=PREFIX),
RealQuantityMixin('bottomlatitude', global_column_prefix=PREFIX),
RealQuantityMixin('bottomdepth', global_column_prefix=PREFIX),
RealQuantityMixin('holediameter', global_column_prefix=PREFIX),
RealQuantityMixin('casingdiameter', global_column_prefix=PREFIX),
PublicIDMixin(global_column_prefix=PREFIX),
ORMBase):
"""
ORM representation of a borehole. The attributes are in accordance with
......@@ -70,29 +70,29 @@ class BoreholeSection(EpochMixin('Epoch', epoch_type='open',
*Quantities* are implemented as `QuakeML
<https://quake.ethz.ch/quakeml>`_ quantities.
"""
topclosed = Column('{}topclosed'.format(KEY_PREFIX), Boolean)
bottomclosed = Column('{}bottomclosed'.format(KEY_PREFIX), Boolean)
sectiontype = Column('{}sectiontype'.format(KEY_PREFIX), String)
casingtype = Column('{}casingtype'.format(KEY_PREFIX), String)
description = Column('{}description'.format(KEY_PREFIX), String)
topclosed = Column('{}topclosed'.format(PREFIX), Boolean)
bottomclosed = Column('{}bottomclosed'.format(PREFIX), Boolean)
sectiontype = Column('{}sectiontype'.format(PREFIX), String)
casingtype = Column('{}casingtype'.format(PREFIX), String)
description = Column('{}description'.format(PREFIX), String)
borehole_oid = Column('{}borehole_oid'.format(KEY_PREFIX), Integer, ForeignKey('borehole._oid'))
borehole_oid = Column('{}borehole_oid'.format(PREFIX), Integer, ForeignKey('borehole._oid'))
_borehole = relationship("Borehole", back_populates="_sections")
_hydraulics = relationship("HydraulicSample", back_populates="_section")
class HydraulicSample(TimeQuantityMixin('datetime', key_prefix=KEY_PREFIX),
RealQuantityMixin('bottomtemperature', key_prefix=KEY_PREFIX),
RealQuantityMixin('bottomflow', key_prefix=KEY_PREFIX),
RealQuantityMixin('bottompressure', key_prefix=KEY_PREFIX),
RealQuantityMixin('toptemperature', key_prefix=KEY_PREFIX),
RealQuantityMixin('topflow', key_prefix=KEY_PREFIX),
RealQuantityMixin('toppressure', key_prefix=KEY_PREFIX),
RealQuantityMixin('fluiddensity', key_prefix=KEY_PREFIX),
RealQuantityMixin('fluidviscosity', key_prefix=KEY_PREFIX),
RealQuantityMixin('fluidph', key_prefix=KEY_PREFIX),
PublicIDMixin(column_prefix=KEY_PREFIX),
class HydraulicSample(TimeQuantityMixin('datetime', global_column_prefix=PREFIX),
RealQuantityMixin('bottomtemperature', global_column_prefix=PREFIX),
RealQuantityMixin('bottomflow', global_column_prefix=PREFIX),
RealQuantityMixin('bottompressure', global_column_prefix=PREFIX),
RealQuantityMixin('toptemperature', global_column_prefix=PREFIX),
RealQuantityMixin('topflow', global_column_prefix=PREFIX),
RealQuantityMixin('toppressure', global_column_prefix=PREFIX),
RealQuantityMixin('fluiddensity', global_column_prefix=PREFIX),
RealQuantityMixin('fluidviscosity', global_column_prefix=PREFIX),
RealQuantityMixin('fluidph', global_column_prefix=PREFIX),
PublicIDMixin(global_column_prefix=PREFIX),
ORMBase):
"""
Represents an hydraulics sample. The definition is based on `QuakeML
......@@ -103,7 +103,7 @@ class HydraulicSample(TimeQuantityMixin('datetime', key_prefix=KEY_PREFIX),
*Quantities* are implemented as `QuakeML
<https://quake.ethz.ch/quakeml>`_ quantities.
"""
fluidcomposition = Column('{}fluidcomposition'.format(KEY_PREFIX), String)
fluidcomposition = Column('{}fluidcomposition'.format(PREFIX), String)
boreholesection_oid = Column('boreholesection_oid'.format(KEY_PREFIX), Integer, ForeignKey('boreholesection._oid'))
boreholesection_oid = Column('boreholesection_oid'.format(PREFIX), Integer, ForeignKey('boreholesection._oid'))
_section = relationship("BoreholeSection", back_populates="_hydraulics")
......@@ -30,7 +30,7 @@ class QuakeMLQuantityField(fields.Field):
def _serialize(self, value, attr, obj, **kwargs):
retval = {}
for _attr in self.ATTRS:
key = f"{_ATTR_PREFIX}{attr}_{_attr}".lower()
key = f"{attr}_{_attr}".lower()
value = get_value(obj, key, default=None)
if isinstance(value, datetime.datetime):
......@@ -51,8 +51,10 @@ class SchemaBase(Schema):
Custom accessor method extracting values from objects applying the
:code:`m_` prefix to attribute keys.
"""
if not key.startswith(_ATTR_PREFIX) and not key.startswith('_'):
key = _ATTR_PREFIX + key.lower()
#print(key, _ATTR_PREFIX)
#if key.startswith(_ATTR_PREFIX):
# key = _ATTR_PREFIX + key.lower()
return get_value(obj, key, default)
@post_dump
......@@ -103,6 +105,7 @@ class SectionSchema(SchemaBase):
casingtype = fields.String()
description = fields.String()
class SectionHydraulicSampleSchema(SectionSchema, SchemaBase):
hydraulics = fields.Nested(HydraulicSampleSchema, many=True,
......@@ -121,6 +124,8 @@ class BoreholeSchema(SchemaBase):
depth = QuakeMLQuantityField()
bedrockdepth = QuakeMLQuantityField()
literature_source = LiteratureSource()
class BoreholeSectionSchema(BoreholeSchema, SchemaBase):
sections = fields.Nested(SectionSchema, many=True,
attribute='_sections')
......
......@@ -7,13 +7,14 @@ import logging
from flask_restful import Api, Resource
from sqlalchemy.orm.exc import NoResultFound
from webargs.flaskparser import use_kwargs
from marshmallow import fields
from hydws import __version__
from hydws.db import orm
from hydws.server import db, settings
from hydws.server.errors import FDSNHTTPError
from hydws.server.misc import (with_fdsnws_exception_handling, decode_publicid,
make_response, DynamicQuery)
make_response)
from hydws.server.v1 import blueprint
from hydws.server.v1.ostream.schema import (BoreholeSchema,
BoreholeSectionSchema,
......@@ -24,40 +25,45 @@ from hydws.server.v1.parser import (
BoreholeHydraulicSampleListResourceSchema,
BoreholeListResourceSchema,
SectionHydraulicSampleListResourceSchema)
from hydws.server.query_filters import DynamicQuery
api_v1 = Api(blueprint)
some_parser = {"maxlatitude": fields.Str(), "maxlongitude": fields.Str()}
# Mapping of columns to comparison operator and input parameter.
# [(orm column, operator, input comparison value)]
# Filter on hydraulics fields:
filter_hydraulics = [
('m_datetime', 'ge', 'starttime'),
('m_datetime', 'le', 'endtime'),
('m_toptemperature', 'ge', 'mintoptemperature'),
('m_toptemperature', 'le', 'maxtoptemperature'),
('m_bottomtemperature', 'ge', 'minbottomtemperature'),
('m_bottomtemperature', 'le', 'maxbottomtemperature'),
('m_toppressure', 'ge', 'mintoppressure'),
('m_toppressure', 'le', 'maxtoppressure'),
('m_bottompressure', 'ge', 'minbottompressure'),
('m_bottompressure', 'le', 'maxbottompressure'),
('m_topflow', 'ge', 'mintopflow'),
('m_topflow', 'le', 'maxtopflow'),
('m_bottomflow', 'ge', 'minbottomflow'),
('m_bottomflow', 'le', 'maxbottomflow'),
('m_fluiddensity', 'ge', 'minfluiddensity'),
('m_fluiddensity', 'le', 'maxfluiddensity'),
('m_fluidviscosity', 'ge', 'minfluidviscosity'),
('m_fluidviscosity', 'le', 'maxfluidviscosity'),
('m_fluidph', 'ge', 'minfluidph'),
('m_fluidph', 'le', 'maxfluidph')]
('datetime', 'ge', 'starttime'),
('datetime', 'le', 'endtime'),
('toptemperature', 'ge', 'mintoptemperature'),
('toptemperature', 'le', 'maxtoptemperature'),
('bottomtemperature', 'ge', 'minbottomtemperature'),
('bottomtemperature', 'le', 'maxbottomtemperature'),
('toppressure', 'ge', 'mintoppressure'),
('toppressure', 'le', 'maxtoppressure'),
('bottompressure', 'ge', 'minbottompressure'),
('bottompressure', 'le', 'maxbottompressure'),
('topflow', 'ge', 'mintopflow'),
('topflow', 'le', 'maxtopflow'),
('bottomflow', 'ge', 'minbottomflow'),
('bottomflow', 'le', 'maxbottomflow'),
('fluiddensity', 'ge', 'minfluiddensity'),
('fluiddensity', 'le', 'maxfluiddensity'),
('fluidviscosity', 'ge', 'minfluidviscosity'),
('fluidviscosity', 'le', 'maxfluidviscosity'),
('fluidph', 'ge', 'minfluidph'),
('fluidph', 'le', 'maxfluidph')]
filter_boreholes = [
('m_latitude', 'ge', 'minlatitude'),
('m_latitude', 'le', 'maxlatitude'),
('m_longitude', 'ge', 'minlongitude'),
('m_longitude', 'le', 'maxlongitude')]
('latitude', 'ge', 'minlatitude'),
('latitude', 'le', 'maxlatitude'),
('longitude', 'ge', 'minlongitude'),
('longitude', 'le', 'maxlongitude')]
class ResourceBase(Resource):
......@@ -100,12 +106,16 @@ class ResourceBase(Resource):
raise NotImplementedError
class BoreholeListResource(ResourceBase):
LOGGER = 'hydws.server.v1.boreholelistresource'
# For some reason, if invalid query parameters are used,
# no exception or anything is raised, even though the default
# functionality means that an exception should be raised.
@with_fdsnws_exception_handling(__version__)
@use_kwargs(BoreholeListResourceSchema(), locations=("query",))
@use_kwargs(BoreholeListResourceSchema, locations=("query",))
def get(self, **query_params):
self.logger.debug(
......@@ -176,14 +186,13 @@ class BoreholeHydraulicSampleListResource(ResourceBase):
# TODO(damb): Serialize according to query_param format=JSON|XML
# format response
print("#################### level: ", query_params.get('level'))
level = query_params.get('level')
if level == 'borehole':
resp = BoreholeSchema(many=True).dumps(resp)
elif level == 'section':
resp = BoreholeSectionSchema(many=True).dumps(resp)
elif level == 'hydraulics':
resp = BoreholeHydraulicSampleSchema(many=True).dumps(resp)
elif level == 'hydraulic':
resp = BoreholeSectionHydraulicSampleSchema(many=True).dumps(resp)
return make_response(resp, settings.MIMETYPE_JSON)
......@@ -193,17 +202,35 @@ class BoreholeHydraulicSampleListResource(ResourceBase):
if not borehole_id:
raise ValueError(f"Invalid borehole identifier: {borehole_id!r}")
# XXX(sarsonl) explicitly adding on tables seperately on condition
# results in problems joining tables - outer join undefined.
level = query_params.get('level')
query = session.query(orm.Borehole)
if level == 'borehole':
query = session.query(orm.Borehole)
if level == 'section':
query = query.join(orm.BoreholeSection)
elif level == 'hydraulics':
query = query.join(orm.HydraulicsSample)
query = session.query(orm.Borehole).\
join(orm.BoreholeSection)
order_by_columns = [
getattr(orm.BoreholeSection,
settings.HYDWS_SECTIONS_ORDER_BY)]
elif level == 'hydraulic':
query = session.query(orm.Borehole).\
join(orm.BoreholeSection).\
join(orm.HydraulicSample)
order_by_columns = [
getattr(orm.BoreholeSection,
settings.HYDWS_SECTIONS_ORDER_BY),
getattr(orm.HydraulicSample,
settings.HYDWS_HYDRAULICS_ORDER_BY)]
query = query.filter(orm.Borehole.m_publicid==borehole_id)
query = query.filter(orm.Borehole.publicid==borehole_id)
dynamic_query = DynamicQuery(query)
# XXX(damb): Emulate QuakeML type Epoch (though on DB level it is
# defined as QuakeML type OpenEpoch
......@@ -213,67 +240,27 @@ class BoreholeHydraulicSampleListResource(ResourceBase):
# XXX(lsarson): Filter None first or query will fail due to type differences.
dynamic_query.filter_query(orm.HydraulicSample, query_params,
filter_hydraulics)
try:
return dynamic_query.query.all()
except NoResultFound:
return None
# XXX(lsarson): should this be defined on the orm instead,
# so that if this table returned it will always be in that order?
if level == 'sections':
dynamic_query.order_by_query(
orm.BoreholeSection, settings.HYDWS_SECTIONS_ORDER_BY)
if level == 'hydraulic':
dynamic_query.order_by_query(
orm.BoreholeSection, settings.HYDWS_SECTIONS_ORDER_BY)
dynamic_query.order_by_query(
orm.HydraulicSample, settings.HYDWS_HYDRAULICS_ORDER_BY)
if query_params.get('limit'):
paginate_obj = dynamic_query.paginate_query(
query_params.get('limit'), query_params.get('page'))
# TODO(lsarson): do something with the properties
# next_url, has_next.
return paginate_obj.items
else:
return dynamic_query.return_all()
#class BoreholeHydraulicSampleListResource(ResourceBase):
#
# LOGGER = 'hydws.server.v1.boreholehydraulicsamplelistresource'
#
# @with_fdsnws_exception_handling(__version__)
# @use_kwargs(BoreholeHydraulicSampleListResourceSchema(),
# locations=("query", ))
# def get(self, borehole_id, **query_params):
# borehole_id = decode_publicid(borehole_id)
#
# self.logger.debug(
# f"Received request: borehole_id={borehole_id}, "
# f"query_params={query_params}")
#
# resp = self._process_request(db.session, borehole_id=borehole_id,
# **query_params)
#
# if not resp:
# self._handle_nodata(query_params)
#
# # TODO(damb): Serialize according to query_param format=JSON|XML
# # format response
# resp = SectionHydraulicSampleSchema(many=True).dumps(resp)
#
# return make_response(resp, settings.MIMETYPE_JSON)
#
#
# def _process_request(self, session, borehole_id=None, section_id=None,
# **query_params):
#
# if not borehole_id:
# raise ValueError(f"Invalid borehole identifier: {borehole_id!r}")
#
# query = session.query(orm.Borehole).\
# join(orm.BoreholeSection).\
# join(orm.HydraulicSample).\
# filter(orm.Borehole.m_publicid==borehole_id)
#
# dynamic_query = DynamicQuery(query)
#
# # XXX(damb): Emulate QuakeML type Epoch (though on DB level it is
# # defined as QuakeML type OpenEpoch
#
# # XXX(lsarson): Should there be functionality to add or queries?
# # if so then there should have another method added to DynamicQuery
#
# # XXX(lsarson): Filter None first or query will fail due to type differences.
# dynamic_query.filter_query(orm.HydraulicSample, query_params,
# filter_hydraulics)
#
# try:
# return dynamic_query.query.all()
# except NoResultFound:
# return None
class SectionHydraulicSampleListResource(ResourceBase):
......@@ -312,8 +299,8 @@ class SectionHydraulicSampleListResource(ResourceBase):
query = session.query(orm.HydraulicSample).\
join(orm.BoreholeSection).\
join(orm.Borehole).\
filter(orm.Borehole.m_publicid==borehole_id).\
filter(orm.BoreholeSection.m_publicid==section_id)
filter(orm.Borehole.publicid==borehole_id).\
filter(orm.BoreholeSection.publicid==section_id)
dynamic_query = DynamicQuery(query)
......@@ -337,15 +324,20 @@ class SectionHydraulicSampleListResource(ResourceBase):
dynamic_query.filter_query(orm.HydraulicSample, query_params,
filter_hydraulics)
try:
return dynamic_query.query.all()
except NoResultFound:
return None
dynamic_query.order_by_query(
orm.BoreholeSection, settings.HYDWS_SECTIONS_ORDER_BY)
dynamic_query.order_by_query(
orm.HydraulicSample, settings.HYDWS_HYDRAULICS_ORDER_BY)
if query_params.get('limit'):
paginate_obj = dynamic_query.paginate_query(
query_params.get('limit'), query_params.get('page'))
# Todo(lsarson): do something with the properties
# next_url, has_next.
return paginate_obj.items
else:
return dynamic_query.return_all()
# TODO(damb):
# Add resources to API
api_v1.add_resource(BoreholeListResource,
'{}/'.format(settings.HYDWS_PATH_BOREHOLES))
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment