Custom query instance nodes specification

TypeScript type: CustomQueryInstanceNodesSpecification.

Returns nodes for instances returned by a provided ECSQL query.

Attributes

Name Required? Type Default
Filtering
queries No QuerySpecification[] []
hideNodesInHierarchy No boolean false
hideIfNoChildren No boolean false
hideExpression No ECExpression ""
suppressSimilarAncestorsCheck No boolean false
Ordering
priority No number 1000
doNotSort No boolean false
Grouping
groupByClass No boolean true
groupByLabel No boolean true
Misc.
hasChildren No "Always" | "Never" | "Unknown" "Unknown"
relatedInstances No RelatedInstanceSpecification[] []
nestedRules No ChildNodeRule[] []

Attribute: queries

Specifications of queries used to create the content. Query specifications define the actual results of the specification. There are 2 types of supported query specifications:

The queries used in the specifications must return ECClassId and ECInstanceId columns, e.g.:

SELECT e.ECClassId, e.ECInstanceId FROM bis.Element e WHERE e.Parent.Id = 0x123

Note: sorting and grouping happens after results of multiple query specifications are aggregated.

Type QuerySpecification[]
Is Required No
Default Value []

String query specification

The specification contains an ECSQL query which is used to query for instances.

Name Required? Type Meaning
query Yes string Specifies the search ECSQL query.
class Yes SingleSchemaClassSpecification Specification of ECClass whose instances the query returns. The specification may also point to a base class of instances returned by the query. If the query returns instances that are not of this class, they aren't included in the result set.
// The ruleset has a root nodes' specification that uses a given query to get all `bis.Model` instances.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "CustomQueryInstanceNodes",
          queries: [
            {
              specType: "String",
              class: { schemaName: "BisCore", className: "Model" },
              query: `SELECT * FROM bis.Model`,
            },
          ],
        },
      ],
    },
  ],
};

Example of using string query specification in "queries" attribute

ECProperty value query specification

The specification specifies the name of the parent node instance property whose value is the ECSQL used to query for instances.

Precondition: can be used only if parent node is ECInstance node. If there is no immediate parent instance node, the rules engine walks up the hierarchy until it finds one. If that fails, this specification has no effect.

Name Required? Type Meaning
parentPropertyName Yes string Specifies name of the parent instance property whose value contains the ECSQL query. Warning: the property whose name is specified must be of string type.
class Yes SingleSchemaClassSpecification Specification of ECClass whose instances the query returns. The specification may also point to a base class of instances returned by the query. If the query returns instances that are not of this class, they aren't included in the result set.
// The ruleset has a root nodes' specification that returns `MyDomain.MyParentElement` nodes. It also has
// a children specification that returns `MyDomain.MyChildElement` children for `MyDomain.MyParentElement`
// parent nodes using `ChildrenQuery` property value of the parent element.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: { schemaName: "MyDomain", classNames: ["MyParentElement"], arePolymorphic: true },
          groupByClass: false,
        },
      ],
    },
    {
      ruleType: "ChildNodes",
      condition: `ParentNode.IsOfClass("MyParentElement", "MyDomain")`,
      specifications: [
        {
          specType: "CustomQueryInstanceNodes",
          queries: [
            {
              specType: "ECPropertyValue",
              class: { schemaName: "MyDomain", className: "MyChildElement" },
              parentPropertyName: "ChildrenQuery",
            },
          ],
        },
      ],
    },
  ],
};

Attribute: hideNodesInHierarchy

When true, instances nodes produced by this specification are omitted and their children appear one hierarchy level higher. Note: only instance nodes are hidden - grouping nodes are not affected by this attribute.

