@platforma-sdk/model 1.48.4 → 1.48.12

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.
@@ -14,7 +14,11 @@ function filterPredicate(item) {
14
14
  if (item.type === 'and') {
15
15
  return item.filters.length > 0;
16
16
  }
17
- return true;
17
+ if (item.type === 'not') {
18
+ return filterPredicate(item.filter);
19
+ }
20
+ // Filter out any item that has undefined values in required fields
21
+ return !Object.values(item).some((v) => v === undefined);
18
22
  }
19
23
  function filterEmptyPeaces(item) {
20
24
  if (item.type === 'or' || item.type === 'and') {
@@ -1 +1 @@
1
- {"version":3,"file":"converter.cjs","sources":["../../src/annotations/converter.ts"],"sourcesContent":["import { when } from '@milaboratories/ptabler-expression-js';\nimport type { FilterSpec } from '../filters';\nimport { convertFilterUiToExpressionImpl } from '../filters/converter';\nimport type { ExpressionSpec, FilterSpecUi } from './types';\n\nfunction filterPredicate(item: FilterSpec): boolean {\n // No need to convert empty steps\n if (item.type == null) {\n return false;\n }\n\n if (item.type === 'or') {\n return item.filters.length > 0;\n }\n\n if (item.type === 'and') {\n return item.filters.length > 0;\n }\n\n return true;\n}\n\nfunction filterEmptyPeaces(item: FilterSpec): FilterSpec {\n if (item.type === 'or' || item.type === 'and') {\n const filtered = item.filters\n .map(filterEmptyPeaces)\n .filter(filterPredicate);\n return {\n ...item,\n filters: filtered,\n };\n }\n\n return item;\n}\n\nexport function convertFilterSpecsToExpressionSpecs(annotationsUI: FilterSpecUi[]): ExpressionSpec[] {\n const validAnnotationsUI = annotationsUI.map((step) => ({\n label: step.label,\n filter: filterEmptyPeaces(step.filter),\n }));\n return validAnnotationsUI\n .map((step): ExpressionSpec => ({\n type: 'alias',\n name: step.label.trim(),\n value: when(convertFilterUiToExpressionImpl(step.filter)).then(true).otherwise(false).toJSON(),\n }));\n}\n"],"names":["when","convertFilterUiToExpressionImpl"],"mappings":";;;;;AAKA,SAAS,eAAe,CAAC,IAAgB,EAAA;;AAEvC,IAAA,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE;AACrB,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE;AACtB,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;IAChC;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AACvB,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;IAChC;AAEA,IAAA,OAAO,IAAI;AACb;AAEA,SAAS,iBAAiB,CAAC,IAAgB,EAAA;AACzC,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AAC7C,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC;aACnB,GAAG,CAAC,iBAAiB;aACrB,MAAM,CAAC,eAAe,CAAC;QAC1B,OAAO;AACL,YAAA,GAAG,IAAI;AACP,YAAA,OAAO,EAAE,QAAQ;SAClB;IACH;AAEA,IAAA,OAAO,IAAI;AACb;AAEM,SAAU,mCAAmC,CAAC,aAA6B,EAAA;IAC/E,MAAM,kBAAkB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM;QACtD,KAAK,EAAE,IAAI,CAAC,KAAK;AACjB,QAAA,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;AACvC,KAAA,CAAC,CAAC;AACH,IAAA,OAAO;AACJ,SAAA,GAAG,CAAC,CAAC,IAAI,MAAsB;AAC9B,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QACvB,KAAK,EAAEA,wBAAI,CAACC,yCAA+B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AAC/F,KAAA,CAAC,CAAC;AACP;;;;"}
1
+ {"version":3,"file":"converter.cjs","sources":["../../src/annotations/converter.ts"],"sourcesContent":["import { when } from '@milaboratories/ptabler-expression-js';\nimport type { FilterSpec } from '../filters';\nimport { convertFilterUiToExpressionImpl } from '../filters/converter';\nimport type { ExpressionSpec, FilterSpecUi } from './types';\n\nfunction filterPredicate(item: FilterSpec): boolean {\n // No need to convert empty steps\n if (item.type == null) {\n return false;\n }\n\n if (item.type === 'or') {\n return item.filters.length > 0;\n }\n\n if (item.type === 'and') {\n return item.filters.length > 0;\n }\n\n if (item.type === 'not') {\n return filterPredicate(item.filter);\n }\n\n // Filter out any item that has undefined values in required fields\n return !Object.values(item).some((v) => v === undefined);\n}\n\nfunction filterEmptyPeaces(item: FilterSpec): FilterSpec {\n if (item.type === 'or' || item.type === 'and') {\n const filtered = item.filters\n .map(filterEmptyPeaces)\n .filter(filterPredicate);\n return {\n ...item,\n filters: filtered,\n };\n }\n\n return item;\n}\n\nexport function convertFilterSpecsToExpressionSpecs(annotationsUI: FilterSpecUi[]): ExpressionSpec[] {\n const validAnnotationsUI = annotationsUI.map((step) => ({\n label: step.label,\n filter: filterEmptyPeaces(step.filter),\n }));\n return validAnnotationsUI\n .map((step): ExpressionSpec => ({\n type: 'alias',\n name: step.label.trim(),\n value: when(convertFilterUiToExpressionImpl(step.filter)).then(true).otherwise(false).toJSON(),\n }));\n}\n"],"names":["when","convertFilterUiToExpressionImpl"],"mappings":";;;;;AAKA,SAAS,eAAe,CAAC,IAAgB,EAAA;;AAEvC,IAAA,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE;AACrB,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE;AACtB,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;IAChC;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AACvB,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;IAChC;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AACvB,QAAA,OAAO,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;IACrC;;AAGA,IAAA,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC;AAC1D;AAEA,SAAS,iBAAiB,CAAC,IAAgB,EAAA;AACzC,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AAC7C,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC;aACnB,GAAG,CAAC,iBAAiB;aACrB,MAAM,CAAC,eAAe,CAAC;QAC1B,OAAO;AACL,YAAA,GAAG,IAAI;AACP,YAAA,OAAO,EAAE,QAAQ;SAClB;IACH;AAEA,IAAA,OAAO,IAAI;AACb;AAEM,SAAU,mCAAmC,CAAC,aAA6B,EAAA;IAC/E,MAAM,kBAAkB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM;QACtD,KAAK,EAAE,IAAI,CAAC,KAAK;AACjB,QAAA,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;AACvC,KAAA,CAAC,CAAC;AACH,IAAA,OAAO;AACJ,SAAA,GAAG,CAAC,CAAC,IAAI,MAAsB;AAC9B,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QACvB,KAAK,EAAEA,wBAAI,CAACC,yCAA+B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AAC/F,KAAA,CAAC,CAAC;AACP;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"converter.d.ts","sourceRoot":"","sources":["../../src/annotations/converter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAiC5D,wBAAgB,mCAAmC,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,cAAc,EAAE,CAWnG"}
1
+ {"version":3,"file":"converter.d.ts","sourceRoot":"","sources":["../../src/annotations/converter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAsC5D,wBAAgB,mCAAmC,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,cAAc,EAAE,CAWnG"}
@@ -12,7 +12,11 @@ function filterPredicate(item) {
12
12
  if (item.type === 'and') {
13
13
  return item.filters.length > 0;
14
14
  }
15
- return true;
15
+ if (item.type === 'not') {
16
+ return filterPredicate(item.filter);
17
+ }
18
+ // Filter out any item that has undefined values in required fields
19
+ return !Object.values(item).some((v) => v === undefined);
16
20
  }
17
21
  function filterEmptyPeaces(item) {
18
22
  if (item.type === 'or' || item.type === 'and') {
@@ -1 +1 @@
1
- {"version":3,"file":"converter.js","sources":["../../src/annotations/converter.ts"],"sourcesContent":["import { when } from '@milaboratories/ptabler-expression-js';\nimport type { FilterSpec } from '../filters';\nimport { convertFilterUiToExpressionImpl } from '../filters/converter';\nimport type { ExpressionSpec, FilterSpecUi } from './types';\n\nfunction filterPredicate(item: FilterSpec): boolean {\n // No need to convert empty steps\n if (item.type == null) {\n return false;\n }\n\n if (item.type === 'or') {\n return item.filters.length > 0;\n }\n\n if (item.type === 'and') {\n return item.filters.length > 0;\n }\n\n return true;\n}\n\nfunction filterEmptyPeaces(item: FilterSpec): FilterSpec {\n if (item.type === 'or' || item.type === 'and') {\n const filtered = item.filters\n .map(filterEmptyPeaces)\n .filter(filterPredicate);\n return {\n ...item,\n filters: filtered,\n };\n }\n\n return item;\n}\n\nexport function convertFilterSpecsToExpressionSpecs(annotationsUI: FilterSpecUi[]): ExpressionSpec[] {\n const validAnnotationsUI = annotationsUI.map((step) => ({\n label: step.label,\n filter: filterEmptyPeaces(step.filter),\n }));\n return validAnnotationsUI\n .map((step): ExpressionSpec => ({\n type: 'alias',\n name: step.label.trim(),\n value: when(convertFilterUiToExpressionImpl(step.filter)).then(true).otherwise(false).toJSON(),\n }));\n}\n"],"names":[],"mappings":";;;AAKA,SAAS,eAAe,CAAC,IAAgB,EAAA;;AAEvC,IAAA,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE;AACrB,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE;AACtB,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;IAChC;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AACvB,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;IAChC;AAEA,IAAA,OAAO,IAAI;AACb;AAEA,SAAS,iBAAiB,CAAC,IAAgB,EAAA;AACzC,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AAC7C,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC;aACnB,GAAG,CAAC,iBAAiB;aACrB,MAAM,CAAC,eAAe,CAAC;QAC1B,OAAO;AACL,YAAA,GAAG,IAAI;AACP,YAAA,OAAO,EAAE,QAAQ;SAClB;IACH;AAEA,IAAA,OAAO,IAAI;AACb;AAEM,SAAU,mCAAmC,CAAC,aAA6B,EAAA;IAC/E,MAAM,kBAAkB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM;QACtD,KAAK,EAAE,IAAI,CAAC,KAAK;AACjB,QAAA,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;AACvC,KAAA,CAAC,CAAC;AACH,IAAA,OAAO;AACJ,SAAA,GAAG,CAAC,CAAC,IAAI,MAAsB;AAC9B,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QACvB,KAAK,EAAE,IAAI,CAAC,+BAA+B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AAC/F,KAAA,CAAC,CAAC;AACP;;;;"}
1
+ {"version":3,"file":"converter.js","sources":["../../src/annotations/converter.ts"],"sourcesContent":["import { when } from '@milaboratories/ptabler-expression-js';\nimport type { FilterSpec } from '../filters';\nimport { convertFilterUiToExpressionImpl } from '../filters/converter';\nimport type { ExpressionSpec, FilterSpecUi } from './types';\n\nfunction filterPredicate(item: FilterSpec): boolean {\n // No need to convert empty steps\n if (item.type == null) {\n return false;\n }\n\n if (item.type === 'or') {\n return item.filters.length > 0;\n }\n\n if (item.type === 'and') {\n return item.filters.length > 0;\n }\n\n if (item.type === 'not') {\n return filterPredicate(item.filter);\n }\n\n // Filter out any item that has undefined values in required fields\n return !Object.values(item).some((v) => v === undefined);\n}\n\nfunction filterEmptyPeaces(item: FilterSpec): FilterSpec {\n if (item.type === 'or' || item.type === 'and') {\n const filtered = item.filters\n .map(filterEmptyPeaces)\n .filter(filterPredicate);\n return {\n ...item,\n filters: filtered,\n };\n }\n\n return item;\n}\n\nexport function convertFilterSpecsToExpressionSpecs(annotationsUI: FilterSpecUi[]): ExpressionSpec[] {\n const validAnnotationsUI = annotationsUI.map((step) => ({\n label: step.label,\n filter: filterEmptyPeaces(step.filter),\n }));\n return validAnnotationsUI\n .map((step): ExpressionSpec => ({\n type: 'alias',\n name: step.label.trim(),\n value: when(convertFilterUiToExpressionImpl(step.filter)).then(true).otherwise(false).toJSON(),\n }));\n}\n"],"names":[],"mappings":";;;AAKA,SAAS,eAAe,CAAC,IAAgB,EAAA;;AAEvC,IAAA,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE;AACrB,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE;AACtB,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;IAChC;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AACvB,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;IAChC;AAEA,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AACvB,QAAA,OAAO,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;IACrC;;AAGA,IAAA,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC;AAC1D;AAEA,SAAS,iBAAiB,CAAC,IAAgB,EAAA;AACzC,IAAA,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AAC7C,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC;aACnB,GAAG,CAAC,iBAAiB;aACrB,MAAM,CAAC,eAAe,CAAC;QAC1B,OAAO;AACL,YAAA,GAAG,IAAI;AACP,YAAA,OAAO,EAAE,QAAQ;SAClB;IACH;AAEA,IAAA,OAAO,IAAI;AACb;AAEM,SAAU,mCAAmC,CAAC,aAA6B,EAAA;IAC/E,MAAM,kBAAkB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM;QACtD,KAAK,EAAE,IAAI,CAAC,KAAK;AACjB,QAAA,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;AACvC,KAAA,CAAC,CAAC;AACH,IAAA,OAAO;AACJ,SAAA,GAAG,CAAC,CAAC,IAAI,MAAsB;AAC9B,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QACvB,KAAK,EAAE,IAAI,CAAC,+BAA+B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AAC/F,KAAA,CAAC,CAAC;AACP;;;;"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.48.4";
3
+ var version = "1.48.12";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.map
@@ -1,4 +1,4 @@
1
- var version = "1.48.4";
1
+ var version = "1.48.12";
2
2
 
3
3
  export { version };
4
4
  //# sourceMappingURL=package.json.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/model",
3
- "version": "1.48.4",
3
+ "version": "1.48.12",
4
4
  "description": "Platforma.bio SDK / Block Model",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -23,19 +23,19 @@
23
23
  "canonicalize": "~2.1.0",
24
24
  "es-toolkit": "^1.39.10",
25
25
  "zod": "~3.23.8",
26
- "@milaboratories/ptabler-expression-js": "1.1.7",
27
26
  "@milaboratories/pl-model-common": "1.21.10",
28
- "@milaboratories/pl-error-like": "1.12.5"
27
+ "@milaboratories/pl-error-like": "1.12.5",
28
+ "@milaboratories/ptabler-expression-js": "1.1.7"
29
29
  },
30
30
  "devDependencies": {
31
31
  "typescript": "~5.6.3",
32
32
  "vitest": "^4.0.7",
33
33
  "fast-json-patch": "^3.1.1",
34
- "@milaboratories/build-configs": "1.2.0",
34
+ "@milaboratories/build-configs": "1.2.1",
35
35
  "@platforma-sdk/eslint-config": "1.2.0",
36
- "@milaboratories/helpers": "1.12.0",
37
- "@milaboratories/ts-builder": "1.2.0",
38
- "@milaboratories/ts-configs": "1.2.0"
36
+ "@milaboratories/ts-configs": "1.2.0",
37
+ "@milaboratories/helpers": "1.12.1",
38
+ "@milaboratories/ts-builder": "1.2.1"
39
39
  },
40
40
  "scripts": {
41
41
  "type-check": "ts-builder types --target node",
@@ -1,4 +1,3 @@
1
- import type { SUniversalPColumnId } from '@milaboratories/pl-model-common';
2
1
  import { describe, expect, test } from 'vitest';
3
2
  import { convertFilterSpecsToExpressionSpecs } from './converter';
4
3
  import { FilterSpecUi } from './types';
@@ -16,8 +15,8 @@ describe('convertFilterSpecsToExpressionSpecs', () => {
16
15
  filter: {
17
16
  type: 'and',
18
17
  filters: [
19
- { type: 'isNA', column: 'colA' as unknown as SUniversalPColumnId },
20
- { type: 'patternEquals', column: 'colB' as unknown as SUniversalPColumnId, value: 'abc' },
18
+ { type: 'isNA', column: 'colA' } as any,
19
+ { type: 'patternEquals', column: 'colB', value: 'abc' } as any,
21
20
  ],
22
21
  },
23
22
  },
@@ -69,6 +68,144 @@ describe('convertFilterSpecsToExpressionSpecs', () => {
69
68
  const script = convertFilterSpecsToExpressionSpecs(filters);
70
69
  expect(script).toEqual(expected);
71
70
  });
72
- });
73
-
74
71
 
72
+ test('should filter out empty/unset filter conditions', () => {
73
+ const filters: FilterSpecUi[] = [
74
+ {
75
+ label: 'Step with various unset filters',
76
+ filter: {
77
+ type: 'and',
78
+ filters: [
79
+ {} as any,
80
+ { type: undefined } as any,
81
+ { type: 'isNA', column: 'colA' },
82
+ { type: 'isNA', column: undefined } as any,
83
+ { type: 'isNotNA', column: undefined } as any,
84
+ { type: 'patternEquals', column: undefined, value: 'test' },
85
+ { type: 'patternEquals', column: 'colX', value: undefined } as any,
86
+ { type: 'patternNotEquals', column: undefined, value: 'test' } as any,
87
+ { type: 'patternNotEquals', column: 'colX', value: undefined } as any,
88
+ { type: 'patternContainSubsequence', column: undefined, value: 'test' } as any,
89
+ { type: 'patternContainSubsequence', column: 'colX', value: undefined } as any,
90
+ { type: 'equal', column: undefined, x: 5 } as any,
91
+ { type: 'equal', column: 'colX', x: undefined } as any,
92
+ { type: 'lessThan', column: undefined, x: 5 } as any,
93
+ { type: 'lessThan', column: 'colX', x: undefined } as any,
94
+ { type: 'greaterThan', column: undefined, x: 5 } as any,
95
+ { type: 'greaterThan', column: 'colX', x: undefined } as any,
96
+ { type: 'topN', column: undefined, n: 5 } as any,
97
+ { type: 'topN', column: 'colX', n: undefined } as any,
98
+ { type: 'bottomN', column: undefined, n: 5 } as any,
99
+ { type: 'bottomN', column: 'colX', n: undefined } as any,
100
+ { type: 'equalToColumn', column: undefined, rhs: 'colY' } as any,
101
+ { type: 'equalToColumn', column: 'colX', rhs: undefined } as any,
102
+ { type: 'greaterThanColumn', column: undefined, rhs: 'colY' } as any,
103
+ { type: 'greaterThanColumn', column: 'colX', rhs: undefined } as any,
104
+ { type: 'lessThanColumn', column: undefined, rhs: 'colY' } as any,
105
+ { type: 'lessThanColumn', column: 'colX', rhs: undefined } as any,
106
+ { type: undefined, column: 'colX', value: 'someValue' } as any,
107
+ ],
108
+ },
109
+ },
110
+ {
111
+ label: 'Step with nested unset filters',
112
+ filter: {
113
+ type: 'or',
114
+ filters: [
115
+ {
116
+ type: 'and',
117
+ filters: [
118
+ { type: undefined } as any,
119
+ { type: 'patternEquals', column: 'colB', value: 'test' },
120
+ { type: undefined, column: undefined } as any,
121
+ ],
122
+ },
123
+ { type: undefined } as any,
124
+ {
125
+ type: 'or',
126
+ filters: [
127
+ { type: undefined } as any,
128
+ { type: undefined, value: undefined } as any,
129
+ ],
130
+ } as any,
131
+ ],
132
+ },
133
+ },
134
+ ];
135
+ const expected = [
136
+ {
137
+ name: 'Step with various unset filters',
138
+ type: 'alias',
139
+ value: {
140
+ conditions: [
141
+ {
142
+ then: {
143
+ type: 'const',
144
+ value: true,
145
+ },
146
+ when: {
147
+ type: 'and',
148
+ operands: [
149
+ {
150
+ type: 'is_na',
151
+ value: {
152
+ name: 'colA',
153
+ type: 'col',
154
+ },
155
+ },
156
+ ],
157
+ },
158
+ },
159
+ ],
160
+ otherwise: {
161
+ type: 'const',
162
+ value: false,
163
+ },
164
+ type: 'when_then_otherwise',
165
+ },
166
+ },
167
+ {
168
+ name: 'Step with nested unset filters',
169
+ type: 'alias',
170
+ value: {
171
+ conditions: [
172
+ {
173
+ then: {
174
+ type: 'const',
175
+ value: true,
176
+ },
177
+ when: {
178
+ type: 'or',
179
+ operands: [
180
+ {
181
+ type: 'and',
182
+ operands: [
183
+ {
184
+ lhs: {
185
+ name: 'colB',
186
+ type: 'col',
187
+ },
188
+ rhs: {
189
+ type: 'const',
190
+ value: 'test',
191
+ },
192
+ type: 'eq',
193
+ },
194
+ ],
195
+ },
196
+ ],
197
+ },
198
+ },
199
+ ],
200
+ otherwise: {
201
+ type: 'const',
202
+ value: false,
203
+ },
204
+ type: 'when_then_otherwise',
205
+ },
206
+ },
207
+ ];
208
+ const script = convertFilterSpecsToExpressionSpecs(filters);
209
+ expect(script).toEqual(expected);
210
+ });
211
+ });
@@ -17,7 +17,12 @@ function filterPredicate(item: FilterSpec): boolean {
17
17
  return item.filters.length > 0;
18
18
  }
19
19
 
20
- return true;
20
+ if (item.type === 'not') {
21
+ return filterPredicate(item.filter);
22
+ }
23
+
24
+ // Filter out any item that has undefined values in required fields
25
+ return !Object.values(item).some((v) => v === undefined);
21
26
  }
22
27
 
23
28
  function filterEmptyPeaces(item: FilterSpec): FilterSpec {