cult-of-coders / grapher

Grapher: Meteor Collection Joins + Reactive GraphQL like queries
https://atmospherejs.com/cultofcoders/grapher
MIT License
275 stars 53 forks source link

[ambitious project] What if reducers had links? #359

Open theodorDiaconu opened 5 years ago

theodorDiaconu commented 5 years ago

Quest

Find a way to sneak-into reducers like we do through collections, not treating them as leafs.

Concept

When I request data via grapher and I reach a reducer things look like this:

{
  "users": {
     $filters: { _id },
     // ...
     stripePaymentProfile: 1, // a reducer, but what if it can be a collection reducer: { stripeHistory: 1 }
  }
}

So it stops permanently. What if we open: reducers can have other reducers, reducers can reference back links.

Collection.addReducers({
   "stripePaymentProfile": {
       body: { stripePaymentCustomerId: 1 },
       reduce({ stripePaymentCustomerId }) {
          return StripeService.fetchByCustomerId(...);
       } 
    }
})

How we extend it?

.addReducers({
  "stripePaymentProfile": {
      reducers:[ 
           { stripeHistory: ReducerInterface }
      ]
   }
});

Making Reducers recursive, re-usable, hackable.

How to implement ?

Extend reducerNode class to properly read the reducer property, and build the tree.

Autocomplete?

Flow or TypeScript. Properly adapt your models' type:

type StripePaymentProfile = {
  StripeHistory: ...
}
type User = {
  StripePaymentProfile,
}
let user: User = db.users.findOne(userId);
// nice autocomplete

Data Loader

We should have something similar like data loader to cache reducer results, via a cache function:

// in a reducer config alognside body, `reduce, reducers`
cache(cacheModel: ReducerCacheModel, defaultReducer) {
     cache.find(key: string = args.userId, defaultReducer, storeCache)
}
// standard should be reducer by _id, something configurable?

What you guys think?

bhunjadi commented 4 years ago

Maybe it would be beneficial to allow reducers to be passed their own params, just as you said that we might have collection reducers or another API reducers.

What if we allow passing params to reducers, something like:

{
  // instead of 
  collectionReducer: 1,
  // we could have this
  collectionReducer: {
       field1: 1,
       field2: 2,
   }
}

Each reducer would then be configurable, but grapher would not care if it is collectionReducer: 1 or collectionReducer: someObject.

Declaration:

Collection.addReducers({
   body: {...},
   reduce(document, queryParams, reducerParams) {
      return Collection2.find(...some filter..., {fields: reducerParams}); // lets say that we expect projection in reducerParams
   }
});

This is probably something you meant by ReducerInterface in the above example. I know this is a really small subset of your proposal, but it could be useful for certain use cases.