com.almworks.jira.structure.api.query.StructureQuery Maven / Gradle / Ivy
Show all versions of structure-api Show documentation
package com.almworks.jira.structure.api.query;
import com.almworks.integers.*;
import com.almworks.jira.structure.api.forest.raw.Forest;
import com.almworks.jira.structure.api.settings.StructureConfiguration;
import com.atlassian.annotations.PublicApi;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.util.MessageSet;
import com.atlassian.query.Query;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* A structure query is a condition on rows and their relationships in a {@link Forest}, such as
* rows that are children of issues satisfying JQL 'type = Epic' or
* rows at the top level of the forest.
* An object of class {@code StructureQuery} lets you search for matching rows in a given {@code Forest}.
* It also lets you validate the structure query it represents, returning error messages that you can display
* to the user.
*
* This class is the API counterpart of the {@code structure()} JQL function bundled with the Structure plugin,
* along with the ability to retrieve {@code Structure} objects from {@code StructureManager} and
* structure's {@code Forest} from {@code Structure}.
*
* {@code StructureQuery} is obtained by either {@link StructureQueryParser parsing} the query
* expressed in the StructuredJQL language, or by building it with {@link StructureQueryBuilder}.
* If you have obtained this {@code StructureQuery} by parsing a String, you can get this string back
* via {@link #getQueryString()}. Otherwise, you can use {@code toString()}, which either returns the parsed
* query string or generates a query string if this query was built.
*
* {@code StructureQuery}'s {@code equals()} and {@code hashCode()} provide structural equality:
* if you have a query built by {@code StructureQueryBuilder} and a similar-looking query built by
* {@code StructureQueryParser}, they are equal, if they happen to have equal JQL constraints.
* That is, if you use {@code JqlQueryParser} instead of {@code JqlQueryBuilder} to create JQL {@code Query}
* that you put into {@code StructureQueryBuilder}, the resulting Structure query will be equal to the
* parsed one; this is due to the way Atlassian's {@code Query.equals()} and {@code Query.hashCode()} work.
*
* Note: this class is not thread-safe.
*
* @see StructureQueryParser
* @see StructureQueryBuilder
*
* @since 8.1.0 (Structure 2.4)
*
* @author Igor Baltiyskiy
* */
@PublicApi
public abstract class StructureQuery {
/**
* Validates this {@code StructureQuery} in the current authentication context. The following things are checked:
*
* - Whether all nested JQL constraints are valid, as per {@code SearchService.validateQuery(User, Query).}
*
- Whether referenced items exist and are accessible to the current user.
* - Whether all nested constraints have valid arguments, as per {@link StructureQueryConstraint#validate(List)}.
* - Whether all saved filters (aka search requests) referenced in the nested JQL constraints don't
* reference themselves through the {@code structure()} JQL function.
*
* The resulting human-readable errors and warnings are reported in the returned {@code MessageSet}.
*
*
The result of the validation is remembered, so that validation is not repeated at the execution time.
*
* @return human-readable validation error messages and warnings in the current user's locale;
* if there are no error messages, this query has passed the validation
* @see com.atlassian.jira.bc.issue.search.SearchService#validateQuery(ApplicationUser, Query)
* @see StructureQueryConstraint#validate(List)
* */
@NotNull
public abstract MessageSet validate();
/**
* Returns a string representation of this query, with all the potential "information leaks" removed,
* with regards to the current user.
* @return sanitized string representation of this query
* @see com.atlassian.jira.bc.issue.search.SearchService#sanitiseSearchQuery
* @since 8.5.0 (Structure 2.8)
*/
@NotNull
public abstract String getSanitizedQueryString();
/**
*
Executes this query against the specified {@link Forest}, returning IDs of all matching rows
* in the forest order.
*
* This method observes JIRA and Structure permissions in the following ways:
*
* - Only rows visible to the current user are returned.
* - All JIRA searches for nested JQL constraints are executed under the current user.
*
- If the current user
* {@link StructureConfiguration#getEnabledPermissionSubjects() cannot use Structure},
* an empty list is returned.
*
*
* Prior to execution, validation status is checked. If {@link #validate()} hasn't been called on this
* object before, validation is carried out. If validation fails, returns an empty list.
*
If you are doing administrative tasks under a trusted account, and you need to ensure that you know
* all certain rows in a forest, override security in the current authentication context
* to skip validation and permission checks.
* In this case, this method will not require you to call nor call itself {@link #validate()},
* and all JIRA searches for nested JQL constraints will be executed without permission checks.
*
* @param forest the forest in which to search the rows
* @return the list of IDs of rows matching this query in {@code forest} in the forest order,
* subject to permission restrictions unless security is overridden
* */
@NotNull
public abstract LongArray execute(@NotNull Forest forest);
/**
*
Executes this query against the specified {@link Forest}, returning an iterator over all matching row IDs
* in the forest order.
*
* Behaves the same as {@link #execute(Forest)} with respect to validation and permission checks.
* @param forest the forest in which to search the rows
* @return an iterator over matching row IDs in the forest order,
* subject to permission restrictions unless security is overridden
* */
public abstract LongIterator executeUnbuffered(@NotNull Forest forest);
/**
* Executes this query against the specified {@link Forest}, returning {@link Forest#indexOf indices}
* of all matching rows in the forest order (i.e., the sequence of indices strictly increases.)
*
* Behaves the same as {@link #execute(Forest)} with respect to validation and permission
* checks.
*
* @param forest the forest in which to search the rows
* @return increasing positions of rows in {@code forest} matching this query
* */
@NotNull
public abstract IntArray executeIndices(@NotNull Forest forest);
/**
* Executes this query against the specified {@link Forest}, returning an iterator over {@link Forest#indexOf indices}
* of all matching rows in the forest order (i.e., iterator values strictly increase.)
*
* Behaves the same as {@link #execute(Forest)} with respect to validation and permission
* checks.
*
* @param forest the forest in which to search the rows
* @return an iterator over increasing positions of rows in {@code forest} matching this query
* */
public abstract IntIterator executeIndicesUnbuffered(@NotNull Forest forest);
/**
* Checks if the specified row matches the query against the specified {@link Forest}.
*
* If {@code rowId} is {@code null} or the forest does not contain the row, {@code false} is returned.
*
* Because of possible implementation optimizations, it's better to use this method rather than calling
* {@link #execute(Forest)} and checking if the row ID is contained in the result.
*
* Behaves the same as {@link #execute(Forest)} with respect to validation and permission checks.
* @param rowId ID of the row to check
* @param forest the forest against which the row should be checked
* @return {@code true} if the row matches the query, otherwise {@code false}
*/
public abstract boolean checkRow(Long rowId, @NotNull Forest forest);
/**
* Checks if the row at the given {@link Forest#indexOf index} in the {@link Forest} matches the query.
*
* If {@code index} is out of the forest bounds, {@code false} is returned.
*
* Because of possible implementation optimizations, it's better to use this method rather than calling
* {@link #executeIndices} and checking if the index is contained in the result.
*
* Behaves the same as {@link #execute(Forest)} with respect to validation and permission checks.
* @param index index in the forest
* @param forest the forest for which to check the row at the specified index
* @return {@code true} if the row at the specified index matches the query, otherwise {@code false}
*/
public abstract boolean checkIndex(int index, Forest forest);
/**
* @return If this query was created by {@link StructureQueryParser#parse parsing} a String, returns that String.
* Otherwise, returns {@code null}.
* */
@Nullable
public abstract String getQueryString();
}