def _proto_read(self, layer): """ Read features for the layer based on the self.request. """ proto = self._get_protocol_for_layer(layer) if layer.public: return proto.read(self.request) user = self.request.user if user is None: raise HTTPForbidden() cls = proto.mapped_class geom_attr = proto.geom_attr ras = DBSession.query(RestrictionArea.area, functions.srid(RestrictionArea.area)) ras = ras.join(RestrictionArea.roles) ras = ras.join(RestrictionArea.layers) ras = ras.filter(Role.id == user.role.id) ras = ras.filter(Layer.id == layer.id) collect_ra = [] use_srid = -1 for ra, srid in ras.all(): if ra is None: return proto.read(self.request) else: use_srid = srid collect_ra.append(wkb.loads(str(ra.geom_wkb))) if len(collect_ra) == 0: # pragma: no cover raise HTTPForbidden() ra = cascaded_union(collect_ra) filter_ = and_( create_filter(self.request, cls, geom_attr), functions.gcontains(func.st_geomfromtext(ra.wkt, use_srid), getattr(cls, geom_attr))) return proto.read(self.request, filter=filter_)
def _proto_read(self, layer): """ Read features for the layer based on the self.request. """ proto = self._get_protocol_for_layer(layer) if layer.public: return proto.read(self.request) user = self.request.user if user is None: raise HTTPForbidden() cls = proto.mapped_class geom_attr = proto.geom_attr ras = DBSession.query(RestrictionArea.area, functions.srid(RestrictionArea.area)) ras = ras.join(RestrictionArea.roles) ras = ras.join(RestrictionArea.layers) ras = ras.filter(Role.id == user.role.id) ras = ras.filter(Layer.id == layer.id) collect_ra = [] use_srid = -1 for ra, srid in ras.all(): if ra is None: return proto.read(self.request) else: use_srid = srid collect_ra.append(wkb.loads(str(ra.geom_wkb))) if len(collect_ra) == 0: # pragma: no cover raise HTTPForbidden() ra = cascaded_union(collect_ra) filter_ = and_( create_filter(self.request, cls, geom_attr), functions.gcontains( func.st_geomfromtext(ra.wkt, use_srid), getattr(cls, geom_attr) ) ) return proto.read(self.request, filter=filter_)
def __call__(self): tableinfo = TableInfo.from_layer(self.layer) tableinfo.setup_metadata(self.layer._tablename) table = tableinfo.table columns = [ table.columns.id, ] where = [] srsid = self.layer.srs_id if self._srs is None else self._srs.id geomcol = table.columns.geom geomexpr = func.st_transform(geomcol, srsid) if self._clip_by_box is not None: if _clipbybox2d_exists(): clip = func.st_setsrid( func.st_makeenvelope(*self._clip_by_box.bounds), self._clip_by_box.srid) geomexpr = func.st_clipbybox2d(geomexpr, clip) else: clip = func.st_setsrid( func.st_geomfromtext(self._clip_by_box.wkt), self._clip_by_box.srid) geomexpr = func.st_intersection(geomexpr, clip) if self._simplify is not None: geomexpr = func.st_simplifypreservetopology( geomexpr, self._simplify) if self._geom: if self._single_part: class geom(ColumnElement): def __init__(self, base): self.base = base @compiles(geom) def compile(expr, compiler, **kw): return "(%s).geom" % str(compiler.process(expr.base)) columns.append( func.st_asewkb(geom(func.st_dump(geomexpr))).label('geom')) else: columns.append(func.st_asewkb(geomexpr).label('geom')) if self._geom_len: columns.append( func.st_length( func.geography(func.st_transform(geomexpr, 4326))).label('geom_len')) if self._box: columns.extend(( func.st_xmin(geomexpr).label('box_left'), func.st_ymin(geomexpr).label('box_bottom'), func.st_xmax(geomexpr).label('box_right'), func.st_ymax(geomexpr).label('box_top'), )) selected_fields = [] for f in tableinfo.fields: if not self._fields or f.keyname in self._fields: columns.append(table.columns[f.key].label(f.keyname)) selected_fields.append(f) if self._filter_by: for k, v in six.iteritems(self._filter_by): if k == 'id': where.append(table.columns.id == v) else: where.append(table.columns[tableinfo[k].key] == v) if self._filter: token = [] for k, o, v in self._filter: supported_operators = ( "eq", "ge", "gt", "ilike", "in", "le", "like", "lt", "ne", "notin", "startswith", ) if o not in supported_operators: raise ValueError( "Invalid operator '%s'. Only %r are supported." % (o, supported_operators)) if v and o in ['in', 'notin']: v = v.split(',') if o in [ "ilike", "in", "like", "notin", "startswith", ]: o += "_op" op = getattr(db.sql.operators, o) if k == "id": token.append(op(table.columns.id, v)) else: token.append(op(table.columns[tableinfo[k].key], v)) where.append(db.and_(*token)) if self._filter_sql: token = [] for _filter_sql_item in self._filter_sql: if len(_filter_sql_item) == 3: table_column, op, val = _filter_sql_item if table_column == 'id': token.append(op(table.columns.id, val)) else: token.append( op(table.columns[tableinfo[table_column].key], val)) elif len(_filter_sql_item) == 4: table_column, op, val1, val2 = _filter_sql_item token.append( op(table.columns[tableinfo[table_column].key], val1, val2)) where.append(db.and_(*token)) if self._like: token = [] for f in tableinfo.fields: token.append( cast(table.columns[f.key], db.Unicode).ilike("%" + self._like + "%")) where.append(db.or_(*token)) if self._intersects: intgeom = func.st_setsrid( func.st_geomfromtext(self._intersects.wkt), self._intersects.srid) where.append( func.st_intersects( geomcol, func.st_transform(intgeom, self.layer.srs_id))) order_criterion = [] if self._order_by: for order, colname in self._order_by: order_criterion.append( dict(asc=db.asc, desc=db.desc)[order]( table.columns[tableinfo[colname].key])) order_criterion.append(table.columns.id) class QueryFeatureSet(FeatureSet): fields = selected_fields layer = self.layer _geom = self._geom _geom_len = self._geom_len _box = self._box _limit = self._limit _offset = self._offset def __iter__(self): query = sql.select( columns, whereclause=db.and_(*where), limit=self._limit, offset=self._offset, order_by=order_criterion, ) rows = DBSession.connection().execute(query) for row in rows: fdict = dict( (f.keyname, row[f.keyname]) for f in selected_fields) if self._geom: geom = geom_from_wkb(row['geom'].tobytes( ) if six.PY3 else six.binary_type(row['geom'])) else: geom = None calculated = dict() if self._geom_len: calculated['geom_len'] = row['geom_len'] yield Feature( layer=self.layer, id=row.id, fields=fdict, geom=geom, calculations=calculated, box=box(row.box_left, row.box_bottom, row.box_right, row.box_top) if self._box else None) @property def total_count(self): query = sql.select([ func.count(table.columns.id), ], whereclause=db.and_(*where)) res = DBSession.connection().execute(query) for row in res: return row[0] return QueryFeatureSet()
def __call__(self): tab = self.layer._sa_table(True) idcol = tab.columns[self.layer.column_id] columns = [idcol.label('id')] where = [] geomcol = tab.columns[self.layer.column_geom] srs = self.layer.srs if self._srs is None else self._srs if srs.id != self.layer.geometry_srid: geomexpr = func.st_transform(geomcol, srs.id) else: geomexpr = geomcol if self._geom: if self._geom_format == 'WKB': geomexpr = func.st_asbinary(geomexpr, 'NDR') else: geomexpr = func.st_astext(geomexpr) columns.append(geomexpr.label('geom')) fieldmap = [] for idx, fld in enumerate(self.layer.fields, start=1): if self._fields is None or fld.keyname in self._fields: clabel = 'f%d' % idx columns.append( getattr(tab.columns, fld.column_name).label(clabel)) fieldmap.append((fld.keyname, clabel)) if self._filter_by: for k, v in self._filter_by.items(): if k == 'id': where.append(idcol == v) else: field = self.layer.field_by_keyname(k) where.append(tab.columns[field.column_name] == v) if self._filter: token = [] for k, o, v in self._filter: supported_operators = ( 'eq', 'ne', 'isnull', 'ge', 'gt', 'le', 'lt', 'like', 'ilike', ) if o not in supported_operators: raise ValueError( "Invalid operator '%s'. Only %r are supported." % (o, supported_operators)) if o == 'like': o = 'like_op' elif o == 'ilike': o = 'ilike_op' elif o == "isnull": if v == 'yes': o = 'is_' elif v == 'no': o = 'isnot' else: raise ValueError( "Invalid value '%s' for operator '%s'." % (v, o)) v = db.sql.null() op = getattr(db.sql.operators, o) if k == 'id': column = idcol else: field = self.layer.field_by_keyname(k) column = tab.columns[field.column_name] token.append(op(column, v)) where.append(db.and_(True, *token)) if self._like: token = [] for fld in self.layer.fields: token.append( db.sql.cast(tab.columns[fld.column_name], db.Unicode).ilike('%' + self._like + '%')) where.append(db.or_(*token)) if self._intersects: reproject = self._intersects.srid is not None \ and self._intersects.srid != self.layer.geometry_srid int_srs = SRS.filter_by(id=self._intersects.srid).one() \ if reproject else self.layer.srs int_geom = func.st_geomfromtext(self._intersects.wkt) if int_srs.is_geographic: # Prevent tolerance condition error bound_geom = func.st_makeenvelope(-180, -89.9, 180, 89.9) int_geom = func.st_intersection(bound_geom, int_geom) int_geom = func.st_setsrid(int_geom, int_srs.id) if reproject: int_geom = func.st_transform(int_geom, self.layer.geometry_srid) where.append(func.st_intersects(geomcol, int_geom)) if self._box: columns.extend(( func.st_xmin(geomexpr).label('box_left'), func.st_ymin(geomexpr).label('box_bottom'), func.st_xmax(geomexpr).label('box_right'), func.st_ymax(geomexpr).label('box_top'), )) gt = self.layer.geometry_type where.append(func.geometrytype(geomcol) == gt) order_criterion = [] if self._order_by: for order, k in self._order_by: field = self.layer.field_by_keyname(k) order_criterion.append( dict(asc=db.asc, desc=db.desc)[order](tab.columns[field.column_name])) order_criterion.append(idcol) class QueryFeatureSet(FeatureSet): layer = self.layer _geom = self._geom _geom_format = self._geom_format _box = self._box _fields = self._fields _limit = self._limit _offset = self._offset def __iter__(self): query = sql.select(*columns) \ .where(db.and_(True, *where)) \ .limit(self._limit) \ .offset(self._offset) \ .order_by(*order_criterion) conn = self.layer.connection.get_connection() try: result = conn.execute(query) for row in result.mappings(): fdict = dict((k, row[l]) for k, l in fieldmap) if self._geom: if self._geom_format == 'WKB': geom_data = row['geom'].tobytes() geom = Geometry.from_wkb(geom_data, validate=False) else: geom = Geometry.from_wkt(row['geom'], validate=False) else: geom = None yield Feature( layer=self.layer, id=row['id'], fields=fdict, geom=geom, box=box(row['box_left'], row['box_bottom'], row['box_right'], row['box_top']) if self._box else None) except SQLAlchemyError as exc: raise ExternalDatabaseError(sa_error=exc) finally: conn.close() @property def total_count(self): conn = self.layer.connection.get_connection() try: query = sql.select(func.count(idcol)) \ .where(db.and_(True, *where)) result = conn.execute(query) return result.scalar() except SQLAlchemyError as exc: raise ExternalDatabaseError(sa_error=exc) finally: conn.close() return QueryFeatureSet()
def _pg_wkt_to_wkb_ext(wkt): return _query_scalar_bytes( sa_func.st_asewkb(sa_func.st_geomfromtext(wkt), 'NDR'))
def _pg_wkt_to_wkb_iso(wkt): return _query_scalar_bytes( sa_func.st_asbinary(sa_func.st_geomfromtext(wkt), 'NDR'))