QgsSqlExpressionCompiler::Result QgsPostgresExpressionCompiler::compileNode( const QgsExpressionNode *node, QString &result )
{
  switch ( node->nodeType() )
  {
    case QgsExpressionNode::ntFunction:
    {
      const QgsExpressionNodeFunction *n = static_cast<const QgsExpressionNodeFunction *>( node );

      QgsExpressionFunction *fd = QgsExpression::Functions()[n->fnIndex()];
      if ( fd->name() == "$geometry" )
      {
        result = quotedIdentifier( mGeometryColumn );
        return Complete;
      }
#if 0
      /*
       * These methods are tricky
       * QGIS expression versions of these return ellipsoidal measurements
       * based on the project settings, and also convert the result to the
       * units specified in project properties.
       */
      else if ( fd->name() == "$area" )
      {
        result = QStringLiteral( "ST_Area(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
        return Complete;
      }
      else if ( fd->name() == "$length" )
      {
        result = QStringLiteral( "ST_Length(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
        return Complete;
      }
      else if ( fd->name() == "$perimeter" )
      {
        result = QStringLiteral( "ST_Perimeter(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
        return Complete;
      }
      else if ( fd->name() == "$x" )
      {
        result = QStringLiteral( "ST_X(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
        return Complete;
      }
      else if ( fd->name() == "$y" )
      {
        result = QStringLiteral( "ST_Y(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
        return Complete;
      }
#endif
    }

    default:
      return QgsSqlExpressionCompiler::compileNode( node, result );
  }

  return Fail;
}
void QgsCodeEditorExpression::setExpressionContext( const QgsExpressionContext &context )
{
  mVariables.clear();

  const QStringList variableNames = context.filteredVariableNames();
  for ( const QString &var : variableNames )
  {
    mVariables << '@' + var;
  }

  mContextFunctions = context.functionNames();

  mFunctions.clear();

  const int count = QgsExpression::functionCount();
  for ( int i = 0; i < count; i++ )
  {
    QgsExpressionFunction *func = QgsExpression::Functions()[i];
    if ( func->isDeprecated() ) // don't show deprecated functions
      continue;
    if ( func->isContextual() )
    {
      //don't show contextual functions by default - it's up the the QgsExpressionContext
      //object to provide them if supported
      continue;
    }

    QString signature = func->name();
    if ( !signature.startsWith( '$' ) )
    {
      signature += '(';

      QStringList paramNames;
      const auto &parameters = func->parameters();
      for ( const auto &param : parameters )
      {
        paramNames << param.name();
      }

      // No named parameters but there should be parameteres? Show an ellipsis at least
      if ( parameters.isEmpty() && func->params() )
        signature += QChar( 0x2026 );

      signature += paramNames.join( ", " );

      signature += ')';
    }
    mFunctions << signature;
  }

  updateApis();
}