@@ -4,7 +4,7 @@ import { pluralize } from 'ember-inflector';
44import { get , set } from '@ember/object' ;
55import { inject as service } from '@ember/service' ;
66import { camelize } from '@ember/string' ;
7- import RSVP from 'rsvp' ;
7+ import RSVP , { resolve } from 'rsvp' ;
88import Ember from 'ember' ;
99import FirebaseAppService from '../services/firebase-app' ;
1010import ModelRegistry from 'ember-data/types/registries/model' ;
@@ -117,12 +117,14 @@ export default class FirestoreAdapter extends DS.Adapter.extend({
117117 // @ts -ignore repeat here for the tyepdocs
118118 firebaseApp : Ember . ComputedProperty < FirebaseAppService , FirebaseAppService > ;
119119
120- findRecord < K extends keyof ModelRegistry > ( _store : DS . Store , type : ModelRegistry [ K ] , id : string ) {
121- return rootCollection ( this , type ) . then ( ref => ref . doc ( id ) . get ( ) ) ;
120+ findRecord < K extends keyof ModelRegistry > ( store : DS . Store , type : ModelRegistry [ K ] , id : string , snapshot : any ) {
121+ return rootCollection ( this , type ) . then ( ref =>
122+ includeRelationships ( ref . doc ( id ) . get ( ) , store , this , snapshot , type )
123+ ) ;
122124 }
123125
124126 findAll < K extends keyof ModelRegistry > ( store : DS . Store , type : ModelRegistry [ K ] ) {
125- return this . query ( store , type )
127+ return this . query ( store , type ) ;
126128 }
127129
128130 findHasMany < K extends keyof ModelRegistry > ( store : DS . Store , snapshot : DS . Snapshot < K > , url : string , relationship : { [ key :string ] : any } ) {
@@ -145,22 +147,25 @@ export default class FirestoreAdapter extends DS.Adapter.extend({
145147 }
146148 }
147149
148- query < K extends keyof ModelRegistry > ( _store : DS . Store , type : ModelRegistry [ K ] , options ?: QueryOptions , _recordArray ?: DS . AdapterPopulatedRecordArray < any > ) {
149- return rootCollection ( this , type ) . then ( collection => queryDocs ( collection , queryOptionsToQueryFn ( options ) ) ) ;
150+ query < K extends keyof ModelRegistry > ( store : DS . Store , type : ModelRegistry [ K ] , options ?: QueryOptions , _recordArray ?: DS . AdapterPopulatedRecordArray < any > ) {
151+ return rootCollection ( this , type ) . then ( collection =>
152+ queryDocs ( collection , queryOptionsToQueryFn ( options ) )
153+ ) . then ( q => includeCollectionRelationships ( q , store , this , options , type ) ) ;
150154 }
151155
152- queryRecord < K extends keyof ModelRegistry > ( _store : DS . Store , type : ModelRegistry [ K ] , options ?: QueryOptions | QueryRecordOptions ) {
156+ queryRecord < K extends keyof ModelRegistry > ( store : DS . Store , type : ModelRegistry [ K ] , options ?: QueryOptions | QueryRecordOptions ) {
153157 return rootCollection ( this , type ) . then ( ( ref :firestore . CollectionReference ) => {
154158 const queryOrRef = queryRecordOptionsToQueryFn ( options ) ( ref ) ;
155159 if ( isQuery ( queryOrRef ) ) {
156160 if ( queryOrRef . limit ) { throw "Dont specify limit on queryRecord" }
157161 return queryOrRef . limit ( 1 ) . get ( ) ;
158162 } else {
159- return queryOrRef . get ( ) as any ; // TODO fix the types here, they're a little broken
163+ ( options as any ) . id = queryOrRef . id ;
164+ return includeRelationships ( queryOrRef . get ( ) as any , store , this , options , type ) ; // TODO fix the types here, they're a little broken
160165 }
161166 } ) . then ( ( snapshot :firestore . QuerySnapshot | firestore . DocumentSnapshot ) => {
162167 if ( isQuerySnapshot ( snapshot ) ) {
163- return snapshot . docs [ 0 ] ;
168+ return includeRelationships ( resolve ( snapshot . docs [ 0 ] ) , store , this , options , type ) ;
164169 } else {
165170 return snapshot ;
166171 }
@@ -195,7 +200,6 @@ export default class FirestoreAdapter extends DS.Adapter.extend({
195200
196201}
197202
198-
199203export type CollectionReferenceOrQuery = firestore . CollectionReference | firestore . Query ;
200204export type QueryFn = ( ref : CollectionReferenceOrQuery ) => CollectionReferenceOrQuery ;
201205export type QueryRecordFn = ( ref : firestore . CollectionReference ) => firestore . DocumentReference ;
@@ -302,6 +306,77 @@ const getFirestore = (adapter: FirestoreAdapter) => {
302306 return cachedFirestoreInstance ! ;
303307} ;
304308
309+ const includeCollectionRelationships = ( collection : firestore . QuerySnapshot , store : DS . Store , adapter : FirestoreAdapter , snapshot : any , type : any ) : Promise < firestore . QuerySnapshot > => {
310+ if ( snapshot && snapshot . include ) {
311+ const includes = snapshot . include . split ( ',' ) as Array < string > ;
312+ const relationshipsToInclude = includes . map ( e => type . relationshipsByName . get ( e ) as { [ key :string ] : any } ) . filter ( r => ! ! r && ! r . options . embedded ) ;
313+ return Promise . all (
314+ relationshipsToInclude . map ( r => {
315+ if ( r . meta . kind == 'hasMany' ) {
316+ return Promise . all ( collection . docs . map ( d => adapter . findHasMany ( store , { id : d . id } as any , '' , r ) ) )
317+ } else {
318+ const belongsToIds = [ ...new Set ( collection . docs . map ( d => d . data ( ) [ r . meta . key ] ) . filter ( id => ! ! id ) ) ]
319+ return Promise . all ( belongsToIds . map ( id => adapter . findBelongsTo ( store , { id } as any , '' , r ) ) )
320+ }
321+ } )
322+ ) . then ( allIncludes => {
323+ relationshipsToInclude . forEach ( ( r : any , i :number ) => {
324+ const relationship = r . meta ;
325+ const pluralKey = pluralize ( relationship . key ) ;
326+ const key = relationship . kind == 'belongsTo' ? relationship . key : pluralKey ;
327+ const includes = allIncludes [ i ] ;
328+ collection . docs . forEach ( doc => {
329+ if ( relationship . kind == 'belongsTo' ) {
330+ const result = includes . find ( ( r :any ) => r . id == doc . data ( ) [ key ] ) ;
331+ if ( result ) {
332+ if ( ! ( doc as any ) . _document . _included ) { ( doc as any ) . _document . _included = { } }
333+ ( doc as any ) . _document . _included [ key ] = result ;
334+ }
335+ } else {
336+ if ( ! ( doc as any ) . _document . _included ) { ( doc as any ) . _document . _included = { } }
337+ ( doc as any ) . _document . _included [ pluralKey ] = includes ;
338+ }
339+ } ) ;
340+ } ) ;
341+ return collection ;
342+ } ) ;
343+ } else {
344+ return resolve ( collection ) ;
345+ }
346+ }
347+
348+ const includeRelationships = < T = any > ( promise : Promise < T > , store : DS . Store , adapter : FirestoreAdapter , snapshot : any , type : any ) : Promise < T > => {
349+ if ( snapshot && snapshot . include ) {
350+ const includes = snapshot . include . split ( ',' ) as Array < string > ;
351+ const relationshipsToInclude = includes . map ( e => type . relationshipsByName . get ( e ) as { [ key :string ] : any } ) . filter ( r => ! ! r && ! r . options . embedded ) ;
352+ const hasManyRelationships = relationshipsToInclude . filter ( r => r . meta . kind == 'hasMany' ) ;
353+ const belongsToRelationships = relationshipsToInclude . filter ( r => r . meta . kind == 'belongsTo' ) ;
354+ return Promise . all ( [
355+ promise ,
356+ ...hasManyRelationships . map ( r => adapter . findHasMany ( store , snapshot , '' , r ) )
357+ ] ) . then ( ( [ doc , ...includes ] ) => {
358+ doc . _document . _included = hasManyRelationships . reduce ( ( c , e , i ) => {
359+ c [ pluralize ( e . key ) ] = includes [ i ] ;
360+ return c ;
361+ } , { } ) ;
362+ return Promise . all ( [
363+ resolve ( doc ) ,
364+ ...belongsToRelationships . filter ( r => ! ! doc . data ( ) [ r . meta . key ] ) . map ( r => {
365+ return adapter . findBelongsTo ( store , { id : doc . data ( ) [ r . meta . key ] } as any , '' , r )
366+ } )
367+ ] ) ;
368+ } ) . then ( ( [ doc , ...includes ] ) => {
369+ doc . _document . _included = { ...doc . _document . _included , ...belongsToRelationships . reduce ( ( c , e , i ) => {
370+ c [ e . key ] = includes [ i ] ;
371+ return c ;
372+ } , { } ) } ;
373+ return doc ;
374+ } ) ;
375+ } else {
376+ return promise ;
377+ }
378+ }
379+
305380declare module 'ember-data' {
306381 interface AdapterRegistry {
307382 'firestore' : FirestoreAdapter ;
0 commit comments