Evaluating Expressions via the API

View as Markdown

Summary

  • AdapTableQL can evaluate an Expression as an explicit call — no Module has to own it
  • Use it when you want the same engine as Grid Filter, Alerts and Calculated Columns, but from your own code
  • There are 4 methods available to meet all potential use cases and the types of Expressions AdapTable offers

AdapTable typically evaluates an Expression in response to an event in the UI.

For example when running a Grid Filter, calculating a Calculated Column value, or rendering a Cell with a Conditional Style, AdapTable will hand over the evaluation to AdapTableQL which will return the result.

However it is possible to leverage AdapTableQL programmatically - to evaluate an Expression entirely via the API.

Note

const result = adaptableApi.expressionApi.evaluateStandardExpression({
  expression: '[price] * [qty] > 1000',
  primaryKeyValue: 42,
});

if (result.success) {
  console.log(result.value); // true | false
} else {
  console.warn(result.errorMessage);
}

Important

  • AdapTableQL still evaluates the Expression
  • The difference is that you ask for the result yourself, instead of hanging it off a Grid Filter, Calculated Column etc.

Why evaluate via API

There are many potential use cases where you might want to evaluate an Expression using the API.

For instance you might want to:

  • ask a question once (“does this row pass?”, “what is this value?”) outside of a Module
  • drive your own UI — a toolbar button or custom form — from an Expression the user typed or you shipped
  • run a what-if: would this row still match if price were 120?
  • filter your own array of rows, not the grid

Note

  • The Expression string is the same one you would put in Initial State or the Expression Editor
  • AdapTableQL evaluates it exactly the same way as it would evaluate if invoked by AdapTable's UI

API Methods

AdapTable provides 4 Expression-evaluation methods in Expression API:

  • evaluateStandardExpression
  • evaluateAggregatedExpression
  • filterRowNodes
  • filterDataSet

These are designed to be able to meet a range of potential use cases:

You wantCall
a true / false resultevaluateStandardExpression
a value for one rowevaluateStandardExpression
the rows that matchfilterRowNodes or filterDataSet
a snapshot (SUM, AVG, GROUP_BY, RANK, …)evaluateAggregatedExpression

evaluateStandardExpression

Use this function to evaluate a Standard Expression against a single row.

The Expression determines the return value: a boolean condition will yields true / false, while a value Expression will yield that value.

evaluateStandardExpression

request: EvaluateStandardExpressionRequest
ExpressionEvaluationResult<unknown>
Evaluates a Standard Expression against one row

Hint

  • If you are looping evaluateStandardExpression over every row, use filterRowNodes / filterDataSet instead
  • Validation runs once, and matching rows keep their source order and object identity

evaluateAggregatedExpression

Use this function to evaluate an Aggregation Expression over a set of rows (the grid, a narrowed subset, or an array you supply).

It returns a snapshot of the result — the aggregated value, any GROUP_BY breakdown, and a per-row projection.

When the Expression is a condition, you also get whether it matches.

evaluateAggregatedExpression

request: EvaluateAggregatedExpressionRequest
ExpressionEvaluationResult<AggregatedExpressionEvaluationValue>
Evaluates an Aggregation Expression and returns a snapshot (value, groups, per-row projection, rowCount). Conditions also set matches.

Observable Expressions

There is no API method to subscribe to an Observable Expression.

Note

  • evaluateStandardExpression can evaluate an Observable Expression (e.g. HIGHEST{[price], WITHIN(1h)}) against a grid row, returning its current value
  • Observable Expressions are grid-only, so passing data or dataSet is rejected

To react live to an Observable pattern, create an Observable Alert and listen to the Alert Fired Event, or display the value in an Observable Calculated Column.

filterRowNodes

Use this function to return the grid rows that match a boolean Expression.

It evaluates the Expression once per row and returns the matching IRowNodes in source order.

filterRowNodes

request: FilterRowNodesRequest
ExpressionEvaluationResult<IRowNode[]>
Returns the grid rows matching a boolean Expression, in source order.

filterDataSet

Use this function to filter an array of your own rows with a boolean Expression.

Same behaviour as filterRowNodes, but the input and output are your objects rather than grid row nodes.

filterDataSet

request: FilterDataSetRequest
ExpressionEvaluationResult<Record<string, unknown>[]>
Returns the subset of a caller-supplied array matching a boolean Expression, in original order and with the same object references.
AdapTableQL: Evaluating Expressions via the API
Fork
  • The Evaluate Toolbar has 4 buttons; each calls one method and shows the result in the System Status:
    • Large Open Trades - filterRowNodes with [notional] > 75000 AND [status] = 'Open'
    • What If Price +10% - evaluateStandardExpression on trade 1, with and without a cellValueOverride raising its Price by 10%
    • Check Proposed Orders - filterDataSet over an array of orders which are not in the grid
    • P&L by Desk - evaluateAggregatedExpression with SUM{[pnl], GROUP_BY([desk])}, reading groupValues
Try It Out
  • Click each button and read the result in the System Status
  • Change trade 1's Status to Closed and click Large Open Trades again
  • Change a P&L value and click P&L by Desk - the snapshot is recalculated on each call
Loading demo…

The rest of ExpressionApi is supporting: isValid* before you evaluate, getColumnsFromExpression, getASTForExpression (also used by Server Evaluation).

Function Results

Synchronous evaluate / filter methods never throw for expected input errors (typos, unknown columns, missing row, unavailable functions).

type ExpressionEvaluationResult<T> =
  | {success: true; value: T}
  | {success: false; errorMessage: string};

Always check success before reading value.

The Expression decides what value is.

A condition such as [price] > 100 yields true / false. [price] * 1.19 yields a number.

Deep Dive

Evaluating your own data

Caution

  • There are a number of "Gotchas" that you need to be aware of when evaluating Expressions via the API:
    • Check success. The API does not throw for bad Expressions or missing rows
    • This is not Server Evaluation. evaluateAdaptableQLExternally does not apply here
    • One row target for evaluateStandardExpression. Pass exactly one of rowNode, primaryKeyValue or data
    • $SCOPE and Relative Change need extra context. Provide columnScope / dataChangedEvent or evaluation fails
    • module changes the function pool. Default is every function. Pass Module name to see what that Module allows
    • Aggregations are snapshots. Re-evaluate if you need them to track the grid. Read matches when the Expression is a condition
    • SSRM aggregations are partial. Use rowCount
    • Observables cannot use data / dataSet, and cannot be subscribed to via the API
    • Filter helpers fail the whole call if any row errors

FAQ

Can I use the API to evaluate an Expression that lives in a Module? Yes, read the Rule / Query string from State and pass it to the matching evaluate* / filter* method

Can I evaluate against rows that are not in the grid? Yes, pass data (one row) or dataSet (many rows). Remember that valueGetters will not run

Does this replace Grid Filter? No, Grid Filter still owns what the user sees. Use filterRowNodes when your code needs the matching rows.