Just a heads up: On March 24, 2025, starting at 4:30pm CDT / 19:30 UTC, the site will be undergoing scheduled maintenance for a few hours. During this time, the site might be unavailable for a short while. Thanks for your patience.

×
Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

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 Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
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 Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
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