Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
fix

.
  • Loading branch information
ukrbublik committed May 22, 2024
1 parent 1143c88 commit 745ac21
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 67 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Changelog
- 6.6.0
- Add JsonLogic Export for SwitchCase (PR #1013)
- 6.5.2
- Updated dependencies. `@babel/runtime` is now dep for core package (PR #1051) (issue #964)
- 6.5.1
Expand Down
5 changes: 4 additions & 1 deletion packages/core/modules/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,10 @@ const widgets = {
},
spelImportValue: (val) => {
return [val.value, []];
}
},
jsonLogic: function (val) {
return val === "" ? null : val;
},
}
};

Expand Down
73 changes: 38 additions & 35 deletions packages/core/modules/export/jsonLogic.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const formatItem = (item, config, meta, isRoot, parentField = null) => {
} else if (type === "rule") {
ret = formatRule(item, config, meta, parentField);
} else if (type == "switch_group") {
ret = formatSwitch(item, config, meta, parentField);
ret = formatSwitch(item, config, meta);
} else if (type == "case_group") {
ret = formatCase(item, config, meta, parentField);
}
Expand Down Expand Up @@ -207,73 +207,76 @@ const formatRule = (item, config, meta, parentField = null) => {
return formatLogic(config, properties, formattedField, formattedValue, operator, operatorOptions, fieldDefinition, isRev);
};

