@truedat/dq 5.2.8 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.3.0] 2023-03-08
4
+
5
+ ### Added
6
+
7
+ - [TD-4438] Referenced in/not in reference dataset field validation operator
8
+
3
9
  ## [5.2.8] 2023-02-28
4
10
 
5
11
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "5.2.8",
3
+ "version": "5.3.0",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -92,8 +92,8 @@
92
92
  },
93
93
  "dependencies": {
94
94
  "@apollo/client": "^3.7.1",
95
- "@truedat/core": "5.2.4",
96
- "@truedat/df": "5.2.4",
95
+ "@truedat/core": "5.3.0",
96
+ "@truedat/df": "5.3.0",
97
97
  "decode-uri-component": "^0.2.2",
98
98
  "graphql": "^15.5.3",
99
99
  "moment": "^2.29.4",
@@ -118,5 +118,5 @@
118
118
  "react-dom": ">= 16.8.6 < 17",
119
119
  "semantic-ui-react": ">= 2.0.3 < 2.2"
120
120
  },
121
- "gitHead": "562bc4667fa44eeb0e224a886c41849adbd69a18"
121
+ "gitHead": "4893c314084a4ea7ca48a4e251d4e47565f3f030"
122
122
  }
@@ -23,6 +23,17 @@ QualifyAndLinkStructure.propTypes = {
23
23
  aliasArray: PropTypes.array,
24
24
  };
25
25
 
26
+ const referenceDatasetFieldToLink = ({ name, referenceDataset }) => {
27
+ return (
28
+ <>
29
+ <Link to={linkTo.REFERENCE_DATASET({ id: referenceDataset.id })}>
30
+ <div className="highlighted">{`(${referenceDataset.name})`}</div>{" "}
31
+ </Link>
32
+ <span>{`.${name}`}</span>
33
+ </>
34
+ );
35
+ };
36
+
26
37
  const FormattedLink = ({ value, aliasArray, operator = {} }) => {
27
38
  switch (operator?.value_type) {
28
39
  case "field":
@@ -39,6 +50,8 @@ const FormattedLink = ({ value, aliasArray, operator = {} }) => {
39
50
  ))(value)}
40
51
  </>
41
52
  );
53
+ case "reference_dataset_field":
54
+ return referenceDatasetFieldToLink(value);
42
55
  default:
43
56
  return (
44
57
  <span className="highlighted">
@@ -109,6 +122,13 @@ export const getValues = ({ value = [], operator = {}, value_modifier }) => {
109
122
  ["path", "metadata", "id", "type", "parent_index"],
110
123
  value_modifier
111
124
  )
125
+ : operator?.value_type === "reference_dataset_field"
126
+ ? valuesFromKeys(
127
+ defaultOrValue,
128
+ ["referenceDataset", "name"],
129
+ [],
130
+ value_modifier
131
+ )
112
132
  : valuesFromKeys(defaultOrValue, ["raw"], [], value_modifier);
113
133
  };
114
134
 
@@ -30,9 +30,16 @@ const updateDatasetKey = (data) =>
30
30
 
31
31
  // object either field, raw value, list of fields, list of raw values
32
32
  const updateValueKeyContent = (value) => {
33
- if (value?.id || _.negate(_.isUndefined)(value?.raw) || value?.fields) {
33
+ if (
34
+ value?.id ||
35
+ value?.referenceDataset ||
36
+ _.negate(_.isUndefined)(value?.raw) ||
37
+ value?.fields
38
+ ) {
34
39
  return value?.id || value?.type === "reference_dataset_field"
35
- ? _.pick(["id", "parent_index", "name", "type"])(value)
40
+ ? _.pick(["id", "parent_index", "referenceDataset", "name", "type"])(
41
+ value
42
+ )
36
43
  : _.pick(["raw", "fields"])(value);
37
44
  }
38
45
 
@@ -18,5 +18,5 @@ describe("<RemediationForm />", () => {
18
18
  expect(queryByText(/loading/i)).not.toBeInTheDocument()
19
19
  );
20
20
  expect(container).toMatchSnapshot();
21
- });
21
+ }, 70000);
22
22
  });
@@ -2,6 +2,7 @@ import _ from "lodash/fp";
2
2
  import React, { useState } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { getStructureFieldOptionValue } from "@truedat/dd/selectors/getStructureFieldOptionValue";
