GraphQL là cơ sở dữ liệu bất khả tri, vì vậy bạn có thể sử dụng bất cứ thứ gì bạn thường sử dụng để tương tác với cơ sở dữ liệu và sử dụng resolve
của truy vấn hoặc đột biến để gọi một hàm mà bạn đã xác định sẽ lấy / thêm thứ gì đó vào cơ sở dữ liệu.
Không có chuyển tiếp
Dưới đây là một ví dụ về đột biến bằng cách sử dụng trình tạo truy vấn Knex SQL dựa trên lời hứa, trước tiên không có Chuyển tiếp để có cảm nhận về khái niệm này. Tôi sẽ giả sử rằng bạn đã tạo một userType trong lược đồ GraphQL có ba trường:id
, username
và created
:tất cả đều bắt buộc và bạn có getUser
đã xác định hàm nào truy vấn cơ sở dữ liệu và trả về một đối tượng người dùng. Trong cơ sở dữ liệu, tôi cũng có một password
, nhưng vì tôi không muốn nó được truy vấn nên tôi bỏ nó ra khỏi userType
của mình .
// 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,
})
),
},
}),
});
Vì Postgres tạo id
cho tôi và tôi tính toán created
dấu thời gian, tôi không cần chúng trong truy vấn đột biến của mình.
Cách chuyển tiếp
Sử dụng trình trợ giúp trong graphql-relay
và việc gắn bó khá chặt chẽ với Bộ khởi động tiếp sức đã giúp ích cho tôi, bởi vì nó rất nhiều thứ để thực hiện tất cả cùng một lúc. Relay yêu cầu bạn thiết lập lược đồ của mình theo một cách cụ thể để nó có thể hoạt động bình thường, nhưng ý tưởng vẫn giống nhau:sử dụng các hàm của bạn để tìm nạp hoặc thêm vào cơ sở dữ liệu trong các phương thức giải quyết.
Một lưu ý quan trọng là cách Relay mong đợi rằng đối tượng được trả về từ getUser
là một bản sao của một lớp User
, vì vậy bạn sẽ phải sửa đổi getUser
để đáp ứng điều đó.
Ví dụ cuối cùng sử dụng Relay (fromGlobalId
, globalIdField
, mutationWithClientMutationId
và nodeDefinitions
tất cả đều từ 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),
},
}),
});