mongo-graphql-starter
mongo-graphql-starter copied to clipboard
Mongoose schemas / models as input
As mentioned on Twitter (https://twitter.com/AdamRackis/status/921860625395011588), would love to have a look on how to implement Mongoose support.
I think Mongoose schemas tell all there is to know to generate GraphQL ones (types / how they link etc...)
Awesome - thanks. Let me get this pending release out tonight (hopefully), and I'll update this case with some info - I think it'll be fairly straightforward to do.
Hey sorry - ran out of time last night - will definitely take a look at this tonight though
no problem :)
Ok, if you want to add Mongoose support, that should totally be doable. src/createGraphqlSchema/createSchema.js
is the main entry point of the application. Line 23,
Promise.resolve(source).then(module => {
that's where the project metadata module is resolved, and shortly thereafter I'm running
Object.keys(module).forEach(k => {
which goes through each export on the module, and creates all the graphQL schema stuff. For you to support Mongoose, we should just add processing right here, in the very beginning, that translates a Mongoose object into the format I'm expecting. So
Add a third argument, options, and have a mongoose property. (default the options arg to empty object, of course).
As a very first step, right after Promise.resolve(source).then(module => {
, if options.mongoose
is true, then call some new method, that you wrote, that translates each Mongoose object on the module into an object that would be of the same form as the project already uses. So an object with a table
property which is the Mongo collection name, and then a fields object with properties keyed by field name, of values imported from my own dataTypes module - StringType, etc.
Have this new function take the modules object as input, and then return a new object with the same keys, but each object now the normal project metadata, instead of Mongoose stuff.
So it'll look something like
Promise.resolve(source).then(module => {
if (options.mongoose){
module = convertModuleFromMongoose(module);
}
Before you start, get a Mongo instance running, and make sure my tests can connect, and pass.
If you get your feature added, I can help add new tests to run against them, as needed.
Let me know if any of that's not clear.
ok, gonna look into it, might take a bit of time but gonna give it a try
Any progress on this lovely idea?
Nope - I've never used Mongoose, but I'd be happy to help anyone get it PR'd if they're interested.
Hi, I am taking a look at this. From your previous comment @arackaf I assume that the crucial objects are: modules
as an input and objectToCreate
as an output, where module
is in fact a setup
object that eventually gets parsed into objectToCreate
, which then becomes input for these functions: createOutputTypeMetadata()
createGraphqlTypeSchema()
createTypeResolver()
.
So if mongoose schema was to be an initial input, then it would be enough to transform it into objectToCreate
, and then pickup from there as usual. Correct?
@jfcieslak - let me get back to you later tonight - wrapped up tight at work at the moment
@jfcieslak ok here are the updated (simpler) instructions for how Mongoose could be supported. Sorry for the delay - work was quite hectic yesterday.
Check out https://github.com/arackaf/mongo-graphql-starter/blob/master/test/testProject1/spinUp.js#L12 for an example of how this project creates a graphQL endpoint.
The createGraphqlSchema
method is the main entrypoint. It takes as the first arg an object of all the types to create. These types are created by the user, and are explained in the docs. Stuff like
// ...
const Subject = {
table: "subjects",
fields: {
_id: MongoIdType,
name: StringType
}
};
const Tag = {
table: "tags",
fields: {
_id: StringType,
name: StringType,
count: IntType
}
};
export default {
Book,
Subject,
Author,
Tag
};
and then createGraphqlSchema
receives that objects with the Book
, Subject
, Author
, Tag
objects.
If you want to support Mongoose, all you have to do is find some way to take IN a Mongoose schema, and spit OUT types that my library is expecting. Once that's done you could just feed the generated types right to createGraphqlSchema
and be done. Or we could just overload createGraphqlSchema
to be able to handle either the normal types, or Mongoose types, possibly with a new options flag or something.
But the key piece is, again, a function that takes IN a Mongoose schema, and spits OUT the normal types my library is expecting. If you can get that done I'll help get it integrated.
I'd recommend spitting out identical types to what's here: https://github.com/arackaf/mongo-graphql-starter/blob/master/test/testProject1/projectSetup.js so we can just copy over all the same tests, and run them against the Mongoose project.
If you also wanted to get relationships between objects working, you'd want to also get these types working https://github.com/arackaf/mongo-graphql-starter/blob/master/test/testProject4/projectSetup.js
They're pretty similar, and of course I'd be happy to help as needed.
Is there any update on this? I'm searching for something like this exactly. Thank you!
P.S: Nevertheless I'm gonna give it a try! :)
Same as before. I don't use Mongoose, so not really. That said, Mongoose support would just basically be a shortcut to generating the endpoint. You can use it now, you just have to duplicate the Mongo DB metadata that's embedded in your Mongoose config, into this project, which really shouldn't be too terrible.
It might help someone, here's a basic converter with support for few types coded quickly
const { dataTypes } = require('mongo-graphql-starter');
const {
MongoIdType,
MongoIdArrayType,
StringType,
StringArrayType,
BoolType,
IntType,
IntArrayType,
FloatType,
FloatArrayType,
DateType,
arrayOf,
objectOf,
formattedDate,
JSONType,
typeLiteral,
} = dataTypes;
const getMGLType = moongooseType => {
switch (moongooseType) {
case 'ObjectID':
return MongoIdType;
case 'Number':
return IntType;
case 'Date':
return DateType;
case 'Boolean':
return BoolType;
case 'Object':
return JSONType;
// add more cases for types here
case 'String':
default:
return StringType;
}
};
const convertMongooseToMGL = mongooseSchema => {
const mglObject = {
table: `${mongooseSchema.modelName}s`,
fields: {},
};
const attributes = Object.keys(mongooseSchema.schema.paths);
attributes.forEach(attr => {
mglObject.fields[attr] = getMGLType(mongooseSchema.schema.paths[attr].instance);
});
delete mglObject.fields.__v; // to avoid errors in graphql funcs due to '__'
return mglObject;
};
module.exports = {
convertMongooseToMGL,
};
@arackaf looking at your commit message, I think this got closed inadvertently?
(And yeah, I might actually have some desire to use this with Mongoose schemas in the maybe-not-too-distant future...)
@markerikson hm not sure. I may have assumed interest was lost. Or maybe just a mistake.
Reach out if you’re actually interested in implementing. I’d be happy to chat and help out as needed
Nothing immediate atm. We've got a Mongo app using Mongoose now (MEAN.js stack - eep!), and I want to migrate it to React. Looking at hypothetically setting up a new React+TS Next.js client and migrating things page-by-page, and the kinds of data fetching it's doing now seem like a good candidate for GraphQL. Realistically, probably won't have time to investigate that for at least a couple months, but was doing a bit of poking around here since I knew you'd done something with Mongo+GraphQL.
Hey. So I have some code that I have been using based off this repo for a graphql endon't to run mr Sas app CertGround. I used this project to generate the graphql schema then I re wrote most of the xUtilities.js files so that the logic works by giving those functions a mongoose schema instead of the schema that this project requires. I will admit I was not able to work out everything. Especially the relationship sections as it got a bit to complicated for me. However my graphql endpoint is working as I expect it to. Therefore I can share the progress I have so far and would be very happy to get involved to help create a mongoose version of the project as it has helped me so much! :)
Here is a link to a gist which has the files I was talking about. I have them names :x:Helpers.js instead of :x:Utilites.js. And as I have stated they are not complete as I was not able to get the relationship part working. As well I do not have the ability to generate the graphql schema from the mongoose models at this point. I used this project and the required schema syntax to build most of the graphql schemas then I manually edited what I needed to change for everything to work with Mongoose.js However, these files are being used in my graphql endpoint which is working for me. I would be very happy to make this work in a generic sense for public consumption!
I apologize for all the comments in the code. Some of it is from console.log
s and me figuring things out, other parts are the sections I have yet to make work with mongoose from this codebase.