GraphQL 有突变,Postgres 有 INSERT; GraphQL 有查询,Postgres 有 SELECT;我还没有找到一个示例来展示如何在项目中使用这两者,例如在 GraphQL 中传递来自前端(React、Relay)的所有查询,但实际上将数据存储在 Postgres 中。
有谁知道 Facebook 使用什么作为数据库以及它如何与 GraphQL 连接?
目前在 Postgres 中存储数据来构建接受 GraphQL 查询并将其转换为 SQL 的自定义“适配器”是唯一的选择吗?
GraphQL 与数据库无关,因此您可以使用通常用来与数据库交互的任何内容,并使用查询或突变的
resolve
方法来调用您定义的函数,该函数将获取/添加某些内容到数据库中。
这里是使用基于 Promise 的 Knex SQL 查询构建器的突变示例,首先不使用 Relay 来感受这个概念。我假设您已经在 GraphQL 模式中创建了一个 userType,它具有三个字段:
id
、username
和 created
:全部必需,并且您有一个 getUser
函数已经定义了哪些查询数据库并返回一个用户对象。在数据库中,我还有一个 password
列,但由于我不想查询该列,所以我将其保留在我的 userType
之外。
// db.js
// take a user object and use knex to add it to the database, then return the newly
// created user from the db.
const addUser = (user) => (
knex('users')
.returning('id') // returns [id]
.insert({
username: user.username,
password: yourPasswordHashFunction(user.password),
created: Math.floor(Date.now() / 1000), // Unix time in seconds
})
.then((id) => (getUser(id[0])))
.catch((error) => (
console.log(error)
))
);
// schema.js
// the resolve function receives the query inputs as args, then you can call
// your addUser function using them
const mutationType = new GraphQLObjectType({
name: 'Mutation',
description: 'Functions to add things to the database.',
fields: () => ({
addUser: {
type: userType,
args: {
username: {
type: new GraphQLNonNull(GraphQLString),
},
password: {
type: new GraphQLNonNull(GraphQLString),
},
},
resolve: (_, args) => (
addUser({
username: args.username,
password: args.password,
})
),
},
}),
});
由于 Postgres 为我创建了
id
并且我计算了 created
时间戳,因此我在突变查询中不需要它们。
使用
graphql-relay
中的助手并紧贴Relay Starter Kit 对我很有帮助,因为一次要吸收很多东西。 Relay 要求您以特定的方式设置模式,以便它可以正常工作,但想法是相同的:使用您的函数在解析方法中从数据库中获取或添加到数据库。
一个重要的警告是,Relay 方式期望从
getUser
返回的对象是类 User
的实例,因此您必须修改 getUser
来适应这一点。
使用 Relay 的最后一个示例(
fromGlobalId
、globalIdField
、mutationWithClientMutationId
和 nodeDefinitions
均来自 graphql-relay
):
/**
* We get the node interface and field from the Relay library.
*
* The first method defines the way we resolve an ID to its object.
* The second defines the way we resolve an object to its GraphQL type.
*
* All your types will implement this nodeInterface
*/
const { nodeInterface, nodeField } = nodeDefinitions(
(globalId) => {
const { type, id } = fromGlobalId(globalId);
if (type === 'User') {
return getUser(id);
}
return null;
},
(obj) => {
if (obj instanceof User) {
return userType;
}
return null;
}
);
// a globalId is just a base64 encoding of the database id and the type
const userType = new GraphQLObjectType({
name: 'User',
description: 'A user.',
fields: () => ({
id: globalIdField('User'),
username: {
type: new GraphQLNonNull(GraphQLString),
description: 'The username the user has selected.',
},
created: {
type: GraphQLInt,
description: 'The Unix timestamp in seconds of when the user was created.',
},
}),
interfaces: [nodeInterface],
});
// The "payload" is the data that will be returned from the mutation
const userMutation = mutationWithClientMutationId({
name: 'AddUser',
inputFields: {
username: {
type: GraphQLString,
},
password: {
type: new GraphQLNonNull(GraphQLString),
},
},
outputFields: {
user: {
type: userType,
resolve: (payload) => getUser(payload.userId),
},
},
mutateAndGetPayload: ({ username, password }) =>
addUser(
{ username, password }
).then((user) => ({ userId: user.id })), // passed to resolve in outputFields
});
const mutationType = new GraphQLObjectType({
name: 'Mutation',
description: 'Functions to add things to the database.',
fields: () => ({
addUser: userMutation,
}),
});
const queryType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
node: nodeField,
user: {
type: userType,
args: {
id: {
description: 'ID number of the user.',
type: new GraphQLNonNull(GraphQLID),
},
},
resolve: (root, args) => getUser(args.id),
},
}),
});
我们在 Join Monster 中解决了这个问题,这是我们最近开源的一个库,可以根据您的架构定义自动将 GraphQL 查询转换为 SQL。
这个 GraphQL 入门套件 可用于试验 GraphQL.js 和 PostgreSQL:
https://github.com/kriasoft/graphql-starter-kit - Node.js、GraphQL.js、PostgreSQL、Babel、Flow
(免责声明:我是作者)
查看 graphql-sequelize 了解如何使用 Postgres。
对于突变(创建/更新/删除),您可以查看中继存储库中的示例。
Postgraphile https://www.graphile.org/postgraphile/ 是开源的
快速构建高度可定制、快如闪电的 GraphQL API
PostGraphile是一款开源工具,可帮助您快速设计和 提供高性能、安全、面向客户端的 GraphQL API 支持 主要由您的 PostgreSQL 数据库决定。让您的客户满意 令人难以置信的性能,同时保持对数据的完全控制 和你的数据库。使用我们强大的插件系统来定制每一个 根据您的喜好设置 GraphQL API 的各个方面。
如果您使用 Javascript,则可以使用像 sequelize 这样的 ORM;如果您使用 Typescript,则可以使用 Typeorm。
pg_graphql
扩展。
SequelizeJS,它是一个基于 Promise 的 ORM,可以使用多种方言; PostgreSQL、MySQL、SQLite 和 MSSQL
以下代码直接从示例中提取
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql'|'sqlite'|'postgres'|'mssql',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
// SQLite only
storage: 'path/to/database.sqlite',
// http://docs.sequelizejs.com/manual/tutorial/querying.html#operators
operatorsAliases: false
});
const User = sequelize.define('user', {
username: Sequelize.STRING,
birthday: Sequelize.DATE
});
sequelize.sync()
.then(() => User.create({
username: 'janedoe',
birthday: new Date(1980, 6, 20)
}))
.then(jane => {
console.log(jane.toJSON());
});