Last active
May 18, 2017 01:17
-
-
Save moret/fca0ccaf9fd16908131f to your computer and use it in GitHub Desktop.
N to M GraphQL Sequelize Question
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import _ from 'underscore'; | |
import Promise from 'bluebird'; | |
import { | |
GraphQLInt, | |
GraphQLList, | |
GraphQLObjectType, | |
GraphQLSchema, | |
GraphQLString | |
} from 'graphql'; | |
import { | |
resolver, | |
attributeFields, | |
defaultArgs, | |
defaultListArgs | |
} from 'graphql-sequelize'; | |
import Sequelize from 'sequelize'; | |
import express from 'express'; | |
import graphqlHTTP from 'express-graphql'; | |
import cors from 'cors'; | |
const peopleData = [ | |
{id: 1, name: 'John'}, | |
{id: 2, name: 'Jane'}, | |
{id: 3, name: 'Jill'} | |
]; | |
const destinationsData = [ | |
{id: 1, name: 'Paris'}, | |
{id: 2, name: 'Berlin'}, | |
{id: 3, name: 'London'} | |
]; | |
const peopleDestinationData = [ | |
{personId: 1, destinationId: 3, sequence: 1}, | |
{personId: 1, destinationId: 1, sequence: 2}, | |
{personId: 2, destinationId: 3, sequence: 1}, | |
{personId: 2, destinationId: 2, sequence: 2}, | |
{personId: 2, destinationId: 1, sequence: 3}, | |
{personId: 3, destinationId: 1, sequence: 1} | |
]; | |
const sequelize = new Sequelize(process.env.DB); | |
const PersonModel = sequelize.define('Person', { | |
name: {type: Sequelize.STRING} | |
}); | |
const DestinationModel = sequelize.define('Destination', { | |
name: {type: Sequelize.STRING} | |
}); | |
const PersonDestinationModel = sequelize.define('PersonDestination', { | |
sequence: {type: Sequelize.INTEGER} | |
}); | |
// the n-to-m which I couldn't figure out how to use directly | |
PersonModel.Destinations = PersonModel.belongsToMany(DestinationModel, { | |
through: PersonDestinationModel, | |
foreignKey: 'personId', | |
as: 'Destinations' | |
}); | |
DestinationModel.Visitors = DestinationModel.belongsToMany(PersonModel, { | |
through: PersonDestinationModel, | |
foreignKey: 'destinationId', | |
as: 'Visitors' | |
}); | |
PersonModel.PersonDestinations = PersonModel.hasMany(PersonDestinationModel, { | |
foreignKey: 'personId', | |
as: 'PersonDestinations' | |
}); | |
PersonDestinationModel.Destination = PersonDestinationModel.belongsTo(DestinationModel, { | |
foreignKey: 'destinationId', | |
as: 'Destination' | |
}); | |
DestinationModel.DestinationVisitors = DestinationModel.hasMany(PersonDestinationModel, { | |
foreignKey: 'destinationId', | |
as: 'DestinationVisitors' | |
}); | |
PersonDestinationModel.Visitor = PersonDestinationModel.belongsTo(PersonModel, { | |
foreignKey: 'personId', | |
as: 'Visitor' | |
}); | |
const PersonType = new GraphQLObjectType({ | |
name: 'Person', | |
fields: () => ( | |
_.assign(attributeFields(PersonModel), { | |
personDestinations: { | |
type: new GraphQLList(PersonDestinationType), | |
resolve: resolver(PersonModel.PersonDestinations), | |
args: _.assign(defaultListArgs()) | |
}, | |
destinations: { | |
type: new GraphQLList(DestinationType), | |
resolve: resolver(PersonModel.Destinations, { | |
before: (options, args, root) => { | |
if (args.order && args.order == 'sequence') { | |
delete args.order; | |
options.order = options.order || []; | |
options.order.splice(options.order.findIndex( | |
(orderOption) => (_.isEqual(orderOption, ['sequence'])) | |
), 1); | |
options.order.push([PersonDestinationModel, 'sequence']); | |
} | |
return options; | |
} | |
}), | |
args: _.assign(defaultListArgs(), { | |
name: {type: GraphQLString} | |
}) | |
} | |
}) | |
) | |
}); | |
const DestinationType = new GraphQLObjectType({ | |
name: 'Destination', | |
fields: () => ( | |
_.assign(attributeFields(DestinationModel), { | |
destinationVisitors: { | |
type: new GraphQLList(PersonDestinationType), | |
resolve: resolver(DestinationModel.DestinationVisitors), | |
args: _.assign(defaultListArgs(), { | |
sequence: {type: GraphQLString} | |
}) | |
}, | |
visitors: { | |
type: new GraphQLList(PersonType), | |
resolve: resolver(DestinationModel.Visitors), | |
args: _.assign(defaultListArgs(), { | |
sequence: {type: GraphQLString} | |
}) | |
} | |
}) | |
) | |
}); | |
const PersonDestinationType = new GraphQLObjectType({ | |
name: 'PersonDestination', | |
fields: () => ( | |
_.assign(attributeFields(PersonDestinationModel), { | |
destination: { | |
type: DestinationType, | |
resolve: resolver(PersonDestinationModel.Destination) | |
} | |
}) | |
) | |
}); | |
const travelType = new GraphQLObjectType({ | |
name: 'Travels', | |
fields: { | |
people: { | |
type: new GraphQLList(PersonType), | |
resolve: resolver(PersonModel), | |
args: _.assign(defaultListArgs(), { | |
name: {type: GraphQLString} | |
}) | |
}, | |
destinations: { | |
type: new GraphQLList(DestinationType), | |
resolve: resolver(DestinationModel), | |
args: _.assign(defaultListArgs(), { | |
name: {type: GraphQLString} | |
}) | |
} | |
} | |
}); | |
const rootSchema = new GraphQLSchema({ | |
query: new GraphQLObjectType({ | |
name: 'RootQueryType', | |
fields: { | |
travel: { | |
type: travelType, | |
resolve: () => (true) | |
} | |
} | |
}) | |
}); | |
const app = express(); | |
app.use(cors()); | |
app.use('/graphql', graphqlHTTP({ | |
schema: rootSchema, | |
pretty: true, | |
graphiql: true | |
})); | |
//exploded models drop and sync, and data insert for clarity | |
Promise.each( | |
[ | |
PersonDestinationModel, | |
DestinationModel, | |
PersonModel | |
], | |
(Model) => Model.drop() | |
).then(() => ( | |
Promise.each( | |
[ | |
{Model: PersonModel, data: peopleData}, | |
{Model: DestinationModel, data: destinationsData}, | |
{Model: PersonDestinationModel, data: peopleDestinationData} | |
], | |
(pair) => { | |
const {Model, data} = pair; | |
return Model.sync().then(() => ( | |
Promise.each(data, (entry) => ( | |
Model.create(entry) | |
)) | |
)); | |
} | |
) | |
)).then(() => { | |
const server = app.listen(process.env.PORT || 3000, () => { | |
console.log( | |
'Example app listening at http://%s:%s', | |
server.address().address, | |
server.address().port | |
); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment