Skip to content

Commit

Permalink
Expressions: support for visitor pattern, expresion->OGCFilter now a …
Browse files Browse the repository at this point in the history
…visitor
  • Loading branch information
wonder-sk committed Jan 6, 2012
1 parent 9509999 commit 06e3c72
Show file tree
Hide file tree
Showing 8 changed files with 413 additions and 111 deletions.
231 changes: 224 additions & 7 deletions python/core/qgsexpression.sip
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,231 @@ public:
//! (used by internal functions)
QgsDistanceArea* geomCalculator();

//
//

// tells whether the identifier is a name of existing function
static bool isFunctionName( QString name );
enum UnaryOperator
{
uoNot,
uoMinus,
};
enum BinaryOperator
{
// logical
boOr,
boAnd,

// return index of the function in BuiltinFunctions array
static int functionIndex( QString name );
// comparison
boEQ, // =
boNE, // <>
boLE, // <=
boGE, // >=
boLT, // <
boGT, // >
boRegexp,
boLike,
boILike,
boIs,
boIsNot,

// math
boPlus,
boMinus,
boMul,
boDiv,
boMod,
boPow,

// strings
boConcat,
};


struct FunctionDef /NoDefaultCtors/
{
//FunctionDef( QString fnname, int params, FcnEval fcn, QString group, QString helpText = QString(), bool usesGeometry = false );
/** The name of the function. */
QString mName;
/** The number of parameters this function takes. */
int mParams;
/** Pointer to fucntion. */
//FcnEval mFcn;
/** Does this function use a geometry object. */
bool mUsesGeometry;
/** The group the function belongs to. */
QString mGroup;
/** The help text for the function. */
QString mHelpText;
};

static const QList<QgsExpression::FunctionDef> &BuiltinFunctions();

// tells whether the identifier is a name of existing function
static bool isFunctionName( QString name );

// return index of the function in BuiltinFunctions array
static int functionIndex( QString name );

/** Returns the number of functions defined in the parser
* @return The number of function defined in the parser.
*/
static int functionCount();

//! return quoted column reference (in double quotes)
static QString quotedColumnRef( QString name );

//////

class Node
{
public:
virtual ~Node();
// abstract virtual eval function
// errors are reported to the parent
virtual QVariant eval( QgsExpression* parent, QgsFeature* f ) = 0;

// abstract virtual preparation function
// errors are reported to the parent
virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields ) = 0;

virtual QString dump() const = 0;

virtual QStringList referencedColumns() const = 0;
virtual bool needsGeometry() const = 0;

// support for visitor pattern
virtual void accept( QgsExpression::Visitor& v ) = 0;
};

class NodeList
{
public:
NodeList();
~NodeList();
void append( QgsExpression::Node* node );
int count();
QList<QgsExpression::Node*> list();

virtual QString dump() const;
};

class NodeUnaryOperator : QgsExpression::Node
{
public:
NodeUnaryOperator( QgsExpression::UnaryOperator op, QgsExpression::Node* operand );
~NodeUnaryOperator();

QgsExpression::UnaryOperator op();
QgsExpression::Node* operand();

virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;
virtual QStringList referencedColumns() const;
virtual bool needsGeometry() const;
virtual void accept( QgsExpression::Visitor& v );
};

class NodeBinaryOperator : QgsExpression::Node
{
public:
NodeBinaryOperator( QgsExpression::BinaryOperator op, QgsExpression::Node* opLeft, QgsExpression::Node* opRight );
~NodeBinaryOperator();

QgsExpression::BinaryOperator op();
QgsExpression::Node* opLeft();
QgsExpression::Node* opRight();

virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;
virtual QStringList referencedColumns() const;
virtual bool needsGeometry() const;
virtual void accept( QgsExpression::Visitor& v );
};

class NodeInOperator : QgsExpression::Node
{
public:
NodeInOperator( QgsExpression::Node* node, QgsExpression::NodeList* list, bool notin = false );
~NodeInOperator();

QgsExpression::Node* node();
bool isNotIn();
QgsExpression::NodeList* list();

virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;
virtual QStringList referencedColumns() const;
virtual bool needsGeometry() const;
virtual void accept( QgsExpression::Visitor& v );
};

class NodeFunction : QgsExpression::Node
{
public:
NodeFunction( int fnIndex, QgsExpression::NodeList* args );
//NodeFunction( QString name, QgsExpression::NodeList* args );
~NodeFunction();

int fnIndex();
QgsExpression::NodeList* args();

virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;
virtual QStringList referencedColumns() const;
virtual bool needsGeometry() const;
virtual void accept( QgsExpression::Visitor& v );
};