Type boolean
Is Required No
Default Value false
// The ruleset contains a root node specification for `bis.PhysicalModel` nodes which are grouped by class and hidden. This
// means class grouping nodes are displayed, but instance nodes are hidden and instead their children are displayed. The
// children are determined by another rule.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: { schemaName: "BisCore", classNames: ["PhysicalModel"], arePolymorphic: true },
          hideNodesInHierarchy: true,
        },
      ],
    },
    {
      ruleType: "ChildNodes",
      specifications: [
        {
          specType: "CustomNode",
          type: "child",
          label: "Child",
        },
      ],
    },
  ],
};
hideNodesInHierarchy: false hideNodesInHierarchy: true
Example of using "hide nodes in hierarchy" attribute set to "false" Example of using "hide nodes in hierarchy" attribute set to "true"

Attribute: hideIfNoChildren

Specifies whether nodes created through this specification should be hidden if they have no child nodes.

Type boolean
Is Required No
Default Value false
// The ruleset contains root node specifications for two custom nodes which are only
// displayed if they have children. One of them has children and the other - not, so
// only one of them is displayed
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "CustomNode",
          type: "2d",
          label: "2d Elements",
          hideIfNoChildren: true,
        },
        {
          specType: "CustomNode",
          type: "3d",
          label: "3d Elements",
          hideIfNoChildren: true,
        },
      ],
    },
    {
      ruleType: "ChildNodes",
      condition: `ParentNode.Type = "2d"`,
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: { schemaName: "BisCore", classNames: ["GeometricElement2d"], arePolymorphic: true },
        },
      ],
    },
    {
      ruleType: "ChildNodes",
      condition: `ParentNode.Type = "3d"`,
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: { schemaName: "BisCore", classNames: ["GeometricElement3d"], arePolymorphic: true },
        },
      ],
    },
  ],
};
hideIfNoChildren: false hideIfNoChildren: true
Example of using "hide if no children" attribute set to "false" Example of using "hide if no children" attribute set to "true"

Attribute: hideExpression

When specified ECExpression evaluates to true, nodes produced by this specification are omitted and their children appear one hierarchy level higher.

Type ECExpression
Is Required No
Default Value ""
// The ruleset contains root node specifications for two custom nodes which are only
// displayed if they have children. One of them has children and the other - not, so
// only one of them is displayed
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "CustomNode",
          type: "2d",
          label: "2d Elements",
          hideExpression: `ThisNode.HasChildren = FALSE`,
        },
        {
          specType: "CustomNode",
          type: "3d",
          label: "3d Elements",
          hideExpression: `ThisNode.HasChildren = FALSE`,
        },
      ],
    },
    {
      ruleType: "ChildNodes",
      condition: `ParentNode.Type = "2d"`,
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: { schemaName: "BisCore", classNames: ["GeometricElement2d"], arePolymorphic: true },
        },
      ],
    },
    {
      ruleType: "ChildNodes",
      condition: `ParentNode.Type = "3d"`,
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: { schemaName: "BisCore", classNames: ["GeometricElement3d"], arePolymorphic: true },
        },
      ],
    },
  ],
};
hideExpression evaluates to false hideExpression evaluates to true
Example of using "hide expression" attribute evaluating to "false" Example of using "hide expression" attribute evaluating to "true"

Attribute: suppressSimilarAncestorsCheck

Specifies whether similar ancestor nodes' checking should be suppressed when creating nodes based on this specification. See more in Infinite Hierarchies Prevention page.

