BSData / BSData/phalanx

Documenting Querying in BattleScribe

Open
#45 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
152
Forks
24
PR merge metrics
No merged PRs in 30d

Description

We need to document queries: what are legal combinations, how do they work, what are the results.

## BS Nodes

The elements in BattleScribe that use queries are: `condition`, `constraint`, `repeat`.

These elements appear as children in other BattleScribe elements:

- `condition` can be child of: `modifier`, `modifierGroup`, `conditionGroup`.
- `repeat` can be child of: `modifier`, `modifierGroup`.
- `constraint` can be child of: `selectionEntry`, `selectionEntryGroup`, `entryLink`, `forceEntry`, `categoryLink` in `forceEntry`, `categoryEntry`.

It's important to list all elements that can contain `modifier`s, since then they can also contain `conditions` and `repeats` within those `modifier`s. `modifier` can be child of:

- all those that can have `constraint` (see list above)
- `profile`, `rule`, `infoGroup`, `infoLink`.

## Query components

The elements of a query are:

- `field` - *what* is the counted value.
- `scope` - *where* (in what subtree) are the values counted.
- `childId` aka Filter By - *which* of the candidate entries/values do we actually process.
- `value` - reference value that the query result is compared with.
- `comparison` - `condition` and `constraint` uses it to compare the result with a reference `value`.
- additional options: `shared`, `value-is-percentage`, `include-child-selections`, `include-child-forces`, `round-up`.

## Known options

### Field

Allowed values for a `field` in a Query:

- `selections` - count the selections.
- `forces` - count the forces.
- specific Cost - sum cost values of the given Cost Type, looking at elements returned by the query.
- specific Cost Limit - use roster limit of the given Cost Type (`scope` has to be Roster, `filter` is unused).

Special cases:

- `forces` field allows only the following `scope` values: `force`, `roster`, specific force entry.
- Cost Limit field allows only `scope=roster`. The `field` is then formatted like `limit::{type-id}` where `{type-id}` is the ID of the Cost Type.

### Scope

Scope can be one of:

- `self` - restricted
- `parent`
- `ancestor` - restricted
- `primary-category` - restricted
- `force`
- `roster`
- `primary-catalogue`
- specific selection, category, or force entry

Special cases:

- `self` is not allowed in `constraint`s.
- `ancestor` and `primary-category` are only allowed with `comparison` of `(not)instance-of`.
- specific entries allowed:
- any Category Entry
- any Force Entry (including nested ones)
- any Selection Entry that is ancestor of the querying constraint/modifier

### Filter

Filter can be one of:

- `any` (Anything) - noop.
- `unit/model/upgrade` (Unit/Model/Upgrade) - all elements with specified EntryKind (type) are returned.
- specific selection, category, or force entry

When `filter` has specified value:
- `any` (anything) - all elements in the `scope` are returned.
- EntryType (unit/model/upgrade) - all elements in the `scope` with specified EntryKind (type) are returned.
- a Category Entry - all elements in the `scope` with specified category linked are returned.
- a Force Entry - all elements in the `scope` that are instance of that entry.
- any Selection Entry - all elements in the `scope` that are instance of that entry.

Special cases:

- `childId`/`filter` in `constraint` is disabled. It is implicitly the constraint's parent entry.
- complete reference of what is allowed when: https://github.com/BSData/phalanx/issues/45#issuecomment-1197306993

### Value

- in `repeat` used to divide query result into "buckets", and for each such bucket there are N repetitions of the modifier applied (N is `repeats` value in BS XML).
- `repeat` requires a positive `value`.
- in `constraint` used to compare using `comparison` operator.
- in `condition` used to compare using `comparison` operator. If it's a `instance-of` kind of operator, the `value` is unused.

Generally, **negative** values work as expected. The exception here is a `-1` value for a `type=max` `constraint` - in that case, it is interpreted as "infinity" or "no limit". Further modifications of the value (e.g. by Modifiers) are calculated as normal, e.g. when a constraint of `-1` is modifed to increase value by 1, now the maximum is 0 so the selections are not allowed. Any other negative value (e.g. `-2`) is treated normally (no special behavior).

### Comparison

- `repeat` has none.
- `condition` has all numeric comparison operators and two special ones (instance-of):
- `(not-)equal to`
- `greater/less than (or equal)`
- `(not-)instance of`.
- `constraint` has `min` (`greater than or equal`) and `max` (`less than or equal`).

Special cases:

- when `scope` is `ancestor` or `primary-category`, `comparison` must be `(not)instance-of`, thus those scopes are not available for `constraint` and `repeat`.
- `(not-)instance-of` value of `comparison` is a special case in `condition` queries: there's no `field` defined, `scope` defines the checked entry, and `childId`/`filter` defines the type/entry the `scope` should be "instance of". When `filter` is:
- `any` (anything) - it's a noop, always satisfied.
- EntryType (unit/model/upgrade) - the `scope` should have that type.
- a Category Entry - the `scope` should have that category linked.
- a Force Entry - the `scope` should be instance of that entry.
- any Selection Entry - the `scope` should be instance of that entry.

### Options

`shared` - the query should sum up all instances of `childId`/`filter` in scope, disregarding the selection path. [BS author explainer](https://github.com/BSData/wh40k-7th-edition/issues/2880). ❓ When is this option allowed in Data Editor UI?

`value-is-percentage` - the `value` should be interpreted as percentage, and is limited to the range `[0; 100]`.

`include-child-selections` - the scope includes selection subtrees (recursive/all descendants).

`include-child-forces` - the scope includes force subtrees (recursive/all descendants).

`round-up` - used in `repeat` calculations, rounds the division of result by `value` up, instead of down as is by default.

## Loose notes

- `constraint` has `comparison` defined differently: it has `type` of `min` or `max` - those are equivalent to `greater than or equal` and `less than or equal` values of `type` in `condition`.
- `value` can be negative for `constraint` and `condition`. Details: https://github.com/BSData/phalanx/issues/45#issuecomment-1197259096
- `repeat` has no `comparison` (`type`), but instead declares a number of repetitions per multiplications of reference `value` in query result (`(result / value) * repeats`).
- `constraint` of `max` value has an interesting quirk. When an entry has a constraint of type=min scope=parent value=0, the entry is hidden in Roster Editor, as it's not allowed to be selected. As expected, using a Modifier to Set that constraint's value to -1 makes this entry selectable (unlimited) and it's correctly shown in Roster Editor. However, when using a Modifier to Decrease the value by 1 (making it `0 - 1 = -1` - unlimited), the Roster Editor does not show the entry (incorrectly?), as that entry is unlimited due to the new value of max constraint.

❓ What are other unobvious interactions?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.