@@ -186,12 +186,15 @@ export default (config: IDataProviderConfig): DataProvider => ({
186186 the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?`
187187 ) ;
188188 }
189+ const data = json . map ( obj => dataWithVirtualId ( obj , primaryKey ) ) ;
190+ const prefetched = getPrefetchedData ( data , params . meta ?. prefetch ) ;
189191 return {
190- data : json . map ( obj => dataWithVirtualId ( obj , primaryKey ) ) ,
192+ data : removePrefetchedData ( data , params . meta ?. prefetch ) ,
191193 total : parseInt (
192194 headers . get ( 'content-range' ) . split ( '/' ) . pop ( ) ,
193195 10
194196 ) ,
197+ meta : params . meta ?. prefetch ? { prefetched } : undefined ,
195198 } ;
196199 } ) ;
197200 } ,
@@ -213,9 +216,17 @@ export default (config: IDataProviderConfig): DataProvider => ({
213216 ...useCustomSchema ( config . schema , metaSchema , 'GET' ) ,
214217 } ) ,
215218 } )
216- . then ( ( { json } ) => ( {
217- data : dataWithVirtualId ( json , primaryKey ) ,
218- } ) ) ;
219+ . then ( ( { json } ) => {
220+ const data = dataWithVirtualId ( json , primaryKey ) ;
221+ const prefetched = getPrefetchedData (
222+ data ,
223+ params . meta ?. prefetch
224+ ) ;
225+ return {
226+ data : removePrefetchedData ( data , params . meta ?. prefetch ) ,
227+ meta : params . meta ?. prefetch ? { prefetched } : undefined ,
228+ } ;
229+ } ) ;
219230 } ,
220231
221232 getMany : ( resource , params : Partial < GetManyParams > = { } ) => {
@@ -236,9 +247,19 @@ export default (config: IDataProviderConfig): DataProvider => ({
236247 ...useCustomSchema ( config . schema , metaSchema , 'GET' ) ,
237248 } ) ,
238249 } )
239- . then ( ( { json } ) => ( {
240- data : json . map ( data => dataWithVirtualId ( data , primaryKey ) ) ,
241- } ) ) ;
250+ . then ( ( { json } ) => {
251+ const data = json . map ( data =>
252+ dataWithVirtualId ( data , primaryKey )
253+ ) ;
254+ const prefetched = getPrefetchedData (
255+ data ,
256+ params . meta ?. prefetch
257+ ) ;
258+ return {
259+ data : removePrefetchedData ( data , params . meta ?. prefetch ) ,
260+ meta : params . meta ?. prefetch ? { prefetched } : undefined ,
261+ } ;
262+ } ) ;
242263 } ,
243264
244265 getManyReference : (
@@ -292,12 +313,15 @@ export default (config: IDataProviderConfig): DataProvider => ({
292313 the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?`
293314 ) ;
294315 }
316+ const data = json . map ( data => dataWithVirtualId ( data , primaryKey ) ) ;
317+ const prefetched = getPrefetchedData ( data , params . meta ?. prefetch ) ;
295318 return {
296- data : json . map ( data => dataWithVirtualId ( data , primaryKey ) ) ,
319+ data : removePrefetchedData ( data , params . meta ?. prefetch ) ,
297320 total : parseInt (
298321 headers . get ( 'content-range' ) . split ( '/' ) . pop ( ) ,
299322 10
300323 ) ,
324+ meta : params . meta ?. prefetch ? { prefetched } : undefined ,
301325 } ;
302326 } ) ;
303327 } ,
@@ -332,9 +356,17 @@ export default (config: IDataProviderConfig): DataProvider => ({
332356 } ) ,
333357 body,
334358 } )
335- . then ( ( { json } ) => ( {
336- data : dataWithVirtualId ( json , primaryKey ) ,
337- } ) ) ;
359+ . then ( ( { json } ) => {
360+ const data = dataWithVirtualId ( json , primaryKey ) ;
361+ const prefetched = getPrefetchedData (
362+ data ,
363+ params . meta ?. prefetch
364+ ) ;
365+ return {
366+ data : removePrefetchedData ( data , params . meta ?. prefetch ) ,
367+ meta : params . meta ?. prefetch ? { prefetched } : undefined ,
368+ } ;
369+ } ) ;
338370 } ,
339371
340372 updateMany : ( resource , params : Partial < UpdateManyParams > = { } ) => {
@@ -391,12 +423,20 @@ export default (config: IDataProviderConfig): DataProvider => ({
391423 dataWithoutVirtualId ( params . data , primaryKey )
392424 ) ,
393425 } )
394- . then ( ( { json } ) => ( {
395- data : {
426+ . then ( ( { json } ) => {
427+ const data = {
396428 ...json ,
397429 id : encodeId ( json , primaryKey ) ,
398- } ,
399- } ) ) ;
430+ } ;
431+ const prefetched = getPrefetchedData (
432+ data ,
433+ params . meta ?. prefetch
434+ ) ;
435+ return {
436+ data : removePrefetchedData ( data , params . meta ?. prefetch ) ,
437+ meta : params . meta ?. prefetch ? { prefetched } : undefined ,
438+ } ;
439+ } ) ;
400440 } ,
401441
402442 delete : ( resource , params : Partial < DeleteParams > = { } ) => {
@@ -419,9 +459,17 @@ export default (config: IDataProviderConfig): DataProvider => ({
419459 ...useCustomSchema ( config . schema , metaSchema , 'DELETE' ) ,
420460 } ) ,
421461 } )
422- . then ( ( { json } ) => ( {
423- data : dataWithVirtualId ( json , primaryKey ) ,
424- } ) ) ;
462+ . then ( ( { json } ) => {
463+ const data = dataWithVirtualId ( json , primaryKey ) ;
464+ const prefetched = getPrefetchedData (
465+ data ,
466+ params . meta ?. prefetch
467+ ) ;
468+ return {
469+ data : removePrefetchedData ( data , params . meta ?. prefetch ) ,
470+ meta : params . meta ?. prefetch ? { prefetched } : undefined ,
471+ } ;
472+ } ) ;
425473 } ,
426474
427475 deleteMany : ( resource , params : Partial < DeleteManyParams > = { } ) => {
@@ -458,3 +506,76 @@ const getChanges = (data: any, previousData: any) => {
458506 } , { } ) ;
459507 return changes ;
460508} ;
509+
510+ /**
511+ * Extract embeds from Postgrest responses
512+ *
513+ * When calling Postgrest database.getOne('posts', 123, { embed: 'tags' }),
514+ * the Postgrest response adds a `tags` key to the response, containing the
515+ * related tags. Something like:
516+ *
517+ * { id: 123, title: 'React-query in details', tags: [{ id: 1, name: 'react' }, { id: 1, name: 'query' }] }
518+ *
519+ * We want to copy all the embeds in a data object, that will later
520+ * be included into the response meta.prefetched key.
521+ *
522+ * @example getPrefetchedData({ id: 123, title: 'React-query in details', tags: [{ id: 1, name: 'react' }, { id: 1, name: 'query' }] }, ['tags'])
523+ * // {
524+ * // tags: [{ id: 1, name: 'react' }, { id: 1, name: 'query' }]
525+ * // }
526+ */
527+ const getPrefetchedData = ( data , prefetchParam ?: string [ ] ) => {
528+ if ( ! prefetchParam ) return undefined ;
529+ const prefetched = { } ;
530+ const dataArray = Array . isArray ( data ) ? data : [ data ] ;
531+ prefetchParam . forEach ( resource => {
532+ dataArray . forEach ( record => {
533+ if ( ! prefetched [ resource ] ) {
534+ prefetched [ resource ] = [ ] ;
535+ }
536+ const prefetchedData = Array . isArray ( record [ resource ] )
537+ ? record [ resource ]
538+ : [ record [ resource ] ] ;
539+ prefetchedData . forEach ( prefetchedRecord => {
540+ if (
541+ prefetched [ resource ] . some ( r => r . id === prefetchedRecord . id )
542+ ) {
543+ // do not add the record if it's already there
544+ return ;
545+ }
546+ prefetched [ resource ] . push ( prefetchedRecord ) ;
547+ } ) ;
548+ } ) ;
549+ } ) ;
550+
551+ return prefetched ;
552+ } ;
553+
554+ /**
555+ * Remove embeds from Postgrest responses
556+ *
557+ * When calling Postgrest database.getOne('posts', 123, { embed: 'tags' }),
558+ * the Postgrest response adds a `post` key to the response, containing the
559+ * related post. Something like:
560+ *
561+ * { id: 123, title: 'React-query in details', tags: [{ id: 1, name: 'react' }, { id: 1, name: 'query' }] }
562+ *
563+ * We want to remove all the embeds from the response.
564+ *
565+ * @example removePrefetchedData({ id: 123, title: 'React-query in details', tags: [{ id: 1, name: 'react' }, { id: 1, name: 'query' }] }, 'tags')
566+ * // { id: 123, title: 'React-query in details' }
567+ */
568+ const removePrefetchedData = ( data , prefetchParam ?: string [ ] ) => {
569+ if ( ! prefetchParam ) return data ;
570+ const dataArray = Array . isArray ( data ) ? data : [ data ] ;
571+ const newDataArray = dataArray . map ( record => {
572+ const newRecord = { } ;
573+ for ( const key in record ) {
574+ if ( ! prefetchParam . includes ( key ) ) {
575+ newRecord [ key ] = record [ key ] ;
576+ }
577+ }
578+ return newRecord ;
579+ } ) ;
580+ return Array . isArray ( data ) ? newDataArray : newDataArray [ 0 ] ;
581+ } ;
0 commit comments