@sjcrh/proteinpaint-server 2.129.1 → 2.129.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.129.1",
3
+ "version": "2.129.2",
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,10 +62,10 @@
62
62
  "dependencies": {
63
63
  "@sjcrh/augen": "2.121.0",
64
64
  "@sjcrh/proteinpaint-python": "2.118.0",
65
- "@sjcrh/proteinpaint-r": "2.129.1",
66
- "@sjcrh/proteinpaint-rust": "2.129.0",
67
- "@sjcrh/proteinpaint-shared": "2.129.1",
68
- "@sjcrh/proteinpaint-types": "2.129.0",
65
+ "@sjcrh/proteinpaint-r": "2.129.2",
66
+ "@sjcrh/proteinpaint-rust": "2.129.2",
67
+ "@sjcrh/proteinpaint-shared": "2.129.2",
68
+ "@sjcrh/proteinpaint-types": "2.129.2",
69
69
  "@types/express": "^5.0.0",
70
70
  "@types/express-session": "^1.18.1",
71
71
  "better-sqlite3": "^9.4.1",
package/routes/dataset.js CHANGED
@@ -1,4 +1,3 @@
1
- import * as mds2_init from "#src/mds2.init.js";
2
1
  import * as mds3_init from "#src/mds3.init.js";
3
2
  import * as common from "#shared/common.js";
4
3
  import { datasetPayload } from "#types/checkers";
@@ -59,9 +58,6 @@ function mds_clientcopy(ds) {
59
58
  if (ds.queries) {
60
59
  ds2.queries = {};
61
60
  }
62
- if (ds.track) {
63
- ds2.track = mds2_init.client_copy(ds);
64
- }
65
61
  if (ds.singlesamplemutationjson) {
66
62
  ds2.singlesamplemutationjson = 1;
67
63
  }
@@ -88,12 +88,23 @@ async function listMafFiles(q, ds) {
88
88
  if (!Array.isArray(re.data?.hits))
89
89
  throw "re.data.hits[] not array";
90
90
  const files = [];
91
+ const filteredFiles = [];
91
92
  for (const h of re.data.hits) {
92
93
  const c = h.cases?.[0];
93
94
  if (!c)
94
95
  throw "h.cases[0] missing";
95
- if (h.file_size >= maxFileSizeAllowed)
96
+ if (h.file_size >= maxFileSizeAllowed) {
97
+ filteredFiles.push({
98
+ fileId: h.id,
99
+ fileSize: h.file_size,
100
+ reason: `File size (${h.file_size} bytes) exceeds maximum allowed size (${maxFileSizeAllowed} bytes)`
101
+ });
102
+ console.log(
103
+ `File ${h.id} with a size of ${h.file_size} bytes is larger then the allowed file size. It is excluded from the list.
104
+ If you want to include it, please increase the maxFileSizeAllowed in the code.`
105
+ );
96
106
  continue;
107
+ }
97
108
  const file = {
98
109
  id: h.id,
99
110
  project_id: c.project.project_id,
@@ -117,9 +128,42 @@ async function listMafFiles(q, ds) {
117
128
  file.sample_types = [...new Set(file.sample_types)];
118
129
  files.push(file);
119
130
  }
120
- files.sort((a, b) => b.file_size - a.file_size);
131
+ const filesByCase = /* @__PURE__ */ new Map();
132
+ for (const file of files) {
133
+ const caseId = file.case_submitter_id;
134
+ if (!filesByCase.has(caseId)) {
135
+ filesByCase.set(caseId, []);
136
+ }
137
+ filesByCase.get(caseId).push(file);
138
+ }
139
+ const deduplicatedFiles = [];
140
+ let duplicatesRemoved = 0;
141
+ const caseDetails = [];
142
+ for (const [caseId, caseFiles] of filesByCase) {
143
+ if (caseFiles.length > 1) {
144
+ caseFiles.sort((a, b) => b.file_size - a.file_size);
145
+ deduplicatedFiles.push(caseFiles[0]);
146
+ duplicatesRemoved += caseFiles.length - 1;
147
+ caseDetails.push({
148
+ caseName: caseId,
149
+ fileCount: caseFiles.length,
150
+ keptFileSize: caseFiles[0].file_size
151
+ });
152
+ console.log(
153
+ `Case ${caseId}: Found ${caseFiles.length} MAF files, keeping largest (${caseFiles[0].file_size} bytes)`
154
+ );
155
+ } else {
156
+ deduplicatedFiles.push(caseFiles[0]);
157
+ }
158
+ }
159
+ if (duplicatesRemoved > 0) {
160
+ console.log(
161
+ `GRIN2 MAF deduplication: Removed ${duplicatesRemoved} duplicate files, kept ${deduplicatedFiles.length} unique cases`
162
+ );
163
+ }
164
+ deduplicatedFiles.sort((a, b) => b.file_size - a.file_size);
121
165
  const result = {
122
- files,
166
+ files: deduplicatedFiles,
123
167
  filesTotal: re.data.pagination.total,
124
168
  maxTotalSizeCompressed,
125
169
  fileCounts: {
@@ -128,6 +172,13 @@ async function listMafFiles(q, ds) {
128
172
  appliedFilters: {
129
173
  fileTypes: shouldRetrieveMaf ? ["MAF"] : [],
130
174
  experimentalStrategy
175
+ },
176
+ deduplicationStats: {
177
+ originalFileCount: files.length,
178
+ deduplicatedFileCount: deduplicatedFiles.length,
179
+ duplicatesRemoved,
180
+ caseDetails,
181
+ filteredFiles
131
182
  }
132
183
  };
133
184
  return result;
@@ -26,13 +26,14 @@ function init({ genomes }) {
26
26
  const ds = g.datasets.GDC;
27
27
  if (!ds)
28
28
  throw "hg38 GDC missing";
29
- const caseFiles = req.query;
30
- console.log(`[GRIN2] Request received: ${JSON.stringify(caseFiles)}`);
31
- if (!caseFiles) {
32
- throw "Missing or invalid cases data";
33
- }
29
+ console.log(`[GRIN2] Request received:`, JSON.stringify(req.query));
30
+ const parsedRequest = req.query;
31
+ console.log(`[GRIN2] Parsed request: ${JSON.stringify(parsedRequest)}`);
34
32
  console.log("[GRIN2] Calling Rust for file processing...");
35
- const rustInput = JSON.stringify(caseFiles);
33
+ const rustInput = JSON.stringify({
34
+ caseFiles: parsedRequest.caseFiles,
35
+ mafOptions: parsedRequest.mafOptions
36
+ });
36
37
  console.log("[GRIN2] Executing Rust function...");
37
38
  const rustResult = await run_rust("gdcGRIN2", rustInput);
38
39
  console.log("[GRIN2] Rust execution completed");
@@ -40,11 +41,23 @@ function init({ genomes }) {
40
41
  throw new Error("Failed to process MAF files: No result from Rust");
41
42
  }
42
43
  let parsedRustResult;
44
+ let dataForR = [];
43
45
  try {
44
46
  parsedRustResult = typeof rustResult === "string" ? JSON.parse(rustResult) : rustResult;
45
- console.log(`[GRIN2] Parsed Rust result: ${JSON.stringify(parsedRustResult).substring(0, 200)}...`);
47
+ console.log(`[GRIN2] Parsed Rust result structure received`);
48
+ if (parsedRustResult.successful_data && Array.isArray(parsedRustResult.successful_data)) {
49
+ dataForR = parsedRustResult.successful_data.flat();
50
+ console.log(`[GRIN2] Extracted ${dataForR.length} records for R script`);
51
+ console.log(
52
+ `[GRIN2] Success: ${parsedRustResult.summary.successful_files}, Failed: ${parsedRustResult.summary.failed_files}`
53
+ );
54
+ } else {
55
+ console.warn("[GRIN2] Unexpected Rust result format");
56
+ dataForR = [];
57
+ }
46
58
  } catch (parseError) {
47
59
  console.error("[GRIN2] Error parsing Rust result:", parseError);
60
+ dataForR = [];
48
61
  }
49
62
  const genedbfile = path.join(serverconfig.tpmasterdir, g.genedb.dbfile);
50
63
  const imagefile = path.join(serverconfig.cachedir, `grin2_${Date.now()}_${Math.floor(Math.random() * 1e9)}.png`);
@@ -52,7 +65,7 @@ function init({ genomes }) {
52
65
  genedb: genedbfile,
53
66
  chromosomelist: g.majorchr,
54
67
  imagefile,
55
- lesion: rustResult
68
+ lesion: dataForR
56
69
  // The mutation string from Rust
57
70
  });
58
71
  console.log(`R input: ${rInput}`);
@@ -64,7 +77,8 @@ function init({ genomes }) {
64
77
  resultData = JSON.parse(rResult);
65
78
  console.log("[GRIN2] Finished R analysis");
66
79
  const pngImg = resultData.png[0];
67
- return res.json({ pngImg });
80
+ const topGeneTable = resultData.topGeneTable || null;
81
+ return res.json({ pngImg, topGeneTable, rustResult: parsedRustResult, status: "success" });
68
82
  } catch (parseError) {
69
83
  console.error("[GRIN2] Error parsing R result:", parseError);
70
84
  console.log("[GRIN2] Raw R result:", rResult);