simple-graphql
Advanced tools
Comparing version 0.2.1 to 0.2.3
@@ -36,2 +36,24 @@ 'use strict'; | ||
* Relay Connection Helper | ||
* | ||
* @example | ||
* import SG from 'simple-graphql' | ||
* const UserType = GS.modelRef('User') | ||
* export default GS.model('User', {}).fields({ | ||
* firstName: String, | ||
* lastName: String | ||
* }).queries({ | ||
* searchUsers: { | ||
* description: 'Search users by firstName', | ||
* $type: GS.Connection.connectionType(UserType), | ||
* args: { | ||
* ...GS.Connection.args, | ||
* condition: { | ||
* firstName: String | ||
* } | ||
* }, | ||
* resolve: async function (args, context, info, {User}) { | ||
* return GS.Connection.resolve(User, args) | ||
* } | ||
* } | ||
* }) | ||
*/ | ||
@@ -38,0 +60,0 @@ |
@@ -175,2 +175,5 @@ 'use strict'; | ||
}); | ||
Object.assign(obj, _query2.default.hasManyQueryFields(model)); | ||
this.graphQLObjectTypes[typeName] = _transformer2.default.toGraphQLFieldConfig(typeName, '', obj, this, interfaces).type; | ||
@@ -177,0 +180,0 @@ if (this.graphQLObjectTypes[typeName] instanceof graphql.GraphQLObjectType) { |
@@ -7,6 +7,2 @@ 'use strict'; | ||
var _graphql = require('graphql'); | ||
var graphql = _interopRequireWildcard(_graphql); | ||
var _type = require('./type'); | ||
@@ -24,4 +20,2 @@ | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
138
lib/index.js
@@ -58,10 +58,136 @@ 'use strict'; | ||
/** | ||
* @public | ||
* 入口 | ||
* TODO | ||
* Usage: | ||
* | ||
* @example | ||
* | ||
* 1.Define the model | ||
* | ||
* // | ||
* import SG from 'simple-graphql' | ||
* | ||
* const TodoType = SG.modelRef('Todo') | ||
* | ||
* export default SG.model('Todo').fields({ | ||
* title: { | ||
* $type: String, | ||
* required: true | ||
* }, | ||
* description: String, | ||
* completed: { | ||
* $type: Boolean, | ||
* required: true | ||
* }, | ||
* dueAt: Date | ||
* }).queries({ | ||
* dueTodos: { | ||
* description: "Find all due todos", | ||
* $type: [TodoType], | ||
* args: { | ||
* dueBefore: { | ||
* $type: Date, | ||
* required: true | ||
* } | ||
* }, | ||
* resolve: async function ({ dueBefore}, context, info, {Todo}) { | ||
* return Todo.find({ | ||
* where: { | ||
* completed: false, | ||
* dueAt: { | ||
* $lt: dueBefore | ||
* } | ||
* } | ||
* }) | ||
* } | ||
* } | ||
* }).mutations({ | ||
* cpmpletedTodo: { | ||
* description: "Mark the todo task completed.", | ||
* inputFields: { | ||
* todoId: { | ||
* $type: TodoType, | ||
* required: true | ||
* } | ||
* }, | ||
* outputFields: { | ||
* changedTodo: TodoType | ||
* }, | ||
* mutateAndGetPayload: async function ({todoId}, context, info, {Todo}) { | ||
* const todo = await Todo.findOne({where: {id: todoId}}) | ||
* if (!todo) { | ||
* throw new Error("Todo entity not found.") | ||
* } | ||
* if (!todo.completed) { | ||
* todo.completed = true | ||
* await todo.save() | ||
* } | ||
* return {changedTodo: todo} | ||
* } | ||
* } | ||
* }) | ||
* | ||
* 2. Config the Sequelize database connection. | ||
* | ||
* import Sequelize from 'sequelize' | ||
* const sequelize = new Sequelize('test1', 'postgres', 'Password', { | ||
* host: 'localhost', | ||
* port: 5432, | ||
* dialect: 'postgres', | ||
* | ||
* pool: { | ||
* max: 5, | ||
* min: 0, | ||
* idle: 10000 | ||
* } | ||
* }) | ||
* export default sequelize | ||
* | ||
* 3. Generate the GraphQL Schema | ||
* | ||
* import SG from 'simple-graphql' | ||
* | ||
* //import Todo model and sequlize config ... | ||
* | ||
* const schema = GS.build(sequelize, [Todo], {}) | ||
* | ||
* //After bulid, all sequelize models have defined, then call sequelize.sync will automatic create the schema in database. | ||
* sequelize.sync({ | ||
* force: false, | ||
* logging: console.log | ||
* }).then(() => console.log('Init DB Done'), (err) => console.log('Init DB Fail', err)) | ||
* | ||
* export default | ||
* | ||
* 4. Start the GraphQL server | ||
* | ||
* const express = require('express'); | ||
* const graphqlHTTP = require('express-graphql'); | ||
* | ||
* const app = express(); | ||
* | ||
* app.use('/graphql', graphqlHTTP({ | ||
* schema: MyGraphQLSchema, | ||
* graphiql: true | ||
* })); | ||
* app.listen(4000); | ||
*/ | ||
exports.default = { | ||
var SimpleGraphQL = { | ||
/** Available values: | ||
* <table style='text-align: left'> | ||
* <tr><th>Name</th><th>GraphQL Type</th><th>DB Type</th></tr> | ||
* <tr><td>Id</td><td>GraphQLID</td><td>Sequelize.INTEGER</td></tr> | ||
* <tr><td>String</td><td>GraphQLString</td><td>Sequelize.STRING</td></tr> | ||
* <tr><td>Float</td><td>GraphQLFloat</td><td>Sequelize.DOUBLE</td></tr> | ||
* <tr><td>Int</td><td>GraphQLInt</td><td>Sequelize.INTEGER</td></tr> | ||
* <tr><td>Boolean</td><td>GraphQLBoolean</td><td>Sequelize.BOOLEAN</td></tr> | ||
* <tr><td>Date</td><td>GraphQLScalarTypes.Date</td><td>Sequelize.DATE</td></tr> | ||
* <tr><td>JSON</td><td>GraphQLScalarTypes.Json</td><td>Sequelize.JSONB</td></tr> | ||
* </table> | ||
* | ||
*/ | ||
ScalarFieldTypes: _type2.default.ScalarFieldTypes, | ||
/** | ||
* Get the Relay Connction helper | ||
*/ | ||
Connection: _Connection2.default, | ||
@@ -234,2 +360,4 @@ | ||
} | ||
}; | ||
}; | ||
exports.default = SimpleGraphQL; |
@@ -12,3 +12,4 @@ 'use strict'; | ||
/** | ||
* dd | ||
* TODO | ||
* @example | ||
*/ | ||
@@ -40,5 +41,4 @@ var Model = function () { | ||
/** | ||
* | ||
* @param fields | ||
* @returns {Model} | ||
* Add the model base fields, and each field has a corresponding database column. | ||
* In default, each field generate a GraphQL field, unless it config with "hidden:true". | ||
*/ | ||
@@ -63,2 +63,7 @@ | ||
}) | ||
/** | ||
* Add the model link fields, and each link generate a GraphQL field but no corresponding database column. | ||
*/ | ||
}, { | ||
@@ -80,2 +85,7 @@ key: 'links', | ||
}) | ||
/** | ||
* Add the GraphQL query methods. | ||
*/ | ||
}, { | ||
@@ -97,2 +107,7 @@ key: 'queries', | ||
}) | ||
/** | ||
* Add the GraphQL mutataion methods. | ||
*/ | ||
}, { | ||
@@ -114,2 +129,7 @@ key: 'mutations', | ||
}) | ||
/** | ||
* Add instance method to current Model. | ||
*/ | ||
}, { | ||
@@ -131,2 +151,7 @@ key: 'methods', | ||
}) | ||
/** | ||
* Add statics method to current Model. | ||
*/ | ||
}, { | ||
@@ -148,2 +173,7 @@ key: 'statics', | ||
}) | ||
/** | ||
* Add {@link http://docs.sequelizejs.com/en/latest/docs/associations/#hasone|HasOne} relations to current Model. | ||
*/ | ||
}, { | ||
@@ -155,2 +185,7 @@ key: 'hasOne', | ||
} | ||
/** | ||
* Add {@link http://docs.sequelizejs.com/en/latest/docs/associations/#belongsto|BelongsTo} relations to current Model. | ||
*/ | ||
}, { | ||
@@ -162,2 +197,7 @@ key: 'belongsTo', | ||
} | ||
/** | ||
* Add {@link http://docs.sequelizejs.com/en/latest/docs/associations/#one-to-many-associations|HasMany} relations to current Model. | ||
*/ | ||
}, { | ||
@@ -169,2 +209,7 @@ key: 'hasMany', | ||
} | ||
/** | ||
* Add {@link http://docs.sequelizejs.com/en/latest/docs/associations/#belongs-to-many-associations|BelongsToMany} relations to current Model. | ||
*/ | ||
}, { | ||
@@ -171,0 +216,0 @@ key: 'belongsToMany', |
{ | ||
"name": "simple-graphql", | ||
"version": "0.2.1", | ||
"description": "The simple way to build GraphQL style API with MySQL/PostreSQL", | ||
"version": "0.2.3", | ||
"description": "The simple way to generates GraphQL schemas and Sequelize models from your models definition.", | ||
"main": "lib/index.js", | ||
@@ -12,3 +12,4 @@ "scripts": { | ||
"build-dot-flow": "find ./src -name '*.js' | while read filepath; do cp $filepath `echo $filepath | sed 's/\\/src\\//\\/lib\\//g'`.flow; done", | ||
"buildAndPublish": "npm run flow && npm run format && npm run build && npm publish" | ||
"buildAndPublish": "npm run flow && npm run format && npm run build && npm publish", | ||
"docs": "documentation build -c documentation.yml --sort-order alpha -f md -o docs/API.md src/index.js src/Definition.js" | ||
}, | ||
@@ -29,5 +30,7 @@ "author": "logerzhu", | ||
"Relay", | ||
"sequelize", | ||
"Sequelize", | ||
"MySQL", | ||
"PostgreSQL" | ||
"PostgreSQL", | ||
"SQLite", | ||
"MSSQL" | ||
], | ||
@@ -34,0 +37,0 @@ "dependencies": { |
@@ -15,2 +15,6 @@ 'use strict'; | ||
var _hasMany = require('./fields/hasMany'); | ||
var _hasMany2 = _interopRequireDefault(_hasMany); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -20,3 +24,5 @@ | ||
singularQuery: _singular2.default, | ||
pluralQuery: _plural2.default | ||
pluralQuery: _plural2.default, | ||
hasManyQueryFields: _hasMany2.default | ||
}; |
@@ -10,6 +10,2 @@ 'use strict'; | ||
/** | ||
* Returns a GraphQLFieldConfig for the mutation described by the | ||
* provided MutationConfig. | ||
*/ | ||
function mutationWithClientMutationId(config) { | ||
@@ -16,0 +12,0 @@ var name = config.name, |
@@ -74,30 +74,35 @@ 'use strict'; | ||
if (_lodash2.default.isArray(fieldType)) { | ||
var elementType = toGraphQLFieldConfig(name, postfix, fieldType[0], context).type; | ||
var elementType = new graphql.GraphQLList(toGraphQLFieldConfig(name, postfix, fieldType[0], context).type); | ||
return { | ||
type: new graphql.GraphQLList(elementType), | ||
resolve: function () { | ||
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(root) { | ||
var fieldName; | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
// TODO check? | ||
fieldName = name.split('.').slice(-1)[0]; | ||
return _context.abrupt('return', root[fieldName]); | ||
type: elementType, | ||
resolve: context.wrapFieldResolve({ | ||
name: name.split('.').slice(-1)[0], | ||
path: name, | ||
$type: elementType, | ||
resolve: function () { | ||
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(root) { | ||
var fieldName; | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
// TODO check? | ||
fieldName = name.split('.').slice(-1)[0]; | ||
return _context.abrupt('return', root[fieldName]); | ||
case 2: | ||
case 'end': | ||
return _context.stop(); | ||
case 2: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
}, _callee, this); | ||
})); | ||
function resolve(_x2) { | ||
return _ref.apply(this, arguments); | ||
} | ||
function resolve(_x2) { | ||
return _ref.apply(this, arguments); | ||
} | ||
return resolve; | ||
}() | ||
return resolve; | ||
}() | ||
}) | ||
}; | ||
@@ -188,3 +193,8 @@ } | ||
if (fieldType['resolve']) { | ||
result['resolve'] = fieldType['resolve']; | ||
result['resolve'] = context.wrapFieldResolve({ | ||
name: name.split('.').slice(-1)[0], | ||
path: name, | ||
$type: result.type, | ||
resolve: fieldType['resolve'] | ||
}); | ||
} | ||
@@ -197,38 +207,44 @@ if (fieldType['args']) { | ||
} else { | ||
var objType = new graphql.GraphQLObjectType({ | ||
name: typeName(name) + postfix, | ||
interfaces: interfaces, | ||
fields: function fields() { | ||
var fields = {}; | ||
_lodash2.default.forOwn(fieldType, function (value, key) { | ||
if (value['$type'] && value['hidden']) {} else { | ||
fields[key] = toGraphQLFieldConfig(name + postfix + '.' + key, '', value, context); | ||
} | ||
}); | ||
return fields; | ||
} | ||
}); | ||
return { | ||
type: new graphql.GraphQLObjectType({ | ||
name: typeName(name) + postfix, | ||
interfaces: interfaces, | ||
fields: function fields() { | ||
var fields = {}; | ||
_lodash2.default.forOwn(fieldType, function (value, key) { | ||
if (value['$type'] && value['hidden']) {} else { | ||
fields[key] = toGraphQLFieldConfig(name + postfix + '.' + key, '', value, context); | ||
} | ||
}); | ||
return fields; | ||
} | ||
}), | ||
resolve: function () { | ||
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(root) { | ||
return regeneratorRuntime.wrap(function _callee3$(_context3) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
return _context3.abrupt('return', root[name.split('.').slice(-1)[0]]); | ||
type: objType, | ||
resolve: context.wrapFieldResolve({ | ||
name: name.split('.').slice(-1)[0], | ||
path: name, | ||
$type: objType, | ||
resolve: function () { | ||
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(root) { | ||
return regeneratorRuntime.wrap(function _callee3$(_context3) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
return _context3.abrupt('return', root[name.split('.').slice(-1)[0]]); | ||
case 1: | ||
case 'end': | ||
return _context3.stop(); | ||
case 1: | ||
case 'end': | ||
return _context3.stop(); | ||
} | ||
} | ||
} | ||
}, _callee3, this); | ||
})); | ||
}, _callee3, this); | ||
})); | ||
function resolve(_x8) { | ||
return _ref3.apply(this, arguments); | ||
} | ||
function resolve(_x8) { | ||
return _ref3.apply(this, arguments); | ||
} | ||
return resolve; | ||
}() | ||
return resolve; | ||
}() | ||
}) | ||
}; | ||
@@ -235,0 +251,0 @@ } |
@@ -12,8 +12,2 @@ 'use strict'; | ||
/** | ||
* 生产 query or mutation 的inputType,自动把globalId 转换回 id | ||
* @param typeName | ||
* @returns {"graphql".GraphQLScalarType<string>} | ||
*/ | ||
function defGlobalIdInputType(typeName) { | ||
@@ -63,7 +57,2 @@ return new _graphql.GraphQLScalarType({ | ||
/** | ||
* 返回指定类型的Global ID input | ||
* @param typeName | ||
* @returns {GraphQLScalarType<string>} | ||
*/ | ||
function globalIdInputType(typeName) { | ||
@@ -70,0 +59,0 @@ if (!types[typeName]) { |
{ | ||
"name": "simple-graphql", | ||
"version": "0.2.1", | ||
"description": "The simple way to build GraphQL style API with MySQL/PostreSQL", | ||
"version": "0.2.3", | ||
"description": "The simple way to generates GraphQL schemas and Sequelize models from your models definition.", | ||
"main": "lib/index.js", | ||
@@ -12,3 +12,4 @@ "scripts": { | ||
"build-dot-flow": "find ./src -name '*.js' | while read filepath; do cp $filepath `echo $filepath | sed 's/\\/src\\//\\/lib\\//g'`.flow; done", | ||
"buildAndPublish": "npm run flow && npm run format && npm run build && npm publish" | ||
"buildAndPublish": "npm run flow && npm run format && npm run build && npm publish", | ||
"docs": "documentation build -c documentation.yml --sort-order alpha -f md -o docs/API.md src/index.js src/Definition.js" | ||
}, | ||
@@ -29,5 +30,7 @@ "author": "logerzhu", | ||
"Relay", | ||
"sequelize", | ||
"Sequelize", | ||
"MySQL", | ||
"PostgreSQL" | ||
"PostgreSQL", | ||
"SQLite", | ||
"MSSQL" | ||
], | ||
@@ -34,0 +37,0 @@ "dependencies": { |
150
README.md
@@ -1,6 +0,13 @@ | ||
# simple-graphql | ||
# Simple-GraphQL | ||
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) | ||
The simple way to build GraphQL style API with DataBase support. | ||
`Simple-GraphQL` generates [GraphQL](https://github.com/graphql/graphql-js) schemas and [Sequelize](http://docs.sequelizejs.com/en/latest/) models from your models definition(support [FlowType](https://flow.org/) static type check), that's how simple it is. The generated GraphQL schema is compatible with [Relay](https://facebook.github.io/relay/). | ||
>[GraphQL](https://github.com/graphql/graphql-js) is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. | ||
>[Sequelize](http://docs.sequelizejs.com/en/latest/) is a promise-based ORM for Node.js. It supports the dialects `PostgreSQL`, `MySQL`, `SQLite` and `MSSQL` and features solid transaction support, relations, read replication and more. | ||
>[FlowType](https://flow.org/) is a static type checker for your JavaScript code. It does a lot of work to make you more productive. Making you code faster, smarter, more confidently, and to a bigger scale. | ||
## Install | ||
@@ -14,3 +21,3 @@ | ||
Check out the project code (https://github.com/logerzhu/simple-graphql). | ||
Check out the project code (<https://github.com/logerzhu/simple-graphql>). | ||
@@ -20,3 +27,3 @@ ```shell | ||
npm install # install dependencies in the main folder | ||
npm run demo # run the demo and open your browser: http://localhost:9413/graphql | ||
npm run start # run the demo and open your browser: http://localhost:9413/graphql | ||
``` | ||
@@ -26,36 +33,127 @@ | ||
This library support [FlowType](https://flow.org/) (a static typechecker for JavaScript), which can help to check you model defintion. | ||
`Simple-GraphQL` | ||
#### Define the model | ||
TODO | ||
**Examples** | ||
## Supported types | ||
### Define the model | ||
```javascript | ||
// @flow | ||
import SG from 'simple-graphql' | ||
* Number | ||
* String | ||
* Boolean | ||
* Date | ||
* [Number] | ||
* [String] | ||
* [Boolean] | ||
* [Date] | ||
* ObjectId with ref (reference to other document, populate) | ||
TODO | ||
const TodoType = SG.modelRef('Todo') | ||
## Supported queries / mutations | ||
TODO | ||
export default SG.model('Todo').fields({ | ||
title: { | ||
$type: String, | ||
required: true | ||
}, | ||
description: String, | ||
completed: { | ||
$type: Boolean, | ||
required: true | ||
}, | ||
dueAt: Date | ||
}).queries({ | ||
dueTodos: { | ||
description: "Find all due todos", | ||
$type: [TodoType], | ||
args: { | ||
dueBefore: { | ||
$type: Date, | ||
required: true | ||
} | ||
}, | ||
resolve: async function ({ dueBefore}, context, info, {Todo}) { | ||
return Todo.find({ | ||
where: { | ||
completed: false, | ||
dueAt: { | ||
$lt: dueBefore | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
}).mutations({ | ||
cpmpletedTodo: { | ||
description: "Mark the todo task completed.", | ||
inputFields: { | ||
todoId: { | ||
$type: TodoType, | ||
required: true | ||
} | ||
}, | ||
outputFields: { | ||
changedTodo: TodoType | ||
}, | ||
mutateAndGetPayload: async function ({todoId}, context, info, {Todo}) { | ||
const todo = await Todo.findOne({where: {id: todoId}}) | ||
if (!todo) { | ||
throw new Error("Todo entity not found.") | ||
} | ||
if (!todo.completed) { | ||
todo.completed = true | ||
await todo.save() | ||
} | ||
return {changedTodo: todo} | ||
} | ||
} | ||
}) | ||
``` | ||
## Options | ||
TODO | ||
### Config the Sequelize database connection. | ||
```javascript | ||
import Sequelize from 'sequelize' | ||
const sequelize = new Sequelize('test1', 'postgres', 'Password', { | ||
host: 'localhost', | ||
port: 5432, | ||
dialect: 'postgres', | ||
## Test | ||
pool: { | ||
max: 5, | ||
min: 0, | ||
idle: 10000 | ||
} | ||
}) | ||
export default sequelize | ||
``` | ||
TODO | ||
### Generate the GraphQL Schema | ||
## Contributing | ||
```javascript | ||
import SG from 'simple-graphql' | ||
TODO | ||
//import Todo model and sequlize config ... | ||
const schema = GS.build(sequelize, [Todo], {}) | ||
//After bulid, all sequelize models have defined, then call sequelize.sync will automatic create the schema in database. | ||
sequelize.sync({ | ||
force: false, | ||
logging: console.log | ||
}).then(() => console.log('Init DB Done'), (err) => console.log('Init DB Fail', err)) | ||
export default | ||
``` | ||
### Start the GraphQL server | ||
```javascript | ||
const express = require('express'); | ||
const graphqlHTTP = require('express-graphql'); | ||
const app = express(); | ||
app.use('/graphql', graphqlHTTP({ | ||
schema: MyGraphQLSchema, | ||
graphiql: true | ||
})); | ||
app.listen(4000); | ||
``` | ||
## Document | ||
- [API](docs/API.md) | ||
## License | ||
[MIT](https://github.com/logerzhu/simple-graphql/blob/master/LICENSE) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
Found 1 instance in 1 package
0
100
157
459430
91
4523