QueryLayer.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/maptools/QueryLayer.cpp
22 
23  \brief A layer resulting from a query.
24 */
25 
26 // TerraLib
27 #include "../common/StringUtils.h"
28 #include "../dataaccess/dataset/ObjectIdSet.h"
29 #include "../dataaccess/dataset/PrimaryKey.h"
30 #include "../dataaccess/datasource/DataSource.h"
31 #include "../dataaccess/datasource/DataSourceCapabilities.h"
32 #include "../dataaccess/query/And.h"
33 #include "../dataaccess/query/DataSetName.h"
34 #include "../dataaccess/query/Expression.h"
35 #include "../dataaccess/query/Field.h"
36 #include "../dataaccess/query/Function.h"
37 #include "../dataaccess/query/FunctionNames.h"
38 #include "../dataaccess/query/FromItem.h"
39 #include "../dataaccess/query/Join.h"
40 #include "../dataaccess/query/LiteralEnvelope.h"
41 #include "../dataaccess/query/PropertyName.h"
42 #include "../dataaccess/query/Select.h"
43 #include "../dataaccess/query/SQLVisitor.h"
44 #include "../dataaccess/query/ST_Intersects.h"
45 #include "../dataaccess/query/ST_EnvelopeIntersects.h"
46 #include "../dataaccess/query/Where.h"
47 #include "../dataaccess/utils/Utils.h"
48 #include "../datatype/Property.h"
49 #include "../geometry/GeometryProperty.h"
50 #include "Exception.h"
51 #include "QueryLayer.h"
52 #include "RendererFactory.h"
53 #include "Utils.h"
54 
55 // Boost
56 #include <boost/format.hpp>
57 
58 // STL
59 #include <memory>
60 
61 const std::string te::map::QueryLayer::sm_type("QUERYLAYER");
62 
64  : AbstractLayer(parent),
65  m_query(nullptr)
66 {
67 }
68 
69 te::map::QueryLayer::QueryLayer(const std::string& id, AbstractLayer* parent)
70  : AbstractLayer(id, parent),
71  m_query(nullptr)
72 {
73 }
74 
75 te::map::QueryLayer::QueryLayer(const std::string& id,
76  const std::string& title,
77  AbstractLayer* parent)
78  : AbstractLayer(id, title, parent),
79  m_query(nullptr)
80 {
81 }
82 
84 {
85  delete m_query;
86 }
87 
89 {
91 
92  te::map::CopyAbstractLayerInfo(this, layer);
93 
94  te::da::Select* s = dynamic_cast<te::da::Select*>(m_query->clone());
95  if(s)
96  layer->setQuery(s);
97 
99 
100  return layer;
101 }
102 
103 std::unique_ptr<te::map::LayerSchema> te::map::QueryLayer::getSchema() const
104 {
105  std::unique_ptr<te::map::LayerSchema> output(new te::map::LayerSchema(getTitle()));
106 
107  te::da::PrimaryKey* outKey = new te::da::PrimaryKey();
108 
110 
111  const te::da::Fields* fields = m_query->getFields();
112  const te::da::From* from = m_query->getFrom();
113 
114  for(size_t i = 0; i < fields->size(); ++i)
115  {
116  te::da::Field field = fields->at(i);
117  te::da::Expression* exp = field.getExpression();
118 
119  te::da::PropertyName* pName = dynamic_cast<te::da::PropertyName*>(exp);
120 
121  std::vector<std::string> tokens;
122  te::common::Tokenize(pName->getName(), tokens, ".");
123 
124  assert(tokens.size() == 2);
125 
126  std::string name;
127 
128  for(size_t j = 0; j < from->size(); ++j)
129  {
130  const te::da::FromItem& item = from->at(j);
131  const te::da::DataSetName* dsName = dynamic_cast<const te::da::DataSetName*>(&item);
132  if(dsName != nullptr)
133  {
134  if(dsName->getAlias() == tokens[0])
135  name = dsName->getName();
136  }
137  else
138  {
139  const te::da::Join* dsJoin = dynamic_cast<const te::da::Join*>(&item);
140  const te::da::FromItem* first = dsJoin->getFirst();
141  const te::da::DataSetName* dsName = dynamic_cast<const te::da::DataSetName*>(first);
142  if(dsName->getAlias() == tokens[0])
143  {
144  name = dsName->getName();
145  }
146  else
147  {
148  const te::da::FromItem* second = dsJoin->getSecond();
149  const te::da::DataSetName* dsName = dynamic_cast<const te::da::DataSetName*>(second);
150  name = dsName->getName();
151  }
152  }
153  }
154 
155  assert(!name.empty());
156 
157  std::unique_ptr<te::da::DataSetType> input = ds->getDataSetType(name);
158 
159  te::dt::Property* pRef = input->getProperty(tokens[1]);
160  assert(pRef);
161 
162  te::dt::Property* p = (pRef->clone());
163  p->setDatasetName(name);
164  p->setId(static_cast<unsigned int>(i));
165  output->add(p);
166 
167  if(input->getPrimaryKey() != nullptr){
168  if (input->getPrimaryKey()->has(pRef) )
169  {
170  p->setName(tokens[0] + "." + pRef->getName());
171  outKey->add(p);
172  }
173  }
174 
175 
176  }
177 
178  if(!outKey->getProperties().empty())
179  output->setPrimaryKey(outKey);
180 
181  return output;
182 }
183 
184 std::unique_ptr<te::da::DataSet> te::map::QueryLayer::getData(te::common::TraverseType travType,
185  const te::common::AccessPolicy accessPolicy) const
186 {
187  return getData(m_query, travType, accessPolicy);
188 }
189 
190 std::unique_ptr<te::da::DataSet> te::map::QueryLayer::getData(
191  const std::string& propertyName, const te::gm::Envelope* e,
193  const te::common::AccessPolicy accessPolicy) const
194 {
196 
197  te::da::PropertyName* pname = new te::da::PropertyName(propertyName);
198 
200 
201  const te::da::DataSourceCapabilities dsCap = ds->getCapabilities();
202 
203  const te::da::QueryCapabilities queryCap = dsCap.getQueryCapabilities();
204 
205  std::set<std::string> spatialTopOp = queryCap.getSpatialTopologicOperators();
206 
207  // The final select
208  std::unique_ptr<te::da::Select> select(static_cast<te::da::Select*>(m_query->clone()));
209 
210  // Original Where
211  te::da::Where* wh = select->getWhere();
212 
213  if(wh != nullptr)
214  {
215  // Original restriction expression
216  te::da::Expression* exp = wh->getExp()->clone();
217 
218  // TODO: switch that verifies the given te::gm::SpatialRelation and build the query object (ST_Intersects. ST_Touches, etc).
219 
220  if(spatialTopOp.find(te::da::FunctionNames::sm_ST_EnvelopeIntersects) != spatialTopOp.end())
221  {
222  te::da::ST_EnvelopeIntersects* intersects = new te::da::ST_EnvelopeIntersects(pname, lenv);
223 
224  // The final restriction: original restriction expression + extent restriction
225  te::da::And* andop = new te::da::And(exp, intersects);
226 
227  wh->setExp(andop);
228  }
229  else if(spatialTopOp.find(te::da::FunctionNames::sm_ST_Intersects) != spatialTopOp.end())
230  {
231  te::da::ST_Intersects* intersects = new te::da::ST_Intersects(pname, lenv);
232 
233  // The final restriction: original restriction expression + extent restriction
234  te::da::And* andop = new te::da::And(exp, intersects);
235 
236  wh->setExp(andop);
237  }
238  }
239  else
240  {
241  if(spatialTopOp.find(te::da::FunctionNames::sm_ST_EnvelopeIntersects) != spatialTopOp.end())
242  {
243  te::da::ST_EnvelopeIntersects* intersects = new te::da::ST_EnvelopeIntersects(pname, lenv);
244  wh = new te::da::Where(intersects);
245  }
246  else if(spatialTopOp.find(te::da::FunctionNames::sm_ST_Intersects) != spatialTopOp.end())
247  {
248  te::da::ST_Intersects* intersects = new te::da::ST_Intersects(pname, lenv);
249  wh = new te::da::Where(intersects);
250  }
251  select->setWhere(wh);
252  }
253 
254  return getData(select.get(), travType, accessPolicy);
255 }
256 
257 std::unique_ptr<te::da::DataSet> te::map::QueryLayer::getData(
258  const std::string& /*propertyName*/, const te::gm::Geometry* /*g*/,
260  const te::common::AccessPolicy) const
261 {
262  throw Exception("Not implemented yet!");
263 }
264 
265 std::unique_ptr<te::da::DataSet> te::map::QueryLayer::getData(te::da::Expression* restriction,
266  te::common::TraverseType travType,
267  const te::common::AccessPolicy accessPolicy) const
268 {
269  // The final select
270  std::unique_ptr<te::da::Select> select(static_cast<te::da::Select*>(m_query->clone()));
271 
272  // Original Where
273  te::da::Where* wh = select->getWhere();
274 
275  if(wh != nullptr)
276  {
277  // Original restriction expression
278  te::da::Expression* exp = wh->getExp()->clone();
279 
280  // The final restriction: original restriction expression + the given restriction expression
281  te::da::And* andop = new te::da::And(exp, restriction);
282  wh->setExp(andop);
283  }
284  else
285  {
286  wh = new te::da::Where(restriction);
287  select->setWhere(wh);
288  }
289 
290  return getData(select.get(), travType, accessPolicy);
291 }
292 
293 std::unique_ptr<te::da::DataSet> te::map::QueryLayer::getData(const te::da::ObjectIdSet* oids,
294  te::common::TraverseType travType,
295  const te::common::AccessPolicy accessPolicy) const
296 {
297  // The final select
298  std::unique_ptr<te::da::Select> select(static_cast<te::da::Select*>(m_query->clone()));
299 
300  // Original Where
301  te::da::Where* wh = select->getWhere();
302 
303  if(wh != nullptr)
304  {
305  // Original restriction expression
306  te::da::Expression* exp = wh->getExp()->clone();
307 
308  // The final restriction: original restriction expression + the oids restriction
309  te::da::And* andop = new te::da::And(exp, oids->getExpression());
310  wh->setExp(andop);
311  }
312  else
313  {
314  wh = new te::da::Where(oids->getExpression());
315  select->setWhere(wh);
316  }
317 
318  return getData(select.get(), travType, accessPolicy);
319 }
320 
322 {
323  if(m_query == nullptr)
324  return false;
325 
326  if(m_datasourceId.empty())
327  return false;
328 
330  try
331  {
333  }
334  catch(...)
335  {
336  return false;
337  }
338 
339  if(ds.get() == nullptr || !ds->isValid() || !ds->isOpened())
340  return false;
341 
342  return true;
343 }
344 
345 void te::map::QueryLayer::draw(Canvas* canvas, const te::gm::Envelope& bbox, int srid, const double& scale, bool* cancel)
346 {
347  if(m_rendererType.empty())
348  throw Exception((boost::format(TE_TR("Could not draw the query layer %1%. The renderer type is empty!")) % getTitle()).str());
349 
350  // Try get the defined renderer
351  std::unique_ptr<AbstractRenderer> renderer(RendererFactory::make(m_rendererType));
352  if(renderer.get() == nullptr)
353  throw Exception((boost::format(TE_TR("Could not draw the query layer %1%. The renderer %2% could not be created!")) % getTitle() % m_rendererType).str());
354 
355  renderer->draw(this, canvas, bbox, srid, scale, cancel);
356 }
357 
358 const std::string& te::map::QueryLayer::getType() const
359 {
360  return sm_type;
361 }
362 
364 {
365  return m_query;
366 }
367 
369 {
370  std::string sql;
371 
372  if (m_query)
373  {
375  te::da::SQLVisitor visitor(*ds->getDialect(), sql);
376 
377  try
378  {
379  m_query->accept(visitor);
380  }
381  catch (...)
382  {
383  return "";
384  }
385  }
386 
387  return sql;
388 }
389 
391 {
392  delete m_query;
393 
394  m_query = s;
395 }
396 
397 const std::string& te::map::QueryLayer::getRendererType() const
398 {
399  return m_rendererType;
400 }
401 
402 void te::map::QueryLayer::setRendererType(const std::string& t)
403 {
404  m_rendererType = t;
405 }
406 
408 {
409  if(m_mbr.isValid())
410  return;
411 
412  // Get the associated data source
414 
415  std::unique_ptr<te::da::DataSet> dataset;
416 
417  // Get the dataset
418  dataset = ds->query(m_query);
419  assert(dataset.get());
420 
421  // MBR
422  m_mbr = *dataset->getExtent(te::da::GetFirstPropertyPos(dataset.get(), te::dt::GEOMETRY_TYPE));
423 }
424 
425 std::unique_ptr<te::da::DataSet> te::map::QueryLayer::getData(te::da::Select* query,
426  te::common::TraverseType travType,
427  const te::common::AccessPolicy accessPolicy) const
428 {
430 
431  return ds->query(query, travType, accessPolicy);
432 }
TEDATAACCESSEXPORT DataSourcePtr GetDataSource(const std::string &datasourceId, const bool opened=true)
Search for a data source with the informed id in the DataSourceManager.
const std::string & getName() const
It returns the property name.
std::unique_ptr< LayerSchema > getSchema() const
It returns the layer schema.
Definition: QueryLayer.cpp:103
void add(te::dt::Property *p)
It adds a property to the list of properties of the primary key.
Definition: PrimaryKey.h:123
An abstract class that models a source of data in a query.
Definition: FromItem.h:50
The Field class can be used to model an expression that takes part of the output items of a SELECT...
te::da::Select * m_query
The dataset name where we will retrieve the layer objects.
Definition: QueryLayer.h:165
TEMAPEXPORT void CopyAbstractLayerInfo(const te::map::AbstractLayer *refLayer, te::map::AbstractLayer *layer)
Make a copy of refLayer abstract attributes to layer. Creating new id.
Spatial intersects operator.
Definition: ST_Intersects.h:46
An exception class for the MapTools module.
This is the base class for layers.
Definition: AbstractLayer.h:77
A class that models the name of a dataset used in a From clause.
Definition: DataSetName.h:43
boost::shared_ptr< DataSource > DataSourcePtr
virtual const std::string & getTitle() const
It returns the layer title.
A class that models the name of any property of an object.
Base exception class for plugin module.
A class that models the description of a dataset.
Definition: DataSetType.h:72
static const std::string sm_ST_Intersects
Definition: FunctionNames.h:88
Expression * getExpression() const
It returns the expression set for an output select query.
virtual Expression * clone() const =0
It creates a new copy of this expression.
An abstract factory for layer renderers.
SpatialRelation
Spatial relations between geometric objects.
QueryLayer(AbstractLayer *parent=0)
It initializes a new layer.
Definition: QueryLayer.cpp:63
AbstractLayer * clone()
It returns a clone of the object.
Definition: QueryLayer.cpp:88
A class that represents the known capabilities of a specific data source, i.e. this class informs all...
virtual ReturnType accept(VisitorType &guest) const =0
It call the visit method from the guest object.
A layer resulting from a query.
Definition: QueryLayer.h:50
static te::dt::Date ds(2010, 01, 01)
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:242
virtual Property * clone() const =0
It returns a clone of the object.
const QueryCapabilities & getQueryCapabilities() const
void setDatasetName(const std::string &dsName)
It sets the property name.
Definition: Property.h:154
It models a property definition.
Definition: Property.h:59
Boolean logic operator: AND.
const From * getFrom() const
It returns the list of source information to be used by the query.
Definition: Select.cpp:794
This is an abstract class that models a query expression.
const std::vector< te::dt::Property * > & getProperties() const
It returns the properties that take part of the primary key.
Definition: PrimaryKey.h:109
int m_srid
The identifier of the layer spatial reference system.
void setId(unsigned int id)
It sets the property identifier.
Definition: Property.h:118
AccessPolicy
Supported data access policies (can be used as bitfield).
~QueryLayer()
Destructor.
Definition: QueryLayer.cpp:83
TraverseType
A dataset can be traversed in two ways:
void Tokenize(const std::string &str, std::vector< std::string > &tokens, const std::string &delimiters=" ")
It tokenizes a given string with a delimiter of your own choice.
Definition: StringUtils.h:221
void setRendererType(const std::string &t)
Definition: QueryLayer.cpp:402
void setName(const std::string &name)
It sets the property name.
Definition: Property.h:137
A class that informs the query support of a given data source.
std::unique_ptr< te::da::DataSet > getData(te::common::TraverseType travType=te::common::FORWARDONLY, const te::common::AccessPolicy accessPolicy=te::common::RAccess) const
It gets the dataset identified by the layer name.
Definition: QueryLayer.cpp:184
An operator that considers the intersection among approximations or envelopes of geometries.
An Envelope defines a 2D rectangular region.
const std::string & getAlias() const
It returns the alias associated to the source item.
Definition: FromItem.cpp:47
This class represents a set of unique ids created in the same context. i.e. from the same data set...
Definition: ObjectIdSet.h:55
boost::ptr_vector< Field > Fields
Fields is just a boost::ptr_vector of Field pointers.
Definition: Fields.h:37
te::gm::Envelope m_mbr
The layer bounding box.
A class that can be used to model a filter expression that can be applied to a query.
Definition: Where.h:47
te::gm::Polygon * p
static const std::string sm_ST_EnvelopeIntersects
Definition: FunctionNames.h:84
void setExp(Expression *exp)
Sets the expression.
Definition: Where.cpp:63
Expression * getExp() const
Definition: Where.cpp:58
te::da::Select * getQuery() const
Definition: QueryLayer.cpp:363
const Fields * getFields() const
It returns the list of output expressions used to form the result set.
Definition: Select.cpp:784
A Join clause combines two FromItems.
Definition: Join.h:50
Query * clone() const
It creates a new copy of this query.
Definition: Select.cpp:276
Utility functions for the data access module.
Geometry is the root class of the geometries hierarchy, it follows OGC and ISO standards.
static AbstractRenderer * make(const std::string &factoryKey)
It creates an object with the appropriated factory.
A Select models a query to be used when retrieving data from a DataSource.
Definition: Select.h:65
const std::set< std::string > & getSpatialTopologicOperators() const
void draw(Canvas *canvas, const te::gm::Envelope &bbox, int srid, const double &scale, bool *cancel)
It draws the layer geographic objects in the given canvas using the informed SRS. ...
Definition: QueryLayer.cpp:345
boost::ptr_vector< FromItem > From
It models the FROM clause for a query.
Definition: From.h:37
virtual void select(te::da::ObjectIdSet *oids)
It adds the given oids to the selected group of this Layer.
FromItem * getSecond() const
It returns the second item involved in the join.
Definition: Join.cpp:96
std::string getQueryAsString() const
Definition: QueryLayer.cpp:368
A canvas is an abstraction of a drawing area.
void setQuery(te::da::Select *s)
Definition: QueryLayer.cpp:390
std::string m_datasourceId
DataSource id.
It describes a primary key (pk) constraint.
Definition: PrimaryKey.h:52
A layer resulting from a query.
A class that models a literal for Envelope values.
const std::string & getRendererType() const
Definition: QueryLayer.cpp:397
const std::string & getName() const
It returns the dataset name.
Definition: DataSetName.cpp:55
A visitor for building an SQL statement from a given Query hierarchy.
std::string m_rendererType
A pointer to the internal renderer used to paint this layer.
Definition: QueryLayer.h:164
TEDATAACCESSEXPORT std::size_t GetFirstPropertyPos(const te::da::DataSet *dataset, int datatype)
static const std::string sm_type
A static data member used in the implementation of getType method.
Definition: QueryLayer.h:167
const std::string & getType() const
It returns the layer type: QUERY_LAYER.
Definition: QueryLayer.cpp:358
Expression * getExpression() const
It returns the expression that can be used to retrieve the data set that contains the all indentified...
bool isValid() const
It tells if the rectangle is valid or not.
bool isValid() const
It returns true if the layer can be used for instance to draw, otherwise, it returns false...
Definition: QueryLayer.cpp:321
FromItem * getFirst() const
It returns the first from item involved in the join.
Definition: Join.cpp:86
const std::string & getName() const
It returns the property name.
Definition: Property.h:127