const formatSwitch = (item, config, meta, parentField = null) => {
const properties = item.get("properties") || new Map();
const formatSwitch = (item, config, meta) => {
const children = item.get("children1");
if (!children) return undefined;
if (!children)
return undefined;
const cases = children
.map((currentChild) => formatCase(currentChild, config, meta, null))
.filter((currentChild) => typeof currentChild !== "undefined")
.toArray();
.valueSeq().toArray();

if (!cases.length) return undefined;

if (cases.length == 1 && !cases[0][0]) {
// only 1 case without condition
return cases[0][1];
}
let filteredCases = [];
for (let i = 0 ; i < cases.length ; i++) {
if (i != (cases.length - 1) && !cases[i][0]) {
if (i !== (cases.length - 1) && !cases[i][0]) {
meta.errors.push(`No condition for case ${i}`);
} else {
filteredCases.push(cases[i]);
if (i == (cases.length - 1) && cases[i][0]) {
if (i === (cases.length - 1) && cases[i][0]) {
// no default - add null as default
filteredCases.push([undefined, null]);
}
}
}

let left = "", right = "";
const ret = {
"IF": [],
};
for (let i = 0 ; i < filteredCases.length ; i++) {
if (!filteredCases.length)
return undefined;

if (filteredCases.length === 1) {
// only 1 case without condition
let [_cond, defVal] = filteredCases[0];
if (defVal == undefined)
defVal = null;
return defVal;
}

const ret = { if: [] };
let ifArgs = ret.if;
const [_, defVal] = filteredCases[filteredCases.length - 1];
for (let i = 0 ; i < filteredCases.length - 1 ; i++) {
const isLastIf = i === (filteredCases.length - 2);
let [cond, value] = filteredCases[i];
if (value == undefined)
value = "null";
value = null;
if (cond == undefined)
cond = "true";
if (i != (filteredCases.length - 1)) {
ret.IF.push(cond);
cond = true;
ifArgs.push(cond); // if
ifArgs.push(value); // then
if (isLastIf) {
ifArgs.push(defVal); // else
} else {
// elif..
ifArgs.push({ if: [] });
ifArgs = ifArgs[ifArgs.length - 1].if;
}
ret.IF.push(value);
}
return ret;
};

const formatCase = (item, config, meta, isRoot, parentField = null) => {
const type = item.get('type');
if (type != 'case_group') {
const formatCase = (item, config, meta, parentField = null) => {
const type = item.get("type");
if (type != "case_group") {
meta.errors.push(`Unexpected child of type ${type} inside switch`);
return undefined;
}
const properties = item.get('properties') || new Map();
const properties = item.get("properties") || new Map();

const cond = formatGroup(item, config, meta, parentField);
// return [cond, formattedValue];

const values = properties.get('value');
const formattedItem = formatItemValue(
config, properties, meta, null, parentField, "!case_value"
);
if(typeof formattedItem == 'string'){
return [cond, formattedItem];
} else if (Array.isArray(formattedItem)) {
return [cond, formattedItem[0].value];
}
return [cond, null];
return [cond, formattedItem];
};

const formatItemValue = (config, properties, meta, operator, parentField, expectedValueType = null) => {
Expand Down
1 change: 1 addition & 0 deletions packages/core/modules/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ interface ConfigUtils {
interface ExportUtils {
spelEscape(val: any): string;
spelFormatConcat(parts: SpelConcatParts): string;
jsonLogicFormatConcat(parts: SpelConcatParts): any;
spelImportConcat(val: SpelConcatValue): [SpelConcatParts | undefined, Array<string>];
}
interface ListUtils {
Expand Down
10 changes: 10 additions & 0 deletions packages/core/modules/utils/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ export const spelEscape = (val, numberToFloat = false, arrayToArray = false) =>
}
};

export const jsonLogicFormatConcat = (parts) => {
if (parts && Array.isArray(parts) && parts.length) {
return parts
.map(part => part?.value ?? part)
.filter(r => r != undefined);
} else {
return undefined;
}
};

export const spelFormatConcat = (parts) => {
if (parts && Array.isArray(parts) && parts.length) {
return parts
Expand Down
1 change: 1 addition & 0 deletions packages/examples/demo_switch/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default (): Config => {
...InitialConfig.widgets.case_value,
spelFormatValue: QbUtils.ExportUtils.spelFormatConcat,
spelImportValue: QbUtils.ExportUtils.spelImportConcat,
jsonLogic: QbUtils.ExportUtils.jsonLogicFormatConcat,
factory: ({value, setValue, id}: WidgetProps) =>
<ReactSelect
value={value as SpelConcatPart[]}
Expand Down
95 changes: 74 additions & 21 deletions packages/examples/demo_switch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,6 @@ const Demo: React.FC = () => {
/>
);

const renderSpelOutput = () => (
<div className="query-builder-result">
Output SpEL:
<pre>
{QbUtils.spelFormat(state.tree, state.config)}
</pre>
Values:
<pre>
{JSON.stringify(QbUtils.getSwitchValues(state.tree), undefined, 2)}
</pre>
<br/>
<hr/>
<br/>
Tree:
<pre>
{JSON.stringify(QbUtils.getTree(state.tree), undefined, 2)}
</pre>
</div>
);

const renderSpelInput = () => (
<div className="query-import-spel">
Input SpEL:
Expand All @@ -109,11 +89,84 @@ const Demo: React.FC = () => {
</div>
);

const renderSpelBlock = () => {
const [spel, spelErrors] = QbUtils._spelFormat(state.tree, state.config);

return (
<>
<div>
spelFormat:
{ spelErrors.length > 0
&& <pre style={preErrorStyle}>
{JSON.stringify(spelErrors, undefined, 2)}
</pre>
}
<pre style={preStyle}>
{JSON.stringify(spel, undefined, 2)}
</pre>
Values:
<pre>
{JSON.stringify(QbUtils.getSwitchValues(state.tree), undefined, 2)}
</pre>
</div>
<hr/>
</>
);
};

const renderJsTreeBlock = () => {
const treeJs = QbUtils.getTree(state.tree);

return (
<>
Tree:
<pre>
{JSON.stringify(treeJs, undefined, 2)}
</pre>
<br/>
<hr/>
<br/>
</>
);
};

const renderJsonLogicBlock = () => {
const {logic, data: logicData, errors: logicErrors} = QbUtils.jsonLogicFormat(state.tree, state.config);

return (
<>
<div>
<a href="http://jsonlogic.com/play.html" target="_blank" rel="noopener noreferrer">jsonLogicFormat</a>:
{ (logicErrors?.length || 0) > 0
&& <pre style={preErrorStyle}>
{JSON.stringify(logicErrors, undefined, 2)}
</pre>
}
{ !!logic
&& <pre style={preStyle}>
{"// Rule"}:<br />
{JSON.stringify(logic, undefined, 2)}
<br />
<hr />
{"// Data"}:<br />
{JSON.stringify(logicData, undefined, 2)}
</pre>
}
</div>
<hr/>
</>
);
};

return (
<div>
{renderSpelInput()}
{renderQueryBuilder()}
{renderSpelOutput()}
<div className="query-builder-result">
{renderSpelBlock()}
{renderJsonLogicBlock()}
{renderJsTreeBlock()}
</div>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion packages/tests/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let reporters;
if (isCI) {
reporters = ["mocha", "junit", "coverage"];
} else if (useCoverage) {
reporters = ["progress", "coverage"];
reporters = ["coverage", "mocha"]; // "progress"
} else {
reporters = ["mocha"];
}
Expand Down
24 changes: 19 additions & 5 deletions packages/tests/specs/SwitchCase.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,32 @@ import {export_checks} from "../support/utils";

describe("query with switch-case", () => {

describe("simple", () => {
describe("2 cases and 1 default", () => {
export_checks([configs.with_all_types, configs.with_cases], inits.spel_with_cases, "SpEL", {
"spel": "(str == '222' ? 'is_string' : (num == 4 ? 'is_number' : 'unknown'))",
logic:
{"IF":[{"==":[{"var":"str"},"222"]},"is_string",{"==":[{"var":"num"},4]},"is_number","unknown"]}
{"if": [
{"==":[{"var":"str"},"222"]},
"is_string",
{"if": [
{"==":[{"var":"num"},4]},
"is_number",
"unknown"
]}
]}
});
});

describe("simple json", () => {
export_checks([configs.with_concat_case_value, configs.with_cases], inits.spel_with_cases_simple, "SpEL", {
describe("1 case and 1 default", () => {
export_checks([configs.with_all_types, configs.with_cases], inits.spel_with_cases_simple, "SpEL", {
logic:
{"IF": [{"==": [{"var": "str"}, "222"]}, "foo", "bar"]}
{
"if": [
{"==": [{"var": "str"}, "222"]},
"foo",
"bar"
]
}
});
});

Expand Down
1 change: 1 addition & 0 deletions packages/tests/support/configs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1547,6 +1547,7 @@ export const with_concat_case_value = (BasicConfig) => ({
...BasicConfig.widgets.case_value,
spelFormatValue: ExportUtils.spelFormatConcat,
spelImportValue: ExportUtils.spelImportConcat,
jsonLogic: ExportUtils.jsonLogicFormatConcat,
},
},
});
Expand Down
2 changes: 1 addition & 1 deletion packages/tests/support/inits.js
Original file line number Diff line number Diff line change
Expand Up @@ -1480,7 +1480,7 @@ export const spel_with_not_between = "(num < 1 || num > 2)";
export const spel_with_not = "!(num == 2)";
export const spel_with_not_not = "!(num == 2 || !(num == 3))";
export const spel_with_cases = "(str == '222' ? is_string : (num == 4 ? is_number : unknown))";
export const spel_with_cases_simple = "(str == '222' ? foo : foo)";
export const spel_with_cases_simple = "(str == '222' ? foo : bar)";
export const spel_with_cases_and_concat = "(str == '222' ? foo : foo + bar)";

export const spel_with_lhs_toLowerCase = "str.toLowerCase().startsWith('aaa')";
Expand Down
7 changes: 4 additions & 3 deletions packages/tests/support/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -687,9 +687,10 @@ const expect_jlogic_before_and_after = (config: Config, tree: ImmutableTree, onC
};

export const expect_objects_equal = (act: any, exp: any, actLabel?: string, expLabel?: string) => {
const expStr = JSON.stringify(exp);
const actStr = JSON.stringify(act);
expect(actStr).to.equal(expStr);
// const expStr = JSON.stringify(exp);
// const actStr = JSON.stringify(act);
// expect(actStr).to.equal(expStr);
expect(act).to.eql(exp);
};

export function hexToRgb(hex: string) {
Expand Down

0 comments on commit 745ac21

Please sign in to comment.