Skip to content

Commit

Permalink
Option for preserving unnecessary groups in jsonlogic export (#1077)
Browse files Browse the repository at this point in the history
* Option for preserving unnecessary groups in jsonlogic export

see issue #1074

* Tests added for exportPreserveGroups setting

Config description also added.

I also changed validation logic so that if removeEmptyGroupsOnLoad/removeEmptyGroups is false then no errors are added during validation. Logic being that if exporting empty groups can be proper then importing them should be seen as correct as well. We could also do it so that exportPreserveGroups itself being true would prevent errors during validation but it seemed more logical for removeEmptyGroupsOnLoad to toggle that.

* Reverted changes to demo

Demo is changed to original including config that now uses the default(false) setting for exportPreserveGroups
  • Loading branch information
Tupsu-jy authored Jul 2, 2024
1 parent 29fcbe2 commit 48ac775
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 7 deletions.
1 change: 1 addition & 0 deletions CONFIG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ Behaviour settings:
NOTE: To preserve read-only state of rules in JsonLogic, please use `jsonLogic.add_operation("locked", v => v);` in your code
|canDeleteLocked |false |Show "Delete" button for locked rule?
|removeIncompleteRulesOnLoad |false |Remove incomplete rules (without field, operator, value, or if not all required args are present for functin) during initial validation of `value` prop passed to `<Query>`
|exportPreserveGroups |false |Preserve unnecessary groups (ie. groups with only one rule or empty groups) during JsonLogic export
|removeEmptyRulesOnLoad |true |Remove empty rules during initial validation of `value` prop passed to `<Query>`
|removeEmptyGroupsOnLoad |true |Remove empty groups during initial validation of `value` prop passed to `<Query>`
|removeInvalidMultiSelectValuesOnLoad |true |Remove values that are not in `listValues` during initial validation of `value` prop passed to `<Query>`? +
Expand Down
1 change: 1 addition & 0 deletions packages/core/modules/config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const settings = {
canDeleteLocked: false,
canLeaveEmptyGroup: true,
shouldCreateEmptyGroup: false,
exportPreserveGroups: false,
removeEmptyGroupsOnLoad: true,
removeEmptyRulesOnLoad: true,
removeIncompleteRulesOnLoad: false,
Expand Down
6 changes: 4 additions & 2 deletions packages/core/modules/export/jsonLogic.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,19 @@ const formatGroup = (item, config, meta, _not = false, isRoot = false, parentFie
.map((currentChild) => formatItem(currentChild, config, meta, revChildren, false, groupField))
.filter((currentChild) => typeof currentChild !== "undefined");

// allows for unnecessary (ie. empty or only one rule) groups to be exported
const shouldPreserveGroups = !!config.settings.exportPreserveGroups;
if (isRuleGroupArray && !isGroup0) {
// "count" rule can have no "having" children, but should have number value
if (formattedValue == undefined)
return undefined;
} else {
if (!list.size)
if (!list.size && !shouldPreserveGroups)
return undefined;
}

let resultQuery = {};
if (list.size == 1 && !isRoot)
if (list.size == 1 && !isRoot && !shouldPreserveGroups)
resultQuery = list.first();
else
resultQuery[conj] = list.toList().toJS();
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 @@ -1369,6 +1369,7 @@ export interface BehaviourSettings {
maxNumberOfCases?: Number;
showErrorMessage?: boolean;
convertableWidgets?: TypedMap<Array<string>>;
exportPreserveGroups?: boolean;
removeEmptyGroupsOnLoad?: boolean;
removeEmptyRulesOnLoad?: boolean;
removeIncompleteRulesOnLoad?: boolean;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/modules/utils/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ function validateGroup (item, path, itemId, meta, c) {
const cardinality = operator ? config.operators[operator]?.cardinality ?? 1 : undefined;
// tip: for group operators some/none/all children ARE required, for group operator count children are NOT required
// tip: default case should contain only value
const childrenAreRequired = isCase ? !isDefaultCase : (isGroupExt ? cardinality == 0 : true);
const childrenAreRequired = isCase ? !isDefaultCase : (isGroupExt ? cardinality == 0 : removeEmptyGroups);
const canHaveValue = isGroupExt || isCase;

if (!id && itemId) {
Expand Down
27 changes: 27 additions & 0 deletions packages/tests/specs/QueryWithGroupsAndStructs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1024,3 +1024,30 @@ describe("query with dot but without !struct", () => {
});

//////////////////////////////////////////////////////////////////////////////////////////

describe("query with empty and single rule groups", () => {

describe("should preserve unnecessary groups during export when preserveGroups is true", () => {
export_checks(configs.with_export_preserve_groups, inits.with_empty_and_single_rule_groups, "JsonLogic", {
"logic": inits.with_empty_and_single_rule_groups,
}, [], {
// Adding custom sanitization options here
sanitizeOptions: {
removeEmptyGroups: false
}
});
});

describe("should not preserve unnecessary groups during export when preserveGroups is false/default", () => {
export_checks(configs.with_allow_empty_groups_on_load, inits.with_empty_and_single_rule_groups, "JsonLogic", {
"logic":{ "or": [ {"==": [ { "var": "num" }, 1 ]} ]}
}, ["Group #2 (index path: 2) >> Empty group"], {
// Adding custom sanitization options here
sanitizeOptions: {
removeEmptyGroups: false
}
});
});
});

//////////////////////////////////////////////////////////////////////////////////////////
6 changes: 2 additions & 4 deletions packages/tests/specs/Validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -974,8 +974,7 @@ describe("sanitizeTree", () => {
"Number BETWEEN ? AND ? >> [rhs] Incomplete RHS",
"? >> [lhs] Incomplete LHS",
"Number > ? >> [rhs] Incomplete RHS",
"Number < 100 >> [rhs 0] Value 100 should be from 0 to 10",
"Group #3 (index path: 6) >> Empty group"
"Number < 100 >> [rhs 0] Value 100 should be from 0 to 10"
],
sanitizeOptions: {
// don't fix tree in `load_tree`
Expand Down Expand Up @@ -1966,8 +1965,7 @@ describe("checkTree (deprecated)", () => {
"Number BETWEEN ? AND ? >> [rhs] Incomplete RHS",
"? >> [lhs] Incomplete LHS",
"Number > ? >> [rhs] Incomplete RHS",
"Number < 100 >> [rhs 0] Value 100 should be from 0 to 10",
"Group #3 (index path: 6) >> Empty group"
"Number < 100 >> [rhs 0] Value 100 should be from 0 to 10"
],
sanitizeOptions: {
// don't fix tree in `load_tree`
Expand Down
16 changes: 16 additions & 0 deletions packages/tests/support/configs.js
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,22 @@ export const with_dont_leave_empty_group = (BasicConfig) => ({
}
});

export const with_allow_empty_groups_on_load = (BasicConfig) => ({
...simple_with_number(BasicConfig),
settings: {
...BasicConfig.settings,
removeEmptyGroupsOnLoad: false
}
});

export const with_export_preserve_groups = (BasicConfig) => ({
...with_allow_empty_groups_on_load(BasicConfig),
settings: {
...BasicConfig.settings,
exportPreserveGroups: true
}
});

export const with_funcs_validation = (BasicConfig) => ({
...BasicConfig,
funcs: {
Expand Down
10 changes: 10 additions & 0 deletions packages/tests/support/inits.js
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,16 @@ export const with_groups = {
]
};

export const with_empty_and_single_rule_groups = {
"or": [
{ "and": [
{
"==": [ { "var": "num" }, 1 ]
}
]}, { "and": []}
]
};

export const with_nested = {
"and": [
{ "==": [ { "var": "user.info.firstName" }, "abc" ] },
Expand Down

0 comments on commit 48ac775

Please sign in to comment.