Browse Source

Fixed #30994 -- Added Oracle support for AsGeoJSON GIS function.

Sergey Fedoseev 5 years ago
parent
commit
f95b59a1b3

+ 2 - 1
django/contrib/gis/db/backends/oracle/operations.py

@@ -64,6 +64,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
 
     function_names = {
         'Area': 'SDO_GEOM.SDO_AREA',
+        'AsGeoJSON': 'SDO_UTIL.TO_GEOJSON',
         'BoundingCircle': 'SDO_GEOM.SDO_MBC',
         'Centroid': 'SDO_GEOM.SDO_CENTROID',
         'Difference': 'SDO_GEOM.SDO_DIFFERENCE',
@@ -106,7 +107,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
     }
 
     unsupported_functions = {
-        'AsGeoJSON', 'AsKML', 'AsSVG', 'Azimuth', 'ForcePolygonCW', 'GeoHash',
+        'AsKML', 'AsSVG', 'Azimuth', 'ForcePolygonCW', 'GeoHash',
         'GeometryDistance', 'LineLocatePoint', 'MakeValid', 'MemSize',
         'Scale', 'SnapToGrid', 'Translate',
     }

+ 6 - 0
django/contrib/gis/db/models/functions.py

@@ -162,6 +162,12 @@ class AsGeoJSON(GeoFunc):
             expressions.append(options)
         super().__init__(*expressions, **extra)
 
+    def as_oracle(self, compiler, connection, **extra_context):
+        source_expressions = self.get_source_expressions()
+        clone = self.copy()
+        clone.set_source_expressions(source_expressions[:1])
+        return super(AsGeoJSON, clone).as_sql(compiler, connection, **extra_context)
+
 
 class AsGML(GeoFunc):
     geom_param_pos = (1,)

+ 1 - 1
docs/ref/contrib/gis/db-api.txt

@@ -360,7 +360,7 @@ functions are available on each spatial backend.
 Function                              PostGIS  Oracle         MariaDB      MySQL       SpatiaLite
 ====================================  =======  ============== ============ =========== ==========
 :class:`Area`                         X        X              X            X           X
-:class:`AsGeoJSON`                    X                       X (≥ 10.2.4) X (≥ 5.7.5) X
+:class:`AsGeoJSON`                    X        X              X (≥ 10.2.4) X (≥ 5.7.5) X
 :class:`AsGML`                        X        X                                       X
 :class:`AsKML`                        X                                                X
 :class:`AsSVG`                        X                                                X

+ 10 - 4
docs/ref/contrib/gis/functions.txt

@@ -54,7 +54,7 @@ geographic SRSes.
 
 *Availability*: MariaDB (≥ 10.2.4), `MySQL
 <https://dev.mysql.com/doc/refman/en/spatial-geojson-functions.html#function_st-asgeojson>`__ (≥ 5.7.5),
-`PostGIS <https://postgis.net/docs/ST_AsGeoJSON.html>`__, SpatiaLite
+Oracle, `PostGIS <https://postgis.net/docs/ST_AsGeoJSON.html>`__, SpatiaLite
 
 Accepts a single geographic field or expression and returns a `GeoJSON
 <http://geojson.org/>`_ representation of the geometry. Note that the result is
@@ -70,17 +70,23 @@ Example::
 Keyword Argument       Description
 =====================  =====================================================
 ``bbox``               Set this to ``True`` if you want the bounding box
-                       to be included in the returned GeoJSON.
+                       to be included in the returned GeoJSON. Ignored on
+                       Oracle.
 
 ``crs``                Set this to ``True`` if you want the coordinate
                        reference system to be included in the returned
-                       GeoJSON. Ignored on MySQL.
+                       GeoJSON. Ignored on MySQL and Oracle.
 
 ``precision``          It may be used to specify the number of significant
                        digits for the coordinates in the GeoJSON
-                       representation -- the default value is 8.
+                       representation -- the default value is 8. Ignored on
+                       Oracle.
 =====================  =====================================================
 
+.. versionchanged:: 3.1
+
+    Oracle support was added.
+
 ``AsGML``
 =========
 

+ 3 - 0
docs/releases/3.1.txt

@@ -63,6 +63,9 @@ Minor features
 
 * Added the :attr:`.LinearRing.is_counterclockwise` property.
 
+* :class:`~django.contrib.gis.db.models.functions.AsGeoJSON` is now supported
+  on Oracle.
+
 :mod:`django.contrib.messages`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

+ 12 - 9
tests/gis_tests/geoapp/test_functions.py

@@ -32,24 +32,27 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
             return
 
         pueblo_json = '{"type":"Point","coordinates":[-104.609252,38.255001]}'
-        houston_json = (
+        houston_json = json.loads(
             '{"type":"Point","crs":{"type":"name","properties":'
             '{"name":"EPSG:4326"}},"coordinates":[-95.363151,29.763374]}'
         )
-        victoria_json = (
+        victoria_json = json.loads(
             '{"type":"Point","bbox":[-123.30519600,48.46261100,-123.30519600,48.46261100],'
             '"coordinates":[-123.305196,48.462611]}'
         )
-        chicago_json = (
+        chicago_json = json.loads(
             '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},'
             '"bbox":[-87.65018,41.85039,-87.65018,41.85039],"coordinates":[-87.65018,41.85039]}'
         )
-        # MySQL ignores the crs option.
-        if mysql:
-            houston_json = json.loads(houston_json)
+        # MySQL and Oracle ignore the crs option.
+        if mysql or oracle:
             del houston_json['crs']
-            chicago_json = json.loads(chicago_json)
             del chicago_json['crs']
+        # Oracle ignores also the bbox and precision options.
+        if oracle:
+            del chicago_json['bbox']
+            del victoria_json['bbox']
+            chicago_json['coordinates'] = [-87.650175, 41.850385]
 
         # Precision argument should only be an integer
         with self.assertRaises(TypeError):
@@ -75,10 +78,10 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
         # WHERE "geoapp_city"."name" = 'Houston';
         # This time we include the bounding box by using the `bbox` keyword.
         self.assertJSONEqual(
-            victoria_json,
             City.objects.annotate(
                 geojson=functions.AsGeoJSON('point', bbox=True)
-            ).get(name='Victoria').geojson
+            ).get(name='Victoria').geojson,
+            victoria_json,
         )
 
         # SELECT ST_AsGeoJson("geoapp_city"."point", 5, 3) FROM "geoapp_city"