Moving the spatial query. You can enable it loading the spatial_query plugin in the ini file.

This commit is contained in:
Adrià Mercader 2011-04-11 18:04:28 +01:00
parent 76183b6f23
commit 1710205cf9
6 changed files with 264 additions and 1 deletions

View File

@ -0,0 +1,6 @@
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)

View File

@ -0,0 +1,63 @@
import sys
import re
from pprint import pprint
from ckan.lib.cli import CkanCommand
from ckanext.spatial.lib import save_extent
class Extents(CkanCommand):
'''Creates or updates pacakge extents.
Creates or updates the extent geometry column for packages with
a bounding box defined in extras
Usage:
extents update
The commands should be run from the ckanext-spatial directory and expect
a development.ini file to be present. Most of the time you will
specify the config explicitly though::
paster extents update --config=../ckan/development.ini
'''
summary = __doc__.split('\n')[0]
usage = __doc__
max_args = 1
min_args = 0
def command(self):
self._load_config()
print ''
if len(self.args) == 0:
self.parser.print_usage()
sys.exit(1)
cmd = self.args[0]
if cmd == 'update':
self.update_extents()
else:
print 'Command %s not recognized' % cmd
def update_extents(self):
from ckan.model import PackageExtra, Package, Session
conn = Session.connection()
packages = [extra.package \
for extra in \
Session.query(PackageExtra).filter(PackageExtra.key == 'bbox-east-long').all()]
error = False
for package in packages:
try:
save_extent(package)
except:
errors = True
if error:
msg = "There was an error saving the package extent. Have you set up the package_extent table in the DB?"
else:
msg = "Done. Extents generated for %i packages" % len(packages)
print msg

View File

@ -0,0 +1,63 @@
from ckan.lib.helpers import json
import ckan.lib.helpers as h
from ckan.lib.base import c, g, request, \
response, session, render, config, abort, redirect
from ckan.controllers.rest import BaseApiController
from ckan.model import Session
from ckanext.spatial.lib import get_srid
class ApiController(BaseApiController):
db_srid = int(config.get('ckan.spatial.srid', '4258'))
def spatial_query(self):
if not 'bbox' in request.params:
abort(400)
bbox = request.params['bbox'].split(',')
if len(bbox) is not 4:
abort(400)
minx = float(bbox[0])
miny = float(bbox[1])
maxx = float(bbox[2])
maxy = float(bbox[3])
params = {'minx':minx,'miny':miny,'maxx':maxx,'maxy':maxy,'db_srid':self.db_srid}
srid = get_srid(request.params.get('crs')) if 'crs' in request.params else None
if srid and srid != self.db_srid:
# The input bounding box is defined in another projection, we need
# to transform it
statement = """SELECT package_id FROM package_extent WHERE
ST_Intersects(
ST_Transform(
ST_GeomFromText('POLYGON ((%(minx)s %(miny)s,
%(maxx)s %(miny)s,
%(maxx)s %(maxy)s,
%(minx)s %(maxy)s,
%(minx)s %(miny)s))',%(srid)s),
%(db_srid)s)
,the_geom)"""
params.update({'srid': srid})
else:
statement = """SELECT package_id FROM package_extent WHERE
ST_Intersects(
ST_GeomFromText('POLYGON ((%(minx)s %(miny)s,
%(maxx)s %(miny)s,
%(maxx)s %(maxy)s,
%(minx)s %(maxy)s,
%(minx)s %(miny)s))',%(db_srid)s),
the_geom)"""
conn = Session.connection()
rows = conn.execute(statement,params)
ids = [row['package_id'] for row in rows]
output = dict(count=len(ids),results=ids)
return self._finish_ok(output)

View File

@ -0,0 +1,114 @@
from ckan.model import Session, repo
from ckan.model import Package
from ckan.lib.base import config
log = __import__("logging").getLogger(__name__)
def get_srid(crs):
"""Returns the SRID for the provided CRS definition
The CRS can be defined in the following formats
- urn:ogc:def:crs:EPSG::4258
- EPSG:4258
- 4258
"""
if ':' in crs:
crs = crs.split(':')
srid = crs[len(crs)-1]
else:
srid = crs
return int(srid)
def save_extent(package,extent=False):
'''Updates the package extent in the package_extent geometry column
If no extent provided (as a dict with minx,miny,maxx,maxy and srid keys),
the values stored in the package extras are used'''
db_srid = int(config.get('ckan.spatial.srid', '4258'))
conn = Session.connection()
srid = None
if extent:
minx = extent['minx']
miny = extent['miny']
maxx = extent['maxx']
maxy = extent['maxy']
if 'srid' in extent:
srid = extent['srid']
else:
minx = float(package.extras.get('bbox-east-long'))
miny = float(package.extras.get('bbox-south-lat'))
maxx = float(package.extras.get('bbox-west-long'))
maxy = float(package.extras.get('bbox-north-lat'))
crs = package.extras.get('spatial-reference-system')
if crs:
srid = get_srid(crs)
try:
# Check if extent already exists
rows = conn.execute('SELECT package_id FROM package_extent WHERE package_id = %s',package.id).fetchall()
update =(len(rows) > 0)
params = {'id':package.id, 'minx':minx,'miny':miny,'maxx':maxx,'maxy':maxy, 'db_srid': db_srid}
if update:
# Update
if srid and srid != db_srid:
# We need to reproject the input geometry
statement = """UPDATE package_extent SET
the_geom = ST_Transform(
ST_GeomFromText('POLYGON ((%(minx)s %(miny)s,
%(maxx)s %(miny)s,
%(maxx)s %(maxy)s,
%(minx)s %(maxy)s,
%(minx)s %(miny)s))',%(srid)s),
%(db_srid)s)
WHERE package_id = %(id)s
"""
params.update({'srid': srid})
else:
statement = """UPDATE package_extent SET
the_geom = ST_GeomFromText('POLYGON ((%(minx)s %(miny)s,
%(maxx)s %(miny)s,
%(maxx)s %(maxy)s,
%(minx)s %(maxy)s,
%(minx)s %(miny)s))',%(db_srid)s)
WHERE package_id = %(id)s
"""
msg = 'Updated extent for package %s'
else:
# Insert
if srid and srid != db_srid:
# We need to reproject the input geometry
statement = """INSERT INTO package_extent (package_id,the_geom) VALUES (
%(id)s,
ST_Transform(
ST_GeomFromText('POLYGON ((%(minx)s %(miny)s,
%(maxx)s %(miny)s,
%(maxx)s %(maxy)s,
%(minx)s %(maxy)s,
%(minx)s %(miny)s))',%(srid)s),
%(db_srid))
)"""
params.update({'srid': srid})
else:
statement = """INSERT INTO package_extent (package_id,the_geom) VALUES (
%(id)s,
ST_GeomFromText('POLYGON ((%(minx)s %(miny)s,
%(maxx)s %(miny)s,
%(maxx)s %(maxy)s,
%(minx)s %(maxy)s,
%(minx)s %(miny)s))',%(db_srid)s))"""
msg = 'Created new extent for package %s'
conn.execute(statement,params)
Session.commit()
log.info(msg, package.id)
return package
except:
log.error('An error occurred when saving the extent for package %s',package.id)
raise Exception

View File

@ -14,6 +14,20 @@ import html
log = getLogger(__name__)
class SpatialQuery(SingletonPlugin):
implements(IRoutes, inherit=True)
def before_map(self, map):
map.connect('api_spatial_query', '/api/2/search/package/geo',
controller='ckanext.spatial.controllers.api:ApiController',
action='spatial_query')
return map
class WMSPreview(SingletonPlugin):
implements(IGenshiStreamFilter)

View File

@ -24,8 +24,11 @@ setup(
],
entry_points=\
"""
[ckan.plugins]
[ckan.plugins]
# Add plugins here, eg
wms_preview=ckanext.spatial.plugin:WMSPreview
spatial_query=ckanext.spatial.plugin:SpatialQuery
[paste.paster_command]
extents=ckanext.spatial.commands.extents:Extents
""",
)