RisingStack / graffiti-mongoose

⚠️ DEVELOPMENT DISCONTINUED - Mongoose (MongoDB) adapter for graffiti (Node.js GraphQL ORM)
https://risingstack-graffiti.signup.team/
MIT License
382 stars 52 forks source link

About splitting the project into a general adapter and a mongoose. #105

Open nodkz opened 8 years ago

nodkz commented 8 years ago

@tothandras said: I have started to split the project into a general adapter (that waits a graffiti model as input) and a mongoose specific one.

Did you share somewhere a Proposal of your changes? How it will look like?

It will be great if new version will support:

tothandras commented 8 years ago

@nodkz I will write a detailed proposal, but basically the Graffiti model would be the connection between the adapters. The general adapter would have a Graffiti model as an input and a query object that has all the getOneResolver, so on functions.. It is then passed down to every resolve function on info.rootValue.

nodkz commented 8 years ago

Hmm, may be very interesting. Need code example.

nodkz commented 8 years ago

Found this comment https://github.com/RisingStack/graffiti-mongoose/issues/64#issuecomment-158926841

I'd like this idea, and suggest implement it like wrappers:

let Post = mongoose.model('Post');

// current behaviour
const schema = getSchema([Post]);

// add wrapper
const schema = getSchema([withFilesConnection(Post)]);

// add more
const schema = getSchema([withFriendsQueries(withFilesConnection(Post))]);

Reusable wrappers under mongoose models is simple and extendable solution.

nodkz commented 8 years ago

For example virtualFieldsWrapper can solve task of populating a mongoose virtual fields. Mongoose has not define types for virtual fields. So wrapper can solve this problem:

const Post = mongoose.model('Post');
const PostWithVirtual = withVirtualFields(Post, {'name.full': string, 'metaInfo': MetaSchema});

const schema = getSchema([PostWithVirtual]);

Also some hooks may be hidden under wrappers. So wrappers can eliminate extending graffiti options in mongoose schemas.

nodkz commented 8 years ago

Proposal implementation of wrappers: https://github.com/nodkz/graffiti-mongoose/commit/0f72a8b2714312197d3bb149373ecc5e8904faef

import mongoose, { Schema } from 'mongoose';
import { GraphQLString } from 'graphql/type';
import ExtraFieldsWrapper from 'lib/graffiti-mongoose/src/wrappers/extra-fields';
import VirtualFieldsWrapper from 'lib/graffiti-mongoose/src/wrappers/virtual-fields';

const CvSchema = new Schema(
  {
    name: {
      type: String,
      description: 'Person name',
    },
  },
  {
    toObject: { virtuals: true }, // for population virtual values in resolver
  }
);

CvSchema.virtual('name333').get(function () {
  return '!!!!!!!!' + this._id + '!!!!!!!!';
});

const Cv = mongoose.model('Cv', CvSchema);

let CvWrapped = new ExtraFieldsWrapper(Cv, {
  extraFields: {
    _session: {
      type: GraphQLString,
      resolve(rootValue, args, info) {
        return `This is extra field which returns id: ${rootValue._id}`;
      },
    },
  }
});
CvWrapped = new VirtualFieldsWrapper(CvWrapped, {
  virtualFields: {
    name333: 'String',
  }
});

const Schema = getSchema([CvWrapped]);
nodkz commented 8 years ago

New problem reveal today. I have Cv model, and users can leave Notes to it. But Notes must be available only to those users who have left it.

Cv does not store references to Notes (only Note know about user and cvId). So I want get such query:

query {
  Cv(id: "1") {
     onlyMyNotes: notes {
        text
        createdAt
     }
  }
}

To solve this problem I should:

So graffiti does not allow to create gq-types, and use it later for extending other types. After that I may pass needed types to getSchema for root query population. Also I want pass Notes type to mutations, but not for queries.

Right now I will do monkeypatching :wink: of graffity in my wrapper-branch. I think it can give you some new thoughts about splitting the project in right way :stuck_out_tongue_winking_eye:

tothandras commented 8 years ago

@nodkz Thanks for the very detailed proposal! I really appreciate it! :) I will dig into it more as soon as I have some free time.

nodkz commented 8 years ago

Also I will use DataLoader (nice 30 min walkthrough from Lee Byron) between Mongoose and GraphQL. So need ability to switch getOneResolver (use or not) this great feature, which can speed up querying for some graphs.

Eg. if we want load authors metadata for 100 articles, best choice would be using batchLoading via DataLoader (internally it creates queue of promises and for next process tick combines all needed authors ids and make one batch query to retrieve authors data. After that all promises would be resolved in GQL). Awesome speed up!

nodkz commented 8 years ago

App schema example https://gist.github.com/nodkz/164f410c78d7a8f01a0d Extending Cv model by field userData in graphQL manner. This field type obtained from another mongoose model UserData, which does not use mongoose references/population with Cv. Also used custom resolve function, which can use DataLoader, but in this example use filtering by userId.

nodkz commented 8 years ago

For React/Relay components I should have ability use GraphQL Interfaces. Some components can be rendered under different types (so it can be done, if we add interface to such types and will use fragment on interfaceName), so to have such ability I create `ExtraInterfacesWrapper.

Commit: https://github.com/nodkz/graffiti-mongoose/commit/08aa4a394c8b53a442ec05929f1b0035418a1ae0 Updated gist with app/schema.js: https://gist.github.com/nodkz/164f410c78d7a8f01a0d

tothandras commented 8 years ago

@nodkz Thanks for your effort! Sorry for not being active lately, I will try to keep up with your progress asap.

sibelius commented 8 years ago

@nodkz any progress on this?

nodkz commented 8 years ago

@sibelius internally I totally rewrite module with different architecture for our project purposes. But it not ready for OSS yet, cause API is not stable (I don't like that some things can be done via different ways and also I have not enough free time to document it).

nodkz commented 8 years ago

@sibelius @tothandras just started develop new module https://github.com/nodkz/graphql-compose

Also you may see my previous version https://github.com/nodkz/graphql-mongoose which I won't publish to npm (reason - mash code in app).