@sjcrh/proteinpaint-server 2.177.0 → 2.177.1-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.
@@ -373,6 +373,10 @@ function termdb_test_default() {
373
373
  ssGSEA: {
374
374
  file: "files/hg38/TermdbTest/rnaseq/TermdbTest.ssgsea.h5"
375
375
  },
376
+ dnaMethylation: {
377
+ file: "files/hg38/TermdbTest/dnaMeth.h5",
378
+ unit: "Average Beta Value"
379
+ },
376
380
  topVariablyExpressedGenes: {
377
381
  src: "native"
378
382
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.177.0",
3
+ "version": "2.177.1-0",
4
4
  "type": "module",
5
5
  "description": "a genomics visualization tool for exploring a cohort's genotype and phenotype data",
6
6
  "main": "src/app.js",
@@ -62,11 +62,11 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@sjcrh/augen": "2.143.0",
65
- "@sjcrh/proteinpaint-python": "2.174.0",
65
+ "@sjcrh/proteinpaint-python": "2.177.1-0",
66
66
  "@sjcrh/proteinpaint-r": "2.152.1-0",
67
- "@sjcrh/proteinpaint-rust": "2.177.0",
68
- "@sjcrh/proteinpaint-shared": "2.177.0",
69
- "@sjcrh/proteinpaint-types": "2.177.0",
67
+ "@sjcrh/proteinpaint-rust": "2.177.1-0",
68
+ "@sjcrh/proteinpaint-shared": "2.177.1-0",
69
+ "@sjcrh/proteinpaint-types": "2.177.1-0",
70
70
  "@types/express": "^5.0.0",
71
71
  "@types/express-session": "^1.18.1",
72
72
  "better-sqlite3": "^12.4.1",
@@ -870,28 +870,72 @@ function removeLastOccurrence(str, word) {
870
870
  return str.slice(0, index) + str.slice(index + word.length);
871
871
  }
872
872
  }
873
+ function sortSameCategoricalFilterKeys(filters, ds) {
874
+ let html = "";
875
+ const keys = filters.map((f) => f.term);
876
+ if (new Set(keys).size == keys.length) return { filters, html };
877
+ const seen = /* @__PURE__ */ new Set();
878
+ const categorical_filter_terms_with_multiple_fields = /* @__PURE__ */ new Set();
879
+ for (const item of filters) {
880
+ if (seen.has(item.term)) categorical_filter_terms_with_multiple_fields.add(item.term);
881
+ else seen.add(item.term);
882
+ }
883
+ const multiple_fields_keys = [];
884
+ for (const key of categorical_filter_terms_with_multiple_fields) {
885
+ const term = ds.cohort.termdb.q.termjsonByOneid(key);
886
+ if (!term) {
887
+ html += "invalid filter id:" + key;
888
+ } else {
889
+ if (term.type == "categorical") {
890
+ const multiple_fields = filters.filter((x) => x.term == key);
891
+ multiple_fields_keys.push({ key, categories: multiple_fields.map((f) => f.category) });
892
+ }
893
+ }
894
+ }
895
+ const sorted_filter = [];
896
+ const seen2 = /* @__PURE__ */ new Set();
897
+ for (const f of filters) {
898
+ const repeated_term = multiple_fields_keys.find((x) => x.key == f.term);
899
+ if (!repeated_term) {
900
+ sorted_filter.push(f);
901
+ } else {
902
+ if (!seen2.has(f.term)) {
903
+ const new_filter_term = {
904
+ term: f.term,
905
+ category: repeated_term.categories
906
+ };
907
+ seen2.add(f.term);
908
+ sorted_filter.push(new_filter_term);
909
+ }
910
+ }
911
+ }
912
+ return { filters: sorted_filter, html };
913
+ }
873
914
  function validate_filter(filters, ds, group_name) {
874
915
  if (!Array.isArray(filters)) throw "filter is not array";
875
- let filter_result = { html: "" };
876
- if (filters.length <= 2) {
877
- filter_result = generate_filter_term(filters, ds);
916
+ const sorted_filters = sortSameCategoricalFilterKeys(filters, ds);
917
+ let filter_result = { html: sorted_filters.html };
918
+ if (sorted_filters.filters.length <= 2) {
919
+ const generated = generate_filter_term(sorted_filters.filters, ds);
920
+ filter_result.simplefilter = generated.simplefilter;
921
+ filter_result.html += generated.html;
878
922
  } else {
879
- if (filters.length > num_filter_cutoff) {
880
- filter_result.html = "For now, the maximum number of filter terms supported through the chatbot is " + num_filter_cutoff;
923
+ if (sorted_filters.filters.length > num_filter_cutoff) {
924
+ filter_result.html += "For now, the maximum number of filter terms supported through the chatbot is " + num_filter_cutoff;
881
925
  if (group_name.length > 0) {
882
- filter_result.html += " . The number of filter terms for group " + group_name + " is " + filters.length + "\n";
926
+ filter_result.html += " . The number of filter terms for group " + group_name + " is " + sorted_filters.filters.length + "\n";
883
927
  } else {
884
- filter_result.html += "The number of filter terms for this query is " + filters.length;
928
+ filter_result.html += "The number of filter terms for this query is " + sorted_filters.filters.length;
885
929
  }
886
930
  } else {
887
- for (let i = 0; i < filters.length - 1; i++) {
931
+ for (let i = 0; i < sorted_filters.filters.length - 1; i++) {
888
932
  const filter_lst = [];
889
933
  if (i == 0) {
890
- filter_lst.push(filters[i]);
934
+ filter_lst.push(sorted_filters.filters[i]);
891
935
  } else {
892
936
  filter_lst.push(filter_result.simplefilter);
893
937
  }
894
- filter_lst.push(filters[i + 1]);
938
+ filter_lst.push(sorted_filters.filters[i + 1]);
895
939
  filter_result = generate_filter_term(filter_lst, ds);
896
940
  }
897
941
  }
@@ -913,19 +957,35 @@ function generate_filter_term(filters, ds) {
913
957
  localfilter.join = f.join;
914
958
  }
915
959
  if (term.type == "categorical") {
916
- let cat;
917
- for (const ck in term.values) {
918
- if (ck == f.category) cat = ck;
919
- else if (term.values[ck].label == f.category) cat = ck;
920
- }
921
- if (!cat) invalid_html += "invalid category from " + JSON.stringify(f);
922
- localfilter.lst.push({
923
- type: "tvs",
924
- tvs: {
925
- term,
926
- values: [{ key: cat }]
960
+ if (Array.isArray(f.category)) {
961
+ const categories = [];
962
+ for (const category of f.category) {
963
+ const cat = findCategoryKey(term.values, category);
964
+ if (!cat) invalid_html += "invalid category from " + JSON.stringify(f);
965
+ else {
966
+ categories.push({ key: cat });
967
+ }
927
968
  }
928
- });
969
+ localfilter.lst.push({
970
+ type: "tvs",
971
+ tvs: {
972
+ term,
973
+ values: categories
974
+ }
975
+ });
976
+ } else {
977
+ const cat = findCategoryKey(term.values, f.category);
978
+ if (!cat) invalid_html += "invalid category from " + JSON.stringify(f);
979
+ else {
980
+ localfilter.lst.push({
981
+ type: "tvs",
982
+ tvs: {
983
+ term,
984
+ values: [{ key: cat }]
985
+ }
986
+ });
987
+ }
988
+ }
929
989
  } else if (term.type == "float" || term.type == "integer") {
930
990
  const numeric = {
931
991
  type: "tvs",
@@ -958,6 +1018,12 @@ function generate_filter_term(filters, ds) {
958
1018
  }
959
1019
  return { simplefilter: localfilter, html: invalid_html };
960
1020
  }
1021
+ function findCategoryKey(termValues, category) {
1022
+ for (const ck in termValues) {
1023
+ if (ck === category || termValues[ck].label === category) return ck;
1024
+ }
1025
+ return void 0;
1026
+ }
961
1027
  async function parse_geneset_db(genedb) {
962
1028
  let genes_list = [];
963
1029
  const db = new Database(genedb);
@@ -189,6 +189,9 @@ function addNonDictionaryQueries(c, ds, genome) {
189
189
  if (q.geneExpression) {
190
190
  q2.geneExpression = { unit: q.geneExpression.unit };
191
191
  }
192
+ if (q.dnaMethylation) {
193
+ q2.dnaMethylation = { unit: q.dnaMethylation.unit };
194
+ }
192
195
  if (q.ld) {
193
196
  q2.ld = structuredClone(q.ld);
194
197
  }
@@ -264,6 +267,7 @@ function getAllowedTermTypes(ds) {
264
267
  if (ds.queries?.geneExpression) typeSet.add(TermTypes.GENE_EXPRESSION);
265
268
  if (ds.queries?.metaboliteIntensity) typeSet.add(TermTypes.METABOLITE_INTENSITY);
266
269
  if (ds.queries?.ssGSEA) typeSet.add(TermTypes.SSGSEA);
270
+ if (ds.queries?.dnaMethylation) typeSet.add(TermTypes.DNA_METHYLATION);
267
271
  if (ds.cohort.termdb.numericTermCollections) typeSet.add("termCollection");
268
272
  return [...typeSet];
269
273
  }