Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Info

This page describes Query API as of midPoint 3.4. Query API for versions up to 3.3 (although maybe a bit out of date) can be found here and here.

Table of Contents

Objects, queries and filters

midPoint works with tree-shaped data structures, just like hierarchical databases do. These structures are called prism objects.They are stored in various places, namely:

...

Each query consists of a filter and a paging instruction. The former says which records (objects, container values) are to be retrieved. The latter says how they are to be sorted and which ones have to be selected (e.g. those with numbers 100-199). Both of these components (filter, paging instruction) are optional.

Filter classification

A filter is either a primitive or complex one.

Primitive filters

Primitive filters are these that do not contain other filters. They are of two categories:

Trivial filters

FilterDescription
None filterPasses no values, i.e. always evaluates to "false".
All filterPasses all values, i.e. always evaluates to "true".
Undefined filter

Treated like nonexistent or invisible filter. For all fiters F1 and F2 the following holds:

F1 && Undefined = F1

F2 || Undefined = F2

Value filters

These filters decide on value(s) of a given property, reference or container.

...

  1. Resource and workflow filters do not support items on the right side of an operator. Only constant values may be present there.
  2. We should probably introduce special kind of Equal filter (named e.g. In filter) to implement the following comparisons:
    1. Equal filter: multivalued left-hand side (LHS) vs. single-valued right-hand-side (RHS)
    2. In filter: multivalued LHS vs. multivalued RHS ("non empty set intersection" semantics)
  3. Interestingly enough, there is an InFilter available now. It is implemented only when searching in the provisioning module. This filter is mapped to ICF EqualsFilter that provides set equality test. (So the filter name does not match its function.) It should probably be removed.
  4. Question is if we should treat querying by ID/OID in the same way as querying by property, i.e. via Equal filter (and, maybe, Greater filter and the like), where ID/OID would be treated as special kind of property. This would eliminate the need for InOid filter; but it might require deeper changes (e.g. there is no itemDefinition for ID/OID, etc). So, at least for midPoint 3.4, querying by ID/OID is done via InOid filter, not Equal filter.
  5. Ref filter and Org filter can specify a relation to be looked for. It is specified as a relation on the reference value passed to the filter. However, for historical reasons, the null relation value is treated differently:
    1. For Ref filter, null relation means default relation. If you need to check for any relation, you have to provide a value of q:any there.
    2. For Org filter, null relation means any relation. Of course, q:any can be used as well (and is recommended for clarity).
  6. The Org filter relation is supported only for the "directChildOf" and "childOf" queries. It is silently ignored for "parentOf" queries. It is interpreted as a relation of the last (lowest) reference in the path, i.e. if we are looking for a user that is a child of org O1 with the relation of manager, we are looking for a user that is a manager of an org O2, which is either O1 itself or is any of its descendants.

Complex filters

Complex filters do contain other filters. They are:

FilterDescription
And, Or, NotBasic logical filters.
Type (type T, filter F)Accepts iff the object is of type T and filter F passes.
Exists (item I, filter F)Accepts iff there exists a value v of item I so that F(v) passes. This is useful e.g. to find an assignment with a given tenantRef and orgRef.

Logical filters

And, Or and Not filters are quite self explanatory.

Type filter

An example: Imagine that the original query asked for an ObjectType. Then it is possible to set up Type filter with type=UserType, filter=(name equals "xyz") to find only users with the name of "xyz":

Code Block
languagexml
titleExample
<type>
  <type>UserType</type>
  <filter>
    <equal>
      <path>name</path>
      <value>xyz</value>
    </equal>
  </filter>
</type>

Exists filter

First of all, how should be individual value filters evaluated?

...

This feature is a part of midPoint 3.4 and above.

Differences in filter interpretation

There are actually four "query engines" that interpret filters and queries:

...

For authoritative information, see FilterInterpreter and related classes (provisioning); and WorkItemProvider class (workflows).

Creating filters

Filters can be created using Java API (traditional or fluent one) or via XML.

The following samples are taken from TestQueryConvertor class. XML versions are in files named test*.xml in this directory.

Primitive filters

AllFilter

Code Block
languagexml
titleXML
<all/>

...

To be concise, we'll show only filters (no wrapping queries) in the following examples.

Value filters

EqualFilter

Code Block
languagexml
titleXML
<equal>
    <matching>polyStringOrig</matching>
    <path>c:name</path>
    <value>some-name</value>
</equal>

...

Code Block
languagejava
titleFluent Java API
ObjectFilter filter = QueryBuilder.queryFor(UserType.class, prismContext)
      .item(UserType.F_EMPLOYEE_NUMBER).eq().item(UserType.F_COST_CENTER)
      .buildFilter();

Comparisons

Code Block
languagexml
titleXML
<greater>
    <path>c:costCenter</path>
    <value>100000</value>
</greater>

...

Code Block
languagejava
titleFluent Java API
ObjectFilter filter = QueryBuilder.queryFor(UserType.class, prismContext)
      .item(UserType.F_COST_CENTER).gt("100000")
          .and().item(UserType.F_COST_CENTER).lt("999999")
      .or()
      .item(UserType.F_COST_CENTER).ge("X100")
          .and().item(UserType.F_COST_CENTER).le("X999")
      .buildFilter();

Substring filter

