- Timestamp:
- 06/16/10 21:46:02 (2 years ago)
- Location:
- framework/server/trunk
- Files:
-
- 11 modified
- 42 copied
-
. (modified) (1 prop)
-
.gitignore (copied) (copied from sandbox/tsauerwein/server/.gitignore)
-
docs (copied) (copied from sandbox/tsauerwein/server/docs)
-
docs/.gitignore (copied) (copied from sandbox/tsauerwein/server/docs/.gitignore)
-
docs/Makefile (copied) (copied from sandbox/tsauerwein/server/docs/Makefile)
-
docs/_build (copied) (copied from sandbox/tsauerwein/server/docs/_build)
-
docs/_static (copied) (copied from sandbox/tsauerwein/server/docs/_static)
-
docs/_static/geojson.png (copied) (copied from sandbox/tsauerwein/server/docs/_static/geojson.png)
-
docs/_static/mapfish.css (copied) (copied from sandbox/tsauerwein/server/docs/_static/mapfish.css)
-
docs/_static/mapfishapp_layout.js (copied) (copied from sandbox/tsauerwein/server/docs/_static/mapfishapp_layout.js)
-
docs/_static/osm.png (copied) (copied from sandbox/tsauerwein/server/docs/_static/osm.png)
-
docs/_static/pylons.png (copied) (copied from sandbox/tsauerwein/server/docs/_static/pylons.png)
-
docs/_static/query.png (copied) (copied from sandbox/tsauerwein/server/docs/_static/query.png)
-
docs/_templates (copied) (copied from sandbox/tsauerwein/server/docs/_templates)
-
docs/conf.py (copied) (copied from sandbox/tsauerwein/server/docs/conf.py)
-
docs/framework (copied) (copied from sandbox/tsauerwein/server/docs/framework)
-
docs/framework/_static (copied) (copied from sandbox/tsauerwein/server/docs/framework/_static)
-
docs/framework/_static/countries.zip (copied) (copied from sandbox/tsauerwein/server/docs/framework/_static/countries.zip)
-
docs/framework/customizing-webservices.txt (copied) (copied from sandbox/tsauerwein/server/docs/framework/customizing-webservices.txt)
-
docs/framework/index.txt (copied) (copied from sandbox/tsauerwein/server/docs/framework/index.txt)
-
docs/framework/javascript-toolbox.txt (copied) (copied from sandbox/tsauerwein/server/docs/framework/javascript-toolbox.txt)
-
docs/framework/mapfish-application.txt (copied) (copied from sandbox/tsauerwein/server/docs/framework/mapfish-application.txt)
-
docs/framework/spatial-databases.txt (copied) (copied from sandbox/tsauerwein/server/docs/framework/spatial-databases.txt)
-
docs/framework/webservice.txt (copied) (copied from sandbox/tsauerwein/server/docs/framework/webservice.txt)
-
docs/index.txt (copied) (copied from sandbox/tsauerwein/server/docs/index.txt)
-
docs/installation.txt (copied) (copied from sandbox/tsauerwein/server/docs/installation.txt)
-
docs/make.bat (copied) (copied from sandbox/tsauerwein/server/docs/make.bat)
-
docs/protocol.txt (copied) (copied from sandbox/tsauerwein/server/docs/protocol.txt)
-
docs/quickstart.txt (copied) (copied from sandbox/tsauerwein/server/docs/quickstart.txt)
-
docs/reference (copied) (copied from sandbox/tsauerwein/server/docs/reference)
-
docs/reference/filters.comparison.txt (copied) (copied from sandbox/tsauerwein/server/docs/reference/filters.comparison.txt)
-
docs/reference/filters.featureid.txt (copied) (copied from sandbox/tsauerwein/server/docs/reference/filters.featureid.txt)
-
docs/reference/filters.logical.txt (copied) (copied from sandbox/tsauerwein/server/docs/reference/filters.logical.txt)
-
docs/reference/filters.spatial.txt (copied) (copied from sandbox/tsauerwein/server/docs/reference/filters.spatial.txt)
-
docs/reference/filters.txt (copied) (copied from sandbox/tsauerwein/server/docs/reference/filters.txt)
-
docs/reference/index.txt (copied) (copied from sandbox/tsauerwein/server/docs/reference/index.txt)
-
docs/reference/protocol.txt (copied) (copied from sandbox/tsauerwein/server/docs/reference/protocol.txt)
-
docs/reference/sqlalchemygeom.txt (copied) (copied from sandbox/tsauerwein/server/docs/reference/sqlalchemygeom.txt)
-
mapfish/commands.py (modified) (2 diffs)
-
mapfish/lib/filters/spatial.py (modified) (7 diffs)
-
mapfish/lib/protocol.py (modified) (11 diffs)
-
mapfish/plugins/pgrouting.py (modified) (1 diff)
-
mapfish/sqlalchemygeom.py (modified) (10 diffs)
-
mapfish/templates/model.py_tmpl (modified) (1 diff)
-
mapfish/templates/project/+package+/model/meta.py_tmpl (copied) (copied from sandbox/tsauerwein/server/mapfish/templates/project/+package+/model/meta.py_tmpl)
-
mapfish/templates/project/layers.ini_tmpl (modified) (2 diffs)
-
mapfish/tests/test_filter.py (modified) (1 diff)
-
mapfish/tests/test_mysql.py (copied) (copied from sandbox/tsauerwein/server/mapfish/tests/test_mysql.py)
-
mapfish/tests/test_oracle.py (copied) (copied from sandbox/tsauerwein/server/mapfish/tests/test_oracle.py)
-
mapfish/tests/test_postgis.py (copied) (copied from sandbox/tsauerwein/server/mapfish/tests/test_postgis.py)
-
mapfish/tests/test_protocol.py (modified) (4 diffs)
-
mapfish/tests/test_spatialite.py (copied) (copied from sandbox/tsauerwein/server/mapfish/tests/test_spatialite.py)
-
setup.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
framework/server/trunk
- Property svn:mergeinfo set to /sandbox/tsauerwein/server:3435-3568
-
framework/server/trunk/mapfish/commands.py
r3387 r3569 245 245 schema = None 246 246 247 # get geometry type 248 if not config.has_option(sectionName, 'geomtype'): 249 geomtype = 'Geometry' 250 else: 251 raw_geomtype = config.get(sectionName, 'geomtype') 252 # check if the value is valid (geometries supported by GeoAlchemy) 253 valid_types = ['Geometry', 'Point', 'Curve', 'LineString', 'Polygon', 254 'MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection'] 255 256 if raw_geomtype in valid_types: 257 geomtype = raw_geomtype 258 else: 259 raise BadCommand('Geometry type "%s" is unknown, valid values are: %s' 260 % (raw_geomtype, valid_types)) 261 247 262 fileOp = FileOp(source_dir=os.path.join( 248 263 os.path.dirname(__file__), 'templates')) … … 268 283 # set template vars 269 284 modelClass = util.class_name_from_module_name(singularName) 270 modelTabObj = name + '_table'271 285 272 286 # setup the model 273 287 fileOp.template_vars.update( 274 288 {'modelClass': modelClass, 275 'modelTabObj': modelTabObj,276 289 'table': table, 277 290 'epsg': epsg, 278 291 'geomColName': geomColName, 292 'geomType': geomtype, 279 293 'basePkg': basePkg, 280 294 'schema': schema}) -
framework/server/trunk/mapfish/lib/filters/spatial.py
r3083 r3569 20 20 from mapfish.lib.filters import Filter 21 21 22 from sqlalchemy.sql import func, and_23 24 22 from geojson import loads, GeoJSON 25 26 23 27 24 from shapely.geometry import asShape 28 25 from shapely.geometry.point import Point 29 26 from shapely.geometry.polygon import Polygon 27 28 from geoalchemy import WKBSpatialElement 29 from geoalchemy.functions import functions 30 31 from mapfish.sqlalchemygeom import within_distance 30 32 31 33 class Spatial(Filter): … … 38 40 geom_column 39 41 the Column object corresponding to the geometry 40 column .42 column (contains the database column type). 41 43 42 44 \**kwargs … … 44 46 the EPSG code of the lon, lat or box values, see 45 47 below. 48 49 additional_params 50 additional parameters used for the database function 51 call (currently only used for Oracle) 46 52 47 for Spatial.BOX filter: 53 54 For Spatial.BOX filter: 48 55 49 56 box … … 56 63 the projection system of the lon/lat coordinates. 57 64 58 for Spatial.WITHIN filter: 65 66 For Spatial.WITHIN filter: 59 67 60 68 lon … … 73 81 the projection system of the lon/lat coordinates. 74 82 75 for Spatial.GEOMETRY filter: 83 84 For Spatial.GEOMETRY filter: 76 85 77 86 geometry … … 98 107 else: 99 108 self.epsg = self.geom_column.type.srid 109 self.additional_params = self.values.get('additional_params', None) 100 110 101 111 def to_sql_expr(self): … … 110 120 geometry = loads(self.values['geometry'], object_hook=factory) 111 121 geometry = asShape(geometry) 112 122 113 123 if self.epsg != self.geom_column.type.srid: 114 geom_column = func .transform(self.geom_column, self.epsg)124 geom_column = functions.transform(self.geom_column, self.epsg) 115 125 else: 116 126 geom_column = self.geom_column 117 127 118 128 tolerance = self.values['tolerance'] 119 pg_geometry = func.geomfromtext(geometry.wkt, self.epsg) 120 return and_(func.expand(pg_geometry, tolerance).op('&&')(geom_column), 121 func.distance(geom_column, pg_geometry) <= tolerance) 129 wkb_geometry = WKBSpatialElement(buffer(geometry.wkb), self.epsg) 130 131 if self.additional_params is None: 132 return within_distance(geom_column, wkb_geometry, tolerance) 133 else: 134 return within_distance(geom_column, wkb_geometry, tolerance, self.additional_params) 122 135 123 136 def __box_to_geometry(self): -
framework/server/trunk/mapfish/lib/protocol.py
r3462 r3569 27 27 from shapely.geometry import asShape 28 28 29 from sqlalchemy.sql import select, asc, desc 29 from sqlalchemy.sql import asc, desc 30 31 from geoalchemy import WKBSpatialElement 30 32 31 33 from geojson import dumps as _dumps, loads, Feature, FeatureCollection, GeoJSON … … 64 66 return _dumps(obj, cls=cls, **kwargs) 65 67 66 def create_geom_filter(request, mapped_class ):68 def create_geom_filter(request, mapped_class, **kwargs): 67 69 """Create MapFish geometry filter based on the request params. Either 68 a box or within or geometry filter, depending on the request params.""" 70 a box or within or geometry filter, depending on the request params. 71 Additional named arguments are passed to the spatial filter.""" 69 72 70 73 geom_column = mapped_class.geometry_column() … … 94 97 box=box.split(','), 95 98 tolerance=tolerance, 96 epsg=epsg 99 epsg=epsg, 100 **kwargs 97 101 ) 98 102 elif 'lon' and 'lat' in request.params: … … 104 108 lat=float(request.params['lat']), 105 109 tolerance=tolerance, 106 epsg=epsg 110 epsg=epsg, 111 **kwargs 107 112 ) 108 113 elif 'geometry' in request.params: … … 113 118 geometry=request.params['geometry'], 114 119 tolerance=tolerance, 115 epsg=epsg 120 epsg=epsg, 121 **kwargs 116 122 ) 117 123 return filter … … 149 155 return filter 150 156 151 def create_default_filter(request, mapped_class): 152 """ Create MapFish default filter based on the request params.""" 153 154 geom_filter = create_geom_filter(request, mapped_class) 157 def create_default_filter(request, mapped_class, **kwargs): 158 """ Create MapFish default filter based on the request params. Additional 159 named arguments are passed to the spatial filter.""" 160 161 geom_filter = create_geom_filter(request, mapped_class, **kwargs) 155 162 attr_filter = create_attr_filter(request, mapped_class) 156 163 … … 227 234 return dumps( 228 235 FeatureCollection( 229 [self._filter_attrs(o.toFeature(), request) for o in objects if o.geometry ]236 [self._filter_attrs(o.toFeature(), request) for o in objects if o.geometry is not None] 230 237 ) 231 238 ) … … 296 303 297 304 order_by = self._get_order_by(request) 298 if order_by :305 if order_by is not None: 299 306 query = query.order_by(order_by) 300 307 … … 361 368 obj = self.mapped_class() 362 369 create = True 363 obj.geometry = asShape(feature.geometry) 364 for key in feature.properties: 365 obj[key] = feature.properties[key] 370 self.__copy_attributes(feature, obj) 366 371 if create: 367 372 self.Session.add(obj) … … 389 394 if self.before_update is not None: 390 395 self.before_update(request, feature, obj) 391 obj.geometry = asShape(feature.geometry) 392 for key in feature.properties: 393 obj[key] = feature.properties[key] 396 self.__copy_attributes(feature, obj) 394 397 self.Session.commit() 395 398 response.status = 201 … … 409 412 response.status = 204 410 413 return 411 414 415 def __copy_attributes(self, json_feature, obj): 416 """Updates the passed-in object with the values 417 from the GeoJSON feature.""" 418 # create a Shapely geometry from GeoJSON and persist the geometry using WKB 419 shape = asShape(json_feature.geometry) 420 srid = self.mapped_class.geometry_column().type.srid 421 obj.geometry = WKBSpatialElement(buffer(shape.wkb), srid=srid) 422 # also store the Shapely geometry so that we can use it to return the geometry as GeoJSON 423 obj.geometry.shape = shape 424 for key in json_feature.properties: 425 obj[key] = json_feature.properties[key] -
framework/server/trunk/mapfish/plugins/pgrouting.py
r3083 r3569 22 22 def shortest_path(engine, sql, source_id, target_id, 23 23 directed = False, has_reverse_cost = False): 24 # return array of: step, vertex_id, edge_id, cost 25 24 """Calculates the shortest path using the Dijkstra algorithm of the library pgrouting. 25 Returns an array of: vertex_id, edge_id, cost 26 27 see: http://pgrouting.postlbs.org/wiki/Dijkstra 28 """ 26 29 return engine.execute("SELECT * FROM \ 27 30 shortest_path('%(sql)s', %(source_id)s, %(target_id)s, \ 28 %(directed)s, %(has_reverse_cost)s) ORDER BY step"29 %{'sql': sql.replace("'", r" \'"),31 %(directed)s, %(has_reverse_cost)s)" 32 %{'sql': sql.replace("'", r"''"), 30 33 'source_id': source_id, 31 34 'target_id': target_id, -
framework/server/trunk/mapfish/sqlalchemygeom.py
r3453 r3569 18 18 # 19 19 20 __all__ = ['Geometry ', 'GeometryTableMixIn']20 __all__ = ['GeometryTableMixIn'] 21 21 22 22 … … 28 28 ------- 29 29 from sqlalchemy import * 30 from sqlalchemygeom import Geometry 30 from mapfish.sqlalchemygeom import GeometryTableMixIn 31 from geoalchemy import GeometryColumn, Geometry 31 32 32 33 # see: http://www.sqlalchemy.org/docs/dbengine.html … … 36 37 metadata.connect(db) 37 38 38 wifi_t = Table('wifi', metadata, 39 Column('gid', Integer, primary_key=True), 40 # add more columns here ... 41 Column('the_geom', Geometry(4326)) 42 ) 39 Base = declarative_base(metadata=metadata) 40 41 class Wifi(Base, GeometryTableMixIn): 42 __tablename__ = 'wifi' 43 gid = Column(types.Integer, primary_key=True) 44 # add more columns here ... 45 the_geom = GeometryColumn(Geometry(dimension=2, srid=4326)) 46 43 47 44 48 # basic select 45 r = wifi_t.select(wifi_t.c.gid == 10).execute()49 r = Wifi.__table__.select(Wifi.gid == 10).execute() 46 50 w = r.fetchone() 47 51 print w.the_geom … … 49 53 # advanced select 50 54 from shapely.geometry.point import Point 51 from binascii import b2a_hex 55 from geoalchemy import functions, WKBSpatialElement 56 52 57 me = Point(532778, 152205) 53 58 54 r = wifi_t.select(metadata.engine.func.distance(wifi_t.c.the_geom, b2a_hex(me.wkb)) < 100).execute()59 r = Wifi.__table__.select(functions.distance(Wifi.the_geom, WKBSpatialElement(buffer(me.wkb))) < 100).execute() 55 60 print [(i.gid, i.the_geom.distance(me)) for i in r] 56 61 57 62 ## update 58 #u = wifi_t.update(wifi_t.c.gid== 10)63 #u = Wifi.__table__.update(Wifi.the_geom == 10) 59 64 #w.the_geom.y += 9.0 60 65 #u.execute(the_geom = w.the_geom) 61 66 """ 62 67 63 from sqlalchemy.types import TypeEngine64 from sqlalchemy import Table65 68 from shapely.wkb import loads 66 67 69 from geojson import Feature 68 70 69 class Geometry(TypeEngine): 70 71 """The SQLAlchemy Geometry type. 72 73 Use a Geometry instance when defining a geometry column in an 74 ``sqlalchemy.schema.Table`` object of the model. 75 76 Example:: 77 78 wifi_table = Table('wifi', metadata, 79 Column('gid', Integer, primary_key=True), 80 Column('the_geom', Geometry(4326)) 81 ) 82 83 srid 84 The SRID of the geometry column, defaults to -1 (no SRID). 85 86 dims 87 The number of dimensions of the geometry column, defaults 88 to 2. 89 90 """ 91 92 def __init__(self, srid=-1, dims=2): 93 super(Geometry, self).__init__() 94 self.srid = srid 95 self.dims = dims 96 97 def get_col_spec(self): 98 return 'GEOMETRY()' 99 100 def compare_values(self, x, y): 101 t = (x, y) 102 if None not in t: 103 return x.equals(y) 104 return t == (None, None) 105 106 def bind_processor(self, dialect): 107 # convert value from a geometry object to database 108 def convert(value): 109 if value is None: 110 return None 111 else: 112 return "SRID=%s;%s" % (self.srid, value.wkb.encode('hex')) 113 return convert 114 115 def result_processor(self, dialect): 116 # convert value from database to a geometry object 117 def convert(value): 118 if value is None: 119 return None 120 else: 121 return loads(value.decode('hex')) 122 return convert 71 from geoalchemy import Geometry as GeometryBase 72 from geoalchemy.functions import BaseFunction, parse_clause 73 from geoalchemy.geometry import GeometryExtensionColumn 74 from geoalchemy.spatialite import SQLiteSpatialDialect 75 76 from sqlalchemy.ext.compiler import compiles 77 from sqlalchemy.sql import and_, text, table, column 78 from sqlalchemy import select, func 79 from sqlalchemy.schema import Column 80 81 from sqlalchemy.dialects.postgresql.base import PGDialect 82 from sqlalchemy.dialects.sqlite.base import SQLiteDialect 83 from sqlalchemy.dialects.mysql.base import MySQLDialect 84 from sqlalchemy.dialects.oracle.base import OracleDialect 123 85 124 86 class GeometryTableMixIn(object): … … 150 112 151 113 Example:: 152 153 lines_table = Table( 154 "lines", metadata, 155 Column('the_geom', Geometry(4326)), 156 autoload=True, autoload_with=engine) 157 158 class Line(GeometryTableMixIn): 159 # for GeometryTableMixIn to do its job the __table__ property 160 # must be set here 161 __table__ = lines_table 162 163 mapper(Line, lines_table) 114 115 Base = declarative_base(metadata=metadata) 116 117 class Line(Base, GeometryTableMixIn): 118 __tablename__ = 'lines' 119 __table_args__ = { 120 'autoload' : True, 121 'autoload_with' : engine 122 } 123 124 the_geom = GeometryColumn(Geometry(dimension=2, srid=4326)) 164 125 165 126 """ 166 127 167 128 exported_keys = None 168 __geometry_column__ = None 169 __primary_key_column__ = None 129 __column_cache__ = None 170 130 171 131 def _getfid(self): … … 191 151 192 152 def __setitem__(self, key, val): 193 if key in self.__table__.c.keys():194 setattr(self, key, val)153 if key in self.__table__.c.keys(): 154 setattr(self, key, val) 195 155 196 156 def __contains__(self, key): … … 200 160 def geometry_column(cls): 201 161 """ Returns the table's geometry column or None if the table has no geometry column. """ 202 if not cls.__geometry_column__:203 columns = [c for c in cls.__table__.columns if isinstance(c.type, Geometry )]162 if cls.__column_cache__ is None or "geometry" not in cls.__column_cache__: 163 columns = [c for c in cls.__table__.columns if isinstance(c.type, GeometryBase)] 204 164 if not columns: 205 165 return None … … 207 167 raise Exception("There is more than one geometry column") 208 168 else: 209 cls.__geometry_column__ = columns.pop() 210 return cls.__geometry_column__ 169 column = columns.pop() 170 cls.__column_cache__ = dict(geometry=column) 171 return cls.__column_cache__["geometry"] 211 172 212 173 @classmethod 213 174 def primary_key_column(cls): 214 175 """ Returns the table's primary key column """ 215 if not cls.__primary_key_column__:176 if cls.__column_cache__ is None or "primary_key" not in cls.__column_cache__: 216 177 keys = [k for k in cls.__table__.primary_key] 217 178 if not keys: … … 220 181 raise Exception("There is more than one primary key column") 221 182 else: 222 cls.__ primary_key_column__ = keys.pop()223 return cls.__ primary_key_column__224 183 cls.__column_cache__ = dict(primary_key=keys.pop()) 184 return cls.__column_cache__["primary_key"] 185 225 186 def toFeature(self): 226 187 """Create and return a ``geojson.Feature`` object from this mapped object.""" … … 238 199 if k != fid_column and k != geom_column and hasattr(self, k): 239 200 attributes[k] = getattr(self, k) 201 202 if hasattr(self.geometry, 'shape') and self.geometry.shape is not None: 203 # we already have the geometry as Shapely geometry (when updating/inserting) 204 geometry = self.geometry.shape 205 else: 206 # create a Shapely geometry from the WKB geometry returned from the database 207 geometry = loads(str(self.geometry.geom_wkb)) 240 208 241 209 return Feature(id=self.fid, 242 geometry= self.geometry,210 geometry=geometry, 243 211 properties=attributes, 244 bbox=self.geometry.bounds) 212 bbox=geometry.bounds) 213 214 215 class within_distance(BaseFunction): 216 """This class is used as SQLAlchemy function to query features that are 217 within a certain distance of a geometry. 218 When it is used inside a query, the SQLAlchemy compiler calls the 219 method __compile_within_distance. 220 """ 221 pass 222 223 @compiles(within_distance) 224 def __compile_within_distance(element, compiler, **kw): 225 if isinstance(compiler.dialect, PGDialect): 226 function = __within_distance_pg 227 elif isinstance(compiler.dialect, MySQLDialect): 228 function = __within_distance_mysql 229 elif isinstance(compiler.dialect, SQLiteDialect): 230 function = __within_distance_spatialite 231 elif isinstance(compiler.dialect, OracleDialect): 232 function = __within_distance_oracle 233 else: 234 raise NotImplementedError("Operation 'within_distance' is not supported by '%s'" % (compiler.dialect)) 235 236 arguments = list(element.arguments) 237 return compiler.process(function(compiler, parse_clause(arguments.pop(0), compiler), 238 parse_clause(arguments.pop(0), compiler), arguments.pop(0), *arguments)) 239 240 def __within_distance_pg(compiler, geom1, geom2, distance): 241 """Implementation of within_distance for PostGIS 242 243 ST_DWithin in early versions of PostGIS 1.3 does not work when 244 distance = 0. So we are directly using the (correct) internal definition. 245 Note that the definition changed in version 1.3.4, see also: 246 http://postgis.refractions.net/docs/ST_DWithin.html 247 """ 248 return and_(func.ST_Expand(geom2, distance).op('&&')(geom1), 249 func.ST_Expand(geom1, distance).op('&&')(geom2), 250 func.ST_Distance(geom1, geom2) <= distance) 251 252 def __within_distance_mysql(compiler, geom1, geom2, distance): 253 """Implementation of within_distance for MySQL 254 255 MySQL does not support the function distance, so we are doing 256 a kind of "mbr_within_distance". 257 The MBR of 'geom2' is expanded with the amount of 'distance' by 258 manually changing the coordinates. Then we test if 'geom1' intersects 259 this expanded MBR. 260 """ 261 mbr = func.ExteriorRing(func.Envelope(geom2)) 262 263 lower_left = func.StartPoint(mbr) 264 upper_right = func.PointN(mbr, 3) 265 266 xmin = func.X(lower_left) 267 ymin = func.Y(lower_left) 268 xmax = func.X(upper_right) 269 ymax = func.Y(upper_right) 270 271 return func.Intersects( 272 geom1, 273 func.GeomFromText( 274 func.Concat('Polygon((', 275 xmin - distance, ' ', ymin - distance, ',', 276 xmax + distance, ' ', ymin - distance, ',', 277 xmax + distance, ' ', ymax + distance, ',', 278 xmin - distance, ' ', ymax + distance, ',', 279 xmin - distance, ' ', ymin - distance, '))'), func.srid(geom2) 280 ) 281 ) 282 283 def __within_distance_spatialite(compiler, geom1, geom2, distance): 284 """Implementation of within_distance for Spatialite 285 """ 286 if isinstance(geom1, GeometryExtensionColumn) and geom1.type.spatial_index and SQLiteSpatialDialect.supports_rtree(compiler.dialect): 287 """If querying on a geometry column that also has a spatial index, 288 then make use of this index. 289 290 see: http://www.gaia-gis.it/spatialite/spatialite-tutorial-2.3.1.html#t8 and 291 http://groups.google.com/group/spatialite-users/browse_thread/thread/34609c7a711ac92d/7688ced3f909039c?lnk=gst&q=index#f6dbc235471574db 292 """ 293 return and_( 294 func.Distance(geom1, geom2) <= distance, 295 table(geom1.table.fullname, column("rowid")).c.rowid.in_( 296 select([table("idx_%s_%s" % (geom1.table.fullname, geom1.key), column("pkid")).c.pkid]).where( 297 and_(text('xmin') >= func.MbrMinX(geom2) - distance, 298 and_(text('xmax') <= func.MbrMaxX(geom2) + distance, 299 and_(text('ymin') >= func.MbrMinY(geom2) - distance, 300 text('ymax') <= func.MbrMaxY(geom2) + distance))) 301 ) 302 ) 303 ) 304 305 else: 306 return func.Distance(geom1, geom2) <= distance 307 308 309 310 def __within_distance_oracle(compiler, geom1, geom2, distance, additional_params={}): 311 """Implementation of within_distance for Oracle 312 313 If the first parameter is a geometry column, then the Oracle operator SDO_WITHIN_DISTANCE 314 is called and Oracle makes use of the spatial index of this column. 315 316 If the first parameter is not a geometry column but a function, which is the case when a coordinate 317 transformation had to be added by the spatial filter, then the function SDO_GEOM.WITHIN_DISTANCE 318 is called. SDO_GEOM.WITHIN_DISTANCE does not make use of a spatial index and requires 319 additional parameters: either a tolerance value or a dimension information array (DIMINFO) 320 for both geometries. These parameters can be specified when defining the spatial filter, e.g.:: 321 322 additional_params={'tol': '0.005'} 323 324 or 325 326 from sqlalchemy.sql.expression import text 327 diminfo = text("MDSYS.SDO_DIM_ARRAY("\ 328 "MDSYS.SDO_DIM_ELEMENT('LONGITUDE', -180, 180, 0.000000005),"\ 329 "MDSYS.SDO_DIM_ELEMENT('LATITUDE', -90, 90, 0.000000005)"\ 330 ")") 331 additional_params={'dim1': diminfo, 'dim2': diminfo} 332 333 filter = create_default_filter(request, Spot, additional_params=additional_params) 334 proto.count(request, filter=filter) 335 336 For its distance calculation Oracle by default uses meter as unit for geodetic data (like EPSG:4326) 337 and otherwise the 'unit of measurement associated with the data'. The unit used for the 'distance' value 338 can be changed by adding an entry to 'additional_params'. Valid units are defined in the 339 view 'sdo_dist_units':: 340 341 additional_params={'params': 'unit=km'} 342 343 SDO_WITHIN_DISTANCE accepts further parameters, which can also be set using the name 'params' 344 together with the unit:: 345 346 additional_params={'params': 'unit=km max_resolution=10'} 347 348 349 Valid options for 'additional_params' are: 350 351 params 352 A String containing additional parameters, for example the unit. 353 354 tol 355 The tolerance value used for the SDO_GEOM.WITHIN_DISTANCE function call. 356 357 dim1 and dim2 358 If the parameter 'tol' is not set, these two parameters have to be set. 'dim1' is the DIMINFO 359 for the first geometry (the reprojected geometry column) and 'dim2' is the DIMINFO for 360 the second geometry (the input geometry from the request). Values for 'dim1' and 'dim2' 361 have to be SQLAlchemy expressions, either literal text (text(..)) or a select query. 362 363 Note that 'tol' or 'dim1'/'dim2' only have to be set when the input geometry from the request 364 uses a different CRS than the geometry column! 365 366 367 SDO_WITHIN_DISTANCE: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e11830/sdo_operat.htm#i77653 368 SDO_GEOM.WITHIN_DISTANCE: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e11830/sdo_objgeom.htm#i856373 369 DIMINFO: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e11830/sdo_objrelschema.htm#i1010905 370 TOLERANCE: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e11830/sdo_intro.htm#i884589 371 372 """ 373 params = additional_params.get('params', '') 374 375 if isinstance(geom1, Column): 376 return (func.SDO_WITHIN_DISTANCE(geom1, geom2, 377 'distance=%s %s' % (distance, params)) == 'TRUE') 378 else: 379 dim1 = additional_params.get('dim1', None) 380 dim2 = additional_params.get('dim2', None) 381 382 if dim1 is not None and dim2 is not None: 383 return (func.SDO_GEOM.WITHIN_DISTANCE(geom1, dim1, 384 distance, 385 geom2, dim2, 386 params) == 'TRUE') 387 else: 388 tol = additional_params.get('tol', None) 389 390 if tol is not None: 391 return (func.SDO_GEOM.WITHIN_DISTANCE(geom1, 392 distance, 393 geom2, 394 tol, 395 params) == 'TRUE') 396 else: 397 raise Exception('No dimension information ("dim1" and "dim2") or '\ 398 'tolerance value ("tol") specified for calling '\ 399 'SDO_GEOM.WITHIN_DISTANCE on Oracle, which is '\ 400 'required when reprojecting.') -
framework/server/trunk/mapfish/templates/model.py_tmpl
r1589 r3569 1 from sqlalchemy import Column, Table, types 2 from sqlalchemy.orm import mapper 1 from sqlalchemy import Column, types 3 2 4 from mapfish.sqlalchemygeom import Geometry 3 from geoalchemy import GeometryColumn, {{geomType}} 4 5 5 from mapfish.sqlalchemygeom import GeometryTableMixIn 6 from {{basePkg}}.model.meta import engine, Base 6 7 7 from {{basePkg}}.model.meta import metadata, engine 8 9 {{modelTabObj}} = Table( 10 '{{table}}', metadata, 11 Column('{{geomColName}}', Geometry({{epsg}})), 8 class {{modelClass}}(Base, GeometryTableMixIn): 9 __tablename__ = '{{table}}' 10 __table_args__ = { 12 11 {{if schema is not None}} 13 schema='{{schema}}',12 "schema": '{{schema}}', 14 13 {{endif}} 15 autoload=True, autoload_with=engine) 16 17 class {{modelClass}}(GeometryTableMixIn): 18 # for GeometryTableMixIn to do its job the __table__ property 19 # must be set here 20 __table__ = {{modelTabObj}} 21 22 mapper({{modelClass}}, {{modelTabObj}}) 14 "autoload": True, 15 "autoload_with": engine 16 } 17 {{geomColName}} = GeometryColumn({{geomType}}(dimension=2, srid={{epsg}})) -
framework/server/trunk/mapfish/templates/project/layers.ini_tmpl
r1589 r3569 8 8 # table*: the name of the table in the database 9 9 # epsg*: the geometry column's EPSG code 10 # geomcolumn*: the name of the table's geometry colum 10 # geomcolumn*: the name of the table's geometry column 11 # geomtype: the geometry type of the geometry column (default: Geometry) 11 12 # schema: the name of the schema hosting the table 12 13 … … 19 20 #epsg=4326 20 21 #geomcolumn=the_geom 22 #geomtype=Point 21 23 #schema=my_schema -
framework/server/trunk/mapfish/tests/test_filter.py
r2729 r3569 2 2 filters are correct. These tests are SQLAlchemy integration tests. """ 3 3 4 import unittest 4 5 from nose import with_setup 5 6 from sqlalchemy import MetaData, Table, Column 6 from nose.tools import eq_, ok_ 7 8 from sqlalchemy import MetaData, Table, Column, create_engine 7 9 from sqlalchemy.types import Integer, Unicode 8 10 from sqlalchemy.orm import mapper 9 11 from sqlalchemy.sql import func, and_ 10 11 from shapely import wkt 12 from sqlalchemy.ext.declarative import declarative_base 13 14 from shapely import wkt, wkb 12 15 from shapely.geometry.polygon import Polygon 13 16 14 17 from geojson import dumps 15 18 16 from mapfish.sqlalchemygeom import Geometry, GeometryTableMixIn 19 from geoalchemy import GeometryColumn, Geometry 20 21 from mapfish.sqlalchemygeom import GeometryTableMixIn 17 22 from mapfish.lib.filters import spatial, comparison, featureid, logical 18 23 19 24 # 20 25 # Setup 21 #22 23 table = Table("table", MetaData(),24 Column("id", Integer, primary_key=True),25 Column("text", Unicode),26 Column("geom", Geometry(4326))27 )28 29 class MappedClass(GeometryTableMixIn):30 __table__ = table31 32 mapper(MappedClass, table)33 34 26 # 35 # Test Spatial 36 # 37 38 def test_spatial_box(): 39 # with epsg undefined 40 filter = spatial.Spatial( 41 spatial.Spatial.BOX, 42 MappedClass.geometry_column(), 43 box=[-180, -90, 180, 90], 44 tolerance=1 45 ) 46 filter = filter.to_sql_expr() 47 params = filter.compile().params 48 assert str(filter) == '(expand(geomfromtext(:geomfromtext_1, :geomfromtext_2), :expand_1) && "table".geom) AND distance("table".geom, geomfromtext(:geomfromtext_1, :geomfromtext_2)) <= :distance_1' 49 assert wkt.loads(params["geomfromtext_1"]).equals(wkt.loads('POLYGON ((-180 -90, -180 90, 180 90, 180 -90, -180 -90))')) 50 assert params["geomfromtext_2"] == 4326 51 assert params["expand_1"] == 1 52 assert params["distance_1"] == 1 53 54 # with epsg defined 55 filter = spatial.Spatial( 56 spatial.Spatial.BOX, 57 MappedClass.geometry_column(), 58 box=[-180, -90, 180, 90], 59 tolerance=1, 60 epsg=900913 61 ) 62 filter = filter.to_sql_expr() 63 params = filter.compile().params 64 assert str(filter) == '(expand(geomfromtext(:geomfromtext_1, :geomfromtext_2), :expand_1) && transform("table".geom, :transform_1)) AND distance(transform("table".geom, :transform_1), geomfromtext(:geomfromtext_1, :geomfromtext_2)) <= :distance_1' 65 assert wkt.loads(params["geomfromtext_1"]).equals(wkt.loads('POLYGON ((-180 -90, -180 90, 180 90, 180 -90, -180 -90))')) 66 assert params["geomfromtext_2"] == 900913 67 assert params["expand_1"] == 1 68 assert params["transform_1"] == 900913 69 assert params["distance_1"] == 1 70 71 def test_spatial_within(): 72 # with epsg undefined 73 filter = spatial.Spatial( 74 spatial.Spatial.WITHIN, 75 MappedClass.geometry_column(), 76 lon=40, lat=5, tolerance=1 77 ) 78 filter = filter.to_sql_expr() 79 params = filter.compile().params 80 assert str(filter) == '(expand(geomfromtext(:geomfromtext_1, :geomfromtext_2), :expand_1) && "table".geom) AND distance("table".geom, geomfromtext(:geomfromtext_1, :geomfromtext_2)) <= :distance_1' 81 assert wkt.loads(params["geomfromtext_1"]).equals(wkt.loads('POINT (40 5)')) 82 assert params["geomfromtext_2"] == 4326 83 assert params["expand_1"] == 1 84 assert params["distance_1"] == 1 85 86 # with epsg defined 87 filter = spatial.Spatial( 88 spatial.Spatial.WITHIN, 89 MappedClass.geometry_column(), 90 lon=40, lat=5, tolerance=1, epsg=900913 91 ) 92 filter = filter.to_sql_expr() 93 params = filter.compile().params 94 assert str(filter) == '(expand(geomfromtext(:geomfromtext_1, :geomfromtext_2), :expand_1) && transform("table".geom, :transform_1)) AND distance(transform("table".geom, :transform_1), geomfromtext(:geomfromtext_1, :geomfromtext_2)) <= :distance_1' 95 assert wkt.loads(params["geomfromtext_1"]).equals(wkt.loads('POINT (40 5)')) 96 assert params["geomfromtext_2"] == 900913 97 assert params["expand_1"] == 1 98 assert params["transform_1"] == 900913 99 assert params["distance_1"] == 1 100 101 def test_spatial_geometry(): 102 poly = Polygon(((1, 2), (1, 3), (2, 3), (2, 2), (1, 2))) 103 104 # with epsg undefined 105 filter = spatial.Spatial( 106 spatial.Spatial.GEOMETRY, 107 MappedClass.geometry_column(), 108 geometry=dumps(poly), 109 tolerance=1 110 ) 111 filter = filter.to_sql_expr() 112 params = filter.compile().params 113 assert str(filter) == '(expand(geomfromtext(:geomfromtext_1, :geomfromtext_2), :expand_1) && "table".geom) AND distance("table".geom, geomfromtext(:geomfromtext_1, :geomfromtext_2)) <= :distance_1' 114 assert wkt.loads(params["geomfromtext_1"]).equals(poly) 115 assert params["geomfromtext_2"] == 4326 116 assert params["expand_1"] == 1 117 assert params["distance_1"] == 1 118 119 # with epsg defined 120 filter = spatial.Spatial( 121 spatial.Spatial.GEOMETRY, 122 MappedClass.geometry_column(), 123 geometry=dumps(poly), 124 tolerance=1, 125 epsg=900913 126 ) 127 filter = filter.to_sql_expr() 128 params = filter.compile().params 129 assert str(filter) == '(expand(geomfromtext(:geomfromtext_1, :geomfromtext_2), :expand_1) && transform("table".geom, :transform_1)) AND distance(transform("table".geom, :transform_1), geomfromtext(:geomfromtext_1, :geomfromtext_2)) <= :distance_1' 130 assert wkt.loads(params["geomfromtext_1"]).equals(poly) 131 assert params["geomfromtext_2"] == 900913 132 assert params["expand_1"] == 1 133 assert params["transform_1"] == 900913 134 assert params["distance_1"] == 1 135 136 # 137 # Test Comparison 138 # 139 140 def test_comparison_equalto(): 141 filter = comparison.Comparison( 142 comparison.Comparison.EQUAL_TO, 143 MappedClass.id, 144 value=1 145 ) 146 filter = filter.to_sql_expr() 147 params = filter.compile().params 148 assert str(filter) == '"table".id = :id_1' 149 assert params["id_1"] == 1 150 151 def test_comparison_notequalto(): 152 filter = comparison.Comparison( 153 comparison.Comparison.NOT_EQUAL_TO, 154 MappedClass.id, 155 value=1 156 ) 157 filter = filter.to_sql_expr() 158 params = filter.compile().params 159 assert str(filter) == '"table".id != :id_1' 160 assert params["id_1"] == 1 161 162 def test_comparison_lowerthan(): 163 filter = comparison.Comparison( 164 comparison.Comparison.LOWER_THAN, 165 MappedClass.id, 166 value=1 167 ) 168 filter = filter.to_sql_expr() 169 params = filter.compile().params 170 assert str(filter) == '"table".id < :id_1' 171 assert params["id_1"] == 1 172 173 def test_comparison_lowerthanorequalto(): 174 filter = comparison.Comparison( 175 comparison.Comparison.LOWER_THAN_OR_EQUAL_TO, 176 MappedClass.id, 177 value=1 178 ) 179 filter = filter.to_sql_expr() 180 params = filter.compile().params 181 assert str(filter) == '"table".id <= :id_1' 182 assert params["id_1"] == 1 183 184 def test_comparison_greaterthan(): 185 filter = comparison.Comparison( 186 comparison.Comparison.GREATER_THAN, 187 MappedClass.id, 188 value=1 189 ) 190 filter = filter.to_sql_expr() 191 params = filter.compile().params 192 assert str(filter) == '"table".id > :id_1' 193 assert params["id_1"] == 1 194 195 def test_comparison_greaterthanorequalto(): 196 filter = comparison.Comparison( 197 comparison.Comparison.GREATER_THAN_OR_EQUAL_TO, 198 MappedClass.id, 199 value=1 200 ) 201 filter = filter.to_sql_expr() 202 params = filter.compile().params 203 assert str(filter) == '"table".id >= :id_1' 204 assert params["id_1"] == 1 205 206 def test_comparison_between(): 207 filter = comparison.Comparison( 208 comparison.Comparison.BETWEEN, 209 MappedClass.id, 210 lower_bound=1, upper_bound=2 211 ) 212 filter = filter.to_sql_expr() 213 params = filter.compile().params 214 assert str(filter) == '"table".id <= :id_1 AND "table".id >= :id_2' 215 assert params["id_1"] == 2 216 assert params["id_2"] == 1 217 218 def test_comparison_like(): 219 filter = comparison.Comparison( 220 comparison.Comparison.LIKE, 221 MappedClass.text, 222 value="foo" 223 ) 224 filter = filter.to_sql_expr() 225 params = filter.compile().params 226 assert str(filter) == '"table".text LIKE :text_1' 227 assert params["text_1"] == "foo" 228 229 def test_comparison_ilike(): 230 filter = comparison.Comparison( 231 comparison.Comparison.ILIKE, 232 MappedClass.text, 233 value="foo" 234 ) 235 filter = filter.to_sql_expr() 236 params = filter.compile().params 237 assert str(filter) == 'lower("table".text) LIKE lower(:text_1)' 238 assert params["text_1"] == "foo" 239 240 # 241 # Test FeatureId 242 # 243 244 def test_featureid(): 245 filter = featureid.FeatureId( 246 MappedClass.id, 247 1 248 ) 249 filter = filter.to_sql_expr() 250 params = filter.compile().params 251 assert str(filter) == '"table".id = :id_1' 252 assert params["id_1"] == 1 253 254 # 255 # Test Logical 256 # 27 28 # create a dummy engine, no connection is established, we only need the database dialect 29 engine = create_engine('postgresql://user:user@no_connection/no_db', echo=True) 30 Base = declarative_base(metadata=MetaData()) 31 32 class MappedClass(Base, GeometryTableMixIn): 33 __tablename__ = "table" 34 id = Column(Integer, primary_key=True) 35 text = Column(Unicode) 36 geom = GeometryColumn(Geometry(dimension=2, srid=4326)) 37 38 39 def _compiled_to_string(compiled_filter): 40 """Helper method which converts a compiled SQL expression 41 into a string. 42 """ 43 return unicode(compiled_filter).encode('ascii', 'backslashreplace') 44 45 46 class Test(unittest.TestCase): 47 48 # 49 # Test Spatial 50 # 51 52 def test_spatial_box(self): 53 # with epsg undefined 54 filter = spatial.Spatial( 55 spatial.Spatial.BOX, 56 MappedClass.geometry_column(), 57 box=[-180, -90, 180, 90], 58 tolerance=1 59 ) 60 compiled_filter = filter.to_sql_expr().compile(engine) 61 params = compiled_filter.params 62 filter_str = _compiled_to_string(compiled_filter) 63 eq_(filter_str, '(ST_Expand(GeomFromWKB(%(GeomFromWKB_1)s, %(GeomFromWKB_2)s), %(ST_Expand_1)s) && "table".geom) AND (ST_Expand("table".geom, %(ST_Expand_2)s) && GeomFromWKB(%(GeomFromWKB_3)s, %(GeomFromWKB_4)s)) AND ST_Distance("table".geom, GeomFromWKB(%(GeomFromWKB_5)s, %(GeomFromWKB_6)s)) <= %(ST_Distance_1)s') 64 assert wkb.loads(str(params["GeomFromWKB_1"])).equals(wkt.loads('POLYGON ((-180 -90, -180 90, 180 90, 180 -90, -180 -90))')) 65 assert params["GeomFromWKB_2"] == 4326 66 assert params["ST_Expand_1"] == 1 67 assert params["ST_Distance_1"] == 1 68 69 # with epsg defined 70 filter = spatial.Spatial( 71 spatial.Spatial.BOX, 72 MappedClass.geometry_column(), 73 box=[-180, -90, 180, 90], 74 tolerance=1, 75 epsg=900913 76 ) 77 compiled_filter = filter.to_sql_expr().compile(engine) 78 params = compiled_filter.params 79 filter_str = _compiled_to_string(compiled_filter) 80 eq_(filter_str, '(ST_Expand(GeomFromWKB(%(GeomFromWKB_1)s, %(GeomFromWKB_2)s), %(ST_Expand_1)s) && ST_Transform("table".geom, %(param_1)s)) AND (ST_Expand(ST_Transform("table".geom, %(param_2)s), %(ST_Expand_2)s) && GeomFromWKB(%(GeomFromWKB_3)s, %(GeomFromWKB_4)s)) AND ST_Distance(ST_Transform("table".geom, %(param_3)s), GeomFromWKB(%(GeomFromWKB_5)s, %(GeomFromWKB_6)s)) <= %(ST_Distance_1)s') 81 assert wkb.loads(str(params["GeomFromWKB_1"])).equals(wkt.loads('POLYGON ((-180 -90, -180 90, 180 90, 180 -90, -180 -90))')) 82 assert params["GeomFromWKB_2"] == 900913 83 assert params["ST_Expand_1"] == 1 84 assert params["param_1"] == 900913 85 assert params["ST_Distance_1"] == 1 86 87 def test_spatial_within(self): 88 # with epsg undefined 89 filter = spatial.Spatial( 90 spatial.Spatial.WITHIN, 91 MappedClass.geometry_column(), 92 lon=40, lat=5, tolerance=1 93 ) 94 compiled_filter = filter.to_sql_expr().compile(engine) 95 params = compiled_filter.params 96 filter_str = _compiled_to_string(compiled_filter) 97 eq_(filter_str, '(ST_Expand(GeomFromWKB(%(GeomFromWKB_1)s, %(GeomFromWKB_2)s), %(ST_Expand_1)s) && "table".geom) AND (ST_Expand("table".geom, %(ST_Expand_2)s) && GeomFromWKB(%(GeomFromWKB_3)s, %(GeomFromWKB_4)s)) AND ST_Distance("table".geom, GeomFromWKB(%(GeomFromWKB_5)s, %(GeomFromWKB_6)s)) <= %(ST_Distance_1)s') 98 assert wkb.loads(str(params["GeomFromWKB_1"])).equals(wkt.loads('POINT (40 5)')) 99 assert params["GeomFromWKB_2"] == 4326 100 assert params["ST_Expand_1"] == 1 101 assert params["ST_Distance_1"] == 1 257 102 258 def test_logical_not(): 259 filter = logical.Logical( 260 logical.Logical.NOT, 261 filters=[ 262 comparison.Comparison( 263 comparison.Comparison.EQUAL_TO, 264 MappedClass.id, 265 value=1 266 ) 267 ] 268 ) 269 filter = filter.to_sql_expr() 270 params = filter.compile().params 271 assert str(filter) == '"table".id != :id_1' 272 assert params["id_1"] == 1 273 274 filter = logical.Logical( 275 logical.Logical.NOT, 276 filters=[ 277 comparison.Comparison( 278 comparison.Comparison.LIKE, 279 MappedClass.text, 280 value="foo" 281 ) 282 ] 283 ) 284 filter = filter.to_sql_expr() 285 params = filter.compile().params 286 assert str(filter) == '"table".text NOT LIKE :text_1' 287 assert params["text_1"] == "foo" 288 289 def test_logical_and(): 290 filter = logical.Logical( 291 logical.Logical.AND, 292 filters=[ 293 comparison.Comparison( 294 comparison.Comparison.EQUAL_TO, 295 MappedClass.id, 296 value=1 297 ), 298 comparison.Comparison( 299 comparison.Comparison.LIKE, 300 MappedClass.text, 301 value="foo" 302 ) 303 ] 304 ) 305 filter = filter.to_sql_expr() 306 params = filter.compile().params 307 assert str(filter) == '"table".id = :id_1 AND "table".text LIKE :text_1' 308 assert params["id_1"] == 1 309 assert params["text_1"] == "foo" 310 311 def test_logical_or(): 312 filter = logical.Logical( 313 logical.Logical.OR, 314 filters=[ 315 comparison.Comparison( 316 comparison.Comparison.EQUAL_TO, 317 MappedClass.id, 318 value=1 319 ), 320 comparison.Comparison( 321 comparison.Comparison.LIKE, 322 MappedClass.text, 323 value="foo" 324 ) 325 ] 326 ) 327 filter = filter.to_sql_expr() 328 params = filter.compile().params 329 assert str(filter) == '"table".id = :id_1 OR "table".text LIKE :text_1' 330 assert params["id_1"] == 1 331 assert params["text_1"] == "foo" 103 # with epsg defined 104 filter = spatial.Spatial( 105 spatial.Spatial.WITHIN, 106 MappedClass.geometry_column(), 107 lon=40, lat=5, tolerance=1, epsg=900913 108 ) 109 compiled_filter = filter.to_sql_expr().compile(engine) 110 params = compiled_filter.params 111 filter_str = _compiled_to_string(compiled_filter) 112 eq_(filter_str, '(ST_Expand(GeomFromWKB(%(GeomFromWKB_1)s, %(GeomFromWKB_2)s), %(ST_Expand_1)s) && ST_Transform("table".geom, %(param_1)s)) AND (ST_Expand(ST_Transform("table".geom, %(param_2)s), %(ST_Expand_2)s) && GeomFromWKB(%(GeomFromWKB_3)s, %(GeomFromWKB_4)s)) AND ST_Distance(ST_Transform("table".geom, %(param_3)s), GeomFromWKB(%(GeomFromWKB_5)s, %(GeomFromWKB_6)s)) <= %(ST_Distance_1)s') 113 assert wkb.loads(str(params["GeomFromWKB_1"])).equals(wkt.loads('POINT (40 5)')) 114 assert params["GeomFromWKB_2"] == 900913 115 assert params["ST_Expand_1"] == 1 116 assert params["param_1"] == 900913 117 assert params["ST_Distance_1"] == 1 118 119 def test_spatial_geometry(self): 120 poly = Polygon(((1, 2), (1, 3), (2, 3), (2, 2), (1, 2))) 121 122 # with epsg undefined 123 filter = spatial.Spatial( 124 spatial.Spatial.GEOMETRY, 125 MappedClass.geometry_column(), 126 geometry=dumps(poly), 127 tolerance=1 128 ) 129 compiled_filter = filter.to_sql_expr().compile(engine) 130 params = compiled_filter.params 131 filter_str = _compiled_to_string(compiled_filter) 132 eq_(filter_str, '(ST_Expand(GeomFromWKB(%(GeomFromWKB_1)s, %(GeomFromWKB_2)s), %(ST_Expand_1)s) && "table".geom) AND (ST_Expand("table".geom, %(ST_Expand_2)s) && GeomFromWKB(%(GeomFromWKB_3)s, %(GeomFromWKB_4)s)) AND ST_Distance("table".geom, GeomFromWKB(%(GeomFromWKB_5)s, %(GeomFromWKB_6)s)) <= %(ST_Distance_1)s') 133 assert wkb.loads(str(params["GeomFromWKB_1"])).equals(poly) 134 assert params["GeomFromWKB_2"] == 4326 135 assert params["ST_Expand_1"] == 1 136 assert params["ST_Distance_1"] == 1 137 138 # with epsg defined 139 filter = spatial.Spatial( 140 spatial.Spatial.GEOMETRY, 141 MappedClass.geometry_column(), 142 geometry=dumps(poly), 143 tolerance=1, 144 epsg=900913 145 ) 146 compiled_filter = filter.to_sql_expr().compile(engine) 147 params = compiled_filter.params 148 filter_str = _compiled_to_string(compiled_filter) 149 eq_(filter_str, '(ST_Expand(GeomFromWKB(%(GeomFromWKB_1)s, %(GeomFromWKB_2)s), %(ST_Expand_1)s) && ST_Transform("table".geom, %(param_1)s)) AND (ST_Expand(ST_Transform("table".geom, %(param_2)s), %(ST_Expand_2)s) && GeomFromWKB(%(GeomFromWKB_3)s, %(GeomFromWKB_4)s)) AND ST_Distance(ST_Transform("table".geom, %(param_3)s), GeomFromWKB(%(GeomFromWKB_5)s, %(GeomFromWKB_6)s)) <= %(ST_Distance_1)s') 150 assert wkb.loads(str(params["GeomFromWKB_1"])).equals(poly) 151 assert params["GeomFromWKB_2"] == 900913 152 assert params["ST_Expand_1"] == 1 153 assert params["param_1"] == 900913 154 assert params["ST_Distance_1"] == 1 155 156 # 157 # Test Comparison 158 # 159 160 def test_comparison_equalto(self): 161 filter = comparison.Comparison( 162 comparison.Comparison.EQUAL_TO, 163 MappedClass.id, 164 value=1 165 ) 166 filter = filter.to_sql_expr() 167 params = filter.compile().params 168 assert str(filter) == '"table".id = :id_1' 169 assert params["id_1"] == 1 170 171 def test_comparison_notequalto(self): 172 filter = comparison.Comparison( 173 comparison.Comparison.NOT_EQUAL_TO, 174 MappedClass.id, 175 value=1 176 ) 177 filter = filter.to_sql_expr() 178 params = filter.compile().params 179 assert str(filter) == '"table".id != :id_1' 180 assert params["id_1"] == 1 181 182 def test_comparison_lowerthan(self): 183 filter = comparison.Comparison( 184 comparison.Comparison.LOWER_THAN, 185 MappedClass.id, 186 value=1 187 ) 188 filter = filter.to_sql_expr() 189 params = filter.compile().params 190 assert str(filter) == '"table".id < :id_1' 191 assert params["id_1"] == 1 192 193 def test_comparison_lowerthanorequalto(self): 194 filter = comparison.Comparison( 195 comparison.Comparison.LOWER_THAN_OR_EQUAL_TO, 196 MappedClass.id, 197 value=1 198 ) 199 filter = filter.to_sql_expr() 200 params = filter.compile().params 201 assert str(filter) == '"table".id <= :id_1' 202 assert params["id_1"] == 1 203 204 def test_comparison_greaterthan(self): 205 filter = comparison.Comparison( 206 comparison.Comparison.GREATER_THAN, 207 MappedClass.id, 208 value=1 209 ) 210 filter = filter.to_sql_expr() 211 params = filter.compile().params 212 assert str(filter) == '"table".id > :id_1' 213 assert params["id_1"] == 1 214 215 def test_comparison_greaterthanorequalto(self): 216 filter = comparison.Comparison( 217 comparison.Comparison.GREATER_THAN_OR_EQUAL_TO, 218 MappedClass.id, 219 value=1 220 ) 221 filter = filter.to_sql_expr() 222 params = filter.compile().params 223 assert str(filter) == '"table".id >= :id_1' 224 assert params["id_1"] == 1 225 226 def test_comparison_between(self): 227 filter = comparison.Comparison( 228 comparison.Comparison.BETWEEN, 229 MappedClass.id, 230 lower_bound=1, upper_bound=2 231 ) 232 filter = filter.to_sql_expr() 233 params = filter.compile().params 234 assert str(filter) == '"table".id <= :id_1 AND "table".id >= :id_2' 235 assert params["id_1"] == 2 236 assert params["id_2"] == 1 237 238 def test_comparison_like(self): 239 filter = comparison.Comparison( 240 comparison.Comparison.LIKE, 241 MappedClass.text, 242 value="foo" 243 ) 244 filter = filter.to_sql_expr() 245 params = filter.compile().params 246 assert str(filter) == '"table".text LIKE :text_1' 247 assert params["text_1"] == "foo" 248 249 def test_comparison_ilike(self): 250 filter = comparison.Comparison( 251 comparison.Comparison.ILIKE, 252 MappedClass.text, 253 value="foo" 254 ) 255 filter = filter.to_sql_expr() 256 params = filter.compile().params 257 assert str(filter) == 'lower("table".text) LIKE lower(:text_1)' 258 assert params["text_1"] == "foo" 259 260 # 261 # Test FeatureId 262 # 263 264 def test_featureid(self): 265 filter = featureid.FeatureId( 266 MappedClass.id, 267 1 268 ) 269 filter = filter.to_sql_expr() 270 params = filter.compile().params 271 assert str(filter) == '"table".id = :id_1' 272 assert params["id_1"] == 1 273 274 # 275 # Test Logical 276 # 277 278 def test_logical_not(self): 279 filter = logical.Logical( 280 logical.Logical.NOT, 281 filters=[ 282 comparison.Comparison( 283 comparison.Comparison.EQUAL_TO, 284 MappedClass.id, 285 value=1 286 ) 287 ] 288 ) 289 filter = filter.to_sql_expr() 290 params = filter.compile().params 291 assert str(filter) == '"table".id != :id_1' 292 assert params["id_1"] == 1 293 294 filter = logical.Logical( 295 logical.Logical.NOT, 296 filters=[ 297 comparison.Comparison( 298 comparison.Comparison.LIKE, 299 MappedClass.text, 300 value="foo" 301 ) 302 ] 303 ) 304 filter = filter.to_sql_expr() 305 params = filter.compile().params 306 assert str(filter) == '"table".text NOT LIKE :text_1' 307 assert params["text_1"] == "foo" 308 309 def test_logical_and(self): 310 filter = logical.Logical( 311 logical.Logical.AND, 312 filters=[ 313 comparison.Comparison( 314 comparison.Comparison.EQUAL_TO, 315 MappedClass.id, 316 value=1 317 ), 318 comparison.Comparison( 319 comparison.Comparison.LIKE, 320 MappedClass.text, 321 value="foo" 322 ) 323 ] 324 ) 325 filter = filter.to_sql_expr() 326 params = filter.compile().params 327 assert str(filter) == '"table".id = :id_1 AND "table".text LIKE :text_1' 328 assert params["id_1"] == 1 329 assert params["text_1"] == "foo" 330 331 def test_logical_or(self): 332 filter = logical.Logical( 333 logical.Logical.OR, 334 filters=[ 335 comparison.Comparison( 336 comparison.Comparison.EQUAL_TO, 337 MappedClass.id, 338 value=1 339 ), 340 comparison.Comparison( 341 comparison.Comparison.LIKE, 342 MappedClass.text, 343 value="foo" 344 ) 345 ] 346 ) 347 filter = filter.to_sql_expr() 348 params = filter.compile().params 349 assert str(filter) == '"table".id = :id_1 OR "table".text LIKE :text_1' 350 assert params["id_1"] == 1 351 assert params["text_1"] == "foo" -
framework/server/trunk/mapfish/tests/test_protocol.py
r2731 r3569 3 3 from StringIO import StringIO 4 4 5 from nose import with_setup 6 7 from sqlalchemy import MetaData, Table, Column5 import unittest 6 7 from sqlalchemy import MetaData, Column, create_engine 8 8 from sqlalchemy import types 9 9 from sqlalchemy import orm 10 from sqlalchemy.ext.declarative import declarative_base 10 11 11 12 from geojson import dumps, Feature … … 13 14 from shapely.geometry.polygon import Polygon 14 15 15 from mapfish.sqlalchemygeom import Geometry, GeometryTableMixIn 16 from geoalchemy import GeometryColumn, Geometry 17 18 from mapfish.sqlalchemygeom import GeometryTableMixIn 16 19 from mapfish.lib.filters import logical, comparison, spatial 17 20 … … 20 23 # 21 24 22 table = Table("table", MetaData(), 23 Column("id", types.Integer, primary_key=True), 24 Column("text", types.Unicode), 25 Column("geom", Geometry(4326)) 26 ) 27 28 class MappedClass(GeometryTableMixIn): 29 __table__ = table 30 31 orm.mapper(MappedClass, table) 25 Base = declarative_base(metadata=MetaData()) 26 27 class MappedClass(Base, GeometryTableMixIn): 28 __tablename__ = "table" 29 id = Column(types.Integer, primary_key=True) 30 text = Column(types.Unicode) 31 geom = GeometryColumn(Geometry(dimension=2, srid=4326)) 32 32 33 33 class FakeRequest(object): … … 46 46 47 47 # create a session in the same way it's done in a typical Pylons app 48 sm = orm.sessionmaker(autoflush=True, autocommit=False) 48 engine = create_engine('postgresql://user:user@no_connection/no_db', echo=True) 49 sm = orm.sessionmaker(autoflush=True, autocommit=False, bind=engine) 49 50 Session = orm.scoped_session(sm) 50 51 52 def query_to_str(query): 53 """Helper method which compiles a query using a database engine 54 """ 55 return unicode(query.statement.compile(engine)).encode('ascii', 'backslashreplace') 51 56 # 52 57 # Test 53 58 # 54 59 55 from mapfish.lib.protocol import create_geom_filter 56 def test_create_geom_filter(): 57 request = FakeRequest( 58 {"box": "-45,-5,40,0", "tolerance": "1", "epsg": "900913"} 59 ) 60 filter = create_geom_filter(request, MappedClass) 61 assert isinstance(filter, spatial.Spatial) 62 assert filter.type == spatial.Spatial.BOX 63 assert filter.values["tolerance"] == 1 64 assert filter.values["epsg"] == 900913 65 66 request = FakeRequest( 67 {"bbox": "-45,-5,40,0", "tolerance": "1", "epsg": "900913"} 68 ) 69 filter = create_geom_filter(request, MappedClass) 70 assert isinstance(filter, spatial.Spatial) 71 assert filter.type == spatial.Spatial.BOX 72 assert filter.values["tolerance"] == 1 73 assert filter.values["epsg"] == 900913 74 75 request = FakeRequest( 76 {"lon": "-45", "lat": "5", "tolerance": "1", "epsg": "900913"} 77 ) 78 filter = create_geom_filter(request, MappedClass) 79 assert isinstance(filter, spatial.Spatial) 80 assert filter.type == spatial.Spatial.WITHIN 81 assert filter.values["tolerance"] == 1 82 assert filter.values["epsg"] == 900913 83 84 poly = Polygon(((1, 2), (1, 3), (2, 3), (2, 2), (1, 2))) 85 request = FakeRequest( 86 {"geometry": dumps(poly), "tolerance": "1", "epsg": "900913"} 87 ) 88 filter = create_geom_filter(request, MappedClass) 89 assert isinstance(filter, spatial.Spatial) 90 assert filter.type == spatial.Spatial.GEOMETRY 91 assert filter.values["tolerance"] == 1 92 assert filter.values["epsg"] == 900913 93 94 request = FakeRequest({}) 95 filter = create_geom_filter(request, MappedClass) 96 assert filter is None 97 98 from mapfish.lib.protocol import create_attr_filter 99 def test_create_attr_filter(): 100 request = FakeRequest( 101 {"queryable": "id", "id__eq": "1"} 102 ) 103 filter = create_attr_filter(request, MappedClass) 104 assert isinstance(filter, comparison.Comparison) 105 assert filter.type == comparison.Comparison.EQUAL_TO 106 assert filter.values["value"] == "1" 107 108 request = FakeRequest( 109 {"queryable": "id", "id__lt": "1"} 110 ) 111 filter = create_attr_filter(request, MappedClass) 112 assert isinstance(filter, comparison.Comparison) 113 assert filter.type == comparison.Comparison.LOWER_THAN 114 assert filter.values["value"] == "1" 115 116 request = FakeRequest( 117 {"queryable": "id", "id__lte": "1"} 118 ) 119 filter = create_attr_filter(request, MappedClass) 120 assert isinstance(filter, comparison.Comparison) 121 assert filter.type == comparison.Comparison.LOWER_THAN_OR_EQUAL_TO 122 assert filter.values["value"] == "1" 123 124 request = FakeRequest( 125 {"queryable": "id", "id__gt": "1"} 126 ) 127 filter = create_attr_filter(request, MappedClass) 128 assert isinstance(filter, comparison.Comparison) 129 assert filter.type == comparison.Comparison.GREATER_THAN 130 assert filter.values["value"] == "1" 131 132 request = FakeRequest( 133 {"queryable": "id", "id__gte": "1"} 134 ) 135 filter = create_attr_filter(request, MappedClass) 136 assert isinstance(filter, comparison.Comparison) 137 assert filter.type == comparison.Comparison.GREATER_THAN_OR_EQUAL_TO 138 assert filter.values["value"] == "1" 139 140 request = FakeRequest( 141 {"queryable": "text", "text__like": "foo"} 142 ) 143 filter = create_attr_filter(request, MappedClass) 144 assert isinstance(filter, comparison.Comparison) 145 assert filter.type == comparison.Comparison.LIKE 146 assert filter.values["value"] == "foo" 147 148 request = FakeRequest( 149 {"queryable": "text", "text__ilike": "foo"} 150 ) 151 filter = create_attr_filter(request, MappedClass) 152 assert isinstance(filter, comparison.Comparison) 153 assert filter.type == comparison.Comparison.ILIKE 154 assert filter.values["value"] == "foo" 155 156 request = FakeRequest( 157 {"queryable": "text,id", "text__ilike": "foo", "id__eq": "1"} 158 ) 159 filter = create_attr_filter(request, MappedClass) 160 assert isinstance(filter, logical.Logical) 161 assert filter.type == logical.Logical.AND 162 assert len(filter.filters) == 2 163 164 request = FakeRequest( 165 {"text__ilike": "foo", "id__eq": "1"} 166 ) 167 filter = create_attr_filter(request, MappedClass) 168 assert filter is None 169 170 from mapfish.lib.protocol import asbool 171 def test_asbool(): 172 assert asbool(0) == False 173 assert asbool(1) == True 174 assert asbool(2) == True 175 assert asbool("0") == False 176 assert asbool("1") == True 177 assert asbool("false") == False 178 assert asbool("true") == True 179 assert asbool("False") == False 180 assert asbool("True") == True 181 assert asbool(u"0") == False 182 assert asbool(u"1") == True 183 assert asbool(u"false") == False 184 assert asbool(u"true") == True 185 assert asbool(u"False") == False 186 assert asbool(u"True") == True 187 188 from mapfish.lib.protocol import Protocol 189 def test_protocol_query(): 190 proto = Protocol(Session, MappedClass) 191 192 request = FakeRequest({}) 193 query = proto._query(request, execute=False) 194 assert "SELECT" in str(query) 195 196 request = FakeRequest({"queryable": "id", "id__eq": "1"}) 197 query = proto._query(request, execute=False) 198 assert "WHERE" in str(query) 199 200 request = FakeRequest({"queryable": "id", "id__eq": "1"}) 201 filter = create_attr_filter(request, MappedClass) 202 query = proto._query(FakeRequest({}), filter=filter, execute=False) 203 assert "WHERE" in str(query) 204 205 request = FakeRequest({"limit": "2"}) 206 query = proto._query(request, execute=False) 207 assert "LIMIT 2" in str(query) 208 209 request = FakeRequest({"maxfeatures": "2"}) 210 query = proto._query(request, execute=False) 211 assert "LIMIT 2" in str(query) 212 213 request = FakeRequest({"limit": "2", "offset": "10"}) 214 query = proto._query(request, execute=False) 215 assert "OFFSET 10" in str(query) 216 217 request = FakeRequest({"order_by": "text"}) 218 query = proto._query(request, execute=False) 219 assert "ORDER BY" in str(query) 220 assert "ASC" in str(query) 221 222 request = FakeRequest({"sort": "text"}) 223 query = proto._query(request, execute=False) 224 assert "ORDER BY" in str(query) 225 assert "ASC" in str(query) 226 227 request = FakeRequest({"order_by": "text", "dir": "DESC"}) 228 query = proto._query(request, execute=False) 229 assert "ORDER BY" in str(query) 230 assert "DESC" in str(query) 231 232 def test_protocol_create(): 233 proto = Protocol(Session, MappedClass) 234 request = FakeRequest({}) 235 request.body = '{"type": "FeatureCollection", "features": [{"type": "Feature", "properties": {"text": "foo"}, "geometry": {"type": "Point", "coordinates": [45, 5]}}, {"type": "Feature", "properties": {"text": "foo"}, "geometry": {"type": "Point", "coordinates": [45, 5]}}]}' 236 response = FakeResponse() 237 proto.create(request, response, execute=False) 238 assert response.status == 201 239 assert len(Session.new) == 2 240 for obj in Session.new: 241 assert obj["text"] == "foo" 242 assert obj.geometry.x == 45 243 assert obj.geometry.y == 5 244 Session.rollback() 60 class Test(unittest.TestCase): 61 62 def test_create_geom_filter(self): 63 from mapfish.lib.protocol import create_geom_filter 64 request = FakeRequest( 65 {"box": "-45,-5,40,0", "tolerance": "1", "epsg": "900913"} 66 ) 67 filter = create_geom_filter(request, MappedClass) 68 assert isinstance(filter, spatial.Spatial) 69 assert filter.type == spatial.Spatial.BOX 70 assert filter.values["tolerance"] == 1 71 assert filter.values["epsg"] == 900913 72 73 request = FakeRequest( 74 {"bbox": "-45,-5,40,0", "tolerance": "1", "epsg": "900913"} 75 ) 76 filter = create_geom_filter(request, MappedClass) 77 assert isinstance(filter, spatial.Spatial) 78 assert filter.type == spatial.Spatial.BOX 79 assert filter.values["tolerance"] == 1 80 assert filter.values["epsg"] == 900913 81 82 request = FakeRequest( 83 {"lon": "-45", "lat": "5", "tolerance": "1", "epsg": "900913"} 84 ) 85 filter = create_geom_filter(request, MappedClass) 86 assert isinstance(filter, spatial.Spatial) 87 assert filter.type == spatial.Spatial.WITHIN 88 assert filter.values["tolerance"] == 1 89 assert filter.values["epsg"] == 900913 90 91 poly = Polygon(((1, 2), (1, 3), (2, 3), (2, 2), (1, 2))) 92 request = FakeRequest( 93 {"geometry": dumps(poly), "tolerance": "1", "epsg": "900913"} 94 ) 95 filter = create_geom_filter(request, MappedClass) 96 assert isinstance(filter, spatial.Spatial) 97 assert filter.type == spatial.Spatial.GEOMETRY 98 assert filter.values["tolerance"] == 1 99 assert filter.values["epsg"] == 900913 100 101 request = FakeRequest({}) 102 filter = create_geom_filter(request, MappedClass) 103 assert filter is None 104 105 request = FakeRequest({"lon": "-45", "lat": "5"}) 106 filter = create_geom_filter(request, MappedClass, additional_params='unit=KM') 107 assert filter.additional_params is not None 108 109 110 def test_create_attr_filter(self): 111 from mapfish.lib.protocol import create_attr_filter 112 request = FakeRequest( 113 {"queryable": "id", "id__eq": "1"} 114 ) 115 filter = create_attr_filter(request, MappedClass) 116 assert isinstance(filter, comparison.Comparison) 117 assert filter.type == comparison.Comparison.EQUAL_TO 118 assert filter.values["value"] == "1" 119 120 request = FakeRequest( 121 {"queryable": "id", "id__lt": "1"} 122 ) 123 filter = create_attr_filter(request, MappedClass) 124 assert isinstance(filter, comparison.Comparison) 125 assert filter.type == comparison.Comparison.LOWER_THAN 126 assert filter.values["value"] == "1" 127 128 request = FakeRequest( 129 {"queryable": "id", "id__lte": "1"} 130 ) 131 filter = create_attr_filter(request, MappedClass) 132 assert isinstance(filter, comparison.Comparison) 133 assert filter.type == comparison.Comparison.LOWER_THAN_OR_EQUAL_TO 134 assert filter.values["value"] == "1" 135 136 request = FakeRequest( 137 {"queryable": "id", "id__gt": "1"} 138 ) 139 filter = create_attr_filter(request, MappedClass) 140 assert isinstance(filter, comparison.Comparison) 141 assert filter.type == comparison.Comparison.GREATER_THAN 142 assert filter.values["value"] == "1" 143 144 request = FakeRequest( 145 {"queryable": "id", "id__gte": "1"} 146 ) 147 filter = create_attr_filter(request, MappedClass) 148 assert isinstance(filter, comparison.Comparison) 149 assert filter.type == comparison.Comparison.GREATER_THAN_OR_EQUAL_TO 150 assert filter.values["value"] == "1" 151 152 request = FakeRequest( 153 {"queryable": "text", "text__like": "foo"} 154 ) 155 filter = create_attr_filter(request, MappedClass) 156 assert isinstance(filter, comparison.Comparison) 157 assert filter.type == comparison.Comparison.LIKE 158 assert filter.values["value"] == "foo" 159 160 request = FakeRequest( 161 {"queryable": "text", "text__ilike": "foo"} 162 ) 163 filter = create_attr_filter(request, MappedClass) 164 assert isinstance(filter, comparison.Comparison) 165 assert filter.type == comparison.Comparison.ILIKE 166 assert filter.values["value"] == "foo" 167 168 request = FakeRequest( 169 {"queryable": "text,id", "text__ilike": "foo", "id__eq": "1"} 170 ) 171 filter = create_attr_filter(request, MappedClass) 172 assert isinstance(filter, logical.Logical) 173 assert filter.type == logical.Logical.AND 174 assert len(filter.filters) == 2 175 176 request = FakeRequest( 177 {"text__ilike": "foo", "id__eq": "1"} 178 ) 179 filter = create_attr_filter(request, MappedClass) 180 assert filter is None 181 182 183 def test_asbool(self): 184 from mapfish.lib.protocol import asbool 185 assert asbool(0) == False 186 assert asbool(1) == True 187 assert asbool(2) == True 188 assert asbool("0") == False 189 assert asbool("1") == True 190 assert asbool("false") == False 191 assert asbool("true") == True 192 assert asbool("False") == False 193 assert asbool("True") == True 194 assert asbool(u"0") == False 195 assert asbool(u"1") == True 196 assert asbool(u"false") == False 197 assert asbool(u"true") == True 198 assert asbool(u"False") == False 199 assert asbool(u"True") == True 200 201 def test_protocol_query(self): 202 from mapfish.lib.protocol import Protocol, create_attr_filter 203 proto = Protocol(Session, MappedClass) 204 205 request = FakeRequest({}) 206 query = proto._query(request, execute=False) 207 stmt = query.statement 208 stmtm_str = stmt.compile(engine) 209 assert "SELECT" in query_to_str(query) 210 211 request = FakeRequest({"queryable": "id", "id__eq": "1"}) 212 query = proto._query(request, execute=False) 213 assert "WHERE" in query_to_str(query) 214 215 request = FakeRequest({"queryable": "id", "id__eq": "1"}) 216 filter = create_attr_filter(request, MappedClass) 217 query = proto._query(FakeRequest({}), filter=filter, execute=False) 218 assert "WHERE" in query_to_str(query) 219 220 request = FakeRequest({"limit": "2"}) 221 query = proto._query(request, execute=False) 222 assert "LIMIT 2" in query_to_str(query) 223 224 request = FakeRequest({"maxfeatures": "2"}) 225 query = proto._query(request, execute=False) 226 assert "LIMIT 2" in query_to_str(query) 227 228 request = FakeRequest({"limit": "2", "offset": "10"}) 229 query = proto._query(request, execute=False) 230 assert "OFFSET 10" in query_to_str(query) 231 232 request = FakeRequest({"order_by": "text"}) 233 query = proto._query(request, execute=False) 234 assert "ORDER BY" in query_to_str(query) 235 assert "ASC" in query_to_str(query) 236 237 request = FakeRequest({"sort": "text"}) 238 query = proto._query(request, execute=False) 239 assert "ORDER BY" in query_to_str(query) 240 assert "ASC" in query_to_str(query) 241 242 request = FakeRequest({"order_by": "text", "dir": "DESC"}) 243 query = proto._query(request, execute=False) 244 assert "ORDER BY" in query_to_str(query) 245 assert "DESC" in query_to_str(query) 246 247 def test_protocol_create(self): 248 from mapfish.lib.protocol import Protocol 249 proto = Protocol(Session, MappedClass) 250 request = FakeRequest({}) 251 request.body = '{"type": "FeatureCollection", "features": [{"type": "Feature", "properties": {"text": "foo"}, "geometry": {"type": "Point", "coordinates": [45, 5]}}, {"type": "Feature", "properties": {"text": "foo"}, "geometry": {"type": "Point", "coordinates": [45, 5]}}]}' 252 response = FakeResponse() 253 proto.create(request, response, execute=False) 254 assert response.status == 201 255 assert len(Session.new) == 2 256 for obj in Session.new: 257 assert obj["text"] == "foo" 258 assert obj.geometry.shape.x == 45 259 assert obj.geometry.shape.y == 5 260 Session.rollback() -
framework/server/trunk/setup.py
r3140 r3569 27 27 import sys 28 28 29 30 requirements = ['SQLAlchemy>=0.5.0,<=0.5.99', 29 requirements = ['SQLAlchemy>=0.6.1,<=0.6.99', 31 30 'Pylons>=0.9.7,<=0.9.7.99', 32 'geojson>=1.0,<=1.0.99'] 31 'geojson>=1.0,<=1.0.99', 32 'GeoAlchemy>=0.3,<=0.3.99'] 33 33 34 34 # Shapely and Psychopg2 cannot be installed on Windows via python eggs … … 43 43 44 44 setup(name = 'mapfish', 45 version = ' 1.3dev',45 version = '2.0dev', 46 46 license = 'LGPLv3', 47 47 install_requires = requirements, … … 103 103 -------------- 104 104 105 MapFish 1.3dev described in this page is the current stable version.105 MapFish 2.0dev described in this page is the current stable version. 106 106 107 107 Download and Installation
