11import { parentPort } from 'worker_threads' ;
22
3- import type { FormTypes , InstrumentMeasureValue } from '@opendatacapture/runtime-core' ;
4- import { DEFAULT_GROUP_NAME } from '@opendatacapture/schemas/core' ;
5- import type { InstrumentRecordsExport } from '@opendatacapture/schemas/instrument-records' ;
63import { removeSubjectIdScope } from '@opendatacapture/subject-utils' ;
74
8- import type { BeginChunkProcessingData , InitData , ParentMessage , RecordType , WorkerMessage } from './thread-types' ;
9-
10- type ExpandDataType =
11- | {
12- measure : string ;
13- measureValue : FormTypes . RecordArrayFieldValue | InstrumentMeasureValue ;
14- success : true ;
15- }
16- | {
17- message : string ;
18- success : false ;
19- } ;
20-
21- function expandData ( listEntry : any [ ] ) : ExpandDataType [ ] {
22- const validRecordArrayList : ExpandDataType [ ] = [ ] ;
5+ /** @type {typeof import('@opendatacapture/schemas/core').DEFAULT_GROUP_NAME } */
6+ const DEFAULT_GROUP_NAME = 'root' ;
7+
8+ /**
9+ * @typedef {Object } SuccessExpand
10+ * @property {string } measure
11+ * @property {any } measureValue
12+ * @property {true } success
13+ */
14+
15+ /**
16+ * @typedef {Object } FailureExpand
17+ * @property {string } message
18+ * @property {false } success
19+ */
20+
21+ /** @typedef {SuccessExpand | FailureExpand } ExpandDataType */
22+
23+ /**
24+ * Flattens nested record array data into a list of expandable data objects.
25+ * @param {any[] } listEntry - The array of records to expand.
26+ * @returns {ExpandDataType[] } An array of expanded measure objects.
27+ * @throws {Error } If the provided listEntry is empty.
28+ */
29+ function expandData ( listEntry ) {
30+ /** @type {SuccessExpand[] } */
31+ const validRecordArrayList = [ ] ;
2332 if ( listEntry . length < 1 ) {
2433 throw new Error ( 'Record Array is Empty' ) ;
2534 }
2635 for ( const objectEntry of Object . values ( listEntry ) ) {
27- for ( const [ dataKey , dataValue ] of Object . entries (
28- objectEntry as { [ key : string ] : FormTypes . RecordArrayFieldValue }
29- ) ) {
36+ for ( const [ dataKey , dataValue ] of Object . entries ( objectEntry ) ) {
3037 validRecordArrayList . push ( {
3138 measure : dataKey ,
3239 measureValue : dataValue ,
@@ -37,34 +44,48 @@ function expandData(listEntry: any[]): ExpandDataType[] {
3744 return validRecordArrayList ;
3845}
3946
40- let initData : Map <
41- string | undefined ,
42- {
43- edition : number ;
44- id : string ;
45- name : string ;
46- }
47- > ;
48-
49- function handleInit ( data : InitData ) {
47+ /**
48+ * Internal cache for instrument metadata.
49+ * @type {Map<string | undefined, { edition: number, id: string, name: string }> }
50+ */
51+ let initData ;
52+
53+ /**
54+ * Initializes the worker with instrument metadata.
55+ * * @param {Array<{id: string, edition: number, name: string}> } data - The initialization payload.
56+ */
57+ function handleInit ( data ) {
5058 initData = new Map ( data . map ( ( instrument ) => [ instrument . id , instrument ] ) ) ;
51-
5259 parentPort ?. postMessage ( { success : true } ) ;
5360}
5461
55- function handleChunkComplete ( _data : BeginChunkProcessingData ) {
62+ /**
63+ * Processes a chunk of records and posts results back to the parent thread.
64+ * @param {import('./thread-types').BeginChunkProcessingData } _data - The collection of records to process.
65+ * @throws {Error } If initData is not defined.
66+ */
67+ function handleChunkComplete ( _data ) {
5668 if ( ! initData ) {
5769 throw new Error ( 'Expected init data to be defined' ) ;
5870 }
5971 const instrumentsMap = initData ;
6072
61- const processRecord = ( record : RecordType ) : InstrumentRecordsExport => {
62- const instrument = instrumentsMap . get ( record . instrumentId ) ! ;
73+ /**
74+ * Transforms a single record into an array of exportable rows.
75+ * @param {import('./thread-types').RecordType } record - The raw instrument record.
76+ * @returns {import('@opendatacapture/schemas/instrument-records').InstrumentRecordsExport } The processed rows.
77+ */
78+ const processRecord = ( record ) => {
79+ const instrument = instrumentsMap . get ( record . instrumentId ) ;
80+ if ( ! instrument ) {
81+ throw new Error ( `Instrument not found for ID: ${ record . instrumentId } ` ) ;
82+ }
6383
64- if ( ! record . computedMeasures ) return [ ] ;
84+ if ( ! record . computedMeasures ) {
85+ return [ ] ;
86+ }
6587
66- //const instrument = instrumentsMap.get(record.instrumentId)!;
67- const rows : InstrumentRecordsExport = [ ] ;
88+ const rows = [ ] ;
6889
6990 for ( const [ measureKey , measureValue ] of Object . entries ( record . computedMeasures ) ) {
7091 if ( measureValue == null ) continue ;
@@ -83,7 +104,7 @@ function handleChunkComplete(_data: BeginChunkProcessingData) {
83104 subjectSex : record . subject . sex ,
84105 timestamp : record . date ,
85106 username : record . session . user ?. username ?? 'N/A' ,
86- value : measureValue as InstrumentMeasureValue
107+ value : measureValue
87108 } ) ;
88109 continue ;
89110 }
@@ -117,19 +138,27 @@ function handleChunkComplete(_data: BeginChunkProcessingData) {
117138
118139 try {
119140 const results = _data . map ( processRecord ) ;
120- parentPort ?. postMessage ( { data : results . flat ( ) , success : true } satisfies WorkerMessage ) ;
141+ parentPort ?. postMessage ( { data : results . flat ( ) , success : true } ) ;
121142 } catch ( error ) {
122- parentPort ?. postMessage ( { error : ( error as Error ) . message , success : false } satisfies WorkerMessage ) ;
143+ if ( error instanceof Error ) {
144+ parentPort ?. postMessage ( { error : error . message , success : false } ) ;
145+ } else {
146+ parentPort ?. postMessage ( { error : 'Unknown Error' , success : false } ) ;
147+ }
123148 }
124149}
125150
126- parentPort ! . on ( 'message' , ( message : ParentMessage ) => {
151+ /**
152+ * Worker Message Router
153+ * @param {import('./thread-types').ParentMessage } message
154+ */
155+ parentPort ?. on ( 'message' , ( message ) => {
127156 switch ( message . type ) {
128157 case 'BEGIN_CHUNK_PROCESSING' :
129158 return handleChunkComplete ( message . data ) ;
130159 case 'INIT' :
131160 return handleInit ( message . data ) ;
132161 default :
133- throw new Error ( `Unexpected message type: ${ ( message satisfies never as { [ key : string ] : any } ) . type } ` ) ;
162+ throw new Error ( `Unexpected message type: ${ message . type } ` ) ;
134163 }
135164} ) ;
0 commit comments