Skip to content

Commit 9945d59

Browse files
committed
split _add_complex_type's array bit to (hopefully) easier-to-digest subroutines
1 parent 2591700 commit 9945d59

File tree

1 file changed

+111
-103
lines changed

1 file changed

+111
-103
lines changed

spyne/util/sqlalchemy.py

Lines changed: 111 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -499,11 +499,10 @@ def _get_col_o2m(cls, fk_col_name):
499499
yield col
500500

501501

502-
def _get_cols_m2m(cls, k, v, left_fk_col_name, right_fk_col_name):
502+
def _get_cols_m2m(cls, k, child, left_fk_col_name, right_fk_col_name):
503503
"""Gets the parent and child classes and returns foreign keys to both
504504
tables. These columns can be used to create a relation table."""
505505

506-
child, = v._type_info.values()
507506
col_info, left_col = _get_col_o2m(cls, left_fk_col_name)
508507
right_col = _get_col_o2o(cls, k, child, right_fk_col_name)
509508
left_col.primary_key = right_col.primary_key = True
@@ -633,133 +632,142 @@ def _add_simple_type(cls, props, table, k, v, sqla_type):
633632
if not v.Attributes.exc_mapper:
634633
props[k] = col
635634

636-
637-
def _add_complex_type(cls, props, table, k, v):
635+
def _gen_array_m2m(cls, props, k, child, p):
638636
metadata = cls.Attributes.sqla_metadata
637+
638+
col_own, col_child = _get_cols_m2m(cls, k, child, p.left, p.right)
639+
640+
p.left = col_own.key
641+
p.right = col_child.key
642+
643+
if p.multi == True:
644+
rel_table_name = '_'.join([cls.Attributes.table_name, k])
645+
else:
646+
rel_table_name = p.multi
647+
648+
# FIXME: Handle the case where the table already exists.
649+
rel_t = Table(rel_table_name, metadata, *(col_own, col_child))
650+
651+
props[k] = relationship(child, secondary=rel_t,
652+
backref=p.backref, cascade=p.cascade, lazy=p.lazy)
653+
654+
def _gen_array_simple(cls, props, k, child_cust, p):
639655
table_name = cls.Attributes.table_name
640-
col_args, col_kwargs = sanitize_args(v.Attributes.sqla_column_args)
641-
_sp_attrs_to_sqla_constraints(cls, v, col_kwargs)
656+
metadata = cls.Attributes.sqla_metadata
642657

643-
p = getattr(v.Attributes, 'store_as', None)
644-
if p is not None and issubclass(v, Array) and isinstance(p, c_table):
645-
child_cust, = v._type_info.values()
646-
if child_cust.__orig__ is not None:
647-
child = child_cust.__orig__
648-
else:
649-
child = child_cust
658+
# get left (fk) column info
659+
_gen_col = _get_col_o2m(cls, p.left)
660+
col_info = _gen_col.next() # gets the column name
661+
p.left, child_left_col_type = col_info[0] # FIXME: Add support for multi-column primary keys.
662+
child_left_col_name = p.left
663+
664+
# get right(data) column info
665+
child_right_col_type = get_sqlalchemy_type(child_cust)
666+
child_right_col_name = p.right # this is the data column
667+
if child_right_col_name is None:
668+
child_right_col_name = k
669+
670+
# get table name
671+
child_table_name = child_cust.Attributes.table_name
672+
if child_table_name is None:
673+
child_table_name = '_'.join([table_name, k])
674+
675+
if child_table_name in metadata.tables:
676+
child_t = metadata.tables[child_table_name]
677+
assert child_right_col_type is \
678+
child_t.c[child_right_col_name].type.__class__
679+
assert child_left_col_type is \
680+
child_t.c[child_left_col_name].type.__class__
650681