class NodeLiteral : QgsExpression::Node
{
public:
NodeLiteral( QVariant value );

QVariant value();

virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;
virtual QStringList referencedColumns() const;
virtual bool needsGeometry() const;
virtual void accept( QgsExpression::Visitor& v );
};

class NodeColumnRef : QgsExpression::Node
{
public:
NodeColumnRef( QString name );

QString name();

virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;
virtual QStringList referencedColumns() const;
virtual bool needsGeometry() const;
virtual void accept( QgsExpression::Visitor& v );
};

//////

/** support for visitor pattern - algorithms dealing with the expressions
may be implemented without modifying the Node classes */
class Visitor
{
public:
virtual ~Visitor();
virtual void visit( QgsExpression::NodeUnaryOperator* n ) = 0;
virtual void visit( QgsExpression::NodeBinaryOperator* n ) = 0;
virtual void visit( QgsExpression::NodeInOperator* n ) = 0;
virtual void visit( QgsExpression::NodeFunction* n ) = 0;
virtual void visit( QgsExpression::NodeLiteral* n ) = 0;
virtual void visit( QgsExpression::NodeColumnRef* n ) = 0;
};

/** entry function for the visitor pattern */
void acceptVisitor( QgsExpression::Visitor& v );

//! return quoted column reference (in double quotes)
static QString quotedColumnRef( QString name );
};
100 changes: 6 additions & 94 deletions src/core/qgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,12 @@ QString QgsExpression::dump() const
return mRootNode->dump();
}

void QgsExpression::acceptVisitor( QgsExpression::Visitor& v )
{
if ( mRootNode )
mRootNode->accept( v );
}


///////////////////////////////////////////////
// nodes
Expand Down Expand Up @@ -969,97 +975,3 @@ QString QgsExpression::NodeColumnRef::dump() const
{
return mName;
}

bool QgsExpression::toOGCFilter( QDomDocument& doc ) const
{
if ( !mRootNode )
{
return false;
}

doc.clear();
QDomElement filterElem = doc.createElement( "Filter" );
doc.appendChild( filterElem );
return mRootNode->toOGCFilter( doc, filterElem );
}

bool QgsExpression::NodeBinaryOperator::toOGCFilter( QDomDocument& doc, QDomElement& parent ) const
{
QDomElement opElem;
switch ( mOp )
{
case boEQ:
opElem = doc.createElement( "PropertyIsEqualTo" );
break;
case boNE:
opElem = doc.createElement( "PropertyIsNotEqualTo" );
break;
case boLE:
opElem = doc.createElement( "PropertyIsLessThanOrEqualTo" );
break;
case boGE:
opElem = doc.createElement( "PropertyIsLessThanOrEqualTo" );
break;
case boLT:
opElem = doc.createElement( "PropertyIsLessThan" );
break;
case boGT:
opElem = doc.createElement( "PropertyIsGreaterThan" );
break;
case boOr:
opElem = doc.createElement( "Or" );
break;
case boAnd:
opElem = doc.createElement( "And" );
break;
default:
return false;
}

if ( mOpLeft )
{
mOpLeft->toOGCFilter( doc, opElem );
}
if ( mOpRight )
{
mOpRight->toOGCFilter( doc, opElem );
}

parent.appendChild( opElem );
return true;
}

bool QgsExpression::NodeLiteral::toOGCFilter( QDomDocument& doc, QDomElement& parent ) const
{
QDomElement literalElem = doc.createElement( "Literal" );
QDomText literalText = doc.createTextNode( mValue.toString() );
literalElem.appendChild( literalText );
parent.appendChild( literalElem );
return true;
}

bool QgsExpression::NodeColumnRef::toOGCFilter( QDomDocument& doc, QDomElement& parent ) const
{
QDomElement propertyElem = doc.createElement( "PropertyName" );
QDomText propertyText = doc.createTextNode( mName );
propertyElem.appendChild( propertyText );
parent.appendChild( propertyElem );
return true;
}

bool QgsExpression::NodeUnaryOperator::toOGCFilter( QDomDocument& doc, QDomElement& parent ) const
{
if ( mOp == uoNot )
{
QDomElement notElem = doc.createElement( "Not" );
if ( mOperand )
{
if ( mOperand->toOGCFilter( doc, notElem ) )
{
parent.appendChild( notElem );
return true;
}
}
}
return false;
}
Loading

0 comments on commit 06e3c72

Please sign in to comment.