DEPRECATION NOTE:
This project has started a couple of years ago as we intended to create a way to allow developers to focus on building a structured domain based on well defined patterns instead of having the mess of loose uncoupled resolvers.
Unfortunately we haven’t had the proper time to develop this project further, so it has never gained enough momentum. Since then, as well, lots has changed in the ecosystem. A lot of the goals of this project have already been achieved by other projects, such as https://prisma.io.
Prisma is probably the way to go if you look for something mature and reliable. If you feel adventurous, though, you can take a look at our new experiment: https://github.com/zvictor/faugra.
Don't let your graph oriented project become a mess. Add structure to it!
This is an experimental project not ready for production use yet. Part of the features described in this document are still being implemented. The best way to check the features currently implemented is checking out our example app.
We are looking for feedback and are open for discussing the strategy adopted here. Do not hesitate opening an issue and sharing your thoughts with us, it will make us happy. :)
npm install graph-object --save
new MyModel({ field: value })
import{Model}from'graph-object';classAuthorextendsModel{getname(){return`${this.firstName}${this.lastName}`;}}>constorwell=newAuthor({firstName: 'George',lastName: 'Orwell'});>orwell.firstName'George'>orwell.name'George Orwell'allow(object, objectCRUD, fields_RU_)
import{allow,controlAccess}from'graph-object';classPostextendsModel{
...
}classAuthorextendsModel{getposts(){returnPost.objects.find({'author._id': this._id});}getpublicPosts(){returncontrolAccess(Post.objects.find({'author._id': this._id}))}allowedPosts(context){returncontrolAccess(Post.objects.find({'author._id': this._id}),context)}}allow(Post,{read(context){// Post's CRUD permissions could be changedreturnthis.author._id===context.userId||!this.private;},},{views: {// `view` field permissions.// Only `read` and `update` are available for fields.read(context){returnthis.author._id===context.userId;},update(context){returnfalse;}}});>// someAuthor only published a private ({private: 1}) post.>someAuthor.posts
Error: 'read'permissionnotgrantedbyPost>someAuthor.public[]>someAuthor.allowedPosts({userId: 1})[Post]Managers are inspired in the Django's manager concept. More docs to come.
In order to retrieve and persist the data from your objects you should connect your models to your prefered storage provider. Graph-object is agnostic about that, so you can use any database and storage engines, as many as you want, as long as there are adapters available for them.
Note: If no connector is specified for a given class, it will by default use a dumb memory store.
The example below will give your managers access to both mongodb and memory stores.
importmodelsfrom'./models';importadapterfrom'graph-object-adapter-waterline';importmemoryAdapterfrom'sails-memory';importmongoAdapterfrom'sails-mongo';import{injectConnectors}from'graph-object';constpersistingModels=injectConnectors(models,adapter({default: {adapter: mongoAdapter,host: 'localhost',// defaults to `localhost` if omittedport: 27017,// defaults to 27017 if omitteduser: 'username_here',// or omit if not relevantpassword: 'password_here',// or omit if not relevantdatabase: 'database_name_here'// or omit if not relevantidentifiers: {Author: 'authors',Posts: 'posts',}},memory: {adapter: memoryAdapter,identifiers: {Author: 'people',Posts: 'posts',}},});exportdefaultpersistingModels;If these concepts make you confused, this issue could help clarifying it.
Graph-object models are plug & play to GraphQL servers. Just make sure you run generateResolvers(schema, models)
to have the resolvers generated.
importschemafrom'/domain/schemas';importpersistingModelsfrom'./models';import{apolloExpress}from'apollo-server';constresolvers=generateResolvers(schema,persistingModels);addResolveFunctionsToSchema(schema,resolvers);
...
app.use('/graphql',bodyParser.json(),apolloExpress({
schema,
resolvers,context: {},}));Please check out the Perfect GraphQL Starter for a working example app.
If you like this project just give it a star :)