651-
if p.multi != False: # many to many
652-
col_own, col_child = _get_cols_m2m(cls, k, v, p.left, p.right)
682+
else:
683+
# table does not exist, generate table
684+
child_right_col = Column(child_right_col_name,
685+
child_right_col_type)
686+
_sp_attrs_to_sqla_constraints(cls, child_cust,
687+
col=child_right_col)
653688

654-
p.left = col_own.key
655-
p.right = col_child.key
689+
child_left_col = _gen_col.next()
690+
_sp_attrs_to_sqla_constraints(cls, child_cust,
691+
col=child_left_col)
656692

657-
if p.multi == True:
658-
rel_table_name = '_'.join([cls.Attributes.table_name, k])
659-
else:
660-
rel_table_name = p.multi
693+
child_t = Table(child_table_name , metadata,
694+
Column('id', sqlalchemy.Integer, primary_key=True),
695+
child_left_col, child_right_col)
661696

662-
# FIXME: Handle the case where the table already exists.
663-
rel_t = Table(rel_table_name, metadata,
664-
*(col_own, col_child))
697+
# generate temporary class for association proxy
698+
cls_name = ''.join(x.capitalize() or '_' for x in
699+
child_table_name.split('_'))
700+
# generates camelcase class name.
665701

666-
props[k] = relationship(child, secondary=rel_t,
667-
backref=p.backref, cascade=p.cascade, lazy=p.lazy)
702+
def _i(self, *args):
703+
setattr(self, child_right_col_name, args[0])
668704

669-
elif issubclass(child, SimpleModel): # one to many simple type
670-
# get left (fk) column info
671-
_gen_col = _get_col_o2m(cls, p.left)
672-
col_info = _gen_col.next() # gets the column name
673-
p.left, child_left_col_type = col_info[0] # FIXME: Add support for multi-column primary keys.
674-
child_left_col_name = p.left
675-
676-
# get right(data) column info
677-
child_right_col_type = get_sqlalchemy_type(child_cust)
678-
child_right_col_name = p.right # this is the data column
679-
if child_right_col_name is None:
680-
child_right_col_name = k
681-
682-
# get table name
683-
child_table_name = child_cust.Attributes.table_name
684-
if child_table_name is None:
685-
child_table_name = '_'.join([table_name, k])
686-
687-
if child_table_name in metadata.tables:
688-
# table exists, get releavant info
689-
child_t = metadata.tables[child_table_name]
690-
assert child_right_col_type is \
691-
child_t.c[child_right_col_name].type.__class__
692-
assert child_left_col_type is \
693-
child_t.c[child_left_col_name].type.__class__
694-
695-
child_right_col = child_t.c[child_right_col_name]
696-
child_left_col = child_t.c[child_left_col_name]
705+
cls_ = type("_" + cls_name, (object,), {'__init__': _i})
706+
own_mapper(cls_)(cls_, child_t)
707+
props["_" + k] = relationship(cls_)
697708

698-
else:
699-
# table does not exist, generate table
700-
child_right_col = Column(child_right_col_name,
701-
child_right_col_type)
702-
_sp_attrs_to_sqla_constraints(cls, child_cust,
703-
col=child_right_col)
709+
# generate association proxy
710+
setattr(cls, k, association_proxy("_" + k, child_right_col_name))
704711

705-
child_left_col = _gen_col.next()
706-
_sp_attrs_to_sqla_constraints(cls, child_cust,
707-
col=child_left_col)
708712

709-
child_t = Table(child_table_name , metadata,
710-
Column('id', sqlalchemy.Integer, primary_key=True),
711-
child_left_col, child_right_col)
713+
def _gen_array_o2m(cls, props, k, child, child_cust, p):
714+
_gen_col = _get_col_o2m(cls, p.right)
715+
col_info = _gen_col.next() # gets the column name
716+
p.right, col_type = col_info[0] # FIXME: Add support for multi-column primary keys.
712717

