Allow expressions in provision arguments

This commit is contained in:
Zaid Abdulla committed 2020-08-17 16:51:10 -07:00
1 parent fef4ddfbba
commit 6385f54888
6 files changed
+54 -22

No files matched your search

+11 -3
View File
@@ -215,9 +215,7 @@ const lang = parsimmon.createLanguage({
.regexp(/([a-zA-Z0-9_]+)/, 1) .regexp(/([a-zA-Z0-9_]+)/, 1)
.skip(parsimmon.optWhitespace) .skip(parsimmon.optWhitespace)
.desc("function"), .desc("function"),
r.Expression.sepBy( r.ExpressionList.wrap(
parsimmon.string(",").skip(parsimmon.optWhitespace)
).wrap(
parsimmon.string("(").skip(parsimmon.optWhitespace), parsimmon.string("(").skip(parsimmon.optWhitespace),
parsimmon.string(")").skip(parsimmon.optWhitespace) parsimmon.string(")").skip(parsimmon.optWhitespace)
), ),
@@ -330,6 +328,11 @@ const lang = parsimmon.createLanguage({
) )
); );
}, },
ExpressionList: function (r) {
return r.Expression.sepBy(
parsimmon.string(",").skip(parsimmon.optWhitespace)
);
},
Expression: function (r) { Expression: function (r) {
function unary(operatorsParser, nextParser): parsimmon.Parser<unknown> { function unary(operatorsParser, nextParser): parsimmon.Parser<unknown> {
return parsimmon.seq(operatorsParser, nextParser).or(nextParser); return parsimmon.seq(operatorsParser, nextParser).or(nextParser);
@@ -350,6 +353,11 @@ export function parse(str: string): Expression {
return lang.Expression.tryParse(str); return lang.Expression.tryParse(str);
} }
export function parseList(str: string): Expression[] {
if (!str) return [];
return lang.ExpressionList.tryParse(str);
}
export function stringify(exp: Expression, level = 0): string { export function stringify(exp: Expression, level = 0): string {
if (!Array.isArray(exp)) return JSON.stringify(exp); if (!Array.isArray(exp)) return JSON.stringify(exp);
+10 -10
View File
@@ -112,7 +112,8 @@ export function evaluateCallback(exp: Expression): Expression {
if (exp[i]) return exp[i + 1]; if (exp[i]) return exp[i + 1];
} }
return null; return null;
} else if (exp[0] === "FUNC" && exp[1] === "COALESCE") { } else if (exp[0] === "FUNC") {
if (exp[1] === "COALESCE") {
const args: Expression[] = []; const args: Expression[] = [];
for (let i = 2; i < exp.length; ++i) { for (let i = 2; i < exp.length; ++i) {
const e = exp[i]; const e = exp[i];
@@ -123,6 +124,13 @@ export function evaluateCallback(exp: Expression): Expression {
if (!args.length) return null; if (!args.length) return null;
if (args.length === 1) return args[0]; if (args.length === 1) return args[0];
return ["FUNC", "COALESCE", ...args]; return ["FUNC", "COALESCE", ...args];
} else if (exp[1] === "UPPER") {
if (exp[2] == null) return null;
if (!isArray(exp[2])) return toString(exp[2]).toUpperCase();
} else if (exp[1] === "LOWER") {
if (exp[2] == null) return null;
if (!isArray(exp[2])) return toString(exp[2]).toLowerCase();
}
} else if (exp[0] === "AND") { } else if (exp[0] === "AND") {
for (let i = 1; i < exp.length; ++i) for (let i = 1; i < exp.length; ++i)
if (!Array.isArray(exp[i]) && exp[i] != null && !exp[i]) return false; if (!Array.isArray(exp[i]) && exp[i] != null && !exp[i]) return false;
@@ -274,16 +282,8 @@ export function evaluate(
if (cb) e = cb(e); if (cb) e = cb(e);
if (!isArray(e)) return e; if (!isArray(e)) return e;
if (e[0] === "FUNC") { if (e[0] === "FUNC" && e[1] === "NOW") {
if (e[1] === "NOW") {
if (now) return now; if (now) return now;
} else if (e[1] === "UPPER") {
if (e[2] == null) return null;
if (!isArray(e[2])) return `${e[2]}`.toUpperCase();
} else if (e[1] === "LOWER") {
if (e[2] == null) return null;
if (!isArray(e[2])) return `${e[2]}`.toLowerCase();
}
} else if (e[0] === "PARAM") { } else if (e[0] === "PARAM") {
if (e[1] == null) return null; if (e[1] == null) return null;
if (obj && !isArray(e[1])) { if (obj && !isArray(e[1])) {
+28 -4
View File
@@ -45,6 +45,7 @@ import {
SoapMessage, SoapMessage,
InformRequest, InformRequest,
AcsResponse, AcsResponse,
Preset,
} from "./types"; } from "./types";
import { IncomingMessage, ServerResponse } from "http"; import { IncomingMessage, ServerResponse } from "http";
import { Readable } from "stream"; import { Readable } from "stream";
@@ -431,7 +432,7 @@ async function applyPresets(sessionContext: SessionContext): Promise<void> {
} }
const parameters: { [name: string]: Path } = {}; const parameters: { [name: string]: Path } = {};
const filteredPresets = []; const filteredPresets: Preset[] = [];
for (const preset of presets) { for (const preset of presets) {
if (whiteList != null) { if (whiteList != null) {
@@ -460,11 +461,24 @@ async function applyPresets(sessionContext: SessionContext): Promise<void> {
} }
filteredPresets.push(preset); filteredPresets.push(preset);
for (const k of extractParams(preset.precondition)) { for (const k of extractParams(
evaluate(preset.precondition, null, sessionContext.timestamp)
)) {
// Mark channel in case of fault during fetching precondition // Mark channel in case of fault during fetching precondition
sessionContext.channels[preset.channel] = 0; sessionContext.channels[preset.channel] = 0;
if (typeof k === "string") parameters[k] = Path.parse(k); if (typeof k === "string") parameters[k] = Path.parse(k);
} }
for (const prov of preset.provisions) {
for (const arg of prov.slice(1)) {
for (const k of extractParams(
evaluate(arg, null, sessionContext.timestamp)
)) {
// Mark channel in case of fault during fetching precondition
sessionContext.channels[preset.channel] = 0;
if (typeof k === "string") parameters[k] = Path.parse(k);
}
}
}
} }
const declarations = Object.values(parameters).map((v) => ({ const declarations = Object.values(parameters).map((v) => ({
@@ -501,12 +515,22 @@ async function applyPresets(sessionContext: SessionContext): Promise<void> {
session.configContextCallback(sessionContext, e) session.configContextCallback(sessionContext, e)
) )
) { ) {
const provs = p.provisions.map((pp) => [
pp[0],
...pp
.slice(1)
.map((arg) =>
evaluate(arg, {}, sessionContext.timestamp, (e) =>
session.configContextCallback(sessionContext, e)
)
),
]);
if (blackList[p.channel] === 2) { if (blackList[p.channel] === 2) {
appendProvisionsToFaults[p.channel] = ( appendProvisionsToFaults[p.channel] = (
appendProvisionsToFaults[p.channel] || [] appendProvisionsToFaults[p.channel] || []
).concat(p.provisions); ).concat(provs);
} else { } else {
session.addProvisions(sessionContext, p.channel, p.provisions); session.addProvisions(sessionContext, p.channel, provs);
} }
} }
} }
+3 -3
View File
@@ -18,7 +18,7 @@
*/ */
import { ObjectID } from "mongodb"; import { ObjectID } from "mongodb";
import { map, parse, stringify } from "./common/expression-parser"; import { map, parse, stringify, parseList } from "./common/expression-parser";
import { likePatternToRegExp, evaluate } from "./common/expression"; import { likePatternToRegExp, evaluate } from "./common/expression";
import { Expression, Fault, Task } from "./types"; import { Expression, Fault, Task } from "./types";
@@ -593,7 +593,7 @@ export function flattenPreset(
) { ) {
p.provision = provision.name; p.provision = provision.name;
p.provisionArgs = provision.args p.provisionArgs = provision.args
? JSON.stringify(provision.args).slice(1, -1) ? provision.args.map((a) => stringify(a)).join(", ")
: ""; : "";
} }
@@ -650,7 +650,7 @@ export function preProcessPreset(
}; };
if (preset.provisionArgs) if (preset.provisionArgs)
configuration.args = JSON.parse(`[${preset.provisionArgs}]`); configuration.args = parseList(preset.provisionArgs as string);
delete preset.provision; delete preset.provision;
delete preset.provisionArgs; delete preset.provisionArgs;
+1 -1
View File
@@ -323,7 +323,7 @@ export interface Preset {
schedule?: { md5: string; duration: number; schedule: any }; schedule?: { md5: string; duration: number; schedule: any };
events?: { [event: string]: boolean }; events?: { [event: string]: boolean };
precondition?: Expression; precondition?: Expression;
provisions: string[][]; provisions: [string, ...Expression[]][];
} }
export interface Provisions { export interface Provisions {
+1 -1
View File
@@ -43,7 +43,7 @@ const attributes = [
{ id: "events", label: "Events" }, { id: "events", label: "Events" },
{ id: "precondition", label: "Precondition", type: "textarea" }, { id: "precondition", label: "Precondition", type: "textarea" },
{ id: "provision", label: "Provision", type: "combo" }, { id: "provision", label: "Provision", type: "combo" },
{ id: "provisionArgs", label: "Arguments" }, { id: "provisionArgs", label: "Arguments", type: "textarea" },
]; ];
const unpackSmartQuery = memoize((query) => { const unpackSmartQuery = memoize((query) => {