In some cases, the Otter operators may refer to an implicit fact. This is the case for
the dateInNextMinutes
and dateNotInNextMinutes
operators.
The definition of these two operators implies the notion of a current date, hence, the framework needs to expose an
internal, built-in fact that will always be used by them: the o3rCurrentTime
. The operators will not take it as input,
making it an implicit fact of these operators. This also means that, while all the other operators are pure functions,
this is not the case for dateInNextMinutes
nor dateNotInNextMinutes
.
While this fact is provided in the rules engine module, you should be able to override its implementation to fit your needs.
This section explains how to use operators with an implicit fact and how to override the fact implementation.
The operators using a built-in implicit fact are used in the same way as any other operator, the implicit fact will just not be referred to in the Ruleset object:
Example :{
"id": "5467e501-b9ff-414f-8026-56885d0d7a4c",
"name": "The otter is late",
"disabled": false,
"outputRuntimeFacts": [],
"inputRuntimeFacts": [],
"rootElement": {
"elementType": "RULE_BLOCK",
"blockType": "IF_ELSE",
"condition": {
"all": [
{
"lhs": {
"type": "FACT",
"value": "outboundDate"
},
"rhs": {
"type": "LITERAL",
"value": "2880"
},
"operator": "dateInNextMinutes"
}
]
},
"successElements": [
{
"elementType": "ACTION",
"actionType": "UPDATE_ASSET",
"asset": "otter.svg",
"value": "otter-late.svg"
}
],
"failureElements": []
}
}
This does not mean that the fact itself should not be registered. If you fail to register the fact the same way as the non-built-in facts, the whole ruleset will fail.
Example :import {Component, OnInit} from '@angular/core';
import {CurrentTimeFactsService} from '@o3r/rules-engine';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
constructor(private currentTimeFactsService: CurrentTimeFactsService) {}
ngOnInit() {
this.currentTimeFactsService.register();
}
}
To avoid performance issue and to allow you to use the best logic for your needs, the CurrentTimeFactsService
is
based on a simple implementation of a refresh mechanism without a default refresh timer.
Instead, it is up to the application to choose when to refresh the fact via its tick
method (on page navigation, at a
given time interval, etc. ).
[!INFO] The reason why the fact is not registered automatically, even though it is provided by the module, is to allow the override of the fact.
If you do not want to rely on the provided service and its refresh mechanism, you can create your own custom fact
service.
If you want to override the o3rCurrentTime
logic, you just need to make sure that you expose a fact with the same name
that will be used for the dateInNextMinutes
anddateNotInNextMinutes
operators.
import { Injectable } from '@angular/core';
import { CurrentTimeFacts, FactsService, RulesEngineService } from '@o3r/rules-engine';
import { interval } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class CustomCurrentTimeFactsService extends FactsService<CurrentTimeFacts> {
private currentTimeSubject$ = new BehaviorSubject();
/** @inheritDoc */
public facts = {
// Emits every 10 minute
o3rCurrentTime: interval(600000).pipe(map(() => (new Date()).getTime()))
};
constructor(rulesEngine: RulesEngineService) {
super(rulesEngine);
}
}
Then, just register your service in your application following the custom fact documentation.