Stored procedure helpers. Order repo and model. More SQLService updates.
* A generic stored procedure helper added, and support for calling them. * Order and OrderItem tables added, including helpers and calls to SP for creation and updates. * Minor updates to other repositories.
This commit is contained in:
parent
b77a7069ce
commit
0af38e286e
9 changed files with 730 additions and 138 deletions
|
|
@ -2,11 +2,17 @@
|
|||
Define an Abstract Base Class (ABC) for models
|
||||
"""
|
||||
from decimal import Decimal
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy.sql.expression import and_
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.exc import OperationalError
|
||||
|
||||
from sqlservice import ModelBase
|
||||
from sqlalchemy.schema import MetaData, Column
|
||||
from sqlalchemy.types import Integer
|
||||
from sqlalchemy.orm.collections import InstrumentedList
|
||||
|
||||
from sqlservice import ModelBase, as_declarative
|
||||
|
||||
from pyjeeves import logging
|
||||
|
||||
|
|
@ -14,7 +20,19 @@ from . import db
|
|||
|
||||
logger = logging.getLogger("PyJeeves." + __name__)
|
||||
|
||||
logger.info("Reading Jeeves DB structure")
|
||||
|
||||
meta = MetaData()
|
||||
try:
|
||||
meta.reflect(bind=db.raw.connection(),
|
||||
only=['ar', 'ars', 'xae', 'xare', 'fr', 'kus', 'x1k',
|
||||
'oh', 'orp', 'lp', 'vg', 'xp', 'xm', 'prh', 'prl'])
|
||||
except OperationalError as e:
|
||||
logger.error("Failed to read Jeeves DB structure")
|
||||
raise e
|
||||
|
||||
|
||||
@as_declarative(metadata=meta)
|
||||
class RawBaseModel(ModelBase):
|
||||
""" Generalize __init__, __repr__ and to_json
|
||||
Based on the models columns , ForetagKod=1"""
|
||||
|
|
@ -22,6 +40,7 @@ class RawBaseModel(ModelBase):
|
|||
__to_dict_filter__ = []
|
||||
__to_dict_only__ = ()
|
||||
__column_map__ = {}
|
||||
__reversed_column_map__ = lambda self: {v: k for k, v in self.__column_map__.items()} # noqa
|
||||
|
||||
__table_args__ = {
|
||||
'extend_existing': True
|
||||
|
|
@ -29,11 +48,19 @@ class RawBaseModel(ModelBase):
|
|||
|
||||
__dict_args__ = {
|
||||
'adapters': {
|
||||
# datetime: lambda value, col, *_: value.strftime('%Y-%m-%d'),
|
||||
Decimal: lambda value, col, *_: "{:.2f}".format(value)
|
||||
datetime: lambda value, col, *_: value.strftime('%Y-%m-%d %H:%M'),
|
||||
Decimal: lambda value, col, *_: float(value) # "{:.2f}".format(value)
|
||||
}
|
||||
}
|
||||
|
||||
ForetagKod = Column(Integer, primary_key=True)
|
||||
|
||||
def __init__(self, data=None, **kargs):
|
||||
if data:
|
||||
data = self._map_keys(data)
|
||||
self.update(data, **kargs)
|
||||
# super(RawBaseModel, self).__init__(data=None, **kargs)
|
||||
|
||||
@classmethod
|
||||
def _base_filters(self, obj, filters=and_()):
|
||||
# This method provides base filtering, additional filtering can be done in subclasses
|
||||
|
|
@ -50,6 +77,44 @@ class RawBaseModel(ModelBase):
|
|||
return self.__column_map__[key]
|
||||
return key
|
||||
|
||||
def _map_keys(self, data={}):
|
||||
rv = {}
|
||||
for key, value in self.__reversed_column_map__().items():
|
||||
if key in data:
|
||||
rv[value] = data[key]
|
||||
for key, value in data.items():
|
||||
if hasattr(self, key):
|
||||
if key in self.relationships().keys():
|
||||
rv[key] = self._map_relationship_keys(key, value)
|
||||
else:
|
||||
rv[key] = value
|
||||
return rv
|
||||
|
||||
def _map_relationship_keys(self, field, value):
|
||||
"""Get model relationships fields value. Almost a copy from SQLService ModelBase"""
|
||||
relation_attr = getattr(self.__class__, field)
|
||||
uselist = relation_attr.property.uselist
|
||||
relation_class = relation_attr.property.mapper.class_
|
||||
|
||||
if uselist:
|
||||
if not isinstance(value, (list, tuple)): # pragma: no cover
|
||||
value = [value]
|
||||
|
||||
# Convert each value instance to relationship class.
|
||||
value = [relation_class(val) if not isinstance(val, relation_class)
|
||||
else val
|
||||
for val in value]
|
||||
elif value and isinstance(value, dict):
|
||||
# Convert single value object to relationship class.
|
||||
value = relation_class(value)
|
||||
elif not value and isinstance(value, dict):
|
||||
# If value is {} and we're trying to update a relationship
|
||||
# attribute, then we need to set to None to nullify relationship
|
||||
# value.
|
||||
value = None
|
||||
|
||||
return value
|
||||
|
||||
def descriptors_to_dict(self):
|
||||
"""Return a ``dict`` that maps data loaded in :attr:`__dict__` to this
|
||||
model's descriptors. The data contained in :attr:`__dict__` represents
|
||||
|
|
@ -90,6 +155,18 @@ class RawBaseModel(ModelBase):
|
|||
|
||||
return rv
|
||||
|
||||
def from_dict(self, data={}):
|
||||
for key, value in self.__reversed_column_map__().items():
|
||||
if key in data:
|
||||
self[value] = data[key]
|
||||
for key, value in data.items():
|
||||
if hasattr(self, key):
|
||||
if isinstance(self[key], InstrumentedList):
|
||||
pass
|
||||
else:
|
||||
self[key] = value
|
||||
return self
|
||||
|
||||
def merge(self):
|
||||
db.raw_session.merge(self)
|
||||
return self
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue