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

Merge remote-tracking branch 'origin/2.2' into 2.3 #4060

Merged
merged 3 commits into from
Aug 29, 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 geoportal/c2cgeoportal_geoportal/lib/dbreflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,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
target = getattr(obj, self.target)
return getattr(target, self.value_attr) if target else None

Expand Down Expand Up @@ -103,8 +104,9 @@ def xsd_sequence_callback(tb, cls):
target_cls = relationship_property.argument
query = DBSession.query(getattr(target_cls, p.value_attr))
attrs = {}
attrs["minOccurs"] = "0"
attrs["nillable"] = "true"
if p.nullable:
attrs["minOccurs"] = "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 @@ -234,7 +236,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 geoportal/tests/functional/test_dbreflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,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 @@ -115,7 +116,7 @@ def test_get_class_nonexisting_table(self):
def test_get_class(self):
from geoalchemy2 import Geometry
import c2cgeoportal_geoportal.lib.dbreflection
from c2cgeoportal_geoportal.lib.dbreflection import get_class
from c2cgeoportal_geoportal.lib.dbreflection import get_class, _AssociationProxy

self._create_table("table_a")
modelclass = get_class("table_a")
Expand All @@ -132,6 +133,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 @@ -252,7 +258,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 @@ -280,7 +286,7 @@ def test_xsd_sequence_callback(self):
xsd_sequence_callback(tb, self.cls)
e = tb.close()
self.assertIsNotNone(re.search(
'<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