@@ -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