11import { yearsPassed } from '@douglasneuroinformatics/libjs' ;
22import { linearRegression } from '@douglasneuroinformatics/libstats' ;
3- import { Injectable , UnprocessableEntityException } from '@nestjs/common' ;
3+ import { Injectable , NotFoundException , UnprocessableEntityException } from '@nestjs/common' ;
44import type { ScalarInstrument } from '@opendatacapture/runtime-core' ;
55import type {
66 CreateInstrumentRecordData ,
77 InstrumentRecord ,
88 InstrumentRecordQueryParams ,
99 InstrumentRecordsExport ,
10- LinearRegressionResults
10+ LinearRegressionResults ,
11+ UploadInstrumentRecordsData
1112} from '@opendatacapture/schemas/instrument-records' ;
12- import type { InstrumentRecordModel , Prisma } from '@prisma/generated-client' ;
13+ import type { InstrumentRecordModel , Prisma , SessionModel } from '@prisma/generated-client' ;
1314import { isNumber , pickBy } from 'lodash-es' ;
1415
1516import { accessibleQuery } from '@/ability/ability.utils' ;
@@ -19,6 +20,7 @@ import { InstrumentsService } from '@/instruments/instruments.service';
1920import { InjectModel } from '@/prisma/prisma.decorators' ;
2021import type { Model } from '@/prisma/prisma.types' ;
2122import { SessionsService } from '@/sessions/sessions.service' ;
23+ import type { CreateSubjectDto } from '@/subjects/dto/create-subject.dto' ;
2224import { SubjectsService } from '@/subjects/subjects.service' ;
2325import { VirtualizationService } from '@/virtualization/virtualization.service' ;
2426
@@ -61,7 +63,11 @@ export class InstrumentRecordsService {
6163
6264 await this . subjectsService . findById ( subjectId ) ;
6365 await this . sessionsService . findById ( sessionId ) ;
64-
66+ if ( ! instrument . validationSchema . safeParse ( data ) . success ) {
67+ throw new UnprocessableEntityException (
68+ `Data received does not pass validation schema of instrument '${ instrument . id } '`
69+ ) ;
70+ }
6571 return this . instrumentRecordModel . create ( {
6672 data : {
6773 computedMeasures : instrument . measures
@@ -243,4 +249,108 @@ export class InstrumentRecordsService {
243249 }
244250 return results ;
245251 }
252+
253+ async upload (
254+ { groupId, instrumentId, records } : UploadInstrumentRecordsData ,
255+ options ?: EntityOperationOptions
256+ ) : Promise < InstrumentRecordModel [ ] > {
257+ if ( groupId ) {
258+ await this . groupsService . findById ( groupId , options ) ;
259+ }
260+
261+ const instrument = await this . instrumentsService . findById ( instrumentId ) ;
262+ if ( instrument . kind === 'SERIES' ) {
263+ throw new UnprocessableEntityException (
264+ `Cannot create instrument record for series instrument '${ instrument . id } '`
265+ ) ;
266+ }
267+
268+ const createdRecordsArray : InstrumentRecordModel [ ] = [ ] ;
269+ const createdSessionsArray : SessionModel [ ] = [ ] ;
270+
271+ try {
272+ for ( let i = 0 ; i < records . length ; i ++ ) {
273+ const { data, date, subjectId } = records [ i ] ! ;
274+ await this . createSubjectIfNotFound ( subjectId ) ;
275+
276+ const session = await this . sessionsService . create ( {
277+ date : date ,
278+ groupId : groupId ? groupId : null ,
279+ subjectData : {
280+ id : subjectId
281+ } ,
282+ type : 'RETROSPECTIVE'
283+ } ) ;
284+
285+ createdSessionsArray . push ( session ) ;
286+
287+ const sessionId = session . id ;
288+
289+ if ( ! instrument . validationSchema . safeParse ( data ) . success ) {
290+ throw new UnprocessableEntityException (
291+ `Data received for record at index '${ i } ' does not pass validation schema of instrument '${ instrument . id } '`
292+ ) ;
293+ }
294+
295+ const createdRecord = await this . instrumentRecordModel . create ( {
296+ data : {
297+ computedMeasures : instrument . measures
298+ ? this . instrumentMeasuresService . computeMeasures ( instrument . measures , data )
299+ : null ,
300+ data,
301+ date,
302+ group : groupId
303+ ? {
304+ connect : { id : groupId }
305+ }
306+ : undefined ,
307+ instrument : {
308+ connect : {
309+ id : instrumentId
310+ }
311+ } ,
312+ session : {
313+ connect : {
314+ id : sessionId
315+ }
316+ } ,
317+ subject : {
318+ connect : {
319+ id : subjectId
320+ }
321+ }
322+ }
323+ } ) ;
324+
325+ createdRecordsArray . push ( createdRecord ) ;
326+ }
327+ } catch ( err ) {
328+ await this . instrumentRecordModel . deleteMany ( {
329+ where : {
330+ id : {
331+ in : createdRecordsArray . map ( ( record ) => record . id )
332+ }
333+ }
334+ } ) ;
335+ await this . sessionsService . deleteByIds ( createdSessionsArray . map ( ( session ) => session . id ) ) ;
336+ throw err ;
337+ }
338+
339+ return createdRecordsArray ;
340+ }
341+
342+ private async createSubjectIfNotFound ( subjectId : string ) {
343+ try {
344+ await this . subjectsService . findById ( subjectId ) ;
345+ } catch ( exception ) {
346+ if ( exception instanceof NotFoundException ) {
347+ const addedSubject : CreateSubjectDto = {
348+ id : subjectId
349+ } ;
350+ await this . subjectsService . create ( addedSubject ) ;
351+ } else {
352+ throw exception ;
353+ }
354+ }
355+ }
246356}
0 commit comments