Type boolean
Is Required No
Default Value false
// The ruleset contains a root node specification that returns the root `bis.Subject` node. Also, there are two
// child node rules:
// - For any `bis.Model` node, return its contained `bis.Element` nodes.
// - For any `bis.Element` node, return its children `bis.Model` nodes.
// Children of the root `bis.Subject` are all in the single `bis.RepositoryModel` and some of their children are in the same
// `bis.RepositoryModel` as their parent. This means the `bis.RepositoryModel` node has to be repeated in the hierarchy, but
// that wouldn't happen due to duplicate nodes prevention, unless the `suppressSimilarAncestorsCheck` flag is set.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: { schemaName: "BisCore", classNames: ["Subject"] },
          instanceFilter: `this.ECInstanceId = 1`,
          groupByClass: false,
          groupByLabel: false,
        },
      ],
    },
    {
      ruleType: "ChildNodes",
      condition: `ParentNode.IsOfClass("Model", "BisCore")`,
      specifications: [
        {
          specType: "RelatedInstanceNodes",
          relationshipPaths: [
            {
              relationship: { schemaName: "BisCore", className: "ModelContainsElements" },
              direction: "Forward",
            },
          ],
          groupByClass: false,
          groupByLabel: false,
        },
      ],
    },
    {
      ruleType: "ChildNodes",
      condition: `ParentNode.IsOfClass("Element", "BisCore")`,
      specifications: [
        {
          specType: "RelatedInstanceNodes",
          relationshipPaths: [
            [
              {
                relationship: { schemaName: "BisCore", className: "ElementOwnsChildElements" },
                direction: "Forward",
              },
              {
                relationship: { schemaName: "BisCore", className: "ModelContainsElements" },
                direction: "Backward",
              },
            ],
          ],
          suppressSimilarAncestorsCheck: true,
          groupByClass: false,
          groupByLabel: false,
        },
      ],
    },
  ],
};

Example of using "suppress similar ancestors check" attribute

Attribute: priority

Controls the order in which specifications are handled — specification with higher priority value is handled first. If priorities are equal, the specifications are handled in the order they appear in the ruleset.

Type number
Is Required No
Default Value 1000
// This ruleset produces a list of `bis.PhysicalModel` and `bis.SpatialCategory` instances and groups them by
// class. "Spatial Category" group will appear first because it has been given a higher priority value.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          priority: 1,
          classes: { schemaName: "BisCore", classNames: ["PhysicalModel"], arePolymorphic: true },
        },
        {
          specType: "InstanceNodesOfSpecificClasses",
          priority: 2,
          classes: { schemaName: "BisCore", classNames: ["SpatialCategory"], arePolymorphic: true },
        },
      ],
    },
  ],
};

Example of using "priority" attribute

Attribute: doNotSort

By default, nodes are sorted by their display label. This attribute allows suppressing sorting of nodes returned by this specification, which can substantially improve performance when large numbers of nodes are involved. With this attribute set to true, the order of returned nodes is undefined.

Type boolean
Is Required No
Default Value false
// The ruleset has a specification that returns unsorted `bis.Model` nodes - the order is undefined.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: [{ schemaName: "BisCore", classNames: ["Model"], arePolymorphic: true }],
          doNotSort: true,
        },
      ],
    },
  ],
};

Example of using "do not sort" attribute

Attribute: groupByClass

Controls whether returned instances should be grouped by ECClass.

Type boolean
Is Required No
Default Value true
// The ruleset contains a specification that returns `bis.Model` nodes without grouping them
// by class.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: [{ schemaName: "BisCore", classNames: ["Model"], arePolymorphic: true }],
          groupByClass: false,
        },
      ],
    },
  ],
};
groupByClass: false groupByClass: true
Example of using "group by class" attribute set to "false" Example of using "group by class" attribute set to "true"

Attribute: groupByLabel

Controls whether returned instances should be grouped by label.

Label grouping node is created only if all of these conditions match:

  • There are at least two nodes with the same label.
  • There's at least one sibling node with a different label.
Type boolean
Is Required No
Default Value true
// The ruleset contains a specification that returns `meta.ECPropertyDef` nodes without grouping them
// by label.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: [{ schemaName: "ECDbMeta", classNames: ["ECPropertyDef"] }],
          groupByLabel: false,
        },
      ],
    },
  ],
};
groupByLabel: false groupByLabel: true
Example of using "group by label" attribute set to "false" Example of using "group by label" attribute set to "true"

Attribute: hasChildren

Generally, when a node is created, the rules engine has to determine whether it has children before returning it. This requires evaluating child node rules and, usually, executing additional queries. This attribute allows telling the engine that nodes created by this specification always or never have children, which may substantially improve performance of creating nodes in cases when getting child nodes is expensive.

In case when the attribute value "lies":

  • When set to Always, the returned nodes always have hasChildren flag set to true. Requesting children for such nodes returns empty list. It's up to the UI component to handle the case of parent node saying it has children but data source not returning any.

  • When set to Never, the returned nodes always have hasChildren set to false. Requesting children for such nodes returns empty list even if there are child node rules that define children for it.

