1- import { useMutation , useQuery } from "@tanstack/react-query" ;
1+ import { useMutation , useQueries , useQuery , UseQueryResult } from "@tanstack/react-query" ;
22import queryClient from "../plugins/ReactQueryClient.ts" ;
33import { useAppSelector } from "../plugins/ReduxHooks.ts" ;
44import { RootState } from "../store/store.ts" ;
@@ -86,11 +86,7 @@ const useDeleteProjectMetadata = () =>
8686 . forEach ( ( query ) => {
8787 queryClient . setQueryData < SdocMetadataMap > ( query . queryKey , ( oldData ) => {
8888 const newData = { ...oldData } ;
89- const metadataToDelete = Object . values ( newData ) . find (
90- ( metadata ) => metadata . project_metadata_id === data . id ,
91- ) ;
92- if ( ! metadataToDelete ) return newData ;
93- delete newData [ metadataToDelete . id ] ;
89+ delete newData [ data . id ] ;
9490 return newData ;
9591 } ) ;
9692 } ) ;
@@ -109,26 +105,28 @@ const useDeleteProjectMetadata = () =>
109105 } ) ;
110106
111107// SDOC METADATA QUERIES
112-
108+ // mapping from projectMetadataId -> SourceDocumentRead
113109export type SdocMetadataMap = Record < number , SourceDocumentMetadataRead > ;
114110
115111interface UseSdocMetadataQueryParams < T > {
116112 sdocId : number | undefined | null ;
117113 select ?: ( data : SdocMetadataMap ) => T ;
118114}
119115
116+ const sdocMetadataQueryFn = async ( sdocId : number ) => {
117+ const metadata = await SdocMetadataService . getBySdoc ( {
118+ sdocId : sdocId ! ,
119+ } ) ;
120+ return metadata . reduce ( ( acc , metadata ) => {
121+ acc [ metadata . project_metadata_id ] = metadata ;
122+ return acc ;
123+ } , { } as SdocMetadataMap ) ;
124+ } ;
125+
120126const useSdocMetadataQuery = < T = SdocMetadataMap > ( { sdocId, select } : UseSdocMetadataQueryParams < T > ) =>
121127 useQuery ( {
122128 queryKey : [ QueryKey . SDOC_METADATAS , sdocId ] ,
123- queryFn : async ( ) => {
124- const metadata = await SdocMetadataService . getBySdoc ( {
125- sdocId : sdocId ! ,
126- } ) ;
127- return metadata . reduce ( ( acc , metadata ) => {
128- acc [ metadata . id ] = metadata ;
129- return acc ;
130- } , { } as SdocMetadataMap ) ;
131- } ,
129+ queryFn : ( ) => sdocMetadataQueryFn ( sdocId ! ) ,
132130 staleTime : 1000 * 60 * 5 ,
133131 select,
134132 enabled : ! ! sdocId ,
@@ -143,7 +141,72 @@ const useGetSdocMetadata = (sdocId: number | null | undefined) =>
143141const useGetSdocMetadataByProjectMetadataId = ( sdocId : number | null | undefined , projectMetadataId : number ) =>
144142 useSdocMetadataQuery ( {
145143 sdocId,
146- select : ( data ) => Object . values ( data ) . find ( ( metadata ) => metadata . project_metadata_id === projectMetadataId ) ,
144+ select : ( data ) => data [ projectMetadataId ] ,
145+ } ) ;
146+
147+ export type SourceDocumentMetadataReadCombined = Omit < SourceDocumentMetadataRead , "id" | "source_document_id" > & {
148+ ids : number [ ] ;
149+ } ;
150+
151+ // referential stability for bulk queries
152+ const combineBulkData = ( results : UseQueryResult < SdocMetadataMap , Error > [ ] ) => {
153+ const isSuccess = results . every ( ( result ) => result . isSuccess ) ;
154+
155+ let data : SourceDocumentMetadataReadCombined [ ] | undefined = undefined ;
156+ if ( isSuccess ) {
157+ // Aggregate all SourceDocumentMetadataRead objects by project_metadata_id
158+ const combinedMap : Record < number , SourceDocumentMetadataRead [ ] > = { } ;
159+ results . forEach ( ( result ) => {
160+ Object . entries ( result . data ) . forEach ( ( [ projectMetadataId , metadata ] ) => {
161+ const pmid = Number ( projectMetadataId ) ;
162+ if ( ! combinedMap [ pmid ] ) {
163+ combinedMap [ pmid ] = [ metadata ] ;
164+ } else {
165+ combinedMap [ pmid ] . push ( metadata ) ;
166+ }
167+ } ) ;
168+ } ) ;
169+
170+ // Merge values for each project_metadata_id
171+ data = Object . entries ( combinedMap ) . map ( ( [ projectMetadataId , metadatas ] ) => {
172+ // Helper to merge a field
173+ function mergeField < T > ( getter : ( m : SourceDocumentMetadataRead ) => T ) : T | null {
174+ const values = metadatas . map ( getter ) ;
175+ const first = values [ 0 ] ;
176+ return values . every ( ( v ) => v === first ) ? first : null ;
177+ }
178+
179+ return {
180+ int_value : mergeField ( ( m ) => m . int_value ) ,
181+ str_value : mergeField ( ( m ) => m . str_value ) ,
182+ boolean_value : mergeField ( ( m ) => m . boolean_value ) ,
183+ date_value : mergeField ( ( m ) => m . date_value ) ,
184+ list_value :
185+ mergeField ( ( m ) => JSON . stringify ( m . list_value ) ) === JSON . stringify ( metadatas [ 0 ] . list_value )
186+ ? metadatas [ 0 ] . list_value
187+ : null ,
188+ ids : metadatas . map ( ( m ) => m . id ) ,
189+ project_metadata_id : Number ( projectMetadataId ) ,
190+ } ;
191+ } ) ;
192+ }
193+
194+ return {
195+ isLoading : results . some ( ( result ) => result . isLoading ) ,
196+ isError : results . some ( ( result ) => result . isError ) ,
197+ isSuccess,
198+ data,
199+ } ;
200+ } ;
201+
202+ const useGetSdocMetadataBulk = ( sdocIds : number [ ] ) =>
203+ useQueries ( {
204+ queries : sdocIds . map ( ( sdocId ) => ( {
205+ queryKey : [ QueryKey . SDOC_METADATAS , sdocId ] ,
206+ queryFn : ( ) => sdocMetadataQueryFn ( sdocId ) ,
207+ staleTime : 1000 * 60 * 5 ,
208+ } ) ) ,
209+ combine : combineBulkData ,
147210 } ) ;
148211
149212// TODO: REMOVE THIS HOOK
@@ -160,26 +223,13 @@ const useGetSdocMetadataByKey = (sdocId: number | null | undefined, key: string)
160223
161224// SDOC METADATA MUTATIONS
162225
163- const useUpdateSdocMetadata = ( ) =>
164- useMutation ( {
165- mutationFn : SdocMetadataService . updateById ,
166- onSuccess : ( metadata ) => {
167- queryClient . setQueryData < SdocMetadataMap > ( [ QueryKey . SDOC_METADATAS , metadata . source_document_id ] , ( old ) =>
168- old ? { ...old , [ metadata . id ] : metadata } : { [ metadata . id ] : metadata } ,
169- ) ;
170- } ,
171- meta : {
172- successMessage : ( data : SourceDocumentMetadataRead ) => `Updated metadata value for document "${ data . id } "` ,
173- } ,
174- } ) ;
175-
176226const useUpdateBulkSdocMetadata = ( ) =>
177227 useMutation ( {
178228 mutationFn : SdocMetadataService . updateBulk ,
179229 onSuccess : ( metadatas ) => {
180230 metadatas . forEach ( ( metadata ) => {
181231 queryClient . setQueryData < SdocMetadataMap > ( [ QueryKey . SDOC_METADATAS , metadata . source_document_id ] , ( old ) =>
182- old ? { ...old , [ metadata . id ] : metadata } : { [ metadata . id ] : metadata } ,
232+ old ? { ...old , [ metadata . project_metadata_id ] : metadata } : { [ metadata . project_metadata_id ] : metadata } ,
183233 ) ;
184234 } ) ;
185235 } ,
@@ -193,7 +243,7 @@ const MetadataHooks = {
193243 useGetSdocMetadata,
194244 useGetSdocMetadataByKey,
195245 useGetSdocMetadataByProjectMetadataId,
196- useUpdateSdocMetadata ,
246+ useGetSdocMetadataBulk ,
197247 useUpdateBulkSdocMetadata,
198248 // project metadata
199249 useGetProjectMetadataList,
0 commit comments