@molgenis/vip-report-template 6.2.0 → 7.0.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.
Files changed (285) hide show
  1. package/.nvmrc +1 -1
  2. package/.travis.yml +8 -8
  3. package/README.md +411 -1
  4. package/eslint.config.mjs +11 -0
  5. package/package.json +40 -35
  6. package/scripts/deploy_npm_registry.sh +5 -0
  7. package/src/App.tsx +30 -24
  8. package/src/assets/sass/main.scss +12 -4
  9. package/src/components/Allele.tsx +95 -0
  10. package/src/components/Anchor.tsx +1 -1
  11. package/src/components/Breadcrumb.tsx +6 -4
  12. package/src/components/DatasetDropdown.tsx +12 -25
  13. package/src/components/ErrorNotification.tsx +9 -0
  14. package/src/components/GenomeBrowser.tsx +40 -23
  15. package/src/components/HpoTerm.tsx +1 -1
  16. package/src/components/{record/Pager.tsx → Pager.tsx} +21 -14
  17. package/src/components/RecordsPerPage.tsx +9 -7
  18. package/src/components/RecordsTable.tsx +130 -0
  19. package/src/components/SampleTable.tsx +70 -98
  20. package/src/components/SearchBox.tsx +8 -2
  21. package/src/components/Sort.tsx +28 -25
  22. package/src/components/Table.tsx +16 -0
  23. package/src/components/Tooltip.tsx +20 -0
  24. package/src/components/VariantBreadcrumb.tsx +54 -0
  25. package/src/components/VariantConsequenceContainer.tsx +100 -0
  26. package/src/components/VariantConsequenceTable.tsx +58 -0
  27. package/src/components/VariantContainer.tsx +71 -0
  28. package/src/components/VariantFilters.tsx +27 -0
  29. package/src/components/VariantGenotypeTable.tsx +44 -0
  30. package/src/components/VariantInfoTable.tsx +24 -33
  31. package/src/components/VariantResults.tsx +103 -0
  32. package/src/components/VariantTable.tsx +62 -66
  33. package/src/components/VariantTypeSelect.tsx +34 -0
  34. package/src/components/VariantsContainer.tsx +150 -0
  35. package/src/components/VariantsContainerHeader.tsx +70 -0
  36. package/src/components/field/Field.tsx +80 -0
  37. package/src/components/field/FieldAlt.tsx +19 -0
  38. package/src/components/field/FieldChrom.tsx +6 -0
  39. package/src/components/{record/Id.tsx → field/FieldFilter.tsx} +2 -1
  40. package/src/components/field/FieldFormat.tsx +10 -0
  41. package/src/components/{record/Filter.tsx → field/FieldId.tsx} +1 -1
  42. package/src/components/field/FieldPos.tsx +6 -0
  43. package/src/components/field/FieldQual.tsx +6 -0
  44. package/src/components/field/FieldRef.tsx +8 -0
  45. package/src/components/field/composed/FieldClinVar.tsx +72 -0
  46. package/src/components/field/composed/FieldComposed.tsx +68 -0
  47. package/src/components/field/composed/FieldGene.tsx +39 -0
  48. package/src/components/field/composed/FieldGenotype.tsx +35 -0
  49. package/src/components/{record/format/GenotypeField.tsx → field/composed/FieldGenotypeSnvSv.tsx} +20 -16
  50. package/src/components/field/composed/FieldGenotypeStr.tsx +31 -0
  51. package/src/components/field/composed/FieldGnomAd.tsx +58 -0
  52. package/src/components/field/composed/FieldHpo.tsx +50 -0
  53. package/src/components/field/composed/FieldInheritanceModes.tsx +32 -0
  54. package/src/components/field/composed/FieldLocus.tsx +18 -0
  55. package/src/components/field/composed/FieldVipC.tsx +25 -0
  56. package/src/components/field/composed/FieldVipCS.tsx +15 -0
  57. package/src/components/field/composed/FieldVkgl.tsx +37 -0
  58. package/src/components/field/genotype/FieldGenotype.tsx +19 -0
  59. package/src/components/field/genotype/FieldGenotypeType.tsx +9 -0
  60. package/src/components/field/info/FieldConsequence.tsx +15 -0
  61. package/src/components/{record/info/Hgvs.tsx → field/info/FieldHgvs.tsx} +4 -6
  62. package/src/components/field/info/FieldInfo.tsx +27 -0
  63. package/src/components/{record/info/PubMed.tsx → field/info/FieldPubMed.tsx} +4 -7
  64. package/src/components/field/typed/FieldCategorical.tsx +17 -0
  65. package/src/components/{record/field/FieldValueCharacter.tsx → field/typed/FieldCharacter.tsx} +3 -2
  66. package/src/components/{record/field/FieldValueFlag.tsx → field/typed/FieldFlag.tsx} +3 -2
  67. package/src/components/{record/field/FieldValueFloat.tsx → field/typed/FieldFloat.tsx} +3 -2
  68. package/src/components/{record/field/FieldValueInteger.tsx → field/typed/FieldInteger.tsx} +3 -2
  69. package/src/components/{record/field/FieldValueString.tsx → field/typed/FieldString.tsx} +3 -2
  70. package/src/components/field/typed/FieldTyped.tsx +20 -0
  71. package/src/components/field/typed/FieldTypedItem.tsx +49 -0
  72. package/src/components/field/typed/FieldTypedMultiple.tsx +21 -0
  73. package/src/components/filter/Filter.tsx +56 -48
  74. package/src/components/filter/FilterWrapper.scss +23 -0
  75. package/src/components/filter/FilterWrapper.tsx +63 -0
  76. package/src/components/filter/composed/FilterAllelicImbalance.tsx +26 -0
  77. package/src/components/filter/composed/FilterComposed.tsx +92 -0
  78. package/src/components/filter/composed/FilterDeNovo.tsx +35 -0
  79. package/src/components/filter/composed/FilterHpo.tsx +16 -0
  80. package/src/components/filter/composed/FilterInheritance.tsx +42 -0
  81. package/src/components/filter/composed/FilterLocus.tsx +75 -0
  82. package/src/components/filter/composed/FilterVipC.tsx +16 -0
  83. package/src/components/filter/composed/FilterVipCS.tsx +16 -0
  84. package/src/components/filter/fixed/FilterAlt.tsx +20 -0
  85. package/src/components/filter/fixed/FilterChrom.tsx +22 -0
  86. package/src/components/filter/fixed/FilterFilter.tsx +20 -0
  87. package/src/components/filter/fixed/FilterFixed.tsx +96 -0
  88. package/src/components/filter/fixed/FilterId.tsx +20 -0
  89. package/src/components/filter/fixed/FilterPos.tsx +22 -0
  90. package/src/components/filter/fixed/FilterQual.tsx +21 -0
  91. package/src/components/filter/fixed/FilterRef.tsx +22 -0
  92. package/src/components/filter/typed/FilterCategorical.tsx +119 -0
  93. package/src/components/filter/typed/FilterFlag.tsx +23 -0
  94. package/src/components/filter/typed/FilterInterval.tsx +72 -0
  95. package/src/components/filter/typed/FilterString.tsx +43 -0
  96. package/src/components/filter/typed/FilterTyped.tsx +56 -0
  97. package/src/components/form/ButtonApply.tsx +11 -0
  98. package/src/components/form/ButtonDownload.tsx +11 -0
  99. package/src/components/form/ButtonReset.tsx +9 -0
  100. package/src/components/{Checkbox.tsx → form/Checkbox.tsx} +4 -9
  101. package/src/components/form/Input.tsx +19 -0
  102. package/src/components/form/Select.scss +7 -0
  103. package/src/components/form/Select.tsx +34 -0
  104. package/src/components/tree/DecisionTreeBoolMultiQuery.tsx +1 -1
  105. package/src/components/tree/DecisionTreeBoolQuery.tsx +1 -1
  106. package/src/components/tree/DecisionTreeNode.tsx +41 -39
  107. package/src/components/tree/DecisionTreeNodeBool.tsx +1 -1
  108. package/src/components/tree/DecisionTreeNodeBoolMulti.tsx +1 -1
  109. package/src/components/tree/DecisionTreeNodeCategorical.tsx +1 -1
  110. package/src/components/tree/DecisionTreeNodeExists.tsx +1 -1
  111. package/src/components/tree/DecisionTreeNodeLeaf.tsx +1 -1
  112. package/src/components/tree/DecisionTreeOutcomeNode.tsx +1 -1
  113. package/src/components/tree/DecisionTreePath.tsx +1 -1
  114. package/src/igv.d.ts +2 -1
  115. package/src/index.tsx +48 -19
  116. package/src/mocks/GRCh37/decisionTree.json +23 -22
  117. package/src/mocks/GRCh37/field_metadata.json +435 -95
  118. package/src/mocks/GRCh37/sampleTree.json +21 -1
  119. package/src/mocks/GRCh37/static.ts +62 -134
  120. package/src/mocks/GRCh37/vcf/family.vcf.blob +9 -3
  121. package/src/mocks/GRCh38/decisionTree.json +52 -33
  122. package/src/mocks/GRCh38/decisionTreeStr.json +572 -0
  123. package/src/mocks/GRCh38/fasta/chr1_149380406-149403321.fasta.gz.blob +0 -0
  124. package/src/mocks/GRCh38/field_metadata.json +435 -95
  125. package/src/mocks/GRCh38/sampleTree.json +175 -0
  126. package/src/mocks/GRCh38/static.ts +101 -42
  127. package/src/mocks/GRCh38/str.cram.blob +0 -0
  128. package/src/mocks/GRCh38/str.cram.crai.blob +0 -0
  129. package/src/mocks/GRCh38/vcf/family.vcf.blob +25 -24
  130. package/src/mocks/GRCh38/vcf/no_vep.vcf.blob +29 -28
  131. package/src/mocks/GRCh38/vcf/samples_0.vcf.blob +28 -27
  132. package/src/mocks/GRCh38/vcf/samples_1.vcf.blob +29 -28
  133. package/src/mocks/GRCh38/vcf/samples_100.vcf.blob +28 -27
  134. package/src/mocks/GRCh38/vcf/str.vcf.blob +321 -0
  135. package/src/mocks/MockApiClient.ts +339 -332
  136. package/src/mocks/config_cram.json +701 -0
  137. package/src/mocks/config_vcf.json +699 -0
  138. package/src/store/app.ts +30 -0
  139. package/src/store/index.tsx +3 -168
  140. package/src/store/variants.ts +182 -0
  141. package/src/types/config.d.ts +190 -0
  142. package/src/types/configCellComposed.d.ts +86 -0
  143. package/src/types/configCells.d.ts +129 -0
  144. package/src/types/configFilter.d.ts +80 -0
  145. package/src/types/configFilterComposed.d.ts +60 -0
  146. package/src/types/configSort.d.ts +13 -0
  147. package/src/types/filter.d.ts +17 -0
  148. package/src/types/store.d.ts +34 -0
  149. package/src/utils/api.ts +281 -0
  150. package/src/utils/config/config.ts +182 -0
  151. package/src/utils/config/configCells.ts +74 -0
  152. package/src/utils/config/configCellsComposed.ts +508 -0
  153. package/src/utils/config/configCellsField.ts +61 -0
  154. package/src/utils/config/configCellsFixed.ts +126 -0
  155. package/src/utils/config/configFilters.ts +46 -0
  156. package/src/utils/config/configFiltersComposed.ts +208 -0
  157. package/src/utils/config/configFiltersField.ts +49 -0
  158. package/src/utils/config/configFiltersFixed.ts +106 -0
  159. package/src/utils/config/configSorts.ts +44 -0
  160. package/src/utils/config/configValidator.ts +380 -0
  161. package/src/utils/config/configVip.ts +25 -0
  162. package/src/utils/csq.ts +115 -0
  163. package/src/utils/decisionTree.ts +45 -0
  164. package/src/utils/download.ts +30 -0
  165. package/src/utils/error.ts +69 -0
  166. package/src/utils/query/query.ts +55 -0
  167. package/src/utils/query/queryFilter.ts +132 -0
  168. package/src/utils/query/queryFilterComposed.ts +247 -0
  169. package/src/utils/query/queryFilterField.ts +75 -0
  170. package/src/utils/query/queryFilterFixed.ts +44 -0
  171. package/src/utils/query/querySample.ts +18 -0
  172. package/src/utils/query/queryVariantType.ts +76 -0
  173. package/src/utils/query/selector.ts +41 -0
  174. package/src/utils/{sortUtils.ts → query/sort.ts} +32 -11
  175. package/src/utils/sample.ts +19 -35
  176. package/src/utils/utils.ts +66 -2
  177. package/src/utils/variantType.ts +43 -0
  178. package/src/utils/vcf.ts +352 -0
  179. package/src/views/Help.tsx +109 -114
  180. package/src/views/Home.tsx +3 -2
  181. package/src/views/Sample.tsx +12 -7
  182. package/src/views/SampleVariant.tsx +23 -112
  183. package/src/views/SampleVariantConsequence.tsx +54 -144
  184. package/src/views/SampleVariants.tsx +33 -445
  185. package/src/views/SampleVariantsRedirect.tsx +20 -0
  186. package/src/views/Samples.tsx +7 -10
  187. package/src/views/Variant.tsx +31 -61
  188. package/src/views/VariantConsequence.tsx +42 -72
  189. package/src/views/Variants.tsx +29 -138
  190. package/src/views/VariantsRedirect.tsx +25 -0
  191. package/src/views/data/data.tsx +32 -6
  192. package/tests/store/variants.test.ts +122 -0
  193. package/tests/utils/config/config.test.ts +167 -0
  194. package/tests/utils/config/configCells.test.ts +86 -0
  195. package/tests/utils/config/configCellsComposed.test.ts +1163 -0
  196. package/tests/utils/config/configCellsField.test.ts +164 -0
  197. package/tests/utils/config/configCellsFixed.test.ts +99 -0
  198. package/tests/utils/config/configFilters.test.ts +80 -0
  199. package/tests/utils/config/configFiltersComposed.test.ts +504 -0
  200. package/tests/utils/config/configFiltersField.test.ts +140 -0
  201. package/tests/utils/config/configFiltersFixed.test.ts +81 -0
  202. package/tests/utils/config/configSorts.test.ts +55 -0
  203. package/tests/utils/config/configValidator.test.ts +56 -0
  204. package/tests/utils/config/configVip.test.ts +53 -0
  205. package/tests/utils/decisionTree.test.ts +71 -0
  206. package/tests/utils/download.test.ts +20 -0
  207. package/tests/utils/query/query.test.ts +84 -0
  208. package/tests/utils/query/queryFilter.test.ts +243 -0
  209. package/tests/utils/query/queryFilterComposed.test.ts +301 -0
  210. package/tests/utils/query/queryFilterField.test.ts +75 -0
  211. package/tests/utils/query/queryFilterFixed.test.ts +86 -0
  212. package/tests/utils/query/querySample.test.ts +45 -0
  213. package/tests/utils/query/queryVariantType.test.ts +56 -0
  214. package/{src/__tests__/sortUtils.test.ts → tests/utils/query/sort.test.ts} +3 -4
  215. package/tests/utils/sample.test.ts +259 -0
  216. package/tests/utils/utils.test.ts +120 -0
  217. package/tests/utils/variantType.test.ts +48 -0
  218. package/tests/utils/vcf.test.ts +649 -0
  219. package/tsconfig.json +6 -2
  220. package/vite.config.mts +20 -3
  221. package/.eslintignore +0 -4
  222. package/.eslintrc.js +0 -23
  223. package/src/Api.ts +0 -12
  224. package/src/__tests__/decisionTreeUtils.test.ts +0 -75
  225. package/src/__tests__/field.test.ts +0 -107
  226. package/src/__tests__/query.test.ts +0 -188
  227. package/src/__tests__/sample.test.ts +0 -184
  228. package/src/__tests__/utils.test.ts +0 -24
  229. package/src/__tests__/viewUtils.test.ts +0 -125
  230. package/src/components/ConsequenceTable.tsx +0 -45
  231. package/src/components/Error.tsx +0 -9
  232. package/src/components/FieldHeader.tsx +0 -26
  233. package/src/components/InfoCollapsablePane.tsx +0 -90
  234. package/src/components/VariantInfoNestedTable.tsx +0 -127
  235. package/src/components/VariantSampleTable.tsx +0 -58
  236. package/src/components/VariantsSampleTable.tsx +0 -184
  237. package/src/components/VariantsTable.tsx +0 -125
  238. package/src/components/filter/FilterAllelicBalance.tsx +0 -81
  239. package/src/components/filter/FilterCategorical.tsx +0 -81
  240. package/src/components/filter/FilterClinVar.tsx +0 -21
  241. package/src/components/filter/FilterGene.tsx +0 -34
  242. package/src/components/filter/FilterHpo.tsx +0 -161
  243. package/src/components/filter/FilterInheritance.tsx +0 -162
  244. package/src/components/filter/FilterIntegerGq.tsx +0 -47
  245. package/src/components/filter/FilterVI.tsx +0 -68
  246. package/src/components/filter/FilterVariantType.tsx +0 -146
  247. package/src/components/filter/Filters.tsx +0 -29
  248. package/src/components/filter/InfoFilter.tsx +0 -39
  249. package/src/components/filter/InfoFilters.tsx +0 -35
  250. package/src/components/filter/SampleFilters.tsx +0 -93
  251. package/src/components/filter/SamplesFilters.tsx +0 -33
  252. package/src/components/record/Allele.tsx +0 -38
  253. package/src/components/record/AlleleBreakend.tsx +0 -5
  254. package/src/components/record/AlleleMissing.tsx +0 -5
  255. package/src/components/record/AlleleNucs.tsx +0 -49
  256. package/src/components/record/AlleleSymbolic.tsx +0 -5
  257. package/src/components/record/Alt.tsx +0 -17
  258. package/src/components/record/Chrom.tsx +0 -5
  259. package/src/components/record/Format.tsx +0 -40
  260. package/src/components/record/Info.tsx +0 -55
  261. package/src/components/record/Pos.tsx +0 -5
  262. package/src/components/record/Qual.tsx +0 -5
  263. package/src/components/record/RecordDownload.tsx +0 -66
  264. package/src/components/record/Ref.tsx +0 -6
  265. package/src/components/record/field/Field.tsx +0 -36
  266. package/src/components/record/field/FieldMultipleValue.tsx +0 -22
  267. package/src/components/record/field/FieldSingleValue.tsx +0 -35
  268. package/src/components/record/info/ClinVar.tsx +0 -81
  269. package/src/components/record/info/Consequence.tsx +0 -18
  270. package/src/components/record/info/Gene.tsx +0 -56
  271. package/src/components/record/info/GnomAD.tsx +0 -54
  272. package/src/components/record/info/Hpo.tsx +0 -52
  273. package/src/components/record/info/InheritanceModes.tsx +0 -22
  274. package/src/components/record/info/VipC.tsx +0 -23
  275. package/src/components/record/info/Vkgl.tsx +0 -42
  276. package/src/mocks/GRCh37/vcf/no_vep.vcf.blob +0 -61
  277. package/src/mocks/GRCh37/vcf/samples_0.vcf.blob +0 -93
  278. package/src/mocks/GRCh37/vcf/samples_1.vcf.blob +0 -93
  279. package/src/mocks/GRCh37/vcf/samples_100.vcf.blob +0 -93
  280. package/src/utils/ApiUtils.ts +0 -263
  281. package/src/utils/csqUtils.ts +0 -27
  282. package/src/utils/decisionTreeUtils.ts +0 -31
  283. package/src/utils/field.ts +0 -49
  284. package/src/utils/query.ts +0 -154
  285. package/src/utils/viewUtils.ts +0 -32
