Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsexpressionnode.h 3 : : ------------------- 4 : : begin : May 2017 5 : : copyright : (C) 2017 Matthias Kuhn 6 : : email : matthias@opengis.ch 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : 17 : : #ifndef QGSEXPRESSIONNODE_H 18 : : #define QGSEXPRESSIONNODE_H 19 : : 20 : : #include <QSet> 21 : : #include <QVariant> 22 : : #include <QCoreApplication> 23 : : 24 : : #include "qgis.h" 25 : : 26 : : class QgsExpression; 27 : : class QgsExpressionContext; 28 : : 29 : : /** 30 : : * \ingroup core 31 : : * 32 : : * \brief Abstract base class for all nodes that can appear in an expression. 33 : : */ 34 : 0 : class CORE_EXPORT QgsExpressionNode SIP_ABSTRACT 35 : : { 36 : : 37 : : #ifdef SIP_RUN 38 : : SIP_CONVERT_TO_SUBCLASS_CODE 39 : : switch ( sipCpp->nodeType() ) 40 : : { 41 : : case QgsExpressionNode::ntUnaryOperator: 42 : : sipType = sipType_QgsExpressionNodeUnaryOperator; 43 : : break; 44 : : case QgsExpressionNode::ntBinaryOperator: 45 : : sipType = sipType_QgsExpressionNodeBinaryOperator; 46 : : break; 47 : : case QgsExpressionNode::ntInOperator: 48 : : sipType = sipType_QgsExpressionNodeInOperator; 49 : : break; 50 : : case QgsExpressionNode::ntFunction: 51 : : sipType = sipType_QgsExpressionNodeFunction; 52 : : break; 53 : : case QgsExpressionNode::ntLiteral: 54 : : sipType = sipType_QgsExpressionNodeLiteral; 55 : : break; 56 : : case QgsExpressionNode::ntColumnRef: 57 : : sipType = sipType_QgsExpressionNodeColumnRef; 58 : : break; 59 : : case QgsExpressionNode::ntCondition: 60 : : sipType = sipType_QgsExpressionNodeCondition; 61 : : break; 62 : : default: 63 : : sipType = 0; 64 : : break; 65 : : } 66 : : SIP_END 67 : : #endif 68 : : 69 : 0 : Q_DECLARE_TR_FUNCTIONS( QgsExpressionNode ) 70 : : 71 : : public: 72 : : 73 : : //! Known node types. 74 : : enum NodeType 75 : : { 76 : : ntUnaryOperator, //!< \see QgsExpression::Node::NodeUnaryOperator 77 : : ntBinaryOperator, //!< \see QgsExpression::Node::NodeBinaryOperator 78 : : ntInOperator, //!< \see QgsExpression::Node::NodeInOperator 79 : : ntFunction, //!< \see QgsExpression::Node::NodeFunction 80 : : ntLiteral, //!< \see QgsExpression::Node::NodeLiteral 81 : : ntColumnRef, //!< \see QgsExpression::Node::NodeColumnRef 82 : : ntCondition, //!< \see QgsExpression::Node::NodeCondition 83 : : ntIndexOperator, //!< Index operator 84 : : }; 85 : : 86 : : 87 : : /** 88 : : * \brief Named node 89 : : * \ingroup core 90 : : * \since QGIS 2.16 91 : : */ 92 : 0 : struct NamedNode 93 : : { 94 : : public: 95 : : 96 : : /** 97 : : * Constructor for NamedNode 98 : : * \param name node name 99 : : * \param node node 100 : : */ 101 : 0 : NamedNode( const QString &name, QgsExpressionNode *node ) 102 : 0 : : name( name ) 103 : 0 : , node( node ) 104 : 0 : {} 105 : : 106 : : //! Node name 107 : : QString name; 108 : : 109 : : //! Node 110 : : QgsExpressionNode *node = nullptr; 111 : : }; 112 : : 113 : : /** 114 : : * \brief A list of expression nodes. 115 : : * \ingroup core 116 : : */ 117 : 0 : class CORE_EXPORT NodeList 118 : : { 119 : : public: 120 : : virtual ~NodeList(); 121 : : //! Takes ownership of the provided node 122 : 0 : void append( QgsExpressionNode *node SIP_TRANSFER ) { mList.append( node ); mNameList.append( QString() ); } 123 : : 124 : : /** 125 : : * Adds a named node. Takes ownership of the provided node. 126 : : * \since QGIS 2.16 127 : : */ 128 : : void append( QgsExpressionNode::NamedNode *node SIP_TRANSFER ); 129 : : 130 : : /** 131 : : * Returns the number of nodes in the list. 132 : : */ 133 : 0 : int count() const { return mList.count(); } 134 : : 135 : : /** 136 : : * Returns TRUE if list contains any named nodes 137 : : * \since QGIS 2.16 138 : : */ 139 : 0 : bool hasNamedNodes() const { return mHasNamedNodes; } 140 : : 141 : : /** 142 : : * Gets a list of all the nodes. 143 : : */ 144 : 0 : QList<QgsExpressionNode *> list() { return mList; } 145 : : 146 : : /** 147 : : * Gets the node at position i in the list. 148 : : * 149 : : * \since QGIS 3.0 150 : : */ 151 : 0 : QgsExpressionNode *at( int i ) { return mList.at( i ); } 152 : : 153 : : /** 154 : : * Returns a list of names for nodes. Unnamed nodes will be indicated by an empty string in the list. 155 : : * \since QGIS 2.16 156 : : */ 157 : 0 : QStringList names() const { return mNameList; } 158 : : 159 : : //! Creates a deep copy of this list. Ownership is transferred to the caller 160 : : QgsExpressionNode::NodeList *clone() const SIP_FACTORY; 161 : : 162 : : /** 163 : : * Returns a string dump of the expression node. 164 : : */ 165 : : virtual QString dump() const; 166 : : 167 : : private: 168 : : QList<QgsExpressionNode *> mList; 169 : : QStringList mNameList; 170 : : 171 : 0 : bool mHasNamedNodes = false; 172 : : 173 : : /** 174 : : * Cleans up and standardises the name of a named node. 175 : : */ 176 : : static QString cleanNamedNodeName( const QString &name ); 177 : : 178 : : public: 179 : : }; 180 : : 181 : 0 : virtual ~QgsExpressionNode() = default; 182 : : 183 : : /** 184 : : * Gets the type of this node. 185 : : * 186 : : * \returns The type of this node 187 : : */ 188 : : virtual QgsExpressionNode::NodeType nodeType() const = 0; 189 : : 190 : : /** 191 : : * Dump this node into a serialized (part) of an expression. 192 : : * The returned expression does not necessarily literally match 193 : : * the original expression, it's just guaranteed to behave the same way. 194 : : */ 195 : : virtual QString dump() const = 0; 196 : : 197 : : /** 198 : : * Evaluate this node with the given context and parent. 199 : : * This will return a cached value if it has been determined to be static 200 : : * during the prepare() execution. 201 : : * 202 : : * \since QGIS 2.12 203 : : */ 204 : : QVariant eval( QgsExpression *parent, const QgsExpressionContext *context ); 205 : : 206 : : /** 207 : : * Generate a clone of this node. 208 : : * Ownership is transferred to the caller. 209 : : * 210 : : * \returns a deep copy of this node. 211 : : */ 212 : : virtual QgsExpressionNode *clone() const = 0; 213 : : 214 : : /** 215 : : * Abstract virtual method which returns a list of columns required to 216 : : * evaluate this node. 217 : : * 218 : : * When reimplementing this, you need to return any column that is required to 219 : : * evaluate this node and in addition recursively collect all the columns required 220 : : * to evaluate child nodes. 221 : : * 222 : : * \warning If the expression has been prepared via a call to QgsExpression::prepare(), 223 : : * or a call to QgsExpressionNode::prepare() for a node has been made, then some nodes in 224 : : * the expression may have been determined to evaluate to a static pre-calculatable value. 225 : : * In this case the results will omit attribute indices which are used by these 226 : : * pre-calculated nodes, regardless of their actual referenced columns. 227 : : * If you are seeking to use these functions to introspect an expression you must 228 : : * take care to do this with an unprepared expression node. 229 : : * 230 : : * \returns A list of columns required to evaluate this expression 231 : : */ 232 : : virtual QSet<QString> referencedColumns() const = 0; 233 : : 234 : : /** 235 : : * Returns a set of all variables which are used in this expression. 236 : : * 237 : : * \note In contrast to the referencedColumns() function this method 238 : : * is not affected by any previous calls to QgsExpressionNode::prepare(). 239 : : */ 240 : : virtual QSet<QString> referencedVariables() const = 0; 241 : : 242 : : /** 243 : : * Returns a set of all functions which are used in this expression. 244 : : * 245 : : * \note In contrast to the referencedColumns() function this method 246 : : * is not affected by any previous calls to QgsExpressionNode::prepare(). 247 : : */ 248 : : virtual QSet<QString> referencedFunctions() const = 0; 249 : : 250 : : /** 251 : : * Returns a list of all nodes which are used in this expression. 252 : : * 253 : : * \note not available in Python bindings 254 : : * \since QGIS 3.2 255 : : */ 256 : : virtual QList<const QgsExpressionNode *> nodes( ) const = 0; SIP_SKIP 257 : : 258 : : /** 259 : : * Abstract virtual method which returns if the geometry is required to evaluate 260 : : * this expression. 261 : : * 262 : : * This needs to call `needsGeometry()` recursively on any child nodes. 263 : : * 264 : : * \returns TRUE if a geometry is required to evaluate this expression 265 : : */ 266 : : virtual bool needsGeometry() const = 0; 267 : : 268 : : /** 269 : : * Returns TRUE if this node can be evaluated for a static value. This is used during 270 : : * the prepare() step and in case it returns TRUE, the value of this node will already 271 : : * be evaluated and the result cached (and therefore not re-evaluated in subsequent calls 272 : : * to eval()). In case this returns TRUE, prepareNode() will never be called. 273 : : * 274 : : * \since QGIS 3.0 275 : : */ 276 : : virtual bool isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const = 0; 277 : : 278 : : /** 279 : : * Prepare this node for evaluation. 280 : : * This will check if the node content is static and in this case cache the value. 281 : : * If it's not static it will call prepareNode() to allow the node to do initialization 282 : : * work like for example resolving a column name to an attribute index. 283 : : * 284 : : * \since QGIS 2.12 285 : : */ 286 : : bool prepare( QgsExpression *parent, const QgsExpressionContext *context ); 287 : : 288 : : /** 289 : : * First line in the parser this node was found. 290 : : * \note This might not be complete for all nodes. Currently 291 : : * only \see QgsExpressionNode has this complete 292 : : */ 293 : 0 : int parserFirstLine = 0; 294 : : 295 : : /** 296 : : * First column in the parser this node was found. 297 : : * \note This might not be complete for all nodes. Currently 298 : : * only \see QgsExpressionNode has this complete 299 : : */ 300 : 0 : int parserFirstColumn = 0; 301 : : 302 : : /** 303 : : * Last line in the parser this node was found. 304 : : * \note This might not be complete for all nodes. Currently 305 : : * only \see QgsExpressionNode has this complete 306 : : */ 307 : 0 : int parserLastLine = 0; 308 : : 309 : : /** 310 : : * Last column in the parser this node was found. 311 : : * \note This might not be complete for all nodes. Currently 312 : : * only \see QgsExpressionNode has this complete 313 : : */ 314 : 0 : int parserLastColumn = 0; 315 : : 316 : : /** 317 : : * Returns TRUE if the node can be replaced by a static cached value. 318 : : * 319 : : * \see cachedStaticValue() 320 : : * \since QGIS 3.18 321 : : */ 322 : 0 : bool hasCachedStaticValue() const { return mHasCachedValue; } 323 : : 324 : : /** 325 : : * Returns the node's static cached value. Only valid if hasCachedStaticValue() is TRUE. 326 : : * 327 : : * \see hasCachedStaticValue() 328 : : * \since QGIS 3.18 329 : : */ 330 : 0 : QVariant cachedStaticValue() const { return mCachedStaticValue; } 331 : : 332 : : protected: 333 : : 334 : : /** 335 : : * Copies the members of this node to the node provided in \a target. 336 : : * Needs to be called by all subclasses as part of their clone() implementation. 337 : : * 338 : : * \note Not available in python bindings, QgsExpression::Node is not 339 : : * going to be subclassed from python. If that's what you are looking 340 : : * for, look into writing a custom python expression function. 341 : : * \since QGIS 3.0 342 : : */ 343 : : void cloneTo( QgsExpressionNode *target ) const SIP_SKIP; 344 : : 345 : : #ifndef SIP_RUN 346 : : 347 : : /** 348 : : * TRUE if the node has a static, precalculated value. 349 : : * 350 : : * \since QGIS 3.20 351 : : */ 352 : 0 : mutable bool mHasCachedValue = false; 353 : : 354 : : /** 355 : : * Contains the static, precalculated value for the node if mHasCachedValue is TRUE. 356 : : * 357 : : * \since QGIS 3.20 358 : : */ 359 : : mutable QVariant mCachedStaticValue; 360 : : #endif 361 : : 362 : : private: 363 : : 364 : : /** 365 : : * Abstract virtual preparation method 366 : : * Errors are reported to the parent 367 : : * \since QGIS 3.0 368 : : */ 369 : : virtual bool prepareNode( QgsExpression *parent, const QgsExpressionContext *context ) = 0; 370 : : 371 : : /** 372 : : * Abstract virtual eval method 373 : : * Errors are reported to the parent 374 : : * \since QGIS 3.0 375 : : */ 376 : : virtual QVariant evalNode( QgsExpression *parent, const QgsExpressionContext *context ) = 0; 377 : : 378 : : }; 379 : : 380 : 0 : Q_DECLARE_METATYPE( QgsExpressionNode * ) 381 : : 382 : : #endif // QGSEXPRESSIONNODE_H