Skip to content

Commit

Permalink
Converted GIS lookups to use the new Lookup API
Browse files Browse the repository at this point in the history
Thanks Tim Graham, Anssi Kääriäinen and Marc Tamlyn for the
reviews.
  • Loading branch information
claudep committed Oct 9, 2014
1 parent 4ef9618 commit 2bd1bbc
Show file tree
Hide file tree
Showing 11 changed files with 411 additions and 488 deletions.
17 changes: 4 additions & 13 deletions django/contrib/gis/db/backends/base.py
Expand Up @@ -42,19 +42,19 @@ class BaseSpatialFeatures(object):

@property
def supports_bbcontains_lookup(self):
return 'bbcontains' in self.connection.ops.gis_terms
return 'bbcontains' in self.connection.ops.gis_operators

@property
def supports_contained_lookup(self):
return 'contained' in self.connection.ops.gis_terms
return 'contained' in self.connection.ops.gis_operators

@property
def supports_dwithin_lookup(self):
return 'dwithin' in self.connection.ops.distance_functions
return 'dwithin' in self.connection.ops.gis_operators

@property
def supports_relate_lookup(self):
return 'relate' in self.connection.ops.gis_terms
return 'relate' in self.connection.ops.gis_operators

# For each of those methods, the class will have a property named
# `has_<name>_method` (defined in __init__) which accesses connection.ops
Expand Down Expand Up @@ -97,12 +97,6 @@ class BaseSpatialOperations(object):
instantiated by each spatial database backend with the features
it has.
"""
distance_functions = {}
geometry_functions = {}
geometry_operators = {}
geography_operators = {}
geography_functions = {}
gis_terms = set()
truncate_params = {}

# Quick booleans for the type of this spatial backend, and
Expand Down Expand Up @@ -215,9 +209,6 @@ def get_expression_column(self, evaluator):
def spatial_aggregate_sql(self, agg):
raise NotImplementedError('Aggregate support not implemented for this spatial backend.')

def spatial_lookup_sql(self, lvalue, lookup_type, value, field):
raise NotImplementedError('subclasses of BaseSpatialOperations must a provide spatial_lookup_sql() method')

# Routines for getting the OGC-compliant models.
def geometry_columns(self):
raise NotImplementedError('subclasses of BaseSpatialOperations must a provide geometry_columns() method')
Expand Down
47 changes: 15 additions & 32 deletions django/contrib/gis/db/backends/mysql/operations.py
Expand Up @@ -2,6 +2,7 @@

from django.contrib.gis.db.backends.adapter import WKTAdapter
from django.contrib.gis.db.backends.base import BaseSpatialOperations
from django.contrib.gis.db.backends.utils import SpatialOperator


class MySQLOperations(DatabaseOperations, BaseSpatialOperations):
Expand All @@ -16,27 +17,25 @@ class MySQLOperations(DatabaseOperations, BaseSpatialOperations):
Adapter = WKTAdapter
Adaptor = Adapter # Backwards-compatibility alias.

geometry_functions = {
'bbcontains': 'MBRContains', # For consistency w/PostGIS API
'bboverlaps': 'MBROverlaps', # .. ..
'contained': 'MBRWithin', # .. ..
'contains': 'MBRContains',
'disjoint': 'MBRDisjoint',
'equals': 'MBREqual',
'exact': 'MBREqual',
'intersects': 'MBRIntersects',
'overlaps': 'MBROverlaps',
'same_as': 'MBREqual',
'touches': 'MBRTouches',
'within': 'MBRWithin',
gis_operators = {
'bbcontains': SpatialOperator(func='MBRContains'), # For consistency w/PostGIS API
'bboverlaps': SpatialOperator(func='MBROverlaps'), # .. ..
'contained': SpatialOperator(func='MBRWithin'), # .. ..
'contains': SpatialOperator(func='MBRContains'),
'disjoint': SpatialOperator(func='MBRDisjoint'),
'equals': SpatialOperator(func='MBREqual'),
'exact': SpatialOperator(func='MBREqual'),
'intersects': SpatialOperator(func='MBRIntersects'),
'overlaps': SpatialOperator(func='MBROverlaps'),
'same_as': SpatialOperator(func='MBREqual'),
'touches': SpatialOperator(func='MBRTouches'),
'within': SpatialOperator(func='MBRWithin'),
}

gis_terms = set(geometry_functions) | {'isnull'}

def geo_db_type(self, f):
return f.geom_type

def get_geom_placeholder(self, value, srid):
def get_geom_placeholder(self, f, value):
"""
The placeholder here has to include MySQL's WKT constructor. Because
MySQL does not support spatial transformations, there is no need to
Expand All @@ -47,19 +46,3 @@ def get_geom_placeholder(self, value, srid):
else:
placeholder = '%s(%%s)' % self.from_text
return placeholder

def spatial_lookup_sql(self, lvalue, lookup_type, value, field, qn):
geo_col, db_type = lvalue

lookup_info = self.geometry_functions.get(lookup_type, False)
if lookup_info:
sql = "%s(%s, %s)" % (lookup_info, geo_col,
self.get_geom_placeholder(value, field.srid))
return sql, []

# TODO: Is this really necessary? MySQL can't handle NULL geometries
# in its spatial indexes anyways.
if lookup_type == 'isnull':
return "%s IS %sNULL" % (geo_col, ('' if value else 'NOT ')), []

raise TypeError("Got invalid lookup_type: %s" % repr(lookup_type))
6 changes: 6 additions & 0 deletions django/contrib/gis/db/backends/oracle/operations.py
Expand Up @@ -244,6 +244,12 @@ def transform_value(val, srid):
else:
return 'SDO_GEOMETRY(%%s, %s)' % f.srid

def check_relate_argument(self, arg):
masks = 'TOUCH|OVERLAPBDYDISJOINT|OVERLAPBDYINTERSECT|EQUAL|INSIDE|COVEREDBY|CONTAINS|COVERS|ANYINTERACT|ON'
mask_regex = re.compile(r'^(%s)(\+(%s))*$' % (masks, masks), re.I)
if not self.mask_regex.match(arg):
raise ValueError('Invalid SDO_RELATE mask: "%s"' % (self.relate_func, arg))

def spatial_lookup_sql(self, lvalue, lookup_type, value, field, qn):
"Returns the SQL WHERE clause for use in Oracle spatial SQL construction."
geo_col, db_type = lvalue
Expand Down

0 comments on commit 2bd1bbc

Please sign in to comment.