Available: | Confluence 5.9 and later |
The CQL Field Module allows plugins to extend the Confluence Query Language to add additional fields.Field Modules interact with other plugin modules, to produce v2 search queries which map to Lucene queries using a Search Query Mapper Module Lucene Index that has been extracted with an Extractor2 Module.
CQL Field Modules also provide UI support capabilities, allowing fields added by plugins to be presented to users via the UI in components of the application built on top of CQL, for example in the search screen.
Your plugin must depend on the CQL SPI in order to declare CQL fields or functions. Please see the guide Adding a field to CQL for a detailed walkthrough
Here's an example atlassian-plugin.xml
declaring a new CQL field:
1 2<atlassian-plugin name="Sample" key="confluence.cql.sample.field"> ... <cql-query-field fieldName="created" key="created-date-field" name="Created Date CQL Field" class="com.atlassian.confluence.plugins.cql.fields.CreatedDateFieldHandler"> <ui-support value-type="date" i18n-key="cql.field.created" /> </cql-query-field> ... </atlassian-plugin> com.atlassian.querylang.fields.BaseFieldHandler
com.atlassian.querylang.fields.BaseFieldHandler
and implement one of:EqualityFieldHandler
TextFieldHandler
DateTimeFieldHandler
, orNumericFieldHandler
.the ui-support declaration provides information to allow Confluence to render the new field in the UI:
Value Type | Example |
---|---|
contentId | "With Title" Field |
contentType | "Of Type" Field |
date | "Created Date" Field |
label | "Label" Field |
space | "In Space" Field |
user | "Mentioning User" Field |
string | "Status" Field, used in conjuction with a data-uri, see Adding a field to CQL |
The field types determine the syntax of the value and the operations that can be used in an expression. Field handlers must implement at least one of four interfaces, however there are some existing helper classes that provide partial implementation.
Field type | Supported operations | Interface |
---|---|---|
Text | =, !=, IN, NOT IN, ~, !~ | TextFieldHandler |
Equality | =, !=, IN, NOT IN |
|
DateRange | =, !=, >, >=, <, <= | DateTimeFieldHandler |
Number | =, !=, >, >=, <, <= |
|
Here's an example Field Handler implementation.
1 2package com.atlassian.confluence.plugins.cql.fields; import javax.annotation.Nullable; import com.atlassian.confluence.plugins.cql.spi.v2searchhelpers.V2SearchQueryWrapper; import com.atlassian.confluence.plugins.cql.spi.v2searchhelpers.V2SearchSortWrapper; import com.atlassian.confluence.search.lucene.DocumentFieldName; import com.atlassian.confluence.search.v2.BooleanOperator; import com.atlassian.confluence.search.v2.SearchQuery; import com.atlassian.confluence.search.v2.query.TextFieldQuery; import com.atlassian.confluence.search.v2.sort.TitleSort; import com.atlassian.querylang.fields.BaseFieldHandler; import com.atlassian.querylang.fields.EqualityFieldHandler; import com.atlassian.querylang.fields.TextFieldHandler; import com.atlassian.querylang.fields.expressiondata.EqualityExpressionData; import com.atlassian.querylang.fields.expressiondata.SetExpressionData; import com.atlassian.querylang.fields.expressiondata.TextExpressionData; import com.atlassian.querylang.query.FieldOrder; import com.atlassian.querylang.query.OrderDirection; import static com.atlassian.querylang.fields.expressiondata.SetExpressionData.Operator.IN; import static com.atlassian.querylang.fields.expressiondata.SetExpressionData.Operator.NOT_IN; import static com.atlassian.querylang.fields.expressiondata.EqualityExpressionData.Operator.EQUALS; import static com.atlassian.querylang.fields.expressiondata.EqualityExpressionData.Operator.NOT_EQUALS; import static com.atlassian.querylang.fields.expressiondata.TextExpressionData.Operator.CONTAINS; import static com.atlassian.querylang.fields.expressiondata.TextExpressionData.Operator.NOT_CONTAINS; import com.google.common.base.Function; import static com.google.common.collect.Sets.newHashSet; import static com.atlassian.confluence.plugins.cql.spi.v2searchhelpers.V2FieldHandlerHelper.joinSingleValueQueries; import static com.atlassian.confluence.plugins.cql.spi.v2searchhelpers.V2FieldHandlerHelper.wrapV2Search; public class TitleTextFieldHandler extends BaseFieldHandler implements TextFieldHandler<V2SearchQueryWrapper>, EqualityFieldHandler<String, V2SearchQueryWrapper> { private static final String FIELD_NAME = "title"; public TitleTextFieldHandler() { super(FIELD_NAME, true); } @Override public V2SearchQueryWrapper build(TextExpressionData expressionData, String value) { validateSupportedOp(expressionData.getOperator(), newHashSet(CONTAINS, NOT_CONTAINS)); return wrapV2Search(new TextFieldQuery(DocumentFieldName.TITLE, value, BooleanOperator.AND), expressionData); } @Override public FieldOrder buildOrder(OrderDirection direction) { return new V2SearchSortWrapper(new TitleSort(V2SearchSortWrapper.convertOrder(direction))); } @Override public V2SearchQueryWrapper build(SetExpressionData expressionData, Iterable<String> values) { validateSupportedOp(expressionData.getOperator(), newHashSet(IN, NOT_IN)); SearchQuery query = joinSingleValueQueries(values, new Function<String, TextFieldQuery>(){ @Override public TextFieldQuery apply(@Nullable String value) { return createEqualityQuery(value); } }); return wrapV2Search(query, expressionData); } @Override public V2SearchQueryWrapper build(EqualityExpressionData expressionData, String value) { validateSupportedOp(expressionData.getOperator(), newHashSet(EQUALS, NOT_EQUALS)); return wrapV2Search(createEqualityQuery(value), expressionData); } private TextFieldQuery createEqualityQuery(String value) { return new TextFieldQuery(DocumentFieldName.CONTENT_NAME_UNTOKENIZED, "\""+value+"\"", BooleanOperator.AND); } }
Returns the name of the field that this handler handles, this field name will be used in CQL expressions.
Returns true if this field supports being part of an ORDER BY clause. If this is true, the handler must implement the buildOrder method.
Returns a FieldMetaData object describing the CQL field. Metadata includes a flag to indicate if the field is an alias of another field, and if the field has UI support.
Builds and returns a FieldOrder object which is used to sort search results. The FieldOrder object contains the name of the field to which the order applies and an OrderDirection either ascending or descending. If the field does not support ordering, BaseFieldHandler provides an appropriate default implementation.
The BaseFieldHandler class provides a partial FieldHandler implementation from which others should be extended. It implements both the FieldHandler interface as well as the SubFieldHandlerProvider interface which allows for the definition of CQL subfields for example user.fullname = 'Joe Bloggs', user.userkey = 'jbloggs'
The interfaces for each of the field types (Text, Equality, DateTime and Numeric) define a build method which accepts as arguments an ExpressionData object as well as either a single value or Iterable of values. The method returns a V2SearchQueryWrapper object, which as the name suggests, is an object designed to wrap a V2 Search Query and the object and determines which data is queried from the index and returned as CQL search results when a field is used.
Returns the CQL operator used in the query, allowing the FieldHandler to return the appropriate V2 Search Query Wrapped object based on the operator. For example, the CQL query "space = 'MYSPACE'", will yield a result of EQUALS when the EqualityExpressionData.getOperator method is called.
Rate this page: