Fixed #27556 -- Added Oracle support for IsValid function and isvalid lookup.
This commit is contained in:
parent
e17f40f4b5
commit
4464b9b9ad
|
@ -52,6 +52,10 @@ class SDORelate(SpatialOperator):
|
|||
return super(SDORelate, self).as_sql(connection, lookup, template_params, sql_params)
|
||||
|
||||
|
||||
class SDOIsValid(SpatialOperator):
|
||||
sql_template = "%%(func)s(%%(lhs)s, %s) = 'TRUE'" % DEFAULT_TOLERANCE
|
||||
|
||||
|
||||
class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
||||
|
||||
name = 'oracle'
|
||||
|
@ -85,6 +89,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
|||
'Difference': 'SDO_GEOM.SDO_DIFFERENCE',
|
||||
'Distance': 'SDO_GEOM.SDO_DISTANCE',
|
||||
'Intersection': 'SDO_GEOM.SDO_INTERSECTION',
|
||||
'IsValid': 'SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT',
|
||||
'Length': 'SDO_GEOM.SDO_LENGTH',
|
||||
'NumGeometries': 'SDO_UTIL.GETNUMELEM',
|
||||
'NumPoints': 'SDO_UTIL.GETNUMVERTICES',
|
||||
|
@ -109,6 +114,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
|||
'covers': SDOOperator(func='SDO_COVERS'),
|
||||
'disjoint': SDODisjoint(),
|
||||
'intersects': SDOOperator(func='SDO_OVERLAPBDYINTERSECT'), # TODO: Is this really the same as ST_Intersects()?
|
||||
'isvalid': SDOIsValid(func='SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT'),
|
||||
'equals': SDOOperator(func='SDO_EQUAL'),
|
||||
'exact': SDOOperator(func='SDO_EQUAL'),
|
||||
'overlaps': SDOOperator(func='SDO_OVERLAPS'),
|
||||
|
@ -128,7 +134,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
|||
unsupported_functions = {
|
||||
'AsGeoJSON', 'AsGML', 'AsKML', 'AsSVG',
|
||||
'BoundingCircle', 'Envelope',
|
||||
'ForceRHR', 'GeoHash', 'IsValid', 'MakeValid', 'MemSize', 'Scale',
|
||||
'ForceRHR', 'GeoHash', 'MakeValid', 'MemSize', 'Scale',
|
||||
'SnapToGrid', 'Translate',
|
||||
}
|
||||
|
||||
|
|
|
@ -285,9 +285,13 @@ class Intersection(OracleToleranceMixin, GeoFuncWithGeoParam):
|
|||
arity = 2
|
||||
|
||||
|
||||
class IsValid(GeoFunc):
|
||||
class IsValid(OracleToleranceMixin, GeoFunc):
|
||||
output_field_class = BooleanField
|
||||
|
||||
def as_oracle(self, compiler, connection, **extra_context):
|
||||
sql, params = super(IsValid, self).as_oracle(compiler, connection, **extra_context)
|
||||
return "CASE %s WHEN 'TRUE' THEN 1 ELSE 0 END" % sql, params
|
||||
|
||||
|
||||
class Length(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
|
||||
output_field_class = FloatField
|
||||
|
|
|
@ -5,7 +5,7 @@ import re
|
|||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
from django.db.models.expressions import Col, Expression
|
||||
from django.db.models.lookups import BuiltinLookup, Lookup, Transform
|
||||
from django.db.models.lookups import Lookup, Transform
|
||||
from django.db.models.sql.query import Query
|
||||
from django.utils import six
|
||||
|
||||
|
@ -352,15 +352,16 @@ class IntersectsLookup(GISLookup):
|
|||
gis_lookups['intersects'] = IntersectsLookup
|
||||
|
||||
|
||||
class IsValidLookup(BuiltinLookup):
|
||||
class IsValidLookup(GISLookup):
|
||||
lookup_name = 'isvalid'
|
||||
sql_template = '%(func)s(%(lhs)s)'
|
||||
|
||||
def as_sql(self, compiler, connection):
|
||||
if self.lhs.field.geom_type == 'RASTER':
|
||||
raise ValueError('The isvalid lookup is only available on geometry fields.')
|
||||
gis_op = connection.ops.gis_operators[self.lookup_name]
|
||||
sql, params = self.process_lhs(compiler, connection)
|
||||
sql = '%(func)s(%(lhs)s)' % {'func': gis_op.func, 'lhs': sql}
|
||||
sql, params = gis_op.as_sql(connection, self, {'func': gis_op.func, 'lhs': sql}, params)
|
||||
if not self.rhs:
|
||||
sql = 'NOT ' + sql
|
||||
return sql, params
|
||||
|
|
|
@ -347,7 +347,7 @@ Lookup Type PostGIS Oracle MySQL [#]_ SpatiaLite
|
|||
:lookup:`equals` X X X X C
|
||||
:lookup:`exact` X X X X B
|
||||
:lookup:`intersects` X X X X B
|
||||
:lookup:`isvalid` X X (LWGEOM)
|
||||
:lookup:`isvalid` X X X (LWGEOM)
|
||||
:lookup:`overlaps` X X X X B
|
||||
:lookup:`relate` X X X C
|
||||
:lookup:`same_as` X X X X B
|
||||
|
@ -390,7 +390,7 @@ Function PostGIS Oracle MySQL SpatiaLite
|
|||
:class:`ForceRHR` X
|
||||
:class:`GeoHash` X X (LWGEOM)
|
||||
:class:`Intersection` X X X (≥ 5.6.1) X
|
||||
:class:`IsValid` X X (LWGEOM)
|
||||
:class:`IsValid` X X X (LWGEOM)
|
||||
:class:`Length` X X X X
|
||||
:class:`MakeValid` X X (LWGEOM)
|
||||
:class:`MemSize` X
|
||||
|
|
|
@ -298,14 +298,14 @@ intersection between them.
|
|||
|
||||
.. versionadded:: 1.10
|
||||
|
||||
*Availability*: PostGIS, SpatiaLite (LWGEOM)
|
||||
*Availability*: PostGIS, Oracle, SpatiaLite (LWGEOM)
|
||||
|
||||
Accepts a geographic field or expression and tests if the value is well formed.
|
||||
Returns ``True`` if its value is a valid geometry and ``False`` otherwise.
|
||||
|
||||
.. versionchanged:: 1.11
|
||||
|
||||
SpatiaLite support was added.
|
||||
SpatiaLite and Oracle support was added.
|
||||
|
||||
``Length``
|
||||
==========
|
||||
|
|
|
@ -159,6 +159,10 @@ Minor features
|
|||
:class:`~django.contrib.gis.db.models.functions.MakeValid` function, and
|
||||
:lookup:`isvalid` lookup.
|
||||
|
||||
* Added Oracle support for the
|
||||
:class:`~django.contrib.gis.db.models.functions.IsValid` function and
|
||||
:lookup:`isvalid` lookup.
|
||||
|
||||
:mod:`django.contrib.messages`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -295,8 +295,14 @@ class GeoLookupTest(TestCase):
|
|||
def test_isvalid_lookup(self):
|
||||
invalid_geom = fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))')
|
||||
State.objects.create(name='invalid', poly=invalid_geom)
|
||||
self.assertEqual(State.objects.filter(poly__isvalid=False).count(), 1)
|
||||
self.assertEqual(State.objects.filter(poly__isvalid=True).count(), State.objects.count() - 1)
|
||||
qs = State.objects.all()
|
||||
if oracle:
|
||||
# Kansas has adjacent vertices with distance 6.99244813842e-12
|
||||
# which is smaller than the default Oracle tolerance.
|
||||
qs = qs.exclude(name='Kansas')
|
||||
self.assertEqual(State.objects.filter(name='Kansas', poly__isvalid=False).count(), 1)
|
||||
self.assertEqual(qs.filter(poly__isvalid=False).count(), 1)
|
||||
self.assertEqual(qs.filter(poly__isvalid=True).count(), qs.count() - 1)
|
||||
|
||||
@skipUnlessDBFeature("supports_left_right_lookups")
|
||||
def test_left_right_lookups(self):
|
||||
|
|
Loading…
Reference in New Issue