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

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root

Avatar

1 badge earned

Collect

Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!

Challenges
Coins

Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.

Recognition
Ribbon

Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!

Leaderboard

Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,556,190
Community Members
 
Community Events
184
Community Groups

Custom JQL Function Not Accepting Null Operand

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.
Apr 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!

@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.
Apr 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?

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

Thank you Jared!

Suggest an answer

Log in or Sign up to answer