Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documenting Querying in BattleScribe #45

Open
amis92 opened this issue Jul 21, 2022 · 2 comments
Open

Documenting Querying in BattleScribe #45

amis92 opened this issue Jul 21, 2022 · 2 comments

Comments

@amis92
Copy link
Member

amis92 commented Jul 21, 2022

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 modifiers, since then they can also contain conditions and repeats within those modifiers. 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 constraints.
  • 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:

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. ❓ 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: Documenting Querying in BattleScribe #45 (comment)
  • 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?

@amis92
Copy link
Member Author

amis92 commented Jul 27, 2022

Negative value

I've investigated negative values in detail.

Generally, negative values work "as normal", except "-1" for a type=max constraint, which is equivalent to no limit. The logic might not be tied to max, but for min a non-positive value is the same as no limit anyway. Do note, that any other negative value for a max is processed as that value (and not as "no limit").

BattleScribe Data Editor does some additional validations on value:

  • for Repeats, it must be positive
  • when "value is percentage", it must be between 0 and 100

As 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.

@amis92
Copy link
Member Author

amis92 commented Jul 27, 2022

Filter entries

In different comparison/field/scope combinations, different entries are allowed as filters. We'll use numeric comparison to mean all comparison operators that operate on numbers - that excludes the (not)-instance-of comparisons. Those will be called instance-of comparison.

Field selections or Costs

When field is selections or a specific Cost or Cost Limit, the following rules apply.

The comparison must be numeric (for instance-of the field is disabled, and so cannot have value).

scope=self and scope=parent allows filter to be:

  • any, unit, model, upgrade;
  • any Category Entry;
  • any Shared Selection Entry or Shared Selection Entry Group, or any of their descendant selection entries and groups;
  • any descendant selection entry or group of the resolved scope entry.

scope=force and scope=roster allows filter to be:

  • any, unit, model, upgrade;
  • any Category Entry;
  • any Shared Selection Entry or Shared Selection Entry Group, or any of their descendant selection entries and groups;
  • any Force Entry;
  • any Root Selection Entry or any of their descendant selection entries and groups.

scope=specific entry allows filter to be:

  • any, unit, model, upgrade;
  • any Category Entry;
  • any Shared Selection Entry or Shared Selection Entry Group, or any of their descendant selection entries and groups;
  • any descendant selection entry or group of the resolved scope entry.

Field disabled

When comparison is instance-of, the field is disabled and the following rules apply.

scope=self, scope=parent and scope=ancestor allows filter to be:

  • any, unit, model, upgrade;
  • any Category Entry;
  • any Shared Selection Entry or Shared Selection Entry Group, or any of their descendant selection entries and groups;
  • any Force Entry;
  • any Root Selection Entry or any of their descendant selection entries and groups.

scope=primary-category allows filter to be:

  • any, unit, model, upgrade;
  • any Category Entry.

scope=force allows filter to be:

  • any, unit, model, upgrade;
  • any Category Entry;
  • any Force Entry.

scope=primary-catalogue allows filter to be:

  • any Catalogue.

scope=specific entry allows filter to be:

  • any, unit, model, upgrade
  • any Category Entry.

Field forces

When field is forces, the following rules apply.

The comparison must be numeric (for instance-of the field is disabled, and so cannot have value).

scope=force and scope=roster allows filter to be:

  • any;
  • any Force Entry.

scope=specific Force Entry allows filter to be:

  • any;
  • any Force Entry that is a descendant of the resolved scope force entry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant