Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly return nillable for relations in md.xsd #3951

Merged
merged 1 commit into from
Aug 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions c2cgeoportal/lib/dbreflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,18 @@ class an engine, required for the reflection.
class _AssociationProxy(object):
# A specific "association proxy" implementation

def __init__(self, target, value_attr):
def __init__(self, target, value_attr, nullable=True):
self.target = target
self.value_attr = value_attr
self.nullable = nullable

def __get__(self, obj, type_=None):
if obj is None:
# For "hybrid" descriptors that work both at the instance
# and class levels we could return an SQL expression here.
# The code of hybrid_property in SQLAlchemy illustrates
# how to do that.
raise AttributeError # pragma: no cover
return self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks strange to me ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get it from sqlalchemy.ext.AssociationProxy class.

target = getattr(obj, self.target)
return getattr(target, self.value_attr) if target else None

Expand Down Expand Up @@ -109,8 +110,9 @@ def xsd_sequence_callback(tb, cls):
target_cls = relationship_property.argument
query = DBSession.query(getattr(target_cls, p.value_attr))
attrs = {}
attrs["minOccurs"] = str(0)
attrs["nillable"] = "true"
if p.nullable:
attrs["minOccurs"] = str(0)
attrs["nillable"] = "true"
attrs["name"] = k
with tag(tb, "xsd:element", attrs) as tb:
with tag(tb, "xsd:simpleType") as tb:
Expand Down Expand Up @@ -247,7 +249,12 @@ def _add_association_proxy(cls, col):
lazy="immediate")
setattr(cls, rel, relationship_)

setattr(cls, proxy, _AssociationProxy(rel, "name"))
nullable = True
cls_column_property = getattr(cls, col.name).property
for column in cls_column_property.columns:
nullable = nullable and column.nullable

setattr(cls, proxy, _AssociationProxy(rel, "name", nullable=nullable))

if cls.__add_properties__ is None:
cls.__add_properties__ = [proxy]
Expand Down
14 changes: 10 additions & 4 deletions c2cgeoportal/tests/functional/test_dbreflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ def _create_table(self, tablename):
),
Column(
"child2_id", types.Integer,
ForeignKey("public.{0!s}_child.id".format(tablename))
ForeignKey("public.{0!s}_child.id".format(tablename)),
nullable=False
),
Column("point", Geometry("POINT")),
Column("linestring", Geometry("LINESTRING")),
Expand All @@ -122,7 +123,7 @@ def test_get_class_nonexisting_table(self):
def test_get_class(self):
from geoalchemy2 import Geometry
import c2cgeoportal.lib.dbreflection
from c2cgeoportal.lib.dbreflection import get_class
from c2cgeoportal.lib.dbreflection import get_class, _AssociationProxy

self._create_table("table_a")
modelclass = get_class("table_a")
Expand All @@ -139,6 +140,11 @@ def test_get_class(self):
self.assertTrue(isinstance(modelclass.multilinestring.type, Geometry))
self.assertTrue(isinstance(modelclass.multipolygon.type, Geometry))

self.assertTrue(isinstance(modelclass.child1, _AssociationProxy))
self.assertTrue(modelclass.child1.nullable)
self.assertTrue(isinstance(modelclass.child2, _AssociationProxy))
self.assertFalse(modelclass.child2.nullable)

# test the Table object
table = modelclass.__table__
self.assertTrue("id" in table.c)
Expand Down Expand Up @@ -257,7 +263,7 @@ class Parent(Base):
child1_ = relationship(Child, primaryjoin=(child1_id == Child.id))
child1 = _AssociationProxy("child1_", "name")
child2_ = relationship(Child, primaryjoin=(child2_id == Child.id))
child2 = _AssociationProxy("child2_", "name")
child2 = _AssociationProxy("child2_", "name", nullable=False)

Child.__table__.create()
Parent.__table__.create()
Expand Down Expand Up @@ -295,7 +301,7 @@ def test_xsd_sequence_callback(self):
'</xsd:restriction>'
'</xsd:simpleType>'
'</xsd:element>'
'<xsd:element minOccurs="0" name="child2" nillable="true">'
'<xsd:element name="child2">'
'<xsd:simpleType>'
'<xsd:restriction base="xsd:string">'
'<xsd:enumeration value="foo" />'
Expand Down