Type "Always" | "Never" | "Unknown"
Is Required No
Default Value "Unknown"
// This ruleset produces a hierarchy of a single root node that hosts a list of `Model` instances. Assuming all
// iModels contain at least one model, the result of this ruleset can be computed quicker by setting
// `hasChildren` attribute to `"Always"`.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "CustomNode",
          type: "T_ROOT_NODE",
          label: "My Root Node",
          hasChildren: "Always",
        },
      ],
    },
    {
      ruleType: "ChildNodes",
      condition: `ParentNode.Type="T_ROOT_NODE"`,
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: [{ schemaName: "BisCore", classNames: ["Model"], arePolymorphic: true }],
        },
      ],
    },
  ],
};
hasChildren: "Always" hasChildren: "Never"
Example of using "has children" attribute set to "always" Example of using "has children" attribute set to "never"

Attribute: relatedInstances

Specifications of related instances that can be used when creating the nodes. There are several use cases when this is useful:

  • When there's a need to only load instances that have a related instance. Providing a related instance specification with isRequired set to true filters-out the instances that don't have the related instance.

  • When there's a need to filter instances by a related instance value. The alias attribute may then be used in the instanceFilter attribute to reference related instance property values.

  • When there's a need to group by related instance property values. Related instance classes are included when looking for grouping rules, which allows using related instance values for property grouping.

  • When there's a need to customize nodes based on related instance property values. Related instance classes are included when looking for customization rules, which allows referencing related instances and their properties in customization rule ECExpressions by their alias.

Type RelatedInstanceSpecification[]
Is Required No
Default Value []
// The ruleset contains a root nodes' specification that returns nodes for `bis.Elements` that are in
// a category containing "a" in either `UserLabel` or `CodeValue` property.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: [{ schemaName: "BisCore", classNames: ["GeometricElement3d"], arePolymorphic: true }],
          relatedInstances: [
            {
              relationshipPath: [
                {
                  relationship: { schemaName: "BisCore", className: "GeometricElement3dIsInCategory" },
                  direction: "Forward",
                },
              ],
              alias: "category",
              isRequired: true,
            },
          ],
          instanceFilter: `category.UserLabel ~ "%a%" OR category.CodeValue ~ "%a%"`,
        },
      ],
    },
  ],
};

Example of using "related instances" attribute

Attribute: nestedRules

Specifications of nested child node rules that allow creating child nodes without the need of supplying a condition to match the parent node.

This is useful when the same instance node at different hierarchy levels needs to have different child nodes. Specifying a child node rule at the root level with condition to match the instance ECClass makes the rule create children for all nodes of that ECClass. When that's not desired, different child node rules may be specified as nested rules for specifications that return instance nodes of the same ECClass - that makes them have different children.

Type ChildNodeRule[]
Is Required No
Default Value []
// The ruleset contains two root nodes' specifications:
// - The first one returns `bis.SpatialCategory` nodes
// - The second one returns `bis.PhysicalModel` nodes and also has a nested child node rule
//   that creates a static "child" node.
// Nested rules apply only to nodes created by the same specification, so the static "child"
// node is created only for the `bis.PhysicalModel`, but not `bis.SpatialCategory`.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "RootNodes",
      specifications: [
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: [{ schemaName: "BisCore", classNames: ["SpatialCategory"] }],
          groupByClass: false,
        },
        {
          specType: "InstanceNodesOfSpecificClasses",
          classes: [{ schemaName: "BisCore", classNames: ["PhysicalModel"] }],
          groupByClass: false,
          nestedRules: [
            {
              ruleType: "ChildNodes",
              specifications: [
                {
                  specType: "CustomNode",
                  type: "T_CHILD",
                  label: "child",
                },
              ],
            },
          ],
        },
      ],
    },
  ],
};

Example of using "nested rules" attribute

Last Updated: 03 April, 2024