713-
# generate temporary class for association proxy
714-
cls_name = ''.join(x.capitalize() or '_' for x in
715-
child_table_name.split('_'))
716-
# generates camelcase class name.
718+
assert p.left is None, \
719+
"'left' is ignored in one-to-many relationships " \
720+
"with complex types (because they already have a " \
721+
"table). You probably meant to use 'right'."
717722

718-
def _i(self, *args):
719-
setattr(self, child_right_col_name, args[0])
723+
child_t = child.__table__
720724

721-
cls_ = type("_" + cls_name, (object,), {'__init__': _i})
722-
own_mapper(cls_)(cls_, child_t)
723-
props["_" + k] = relationship(cls_)
725+
if p.right in child_t.c:
726+
# FIXME: This branch MUST be tested.
727+
assert col_type is child_t.c[p.right].type.__class__
724728

725-
# generate association proxy
726-
setattr(cls, k, association_proxy("_" + k, child_right_col_name))
729+
# if the column is there, the decision about whether
730+
# it should be in child's mapper should also have been
731+
# made.
732+
#
733+
# so, not adding the child column to to child mapper
734+
# here.
735+
col = child_t.c[p.right]
727736

737+
else:
738+
col = _gen_col.next()
728739

729-
else: # one to many complex type
730-
_gen_col = _get_col_o2m(cls, p.right)
731-
col_info = _gen_col.next() # gets the column name
732-
p.right, col_type = col_info[0] # FIXME: Add support for multi-column primary keys.
740+
_sp_attrs_to_sqla_constraints(cls, child_cust, col=col)
733741

734-
assert p.left is None, \
735-
"'left' is ignored in one-to-many relationships " \
736-
"with complex types (because they already have a " \
737-
"table). You probably meant to use 'right'."
742+
child_t.append_column(col)
743+
child.__mapper__.add_property(col.name, col)
738744

739-
child_t = child.__table__
745+
props[k] = relationship(child, foreign_keys=[col],
746+
backref=p.backref, cascade=p.cascade, lazy=p.lazy)
740747

741-
if p.right in child_t.c:
742-
# FIXME: This branch MUST be tested.
743-
assert col_type is child_t.c[p.right].type.__class__
744748

745-
# if the column is there, the decision about whether
746-
# it should be in child's mapper should also have been
747-
# made.
748-
#
749-
# so, not adding the child column to to child mapper
750-
# here.
751-
col = child_t.c[p.right]
752749

753-
else:
754-
col = _gen_col.next()
750+
def _add_complex_type(cls, props, table, k, v):
751+
table_name = cls.Attributes.table_name
752+
col_args, col_kwargs = sanitize_args(v.Attributes.sqla_column_args)
753+
_sp_attrs_to_sqla_constraints(cls, v, col_kwargs)
755754

756-
_sp_attrs_to_sqla_constraints(cls, child_cust, col=col)
755+
p = getattr(v.Attributes, 'store_as', None)
756+
if p is not None and issubclass(v, Array) and isinstance(p, c_table):
757+
child_cust, = v._type_info.values()
758+
if child_cust.__orig__ is not None:
759+
child = child_cust.__orig__
760+
else:
761+
child = child_cust
757762

758-
child_t.append_column(col)
759-
child.__mapper__.add_property(col.name, col)
763+
if p.multi != False: # many to many
764+
_gen_array_m2m(cls, props, k, child, p)
760765

761-
props[k] = relationship(child, foreign_keys=[col],
762-
backref=p.backref, cascade=p.cascade, lazy=p.lazy)
766+
elif issubclass(child, SimpleModel): # one to many simple type
767+
_gen_array_simple(cls, props, k, child_cust, p)
768+
769+
else: # one to many complex type
770+
_gen_array_o2m(cls, props, k, child, child_cust, p)
763771

764772
elif p is not None and issubclass(v, ComplexModelBase):
765773
# v has the Attribute values we need whereas real_v is what the

0 commit comments

Comments
 (0)