Code Block
languagexml
titleXML
<or>
    <substring>
        <path>c:employeeType</path>
        <value>A</value>
    </substring>
    <substring>
        <path>c:employeeType</path>
        <value>B</value>
        <anchorStart>true</anchorStart>
    </substring>
    <substring>
        <path>c:employeeType</path>
        <value>C</value>
        <anchorEnd>true</anchorEnd>
    </substring>
    <substring>
        <matching>polyStringOrig</matching>
        <path>c:name</path>
        <value>john</value>
        <anchorStart>true</anchorStart>
    </substring>
</or>

...

Code Block
languagejava
titleFluent Java API
ObjectFilter filter = QueryBuilder.queryFor(UserType.class, prismContext)
      .item(UserType.F_EMPLOYEE_TYPE).contains("A")
      .or().item(UserType.F_EMPLOYEE_TYPE).startsWith("B")
      .or().item(UserType.F_EMPLOYEE_TYPE).endsWith("C")
      .or().item(UserType.F_NAME).startsWithPoly("john", "john").matchingOrig()
      .buildFilter();

Ref filter

"Canonical" form is the following:

...

Code Block
<or>
    <ref>
        <path>c:resourceRef</path>
        <value oid="oid1" />               		<!-- no xsi:type for 'value' element (this is not compliant with query-3 XSD) -->
    </ref>
    <ref>
        <path>c:resourceRef</path>
        <value>                                         <!-- no xsi:type, items stored as elements -->
            <c:oid>oid4</c:oid>
            <c:type>c:ResourceType</c:type>
        </value>
    </ref>
</or>

Org filter

Code Block
languagexml
titleXML
<org>
    <isRoot>true</isRoot>
</org>

...

Code Block
languagejava
titleFluent Java API
ObjectFilter filter = QueryBuilder.queryFor(OrgType.class, prismContext).isDirectChildOf("12345678-1234-1234-1234-0123456789abcd").buildFilter();

InOid

Code Block
languagexml
titleXML
<inOid>
    <value>00000000-1111-2222-3333-444444444444</value>
    <value>00000000-1111-2222-3333-555555555555</value>
    <value>00000000-1111-2222-3333-666666666666</value>
</inOid>

...

Code Block
languagejava
titleFluent Java API
ObjectFilter filter = QueryBuilder.queryFor(UserType.class, getPrismContext())
      .id(1, 2, 3)
      .and().ownerId("00000000-1111-2222-3333-777777777777")
      .buildFilter();

Logical filters

An artificial example:

Code Block
languagexml
titleXML
<and>
    <or>
        <all/>
        <none/>
        <undefined/>
    </or>
    <none/>
    <not>
        <and>
            <all/>
            <undefined/>
        </and>
    </not>
</and>

...

Code Block
languagejava
titleFluent Java API
ObjectFilter filter = QueryBuilder.queryFor(UserType.class, getPrismContext())
      .block()
         .all()
         .or().none()
         .or().undefined()
      .endBlock()
      .and().none()
      .and()
         .not()
            .block()
               .all()
               .and().undefined()
            .endBlock()
      .buildFilter();

Type filter

Code Block
languagexml
titleXML
<type>
    <type>c:UserType</type>
    <filter>
        <equal>
            <path>c:name</path>
            <value>somename</value>
        </equal>
    </filter>
</type>

...

Code Block
languagejava
titleFluent Java API
ObjectFilter filter = QueryBuilder.queryFor(ObjectType.class, getPrismContext())
      .type(UserType.class)
         .item(UserType.F_NAME).eqPoly("somename", "somename")
      .buildFilter();

Exists filter

An example: Find all certification cases that have at least one missing response for a given reviewer.

...

Code Block
ObjectFilter filter = QueryBuilder.queryFor(AccessCertificationCaseType.class, prismContext)
        .exists(AccessCertificationCaseType.F_DECISION)
        .block()
            .item(AccessCertificationDecisionType.F_REVIEWER_REF).ref("123456")
            .and().item(AccessCertificationDecisionType.F_STAGE_NUMBER).eq().item(PrismConstants.T_PARENT, AccessCertificationCaseType.F_CURRENT_STAGE_NUMBER)
            .and().block()
                .item(AccessCertificationDecisionType.F_RESPONSE).isNull()
                .or().item(AccessCertificationDecisionType.F_RESPONSE).eq(NO_RESPONSE)
            .endBlock()
        .endBlock()
        .buildFilter();

Expression filter

Code Block
languagexml
titleXML
<substring>
	<matching>polyStringNorm</matching>
	<path>name</path>
	<expression>
		<script>
			<code>
				return 'C';
			</code>
		</script>
	</expression>
	<anchorStart>true</anchorStart>
</substring>

This example returns all objects with a name starting with "C".

Date filtering

Code Block
languagexml
titleXML
<and>
	<greater>
		<path>extension/EndDate</path>
		<expression>
			<script>
				<code>
					return basic.parseDateTime('yyyy-MM-dd', (basic.currentDateTime().getYear()-1) + '-12-31');
				</code>
			</script>
		</expression>
	</greater>
	<less>
		<path>extension/EndDate</path>
		<expression>
			<script>
				<code>
					return basic.parseDateTime('yyyy-MM-dd', basic.currentDateTime().getYear() + '-01-02');
				</code>
			</script>
		</expression>
	</less>
</and>

This example returns all objects with extension attribute "EndDate" (type of XMLGregorianCalendar), which is set since 31 Decenber last year to 01 January of this year.

Paging

TODO

Special symbols in item paths ("..", "@", "#")

TODO

An example: Find all active certification cases for a given reviewer.

...