-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add datasource support to conditional variables (#6270)
- Loading branch information
1 parent
32278ea
commit e43dcfc
Showing
6 changed files
with
353 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
packages/core/src/data_sources/model/conditional_variables/Condition.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import EditorModel from '../../../editor/model/Editor'; | ||
import DataVariable from '../DataVariable'; | ||
import { evaluateVariable, isDataVariable } from '../utils'; | ||
import { Expression, LogicGroup } from './DataCondition'; | ||
import { LogicalGroupStatement } from './LogicalGroupStatement'; | ||
import { Operator } from './operators'; | ||
import { GenericOperation, GenericOperator } from './operators/GenericOperator'; | ||
import { LogicalOperator } from './operators/LogicalOperator'; | ||
import { NumberOperator, NumberOperation } from './operators/NumberOperator'; | ||
import { StringOperator, StringOperation } from './operators/StringOperations'; | ||
|
||
export class Condition { | ||
private condition: Expression | LogicGroup | boolean; | ||
private em: EditorModel; | ||
|
||
constructor(condition: Expression | LogicGroup | boolean, opts: { em: EditorModel }) { | ||
this.condition = condition; | ||
this.em = opts.em; | ||
} | ||
|
||
evaluate(): boolean { | ||
return this.evaluateCondition(this.condition); | ||
} | ||
|
||
/** | ||
* Recursively evaluates conditions and logic groups. | ||
*/ | ||
private evaluateCondition(condition: any): boolean { | ||
if (typeof condition === 'boolean') return condition; | ||
|
||
if (this.isLogicGroup(condition)) { | ||
const { logicalOperator, statements } = condition; | ||
const operator = new LogicalOperator(logicalOperator); | ||
const logicalGroup = new LogicalGroupStatement(operator, statements, { em: this.em }); | ||
return logicalGroup.evaluate(); | ||
} | ||
|
||
if (this.isExpression(condition)) { | ||
const { left, operator, right } = condition; | ||
const evaluateLeft = evaluateVariable(left, this.em); | ||
const evaluateRight = evaluateVariable(right, this.em); | ||
const op = this.getOperator(evaluateLeft, operator); | ||
|
||
const evaluated = op.evaluate(evaluateLeft, evaluateRight); | ||
return evaluated; | ||
} | ||
|
||
throw new Error('Invalid condition type.'); | ||
} | ||
|
||
/** | ||
* Factory method for creating operators based on the data type. | ||
*/ | ||
private getOperator(left: any, operator: string): Operator { | ||
if (this.isOperatorInEnum(operator, GenericOperation)) { | ||
return new GenericOperator(operator as GenericOperation); | ||
} else if (typeof left === 'number') { | ||
return new NumberOperator(operator as NumberOperation); | ||
} else if (typeof left === 'string') { | ||
return new StringOperator(operator as StringOperation); | ||
} | ||
throw new Error(`Unsupported data type: ${typeof left}`); | ||
} | ||
|
||
/** | ||
* Extracts all data variables from the condition, including nested ones. | ||
*/ | ||
getDataVariables(): DataVariable[] { | ||
const variables: DataVariable[] = []; | ||
this.extractVariables(this.condition, variables); | ||
return variables; | ||
} | ||
|
||
/** | ||
* Recursively extracts variables from expressions or logic groups. | ||
*/ | ||
private extractVariables(condition: boolean | LogicGroup | Expression, variables: DataVariable[]): void { | ||
if (this.isExpression(condition)) { | ||
if (isDataVariable(condition.left)) variables.push(condition.left); | ||
if (isDataVariable(condition.right)) variables.push(condition.right); | ||
} else if (this.isLogicGroup(condition)) { | ||
condition.statements.forEach((stmt) => this.extractVariables(stmt, variables)); | ||
} | ||
} | ||
|
||
/** | ||
* Checks if a condition is a LogicGroup. | ||
*/ | ||
private isLogicGroup(condition: any): condition is LogicGroup { | ||
return condition && typeof condition.logicalOperator !== 'undefined' && Array.isArray(condition.statements); | ||
} | ||
|
||
/** | ||
* Checks if a condition is an Expression. | ||
*/ | ||
private isExpression(condition: any): condition is Expression { | ||
return condition && typeof condition.left !== 'undefined' && typeof condition.operator === 'string'; | ||
} | ||
|
||
/** | ||
* Checks if an operator exists in a specific enum. | ||
*/ | ||
private isOperatorInEnum(operator: string, enumObject: any): boolean { | ||
return Object.values(enumObject).includes(operator); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 12 additions & 3 deletions
15
packages/core/src/data_sources/model/conditional_variables/LogicalGroupStatement.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,24 @@ | ||
import { LogicalOperator } from './operators/LogicalOperator'; | ||
import { Expression, LogicGroup } from './DataCondition'; | ||
import { evaluateCondition } from './evaluateCondition'; | ||
import { Condition } from './Condition'; | ||
import EditorModel from '../../../editor/model/Editor'; | ||
|
||
export class LogicalGroupStatement { | ||
private em: EditorModel; | ||
|
||
constructor( | ||
private operator: LogicalOperator, | ||
private statements: (Expression | LogicGroup | boolean)[], | ||
) {} | ||
opts: { em: EditorModel }, | ||
) { | ||
this.em = opts.em; | ||
} | ||
|
||
evaluate(): boolean { | ||
const results = this.statements.map((statement) => evaluateCondition(statement)); | ||
const results = this.statements.map((statement) => { | ||
const condition = new Condition(statement, { em: this.em }); | ||
return condition.evaluate(); | ||
}); | ||
return this.operator.evaluate(results); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import EditorModel from '../../editor/model/Editor'; | ||
import { DataConditionType } from './conditional_variables/DataCondition'; | ||
import DataVariable, { DataVariableType } from './DataVariable'; | ||
|
||
export function isDataVariable(variable: any) { | ||
return variable?.type === DataVariableType; | ||
} | ||
|
||
export function isDataCondition(variable: any) { | ||
return variable?.type === DataConditionType; | ||
} | ||
|
||
export function evaluateVariable(variable: any, em: EditorModel) { | ||
return isDataVariable(variable) ? new DataVariable(variable, { em }).getDataValue() : variable; | ||
} |
Oops, something went wrong.