Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Custom JQL Function Not Accepting Null Operand

Bellina Bui April 11, 2023

Overview 

Hello Atlassian Community! I'm trying to build a custom JQL function that'll allow the subquery to pass as empty OR run the subquery (operand) that is defined by the user. 

Example:

issueFunction in ademoTest()

issueFunction in ademoTest("reporter = name") 

So far I got the script to work where users do not have to enter a subquery.

private com.atlassian.query.Query mergeQuery(FunctionOperand operand) {

def queryStr = MessageFormat.format(TEMPLATE_QUERY, "")

queryParser.parseQuery(queryStr)

Problem 

However, if I add an if/else statement to allow the subquery to pass as empty OR run a subquery, it does not work. By not work, I mean that it'll require users to query 

issueFunction in admoTest("") 

//Instead of querying the below, which is a better user experience

issueFunction in ademoTest()

My If/Else Statement is below.

Any help is appreciated :) 

 

private com.atlassian.query.Query mergeQuery(FunctionOperand operand) {

def queryStr = MessageFormat.format(TEMPLATE_QUERY, operand.args.first())

def queryStrEmpty = MessageFormat.format(TEMPLATE_QUERY, "")

if (operand != null){

queryParser.parseQuery(queryStr)

} else {

queryParser.parseQuery(queryStrEmpty)

}

Code 

import com.atlassian.jira.bc.issue.search.SearchService

import com.atlassian.jira.component.ComponentAccessor

import com.atlassian.jira.jql.parser.JqlQueryParser

import com.atlassian.jira.jql.query.LuceneQueryBuilder

import com.atlassian.jira.jql.query.QueryCreationContext

import com.atlassian.jira.jql.validator.NumberOfArgumentsValidator

import com.atlassian.jira.user.ApplicationUser

import com.atlassian.jira.util.MessageSet

import com.atlassian.query.clause.TerminalClause

import com.atlassian.query.operand.FunctionOperand

import org.apache.lucene.search.Query

import java.text.MessageFormat

class JqlAliasFunction extends AbstractScriptedJqlFunction implements JqlQueryFunction {

/**

* Modify this query as appropriate.

*

* See {@link java.text.MessageFormat} for details

*/

public static final String TEMPLATE_QUERY =

"project = ADEMO OR project = AWOLBP AND type = Task" // the scope of the query. To use a variable, pass it as {0}

def queryParser = ComponentAccessor.getComponent(JqlQueryParser)

def luceneQueryBuilder = ComponentAccessor.getComponent(LuceneQueryBuilder)

def searchService = ComponentAccessor.getComponent(SearchService)

@Override

String getDescription() {

"Pull in ADEMO and AWOLBP Tasks" // The text that appears next to the value defined in getFunctionName()

}

@Override

MessageSet validate(ApplicationUser user, FunctionOperand operand, TerminalClause terminalClause) {

def messageSet = new NumberOfArgumentsValidator(0, 1, getI18n()).validate(operand)

if (messageSet.hasAnyErrors()) {

return messageSet

}

def query = mergeQuery(operand)

messageSet = searchService.validateQuery(user, query)

messageSet

}

@Override

List<Map> getArguments() {

[

[

description: "Enter Subquery Here",

optional : true,

]

]

}

@Override

String getFunctionName() {

"ademoTest" // this is the named function in the query

}

@Override

Query getQuery(QueryCreationContext queryCreationContext, FunctionOperand operand, TerminalClause terminalClause) {

def query = mergeQuery(operand)

luceneQueryBuilder.createLuceneQuery(queryCreationContext, query.whereClause)

}

private com.atlassian.query.Query mergeQuery(FunctionOperand operand) {

def queryStr = MessageFormat.format(TEMPLATE_QUERY, operand.args.first())

def queryStrEmpty = MessageFormat.format(TEMPLATE_QUERY, "")

if (operand != null){

queryParser.parseQuery(queryStr)

} else {

queryParser.parseQuery(queryStrEmpty)

}

}

}

2 answers

0 votes
Aron Gombas _Midori_
Community Champion
April 11, 2023
private com.atlassian.query.Query mergeQuery(FunctionOperand operand) {

def queryStr = MessageFormat.format(TEMPLATE_QUERY, operand.args.first()) // <-- in this line, you assume that operand is not null!

def queryStrEmpty = MessageFormat.format(TEMPLATE_QUERY, "")

if (operand != null){ // <-- here you expect operand be legally null

queryParser.parseQuery(queryStr)

} else {

queryParser.parseQuery(queryStrEmpty)

}

Without looking very deeply into your code, I can see at least one problem. In the first line you implicitly expect that operand is not null, because you call a method on it.

Then in the "if", you test whether it is null, meaning that you expect it can be null.

The two are conflicting!

Bellina Bui April 27, 2023

@Aron Gombas _Midori_ Correct operand is not null, meaning users can enter in a sub-query. 

Such as issueFunction in platformPG("insert operand") 

 

However, if users do not enter a sub-query they can still run the JQL 

issueFunction in platformPG() 

 

So if it's not null parse the queryStr with the operand and if it's null parse it without it :) 

 

Let me know if I'm misunderstanding your point! thank you!

Aron Gombas _Midori_
Community Champion
April 28, 2023

@Bellina Bui 

If you say that operand can be legally null, then:

def queryStr = MessageFormat.format(TEMPLATE_QUERY, operand.args.first())

should rather be:

def queryStr = MessageFormat.format(TEMPLATE_QUERY, operand ? operand.args.first() : "")

Can you follow me?

0 votes
Jared Kells
Contributor
April 11, 2023

You might have more luck in the developer community: https://community.developer.atlassian.com/c/jira/jira-server/8

Bellina Bui April 17, 2023

Thank you Jared!

Suggest an answer

Log in or Sign up to answer