@emuanalytics/flow-rdf-ui 4.0.13 → 4.0.14

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.
@@ -35,7 +35,10 @@ class FlowUiChart extends FlowRdfElement {
35
35
  this._chart.update();
36
36
  }
37
37
  }
38
- firstUpdated() {
38
+ async connectedCallback() {
39
+ super.connectedCallback();
40
+ initializeChartJs();
41
+ await this.updateComplete;
39
42
  this._chart = new Chart(this._chartRef.value, {
40
43
  type: this.type,
41
44
  data: this.data,
@@ -43,10 +46,6 @@ class FlowUiChart extends FlowRdfElement {
43
46
  plugins: this.plugins
44
47
  });
45
48
  }
46
- connectedCallback() {
47
- super.connectedCallback();
48
- initializeChartJs();
49
- }
50
49
  disconnectedCallback() {
51
50
  super.disconnectedCallback();
52
51
  if (this._chart) {
@@ -1,7 +1,11 @@
1
1
  import { DateTime } from 'luxon';
2
2
  import { isNil, isObjectFull, isFunction } from '../../../internal/type-checks.mjs';
3
+ import { escape } from '../../../utilities/regex.mjs';
3
4
  import { filterRuleSet, isRule, isRuleSet } from '../helpers.mjs';
4
5
 
6
+ function isStringType(field) {
7
+ return field.type === "string";
8
+ }
5
9
  function whereClausesFromRuleSet(rule, config, options) {
6
10
  if (isRule(rule)) {
7
11
  if (!rule.enabled) {
@@ -36,12 +40,14 @@ function whereClausesFromRuleSet(rule, config, options) {
36
40
  } else ;
37
41
  }
38
42
  function predicateFromRule(rule, config) {
43
+ const fieldConfig = config.fields[rule.field];
39
44
  const field = config.fields[rule.field];
40
45
  let operator;
41
46
  let value = rule.value;
42
47
  if (isFunction(field.convertValue)) {
43
48
  value = field.convertValue(value);
44
49
  }
50
+ const caseInsensitive = isStringType(fieldConfig) && fieldConfig.caseInsensitive;
45
51
  switch (rule.operator) {
46
52
  case "=":
47
53
  operator = "$eq";
@@ -68,14 +74,32 @@ function predicateFromRule(rule, config) {
68
74
  operator = "$notIn";
69
75
  break;
70
76
  case "like":
71
- operator = "$iLike";
77
+ value = escape(String(value));
78
+ value = value.replace(/\\\?/g, ".");
79
+ value = value.replace(/\\\*/g, ".*");
80
+ value = `^${value}$`;
81
+ operator = caseInsensitive ? "$iRegexp" : "$regexp";
72
82
  break;
73
83
  case "!like":
74
- operator = "$notILike";
84
+ value = escape(String(value));
85
+ value = value.replace(/\\\?/g, ".");
86
+ value = value.replace(/\\\*/g, ".*");
87
+ value = `^${value}$`;
88
+ operator = caseInsensitive ? "$notIRegexp" : "$notRegexp";
75
89
  break;
76
90
  case "contains":
77
- operator = "$iLike";
78
- value = `%${value}%`;
91
+ value = escape(String(value));
92
+ operator = caseInsensitive ? "$iRegexp" : "$regexp";
93
+ break;
94
+ case "!contains":
95
+ value = escape(String(value));
96
+ operator = caseInsensitive ? "$notIRegexp" : "$notRegexp";
97
+ break;
98
+ case "regex":
99
+ operator = caseInsensitive ? "$iRegexp" : "$regexp";
100
+ break;
101
+ case "!regex":
102
+ operator = caseInsensitive ? "$notIRegexp" : "$notRegexp";
79
103
  break;
80
104
  case "null":
81
105
  operator = "$is";
@@ -101,7 +125,11 @@ function predicateFromRule(rule, config) {
101
125
  return { [operator]: value };
102
126
  }
103
127
  const converter = (ruleset, config, options) => {
104
- if (options) {
128
+ options = {
129
+ throwOnError: false,
130
+ ...options
131
+ };
132
+ if (options.excludeFields || options.includeFields || options.renameFields) {
105
133
  ruleset = filterRuleSet(ruleset, options);
106
134
  }
107
135
  return whereClausesFromRuleSet(ruleset, config, options);
@@ -0,0 +1,197 @@
1
+ import { DateTime } from 'luxon';
2
+ import { ensureArray } from '../../../internal/ensure-array.mjs';
3
+ import { isNil, isStringFull, isFunction } from '../../../internal/type-checks.mjs';
4
+ import { escape } from '../../../utilities/regex.mjs';
5
+ import { filterRuleSet, isRule, isRuleSet } from '../helpers.mjs';
6
+
7
+ class JavaScriptFilterError extends Error {
8
+ constructor(msg) {
9
+ super(`JavaScriptFilter error: ${msg}`);
10
+ }
11
+ }
12
+ function isDateType(field) {
13
+ return field.type === "datetime" || field.type === "date" || field.type === "time";
14
+ }
15
+ function isStringType(field) {
16
+ return field.type === "string";
17
+ }
18
+ function convertDateTime(value, field) {
19
+ switch (field.type) {
20
+ case "datetime":
21
+ return +DateTime.fromISO(value);
22
+ case "date":
23
+ return +DateTime.fromISO(value).startOf("day");
24
+ case "time":
25
+ return +DateTime.fromISO(value).set({ year: 1970, day: 1, month: 1 });
26
+ default:
27
+ return 0;
28
+ }
29
+ }
30
+ function rulesetToJavascript(rule, config, options) {
31
+ if (isRule(rule)) {
32
+ if (!rule.enabled) {
33
+ return void 0;
34
+ }
35
+ if (isNil(rule.field) || isNil(rule.operator)) {
36
+ console.warn(`JavascriptFilterConverter: Skipping rule with missing field or operator`, rule);
37
+ return void 0;
38
+ }
39
+ const field = config.fields[rule.field];
40
+ if (!field) {
41
+ console.warn(`JavascriptFilterConverter: Skipping unknown field '${rule.field}' in rule`, rule);
42
+ return void 0;
43
+ }
44
+ if (isNil(rule.value) && field.nullable !== true) {
45
+ console.warn(`JavascriptFilterConverter: Skipping nil field '${rule.field}' in rule (non-nullable)`, rule);
46
+ return void 0;
47
+ }
48
+ let fieldName = rule.field;
49
+ if (options?.renameFields && fieldName in options.renameFields) {
50
+ fieldName = options.renameFields[fieldName];
51
+ }
52
+ return predicateFromRule(rule, config, options);
53
+ } else if (isRuleSet(rule)) {
54
+ const condition = rule.condition === "and" ? " && " : " || ";
55
+ const rules = rule.rules.map((r) => rulesetToJavascript(r, config, options)).filter((r) => isStringFull(r));
56
+ return rules.length ? rules.map((r) => `(${r})`).join(condition) : "true";
57
+ } else ;
58
+ }
59
+ function predicateFromRule(rule, config, options) {
60
+ const fieldConfig = config.fields[rule.field];
61
+ let predicate;
62
+ let fieldName = rule.field;
63
+ if (options.renameFields && fieldName in options.renameFields) {
64
+ fieldName = options.renameFields[fieldName];
65
+ }
66
+ let field = `get("${fieldName}", data)`;
67
+ let operator = "";
68
+ let value = rule.value;
69
+ if (isFunction(fieldConfig.convertValue)) {
70
+ value = fieldConfig.convertValue(value);
71
+ }
72
+ if (isDateType(fieldConfig)) {
73
+ value = convertDateTime(value, fieldConfig);
74
+ }
75
+ const caseInsensitive = isStringType(fieldConfig) && !!fieldConfig.caseInsensitive;
76
+ switch (rule.operator) {
77
+ case "=":
78
+ operator = "==";
79
+ break;
80
+ case "!=":
81
+ operator = "!=";
82
+ break;
83
+ case "<":
84
+ operator = "<";
85
+ break;
86
+ case "<=":
87
+ operator = "<=";
88
+ break;
89
+ case ">":
90
+ operator = ">";
91
+ break;
92
+ case ">=":
93
+ operator = ">=";
94
+ break;
95
+ case "in":
96
+ value = ensureArray(value);
97
+ predicate = `[${value.map(JSON.stringify).join(", ")}].includes(${field})`;
98
+ break;
99
+ case "!in":
100
+ value = ensureArray(value);
101
+ predicate = `![${value.map(JSON.stringify).join(", ")}].includes(${field})`;
102
+ break;
103
+ case "contains":
104
+ field = caseInsensitive ? `${field}.toLowerCase()` : field;
105
+ value = caseInsensitive ? String(value).toLowerCase() : value;
106
+ predicate = `${field}.includes(${JSON.stringify(value)})`;
107
+ break;
108
+ case "!contains":
109
+ field = caseInsensitive ? `${field}.toLowerCase()` : field;
110
+ value = caseInsensitive ? String(value).toLowerCase() : value;
111
+ predicate = `!(${field}.includes(${JSON.stringify(value)}))`;
112
+ break;
113
+ case "like":
114
+ value = escape(String(value));
115
+ value = value.replace(/\\\?/g, ".");
116
+ value = value.replace(/\\\*/g, ".*");
117
+ value = `^${value}$`;
118
+ predicate = `regex(${JSON.stringify(value)}, ${field}, ${caseInsensitive})`;
119
+ break;
120
+ case "!like":
121
+ value = escape(String(value));
122
+ value = value.replace(/\\\?/g, ".");
123
+ value = value.replace(/\\\*/g, ".*");
124
+ value = `^${value}$`;
125
+ predicate = `!(regex(${JSON.stringify(value)}, ${field}, ${caseInsensitive}))`;
126
+ break;
127
+ case "regex":
128
+ predicate = `regex(${JSON.stringify(value)}, ${field}, ${caseInsensitive})`;
129
+ break;
130
+ case "!regex":
131
+ predicate = `!(regex(${JSON.stringify(value)}, ${field}, ${caseInsensitive}))`;
132
+ break;
133
+ default:
134
+ throw new Error(`Unrecognized query operator '${rule.operator}'`);
135
+ }
136
+ predicate ?? (predicate = `${field} ${operator} ${JSON.stringify(value)}`);
137
+ return predicate;
138
+ }
139
+ const converter = (ruleset, config, options) => {
140
+ const warnings = {};
141
+ const regExps = {};
142
+ options = {
143
+ throwOnError: false,
144
+ ...options
145
+ };
146
+ if (options.excludeFields || options.includeFields || options.renameFields) {
147
+ ruleset = filterRuleSet(ruleset, options);
148
+ }
149
+ const hasOwnProperty = (obj, prop) => {
150
+ if (typeof obj === "object" || typeof obj === "function") {
151
+ return Object.prototype.hasOwnProperty.call(obj, prop);
152
+ }
153
+ return false;
154
+ };
155
+ const getProp = (prop, obj) => {
156
+ if (!config.fields[prop])
157
+ throw new JavaScriptFilterError(`Unknown query builder field "${prop}"`);
158
+ if (!hasOwnProperty(obj ?? {}, prop))
159
+ throw new JavaScriptFilterError(`Missing property "${prop}" in supplied data object`);
160
+ const fieldConfig = config.fields[prop];
161
+ let value = obj[prop];
162
+ if (isDateType(fieldConfig)) {
163
+ value = convertDateTime(value, fieldConfig);
164
+ }
165
+ if (isStringType(fieldConfig) && fieldConfig.caseInsensitive) {
166
+ value = String(value).toLowerCase();
167
+ }
168
+ return value;
169
+ };
170
+ const regex = (regex2, val, caseInsensitive = false) => {
171
+ if (!regExps[regex2]) {
172
+ regExps[regex2] = new RegExp(regex2, caseInsensitive ? "i" : "");
173
+ }
174
+ return regExps[regex2].test(val);
175
+ };
176
+ const js = ["return ", rulesetToJavascript(ruleset, config, options), ";"];
177
+ const func = new Function("get", "regex", "data", js.join(""));
178
+ const wrappedFunction = (data) => {
179
+ try {
180
+ return func(getProp, regex, data);
181
+ } catch (e) {
182
+ if (!warnings[e.message]) {
183
+ warnings[e.message] = true;
184
+ console.warn(e.message);
185
+ }
186
+ if (options?.throwOnError) {
187
+ throw e;
188
+ }
189
+ return false;
190
+ }
191
+ };
192
+ wrappedFunction.expression = js.join("");
193
+ return wrappedFunction;
194
+ };
195
+ const converter$1 = converter;
196
+
197
+ export { JavaScriptFilterError, converter$1 as default };
@@ -1,7 +1,11 @@
1
1
  import { ensureArray } from '../../../internal/ensure-array.mjs';
2
2
  import { isNil, isStringFull, isFunction } from '../../../internal/type-checks.mjs';
3
+ import { escape } from '../../../utilities/regex.mjs';
3
4
  import { filterRuleSet, isRule, isRuleSet } from '../helpers.mjs';
4
5
 
6
+ function isStringType(field) {
7
+ return field.type === "string";
8
+ }
5
9
  function mapLayerFilterFromRuleSet(rule, config, options) {
6
10
  if (isRule(rule)) {
7
11
  if (!rule.enabled) {
@@ -24,22 +28,28 @@ function mapLayerFilterFromRuleSet(rule, config, options) {
24
28
  if (options?.renameFields && fieldName in options.renameFields) {
25
29
  fieldName = options.renameFields[fieldName];
26
30
  }
27
- return predicateFromRule(rule, config);
31
+ return predicateFromRule(rule, config, options);
28
32
  } else if (isRuleSet(rule)) {
29
33
  const condition = rule.condition === "and" ? " && " : " || ";
30
34
  const rules = rule.rules.map((r) => mapLayerFilterFromRuleSet(r, config, options)).filter((r) => isStringFull(r));
31
- return rules.length ? rules.map((r) => `(${r})`).join(condition) : "";
35
+ return rules.length ? rules.map((r) => `(${r})`).join(condition) : "true";
32
36
  } else ;
33
37
  }
34
- function predicateFromRule(rule, config) {
38
+ function predicateFromRule(rule, config, options) {
35
39
  const fieldConfig = config.fields[rule.field];
40
+ let fieldName = rule.field;
41
+ if (options.renameFields && fieldName in options.renameFields) {
42
+ fieldName = options.renameFields[fieldName];
43
+ }
36
44
  let predicate;
37
- const field = `get("${rule.field}")`;
45
+ let field = `get("${fieldName}")`;
38
46
  let operator = "";
39
47
  let value = rule.value;
48
+ let negate = false;
40
49
  if (isFunction(fieldConfig.convertValue)) {
41
50
  value = fieldConfig.convertValue(value);
42
51
  }
52
+ const caseInsensitive = isStringType(fieldConfig) && fieldConfig.caseInsensitive;
43
53
  switch (rule.operator) {
44
54
  case "=":
45
55
  operator = "==";
@@ -68,28 +78,53 @@ function predicateFromRule(rule, config) {
68
78
  predicate = `!in(${field}, literal([${value.map(JSON.stringify).join(", ")}]))`;
69
79
  break;
70
80
  case "like":
71
- operator = "~*";
81
+ value = escape(String(value));
82
+ value = value.replace(/\\\?/g, ".");
83
+ value = value.replace(/\\\*/g, ".*");
84
+ value = `^${value}$`;
85
+ operator = caseInsensitive ? "~*" : "~";
86
+ break;
87
+ case "!like":
88
+ value = escape(String(value));
89
+ value = value.replace(/\\\?/g, ".");
90
+ value = value.replace(/\\\*/g, ".*");
91
+ value = `^${value}$`;
92
+ operator = caseInsensitive ? "~*" : "~";
93
+ negate = true;
72
94
  break;
73
95
  case "contains":
96
+ field = caseInsensitive ? `downcase(${field})` : field;
97
+ value = caseInsensitive ? String(value).toLowerCase() : value;
74
98
  predicate = `in(${JSON.stringify(value)}, ${field})`;
75
99
  break;
76
- case "=i":
77
- operator = "=*";
100
+ case "!contains":
101
+ field = caseInsensitive ? `downcase(${field})` : field;
102
+ value = caseInsensitive ? String(value).toLowerCase() : value;
103
+ predicate = `in(${JSON.stringify(value)}, ${field})`;
104
+ negate = true;
78
105
  break;
79
106
  case "regex":
80
- operator = "~";
107
+ operator = caseInsensitive ? "~*" : "~";
81
108
  break;
82
- case "regexi":
83
- operator = "~*";
109
+ case "!regex":
110
+ operator = caseInsensitive ? "~*" : "~";
111
+ negate = true;
84
112
  break;
85
113
  default:
86
114
  throw new Error(`Unrecognized query operator '${rule.operator}'`);
87
115
  }
88
116
  predicate ?? (predicate = `${field} ${operator} ${JSON.stringify(value)}`);
117
+ if (negate) {
118
+ predicate = `!(${predicate})`;
119
+ }
89
120
  return predicate;
90
121
  }
91
122
  const converter = (ruleset, config, options) => {
92
- if (options) {
123
+ options = {
124
+ throwOnError: false,
125
+ ...options
126
+ };
127
+ if (options.excludeFields || options.includeFields || options.renameFields) {
93
128
  ruleset = filterRuleSet(ruleset, options);
94
129
  }
95
130
  return mapLayerFilterFromRuleSet(ruleset, config, options);
@@ -440,7 +440,7 @@ __decorateClass([
440
440
  let FlowUiQueryBuilder = _FlowUiQueryBuilder;
441
441
  FlowUiQueryBuilder.registerFieldDefinition("string", {
442
442
  template: defaultStringTemplate,
443
- operators: ["=", "!=", "like", "contains"]
443
+ operators: ["=", "!=", "contains", "like", "regex"]
444
444
  });
445
445
  FlowUiQueryBuilder.registerFieldDefinition("number", {
446
446
  template: defaultNumberTemplate,