@@ -0,0 +1,55 @@
1
+ import { ComposedQueryOperator, Query } from "@molgenis/vip-report-api";
2
+ import { FilterValueMap } from "../../types/configFilter";
3
+ import { VariantType } from "../variantType.ts";
4
+
5
+ import { Config } from "../../types/config";
6
+ import { SampleContainer } from "../api.ts";
7
+ import { createQueryFilters } from "./queryFilter.ts";
8
+ import { createQueryVariantType } from "./queryVariantType.ts";
9
+ import { createQuerySample } from "./querySample.ts";
10
+
11
+ export function createQuery(
12
+ config: Config,
13
+ variantType: VariantType,
14
+ sample: SampleContainer | null,
15
+ filterValues: FilterValueMap,
16
+ ): Query | null {
17
+ const queryParts: Query[] = [];
18
+
19
+ const queryVariantType = createQueryVariantType(variantType);
20
+ if (queryVariantType !== null) {
21
+ queryParts.push(queryVariantType);
22
+ }
23
+
24
+ if (sample !== null) {
25
+ const querySample = createQuerySample(config.vip, sample);
26
+ queryParts.push(querySample);
27
+ }
28
+
29
+ const queryFilters = createQueryFilters(config.variants.filters, filterValues);
30
+ if (queryFilters !== null) {
31
+ queryParts.push(queryFilters);
32
+ }
33
+
34
+ return queryParts.length > 0 ? createQueryComposed(queryParts, "and") : null;
35
+ }
36
+
37
+ export function createQueryComposed(queryParts: Query[], operator: ComposedQueryOperator): Query {
38
+ const query: Query | null = createQueryComposedNullable(queryParts, operator);
39
+ if (query === null) {
40
+ throw new Error("query cannot be null");
41
+ }
42
+ return query;
43
+ }
44
+
45
+ export function createQueryComposedNullable(queryParts: Query[], operator: ComposedQueryOperator): Query | null {
46
+ let query: Query | null;
47
+ if (queryParts.length === 0) {
48
+ query = null;
49
+ } else if (queryParts.length === 1) {
50
+ query = queryParts[0]!;
51
+ } else {
52
+ query = { operator, args: queryParts }; // TODO simplify query is all query parts are composed queries with the same operator as the given operator
53
+ }
54
+ return query;
55
+ }
@@ -0,0 +1,132 @@
1
+ import {
2
+ ConfigFilter,
3
+ ConfigFilterField,
4
+ FilterValue,
5
+ FilterValueFixed,
6
+ FilterValueInterval,
7
+ FilterValueMap,
8
+ FilterValueString,
9
+ } from "../../types/configFilter";
10
+ import { Query, Selector } from "@molgenis/vip-report-api";
11
+ import { createQueryFilterComposed } from "./queryFilterComposed.ts";
12
+ import { ConfigFilterComposed } from "../../types/configFilterComposed";
13
+ import { createQueryFilterFixed } from "./queryFilterFixed.ts";
14
+ import { RuntimeError, UnexpectedEnumValueException } from "../error.ts";
15
+ import { ConfigFilters } from "../../types/config";
16
+ import { createQueryComposed, createQueryComposedNullable } from "./query.ts";
17
+ import { createQueryFilterField } from "./queryFilterField.ts";
18
+
19
+ /**
20
+ * Create API query for state of list of filters
21
+ *
22
+ * @param filterConfigs filter configurations
23
+ * @param filterValues filter values
24
+ */
25
+ export function createQueryFilters(filterConfigs: ConfigFilters, filterValues: FilterValueMap): Query | null {
26
+ // TODO discuss: can we have id collisions between different types?
27
+ const queryParts = filterConfigs
28
+ .map((filter) => createQueryFilter(filter, filterValues[filter.id]!))
29
+ .filter((query) => query !== null);
30
+ return createQueryComposedNullable(queryParts, "and");
31
+ }
32
+
33
+ /**
34
+ * Create API query for state of one filter
35
+ *
36
+ * @param filterConfig filter configuration
37
+ * @param filterValue filter value
38
+ */
39
+ function createQueryFilter(filterConfig: ConfigFilter, filterValue: FilterValue): Query | null {
40
+ let query: Query | null;
41
+ if (filterValue !== undefined) {
42
+ switch (filterConfig.type) {
43
+ case "composed":
44
+ query = createQueryFilterComposed(filterConfig as ConfigFilterComposed, filterValue);
45
+ break;
46
+ case "fixed":
47
+ query = createQueryFilterFixed(filterConfig, filterValue as FilterValueFixed);
48
+ break;
49
+ case "genotype":
50
+ case "info":
51
+ query = createQueryFilterField(filterConfig as ConfigFilterField, filterValue);
52
+ break;
53
+ default:
54
+ throw new UnexpectedEnumValueException(filterConfig.type);
55
+ }
56
+ } else {
57
+ query = null;
58
+ }
59
+ return query;
60
+ }
61
+
62
+ export function createQueryFilterString(
63
+ selector: Selector,
64
+ filterValue: FilterValueString,
65
+ multiValue: boolean,
66
+ nestedValue: boolean,
67
+ ): Query {
68
+ // null values
69
+ // multi=false --> value=null
70
+ // multi=true --> value=[] or value=[..., null, ...]
71
+ const filterValues = filterValue.map((value) => (value !== "__null" ? value : null));
72
+
73
+ const queryParts: Query[] = [];
74
+ if (filterValues.length > 0) {
75
+ queryParts.push({
76
+ selector,
77
+ operator: nestedValue ? (multiValue ? "any_has_any" : "has_any") : multiValue ? "has_any" : "in",
78
+ args: filterValues,
79
+ });
80
+ }
81
+
82
+ if (multiValue && filterValues.findIndex((value) => value === null) !== -1) {
83
+ queryParts.push({
84
+ selector,
85
+ operator: nestedValue ? (multiValue ? "any_has_any" : "has_any") : "==",
86
+ args: multiValue ? [] : null,
87
+ });
88
+ }
89
+ return createQueryComposed(queryParts, "or");
90
+ }
91
+
92
+ export function createQueryFilterClosedInterval(selector: Selector, filterValue: FilterValueInterval): Query {
93
+ if (filterValue.left === undefined && filterValue.right === undefined) throw new RuntimeError();
94
+
95
+ const queryParts: Query[] = [];
96
+ if (filterValue.left !== undefined) {
97
+ queryParts.push({
98
+ selector,
99
+ operator: ">=",
100
+ args: filterValue.left,
101
+ });
102
+ }
103
+ if (filterValue.right !== undefined) {
104
+ queryParts.push({
105
+ selector,
106
+ operator: "<=",
107
+ args: filterValue.right,
108
+ });
109
+ }
110
+ return createQueryComposed(queryParts, "and");
111
+ }
112
+
113
+ export function createQueryFilterClosedIntervalOutside(selector: Selector, filterValue: FilterValueInterval): Query {
114
+ if (filterValue.left === undefined && filterValue.right === undefined) throw new RuntimeError();
115
+
116
+ const queryParts: Query[] = [];
117
+ if (filterValue.left !== undefined) {
118
+ queryParts.push({
119
+ selector,
120
+ operator: "<",
121
+ args: filterValue.left,
122
+ });
123
+ }
124
+ if (filterValue.right !== undefined) {
125
+ queryParts.push({
126
+ selector,
127
+ operator: ">",
128
+ args: filterValue.right,
129
+ });
130
+ }
131
+ return createQueryComposed(queryParts, "or");
132
+ }
@@ -0,0 +1,247 @@
1
+ import {
2
+ ConfigFilterAllelicImbalance,
3
+ ConfigFilterComposed,
4
+ ConfigFilterDeNovo,
5
+ ConfigFilterHpo,
6
+ ConfigFilterInheritanceMatch,
7
+ ConfigFilterVipC,
8
+ ConfigFilterVipCS,
9
+ FilterValueAllelicImbalance,
10
+ FilterValueDeNovo,
11
+ FilterValueHpo,
12
+ FilterValueInheritanceMatch,
13
+ FilterValueLocus,
14
+ FilterValueVipC,
15
+ FilterValueVipCS,
16
+ } from "../../types/configFilterComposed";
17
+ import { FilterValue } from "../../types/configFilter";
18
+ import { Query } from "@molgenis/vip-report-api";
19
+ import { createQueryComposed } from "./query.ts";
20
+ import { createSelectorInfo, createSelectorSample } from "./selector.ts";
21
+ import {
22
+ createQueryFilterClosedInterval,
23
+ createQueryFilterClosedIntervalOutside,
24
+ createQueryFilterString,
25
+ } from "./queryFilter.ts";
26
+ import { createQueryFilterFieldCategorical } from "./queryFilterField.ts";
27
+
28
+ export function createQueryFilterComposed(filter: ConfigFilterComposed, filterValue: FilterValue): Query {
29
+ let query: Query;
30
+ switch (filter.id) {
31
+ case "composed/hpo":
32
+ query = createQueryFilterHpo(filter as ConfigFilterHpo, filterValue as FilterValueHpo);
33
+ break;
34
+ case "composed/locus":
35
+ query = createQueryFilterLocus(filterValue as FilterValueLocus);
36
+ break;
37
+ case "composed/allelicImbalance":
38
+ query = createQueryFilterAllelicImbalance(
39
+ filter as ConfigFilterAllelicImbalance,
40
+ filterValue as FilterValueAllelicImbalance,
41
+ );
42
+ break;
43
+ case "composed/inheritanceMatch":
44
+ query = createQueryFilterInheritanceMatch(
45
+ filter as ConfigFilterInheritanceMatch,
46
+ filterValue as FilterValueInheritanceMatch,
47
+ );
48
+ break;
49
+ case "composed/deNovo":
50
+ query = createQueryFilterDeNovo(filter as ConfigFilterDeNovo, filterValue as FilterValueDeNovo);
51
+ break;
52
+ case "composed/vipC":
53
+ query = createQueryFilterVipC(filter as ConfigFilterVipC, filterValue as FilterValueVipC);
54
+ break;
55
+ case "composed/vipCS":
56
+ query = createQueryFilterVipCS(filter as ConfigFilterVipCS, filterValue as FilterValueVipCS);
57
+ break;
58
+ default:
59
+ throw new Error(`unexpected filter id '${filter.id}'`);
60
+ }
61
+ return query;
62
+ }
63
+
64
+ function createQueryFilterHpo(filter: ConfigFilterHpo, filterValue: FilterValueHpo): Query {
65
+ const field = filter.field;
66
+ const selector = createSelectorInfo(field);
67
+ return createQueryFilterFieldCategorical(selector, field, filterValue);
68
+ }
69
+
70
+ function createQueryFilterLocus(filterValue: FilterValueLocus): Query {
71
+ const queryParts: Query[] = [createQueryFilterString(["c"], [filterValue.chromosome], false, false)];
72
+
73
+ if (filterValue.start !== undefined || filterValue.end !== undefined) {
74
+ const posQuery = createQueryFilterClosedInterval(["p"], { left: filterValue.start, right: filterValue.end });
75
+ queryParts.push(posQuery);
76
+ }
77
+
78
+ return createQueryComposed(queryParts, "and");
79
+ }
80
+
81
+ function createQueryFilterAllelicImbalance(
82
+ filter: ConfigFilterAllelicImbalance,
83
+ filterValue: FilterValueAllelicImbalance,
84
+ ): Query {
85
+ const viabSelector = createSelectorSample(filter.sample, filter.viabField);
86
+ const gtSelector = [...createSelectorSample(filter.sample, filter.genotypeField), "t"];
87
+
88
+ const queryParts: Query[] = [];
89
+ if (filterValue.includes("true")) {
90
+ const queryPartsTrue: Query[] = [];
91
+ queryPartsTrue.push(
92
+ createQueryComposed(
93
+ [
94
+ {
95
+ operator: "in",
96
+ selector: gtSelector,
97
+ args: ["hom_a", "hom_r"],
98
+ },
99
+ createQueryFilterClosedInterval(viabSelector, { left: 0.02, right: 0.98 }),
100
+ ],
101
+ "and",
102
+ ),
103
+ );
104
+ queryPartsTrue.push(
105
+ createQueryComposed(
106
+ [
107
+ {
108
+ operator: "==",
109
+ selector: gtSelector,
110
+ args: "het",
111
+ },
112
+ createQueryFilterClosedIntervalOutside(viabSelector, { left: 0.2, right: 0.8 }),
113
+ ],
114
+ "and",
115
+ ),
116
+ );
117
+ queryParts.push(createQueryComposed(queryPartsTrue, "or"));
118
+ }
119
+ if (filterValue.includes("false")) {
120
+ const queryPartsFalse: Query[] = [];
121
+ queryPartsFalse.push(
122
+ createQueryComposed(
123
+ [
124
+ {
125
+ operator: "in",
126
+ selector: gtSelector,
127
+ args: ["hom_a", "hom_r"],
128
+ },
129
+ createQueryFilterClosedIntervalOutside(viabSelector, { left: 0.02, right: 0.98 }),
130
+ ],
131
+ "and",
132
+ ),
133
+ );
134
+ queryPartsFalse.push(
135
+ createQueryComposed(
136
+ [
137
+ {
138
+ operator: "==",
139
+ selector: gtSelector,
140
+ args: "het",
141
+ },
142
+ createQueryFilterClosedInterval(viabSelector, { left: 0.2, right: 0.8 }),
143
+ ],
144
+ "and",
145
+ ),
146
+ );
147
+ queryParts.push(createQueryComposed(queryPartsFalse, "or"));
148
+ }
149
+ if (filterValue.includes("__null")) {
150
+ const queryPartsUndefined: Query[] = [];
151
+ queryPartsUndefined.push({
152
+ selector: viabSelector,
153
+ operator: "==",
154
+ args: null,
155
+ });
156
+ queryPartsUndefined.push({
157
+ selector: viabSelector,
158
+ operator: "==",
159
+ args: undefined,
160
+ });
161
+ queryParts.push(createQueryComposed(queryPartsUndefined, "or"));
162
+ }
163
+ return createQueryComposed(queryParts, "or");
164
+ }
165
+
166
+ function createQueryFilterInheritanceMatch(
167
+ filter: ConfigFilterInheritanceMatch,
168
+ filterValue: FilterValueInheritanceMatch,
169
+ ): Query {
170
+ const vimSelector = createSelectorSample(filter.sample, filter.vimField);
171
+ const queryParts: Query[] = [];
172
+ if (filterValue.includes("true")) {
173
+ queryParts.push({
174
+ operator: "==",
175
+ selector: vimSelector,
176
+ args: 1,
177
+ });
178
+ }
179
+ if (filterValue.includes("false")) {
180
+ queryParts.push({
181
+ operator: "==",
182
+ selector: vimSelector,
183
+ args: 0,
184
+ });
185
+ }
186
+ if (filterValue.includes("potential")) {
187
+ const queryPartsUndefined: Query[] = [];
188
+ queryPartsUndefined.push({
189
+ selector: vimSelector,
190
+ operator: "==",
191
+ args: null,
192
+ });
193
+ queryPartsUndefined.push({
194
+ selector: vimSelector,
195
+ operator: "==",
196
+ args: undefined,
197
+ });
198
+ queryParts.push(createQueryComposed(queryPartsUndefined, "or"));
199
+ }
200
+ return createQueryComposed(queryParts, "and");
201
+ }
202
+
203
+ function createQueryFilterDeNovo(filter: ConfigFilterDeNovo, filterValue: FilterValueDeNovo): Query {
204
+ const vidSelector = createSelectorSample(filter.sample, filter.vidField);
205
+ const queryParts: Query[] = [];
206
+ if (filterValue.includes("true")) {
207
+ queryParts.push({
208
+ operator: "==",
209
+ selector: vidSelector,
210
+ args: 1,
211
+ });
212
+ }
213
+ if (filterValue.includes("false")) {
214
+ queryParts.push({
215
+ operator: "==",
216
+ selector: vidSelector,
217
+ args: 0,
218
+ });
219
+ }
220
+ if (filterValue.includes("potential")) {
221
+ const queryPartsUndefined: Query[] = [];
222
+ queryPartsUndefined.push({
223
+ selector: vidSelector,
224
+ operator: "==",
225
+ args: null,
226
+ });
227
+ queryPartsUndefined.push({
228
+ selector: vidSelector,
229
+ operator: "==",
230
+ args: undefined,
231
+ });
232
+ queryParts.push(createQueryComposed(queryPartsUndefined, "or"));
233
+ }
234
+ return createQueryComposed(queryParts, "and");
235
+ }
236
+
237
+ function createQueryFilterVipC(filter: ConfigFilterVipC, filterValue: FilterValueVipC): Query {
238
+ const field = filter.field;
239
+ const selector = createSelectorInfo(field);
240
+ return createQueryFilterFieldCategorical(selector, field, filterValue);
241
+ }
242
+
243
+ function createQueryFilterVipCS(filter: ConfigFilterVipCS, filterValue: FilterValueVipCS): Query {
244
+ const field = filter.field;
245
+ const selector = createSelectorSample(filter.sample, field);
246
+ return createQueryFilterFieldCategorical(selector, field, filterValue);
247
+ }
@@ -0,0 +1,75 @@
1
+ import { Query, Selector, SelectorPart } from "@molgenis/vip-report-api";
2
+ import { FieldMetadata } from "@molgenis/vip-report-vcf";
3
+ import {
4
+ ConfigFilterField,
5
+ ConfigFilterFormat,
6
+ FilterValue,
7
+ FilterValueCategorical,
8
+ FilterValueInterval,
9
+ FilterValueString,
10
+ } from "../../types/configFilter";
11
+ import { UnexpectedEnumValueException } from "../error.ts";
12
+ import { createSelectorInfo, createSelectorSample } from "./selector.ts";
13
+ import { createQueryFilterClosedInterval, createQueryFilterString } from "./queryFilter.ts";
14
+
15
+ export function createQueryFilterField(filter: ConfigFilterField, filterValue: FilterValue): Query {
16
+ const selector = createSelectorFilter(filter);
17
+ const field = filter.field;
18
+
19
+ let query: Query;
20
+ switch (filter.field.type) {
21
+ case "CATEGORICAL":
22
+ query = createQueryFilterFieldCategorical(selector, field, filterValue as FilterValueCategorical);
23
+ break;
24
+ case "CHARACTER":
25
+ case "STRING":
26
+ query = createQueryFilterFieldString(selector, field, filterValue as FilterValueString);
27
+ break;
28
+ case "FLOAT":
29
+ case "INTEGER":
30
+ query = createQueryFilterClosedInterval(selector, filterValue as FilterValueInterval);
31
+ break;
32
+ case "FLAG":
33
+ query = createQueryFilterFlag();
34
+ break;
35
+ default:
36
+ throw new UnexpectedEnumValueException(field.type);
37
+ }
38
+ return query;
39
+ }
40
+
41
+ function createSelectorFilter(filter: ConfigFilterField) {
42
+ let selector: SelectorPart[];
43
+ switch (filter.type) {
44
+ case "genotype":
45
+ selector = createSelectorSample((filter as ConfigFilterFormat).sample, filter.field);
46
+ break;
47
+ case "info":
48
+ selector = createSelectorInfo(filter.field);
49
+ break;
50
+ case "composed":
51
+ default:
52
+ throw new UnexpectedEnumValueException(filter.type);
53
+ }
54
+ return selector;
55
+ }
56
+
57
+ export function createQueryFilterFieldCategorical(
58
+ selector: Selector,
59
+ field: FieldMetadata,
60
+ filterValue: FilterValueCategorical,
61
+ ): Query {
62
+ const multiValue = field.number.count !== 1;
63
+ const nestedValue = field.parent !== undefined;
64
+ return createQueryFilterString(selector, filterValue, multiValue, nestedValue);
65
+ }
66
+
67
+ function createQueryFilterFlag(): Query {
68
+ throw new Error("not implemented"); // FIXME support flag filter queries
69
+ }
70
+
71
+ function createQueryFilterFieldString(selector: Selector, field: FieldMetadata, filterValue: FilterValueString): Query {
72
+ const multiValue = field.number.count !== 1;
73
+ const nestedValue = field.parent !== undefined;
74
+ return createQueryFilterString(selector, filterValue, multiValue, nestedValue);
75
+ }
@@ -0,0 +1,44 @@
1
+ import {
2
+ ConfigFilterFixed,
3
+ FilterValueAlt,
4
+ FilterValueChrom,
5
+ FilterValueFilter,
6
+ FilterValueFixed,
7
+ FilterValueId,
8
+ FilterValuePos,
9
+ FilterValueQual,
10
+ FilterValueRef,
11
+ } from "../../types/configFilter";
12
+ import { Query } from "@molgenis/vip-report-api";
13
+ import { UnexpectedEnumValueException } from "../error.ts";
14
+ import { createQueryFilterClosedInterval, createQueryFilterString } from "./queryFilter.ts";
15
+
16
+ export function createQueryFilterFixed(filter: ConfigFilterFixed, filterValue: FilterValueFixed): Query {
17
+ let query: Query;
18
+ switch (filter.id) {
19
+ case "fixed/chrom":
20
+ query = createQueryFilterString(["c"], filterValue as FilterValueChrom, false, false);
21
+ break;
22
+ case "fixed/pos":
23
+ query = createQueryFilterClosedInterval(["p"], filterValue as FilterValuePos);
24
+ break;
25
+ case "fixed/id":
26
+ query = createQueryFilterString(["i"], filterValue as FilterValueId, true, false);
27
+ break;
28
+ case "fixed/ref":
29
+ query = createQueryFilterString(["r"], filterValue as FilterValueRef, false, false);
30
+ break;
31
+ case "fixed/alt":
32
+ query = createQueryFilterString(["a"], filterValue as FilterValueAlt, true, false);
33
+ break;
34
+ case "fixed/qual":
35
+ query = createQueryFilterClosedInterval(["q"], filterValue as FilterValueQual);
36
+ break;
37
+ case "fixed/filter":
38
+ query = createQueryFilterString(["f"], filterValue as FilterValueFilter, true, false);
39
+ break;
40
+ default:
41
+ throw new UnexpectedEnumValueException(filter.id);
42
+ }
43
+ return query;
44
+ }
@@ -0,0 +1,18 @@
1
+ import { Query } from "@molgenis/vip-report-api";
2
+ import { SampleContainer } from "../api.ts";
3
+ import { createSelectorSample } from "./selector.ts";
4
+ import { ConfigVip } from "../../types/config";
5
+ import { FilterValueCategorical } from "../../types/configFilter";
6
+ import { createQueryFilterFieldCategorical } from "./queryFilterField.ts";
7
+
8
+ export function createQuerySample(config: ConfigVip, sample: SampleContainer): Query {
9
+ const filterValues = getFilterValues(config);
10
+ const selector = createSelectorSample(sample, config.filter_field);
11
+ return createQueryFilterFieldCategorical(selector, config.filter_field, filterValues);
12
+ }
13
+
14
+ function getFilterValues(config: ConfigVip): FilterValueCategorical {
15
+ const filterSamplesClasses = config.params.vcf.filter_samples.classes.split(",");
16
+ // add null values to make query match with records that do not have a value for the field
17
+ return [...filterSamplesClasses, "__null"];
18
+ }
@@ -0,0 +1,76 @@
1
+ import { Query, SelectorPart } from "@molgenis/vip-report-api";
2
+ import { VariantType } from "../variantType.ts";
3
+ import { UnexpectedEnumValueException } from "../error.ts";
4
+ import { createQueryComposed } from "./query.ts";
5
+
6
+ export function createQueryVariantType(variantType: VariantType): Query | null {
7
+ let query: Query | null;
8
+ switch (variantType.id) {
9
+ case "all":
10
+ query = null;
11
+ break;
12
+ case "snv":
13
+ query = createQueryVariantTypeSnv();
14
+ break;
15
+ case "str":
16
+ query = createQueryVariantTypeStr();
17
+ break;
18
+ case "sv":
19
+ query = createQueryVariantTypeSv();
20
+ break;
21
+ default:
22
+ throw new UnexpectedEnumValueException(variantType.id);
23
+ }
24
+ return query;
25
+ }
26
+
27
+ function createQueryVariantTypeSnv(): Query {
28
+ const queryParts: Query[] = [
29
+ {
30
+ selector: createSelectorVariantType(),
31
+ operator: "==",
32
+ args: null,
33
+ },
34
+ {
35
+ selector: createSelectorVariantType(),
36
+ operator: "==",
37
+ args: undefined,
38
+ },
39
+ ];
40
+ return createQueryComposed(queryParts, "or");
41
+ }
42
+
43
+ function createQueryVariantTypeStr(): Query {
44
+ return {
45
+ selector: createSelectorVariantType(),
46
+ operator: "==",
47
+ args: "STR",
48
+ };
49
+ }
50
+
51
+ function createQueryVariantTypeSv(): Query {
52
+ return {
53
+ operator: "and",
54
+ args: [
55
+ {
56
+ selector: createSelectorVariantType(),
57
+ operator: "!=",
58
+ args: "STR",
59
+ },
60
+ {
61
+ selector: createSelectorVariantType(),
62
+ operator: "!=",
63
+ args: null,
64
+ },
65
+ {
66
+ selector: createSelectorVariantType(),
67
+ operator: "!=",
68
+ args: undefined,
69
+ },
70
+ ],
71
+ };
72
+ }
73
+
74
+ function createSelectorVariantType(): SelectorPart[] {
75
+ return ["n", "SVTYPE"];
76
+ }
@@ -0,0 +1,41 @@
1
+ import { FieldMetadata } from "@molgenis/vip-report-vcf";
2
+ import { Selector, SelectorPart, SortPath } from "@molgenis/vip-report-api";
3
+ import { FieldMetadataWrapper } from "../vcf.ts";
4
+ import { SampleContainer } from "../api.ts";
5
+
6
+ export function createSelectorInfo(field: FieldMetadataWrapper): SelectorPart[] {
7
+ return ["n", ...selector(field)];
8
+ }
9
+
10
+ export function createSelectorSample(sample: SampleContainer, field: FieldMetadataWrapper): SelectorPart[] {
11
+ return ["s", sample.item.data.index, ...selector(field)];
12
+ }
13
+
14
+ export function createInfoSortPath(field: FieldMetadata): SortPath {
15
+ return ["n", ...selector(field).filter((part) => part !== "*")];
16
+ }
17
+
18
+ function selector(field: FieldMetadata): SelectorPart[] {
19
+ const selector: Selector = [];
20
+ let currentField: FieldMetadata | undefined = field;
21
+ do {
22
+ if (currentField.parent && currentField.parent.nested) {
23
+ const items = currentField.parent.nested.items;
24
+ let i;
25
+ for (i = 0; i < items.length; ++i) {
26
+ if (items[i]!.id === currentField.id) {
27
+ break;
28
+ }
29
+ }
30
+ selector.push(i);
31
+ if (currentField.parent.number.count !== 1) {
32
+ selector.push("*");
33
+ }
34
+ } else {
35
+ selector.push(currentField.id);
36
+ }
37
+ currentField = currentField.parent;
38
+ } while (currentField);
39
+ selector.reverse();
40
+ return selector;
41
+ }