5
+ import ReferenceDatasetFieldSelector from "@truedat/dd/components/ReferenceDatasetFieldSelector";
5
6
  import { getStructureFields } from "../../selectors/getStructureFields";
6
7
  import DateField from "./DateField";
7
8
  import DateTimeField from "./DateTimeField";
@@ -167,6 +168,19 @@ export const FiltersField = ({
167
168
  )}
168
169
  </>
169
170
  );
171
+
172
+ case "reference_dataset_field":
173
+ return (
174
+ <ReferenceDatasetFieldSelector
175
+ onChange={onChange}
176
+ /* value could be null if the reference dataset dropdown is
177
+ * selected but not the one for the its field.
178
+ */
179
+ referenceDataset={value?.referenceDataset}
180
+ header={value?.name}
181
+ />
182
+ );
183
+
170
184
  case "string_list":
171
185
  return (
172
186
  <StringListField
@@ -129,7 +129,13 @@ export const FiltersFormGroup = ({
129
129
  {!_.isEmpty(clause?.operator) &&
130
130
  _.range(0, clause?.operator?.arity || 1).map((nth_value) => (
131
131
  <Form.Field
132
- width={clause?.operator?.arity === 2 ? 4 : 9}
132
+ width={
133
+ clause?.operator?.arity != null
134
+ ? clause?.operator?.arity === 2
135
+ ? 4
136
+ : 9
137
+ : 4
138
+ }
133
139
  key={`value_${nth_value}`}
134
140
  >
135
141
  <FiltersField
@@ -84,6 +84,8 @@ export const FiltersGrid = ({
84
84
  return composeFieldValue(v);
85
85
  })(value),
86
86
  };
87
+ } else if (value_type === "reference_dataset_field") {
88
+ return value;
87
89
  } else {
88
90
  return { raw: value };
89
91
  }
@@ -3,7 +3,7 @@ import PropTypes from "prop-types";
3
3
  import React from "react";
4
4
  import { Form } from "semantic-ui-react";
5
5
 
6
- const targetValue = e => {
6
+ const targetValue = (e) => {
7
7
  const target = _.path("target.value")(e);
8
8
  return _.isNil(target) || target === "" ? target : parseFloat(target);
9
9
  };
@@ -17,7 +17,7 @@ export const NumberField = ({ name, label, value, onChange }) => {
17
17
  control="input"
18
18
  value={raw}
19
19
  name={name}
20
- onChange={e => onChange(e, targetValue(e))}
20
+ onChange={(e) => onChange(e, targetValue(e))}
21
21
  />
22
22
  );
23
23
  };
@@ -26,7 +26,7 @@ NumberField.propTypes = {
26
26
  name: PropTypes.string,
27
27
  label: PropTypes.string,
28
28
  value: PropTypes.number,
29
- onChange: PropTypes.func
29
+ onChange: PropTypes.func,
30
30
  };
31
31
 
32
32
  export default NumberField;
@@ -216,11 +216,33 @@ export const RuleImplementationForm = ({
216
216
  !emptyAttr(attr, item) &&
217
217
  validArity(attr, item) &&
218
218
  nestedValid(attr, item)
219
- )(attrs);
219
+ )(attrs) && isValidValue(attrs, item?.value);
220
220
 
221
221
  const mandatoryAttr = (attr, item) =>
222
222
  attr === "population" || !_.isNil(_.path(attr)(item));
223
223
 
224
+ /* Some operators have no value (for example, "UNIQUE")
225
+ * In this case, value will be null and that is fine.
226
+ * Other operators will fill value as an array of one or
227
+ * two elements (two in case of "between values", for example)
228
+ * If value is an array it has to contain something
229
+ * other than null. Also check for incomplete reference dataset field
230
+ * (reference dataset selected but not its field).
231
+ */
232
+ const isValidValue = (attrs, value) =>
233
+ attrs.includes("value") && Array.isArray(value)
234
+ ? _.every((val) => val != null && isValidReferenceDatasetField(val))(
235
+ value
236
+ )
237
+ : true;
238
+
239
+ const isValidReferenceDatasetField = (value) =>
240
+ value?.type === "reference_dataset_field"
241
+ ? value?.name != null &&
242
+ value?.referenceDataset?.id != null &&
243
+ value?.referenceDataset?.name != null
244
+ : true;
245
+
224
246
  const emptyAttr = (attr, item) =>
225
247
  attr === "operator" ? _.isEmpty(_.prop(attr)(item)) : false;
226
248
 
@@ -60,7 +60,7 @@ exports[`<FiltersFormGroup /> matches the latest snapshot 1`] = `
60
60
  </div>
61
61
  </div>
62
62
  <div
63
- class="nine wide field"
63
+ class="four wide field"
64
64
  />
65
65
  </div>
66
66
  </div>
@@ -67,7 +67,7 @@ exports[`<FiltersGroup /> matches the latest snapshot when siblings provided 1`]
67
67
  </div>
68
68
  </div>
69
69
  <div
70
- class="nine wide field"
70
+ class="four wide field"
71
71
  />
72
72
  </div>
73
73
  </div>
@@ -66,7 +66,7 @@ exports[`<ValueConditions /> matches the latest snapshot when siblings provided
66
66
  </div>
67
67
  </div>
68
68
  <div
69
- class="nine wide field"
69
+ class="four wide field"
70
70
  />
71
71
  </div>
72
72
  </div>
@@ -164,6 +164,8 @@ export default {
164
164
  "quality_result.under_goal": "Under goal",
165
165
  "quality_result.under_minimum": "Under threshold",
166
166
  "quality_result.under_minumum": "Under threshold",
167
+ "referenceDataset.dropdown.placeholder": "Reference dataset",
168
+ "referenceDatasetFields.dropdown.placeholder": "Reference dataset fields",
167
169
  "remediation": "Remediation plan",
168
170
  "remediation.actions.create": "Create Remediation Plan",
169
171
  "remediation.actions.delete.confirmation.content":
@@ -432,11 +434,13 @@ export default {
432
434
  "ruleImplementation.operator.not_in_list.string_list": "is not in the list",
433
435
  "ruleImplementation.operator.not_references": "is not referenced",
434
436
  "ruleImplementation.operator.not_references.field": "is not referenced",
437
+ "ruleImplementation.operator.not_references.reference_dataset_field": "not in Reference dataset",
435
438
  "ruleImplementation.operator.number_of_decimals": "has a number of decimals",
436
439
  "ruleImplementation.operator.number_of_decimals.number":
437
440
  "has a number of decimals",
438
441
  "ruleImplementation.operator.references": "referenced in",
439
442
  "ruleImplementation.operator.references.field": "referenced in field",
443
+ "ruleImplementation.operator.references.reference_dataset_field": "in Reference dataset",
440
444
  "ruleImplementation.operator.regex_format": "matches regular expression",
441
445
  "ruleImplementation.operator.regex_format.string":
442
446
  "matches regular expression",
@@ -168,6 +168,8 @@ export default {
168
168
  "quality_result.under_goal": "Por debajo del objetivo",
169
169
  "quality_result.under_minimum": "Por debajo del umbral",
170
170
  "quality_result.under_minumum": "Por debajo del umbral",
171
+ "referenceDataset.dropdown.placeholder": "Dato de referencia",
172
+ "referenceDatasetFields.dropdown.placeholder": "Campo de dato de referencia",
171
173
  "remediation": "Plan de remediación",
172
174
  "remediation.actions.create": "Crear plan de remediación",
173
175
  "remediation.actions.delete.confirmation.content":
@@ -442,10 +444,12 @@ export default {
442
444
  "ruleImplementation.operator.not_in_list.string_list": "no está en la lista",
443
445
  "ruleImplementation.operator.not_references": "no está referenciado en",
444
446
  "ruleImplementation.operator.not_references.field": "no referenciado en",
447
+ "ruleImplementation.operator.not_references.reference_dataset_field": "no en Datos de Referencia",
445
448
  "ruleImplementation.operator.number_of_decimals": "tiene nº decimales",
446
449
  "ruleImplementation.operator.number_of_decimals.number": "tiene nº decimales",
447
450
  "ruleImplementation.operator.references": "referenciado en",
448
451
  "ruleImplementation.operator.references.field": "referenciado en",
452
+ "ruleImplementation.operator.references.reference_dataset_field": "en Datos de Referencia",
449
453
  "ruleImplementation.operator.regex_format": "cumple la expresión regular",
450
454
  "ruleImplementation.operator.regex_format.string":
451
455
  "cumple la expresión regular",