@@ -2,8 +2,8 @@ import { replacer, reviver, yearsPassed } from '@douglasneuroinformatics/libjs';
22import { accessibleQuery , InjectModel } from '@douglasneuroinformatics/libnest' ;
33import type { Model } from '@douglasneuroinformatics/libnest' ;
44import { linearRegression } from '@douglasneuroinformatics/libstats' ;
5- import { Injectable , UnprocessableEntityException } from '@nestjs/common' ;
6- import type { ScalarInstrument } from '@opendatacapture/runtime-core' ;
5+ import { BadRequestException , Injectable , NotFoundException , UnprocessableEntityException } from '@nestjs/common' ;
6+ import type { Json , ScalarInstrument } from '@opendatacapture/runtime-core' ;
77import { DEFAULT_GROUP_NAME } from '@opendatacapture/schemas/core' ;
88import type {
99 CreateInstrumentRecordData ,
@@ -15,7 +15,7 @@ import type {
1515} from '@opendatacapture/schemas/instrument-records' ;
1616import { Prisma } from '@prisma/client' ;
1717import type { Session } from '@prisma/client' ;
18- import { isNumber , pickBy } from 'lodash-es' ;
18+ import { isNumber , mergeWith , pickBy } from 'lodash-es' ;
1919
2020import type { EntityOperationOptions } from '@/core/types' ;
2121import { GroupsService } from '@/groups/groups.service' ;
@@ -105,6 +105,10 @@ export class InstrumentRecordsService {
105105 }
106106
107107 async deleteById ( id : string , { ability } : EntityOperationOptions = { } ) {
108+ const isExisting = await this . instrumentRecordModel . exists ( { id } ) ;
109+ if ( ! isExisting ) {
110+ throw new NotFoundException ( `Could not find record with ID '${ id } '` ) ;
111+ }
108112 return this . instrumentRecordModel . delete ( {
109113 where : { AND : [ accessibleQuery ( ability , 'delete' , 'InstrumentRecord' ) ] , id }
110114 } ) ;
@@ -189,12 +193,7 @@ export class InstrumentRecordsService {
189193
190194 const records = await this . instrumentRecordModel . findMany ( {
191195 include : {
192- instrument : {
193- select : {
194- bundle : true ,
195- id : true
196- }
197- }
196+ instrument : false
198197 } ,
199198 where : {
200199 AND : [
@@ -218,9 +217,7 @@ export class InstrumentRecordsService {
218217 if ( groupId ) {
219218 await this . groupsService . findById ( groupId ) ;
220219 }
221- const instrument = await this . instrumentsService
222- . findById ( instrumentId )
223- . then ( ( instrument ) => this . instrumentsService . getInstrumentInstance ( instrument ) ) ;
220+ const instrument = await this . getInstrumentById ( instrumentId ) ;
224221
225222 if ( instrument . kind === 'SERIES' ) {
226223 throw new UnprocessableEntityException ( `Cannot create linear model for series instrument '${ instrument . id } '` ) ;
@@ -261,6 +258,47 @@ export class InstrumentRecordsService {
261258 return results ;
262259 }
263260
261+ async updateById ( id : string , data : unknown [ ] | { [ key : string ] : unknown } , { ability } : EntityOperationOptions = { } ) {
262+ const instrumentRecord = await this . instrumentRecordModel . findFirst ( {
263+ where : { id }
264+ } ) ;
265+ if ( ! instrumentRecord ) {
266+ throw new NotFoundException ( `Could not find record with ID '${ id } '` ) ;
267+ }
268+
269+ if ( Array . isArray ( instrumentRecord . data ) && ! Array . isArray ( data ) ) {
270+ throw new BadRequestException ( 'Data must be an array when the instrument record data is an array' ) ;
271+ }
272+
273+ // all records must be attached to scalar instruments
274+ const instrument = ( await this . getInstrumentById ( instrumentRecord . instrumentId ) ) as ScalarInstrument ;
275+
276+ const updatedData = mergeWith ( instrumentRecord . data , data , ( updatedValue : unknown , sourceValue : unknown ) => {
277+ if ( Array . isArray ( sourceValue ) ) {
278+ return updatedValue ;
279+ }
280+ return undefined ;
281+ } ) ;
282+
283+ const parseResult = await instrument . validationSchema . safeParseAsync ( updatedData ) ;
284+ if ( ! parseResult . success ) {
285+ throw new BadRequestException ( {
286+ issues : parseResult . error . issues ,
287+ message : 'Merged data does not match validation schema'
288+ } ) ;
289+ }
290+
291+ return this . instrumentRecordModel . update ( {
292+ data : {
293+ computedMeasures : instrument . measures
294+ ? this . instrumentMeasuresService . computeMeasures ( instrument . measures , parseResult . data as Json )
295+ : null ,
296+ data : parseResult . data
297+ } ,
298+ where : { AND : [ accessibleQuery ( ability , 'delete' , 'InstrumentRecord' ) ] , id }
299+ } ) ;
300+ }
301+
264302 async upload (
265303 { groupId, instrumentId, records } : UploadInstrumentRecordsData ,
266304 options ?: EntityOperationOptions
@@ -340,6 +378,12 @@ export class InstrumentRecordsService {
340378 }
341379 }
342380
381+ private getInstrumentById ( instrumentId : string ) {
382+ return this . instrumentsService
383+ . findById ( instrumentId )
384+ . then ( ( instrument ) => this . instrumentsService . getInstrumentInstance ( instrument ) ) ;
385+ }
386+
343387 private parseJson ( data : unknown ) {
344388 return JSON . parse ( JSON . stringify ( data ) , reviver ) as unknown ;
345389 }
0 commit comments