Apollo and computed fields


#1

This might be more of a general JS question, instead of Apollo specific, but just giving it a try.

I’m on the verge of “throwing” everything DDP/Minimongo related out the door, and just bite the bullet by switching to Apollo. One thing I can’t put my finger on yet how I would fix it in Apollo though. It’s related to computed fields.

Currently I have js prototypes per object type I have specified in Mongo. That way I can add computed fields (e.g., a computed price field) to the objects returned from the Collection. Using the “transform” function of the collection and applying my prototypes to them.

How could/would this work in an Apollo world? A very simple hello world example

{ name: 'foo', unit_price: 1, amount: 100 }

Is stored in Mongo. In the prototype I add a computed field “value”. e.g.

export const PricePrototype = { value() { return this.amount * this.unit_price; }, };

The the collection would say:
const Products = new Mongo.Collection('products', { transform(doc) { return _.extend(Object.create(PricePrototype), doc); }, });


#2

Taking both minimongo and Apollo out of the equation, you could still use your approach. For example:

const PriceHelper = {
  price() {
    return this.amount * this.unit_price;
  },
};

// Sample products array
const products = [
  {
    amount: 100,
    unit_price: 10,
  },
  {
    amount: 200,
    unit_price: 20,
  }
];

// Call this after you've retrieved your products; this will link each
// product with the PriceHelper object.
const productsWithPrice = products.map((product) => {
  return _.extend(Object.create(ComputedFields), product);
});

// Sample output
console.log(productsWithPrice[0].price()) --> 1000
console.log(productsWithPrice[1].price()) --> 4000

#3

Cool, makes total sense now. Thanks!

Does this approach still makes sense with GraphQL/Apollo? Meaning, the app won’t have complete “objects” anymore if I get it correctly. So you work with shards of properties of something instead of whole instances. Does it then make more sense to externalize that Helper? Curious how people handle this use case currently.

Cheers.


#4

To be honest, it should be even easier in Apollo than you have currently, you add the computed field name to the schema for the object you are after and then in the resolver simply return the calculation.

export const schema = [`
type LabelImage {
  name: String
  unit_price: Int
  amount: Int
  value: Int
}
`];

export const resolvers = {
  RootQuery: {
    product(root, args, context) {
      return Producst.find().fetch();
    },
  },
  Product: {
    value: ({ amount, unit_price }) => amount * unit_price,
  }
};

#5

Nice, thanks. Will dive into those resolvers right away.