我想在RDB中使用GraphQL

首先

就像标题所说的那样,我想在关系型数据库(MySQL)中使用GraphQL,尽管我平时并不使用它,但我还是尝试用Node编写了一下。

!!但需要只读的中文选项!!

因为直接调用ORM的方法进行写入更方便。

环境

    • MySQL 5.7

 

    • Node 10.11

 

    NPM 6.4

这是可在GitHub上访问到的成果物链接:https://github.com/lightstaff/graphql-with-sequelize

准备

我们可以使用适当的npm init等命令创建项目,并安装所需的库。

$: npm install --save apollo-server dataloader-sequelize graphql mysql2 sequelize
    • apollo-server…GraphQLサーバーを簡単に立ち上げてくれる。

 

    • graphql…主役

 

    • sequelize…ORMライブラリ

 

    • dataloader-sequelize…N+1を解決してくれるらしい

 

    mysql2…MySQLドライバ

关系数据库(RDB)的一侧

我们在ORM中使用Sequelize,但由于我刚开始使用,并不会详细解释。请查看Sequelize的官方文档或官方示例以获取更多详细信息。

创建一个名为models的目录,然后在其中创建User和EMail两个模型。

用户○–< 邮件之间的关系。

module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define(
    'user',
    {
      id: {
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      },
      name: DataTypes.STRING,
    },
    {
      timestamps: false,
      tableName: 'user',
    }
  );

  User.associate = models => {
    User.hasMany(models.email);
  };

  return User;
};
module.exports = (sequelize, DataTypes) => {
  const EMail = sequelize.define(
    'email',
    {
      id: {
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      },
      address: DataTypes.STRING,
    },
    {
      timestamps: false,
      tableName: 'email',
    }
  );

  EMail.associate = models => {
    EMail.belongsTo(models.user);
  };

  return EMail;
};

为了能够访问这些内容,我们也需要定义数据库。

const Sequelize = require('sequelize');

const sequelize = new Sequelize('test', 'root', '1234', {
  dialect: 'mysql',
  host: 'localhost',
  port: 3306,
});

module.exports = sequelize;
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');

const sequelize = require('../database');

const db = {
  sequelize,
  Sequelize,
};

fs.readdirSync(__dirname)
  .filter(file => path.extname(file) === '.js' && file !== 'index.js')
  .forEach(file => {
    const model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach(modelName => {
  if ('associate' in db[modelName]) {
    db[modelName].associate(db);
  }
});

module.exports = db;

GraphQL的一侧

终于谈到正题了。

使用ApolloServer似乎可以轻松构建。

由于非常简单,所以我先提供源代码。

const apolloServer = require('apollo-server');
const dataLoaderSequelize = require('dataloader-sequelize');

const db = require('./models');

const { ApolloServer, gql } = apolloServer;
const { createContext, EXPECTED_OPTIONS_KEY } = dataLoaderSequelize;

// GraphQL schema
const typeDefs = gql`
  type User {
    id: ID!
    name: String
    emails: [Email!]!
  }

  type Email {
    id: ID!
    address: String
    user: User!
  }

  type Query {
    users: [User!]!
    user(id: ID!): User
  }
`;

// GraphQL <-> ORM
const resolvers = {
  User: {
    emails: (parent, args, context, info) => parent.getEmails(),
  },
  Email: {
    user: (parent, args, context, info) => parent.getUser(),
  },
  Query: {
    users: (parent, args, { db, eok }, info) =>
      db.user.findAll({ [EXPECTED_OPTIONS_KEY]: eok }),
    user: (parent, { id }, { db, eok }, info) =>
      db.user.findById(id, { [EXPECTED_OPTIONS_KEY]: eok }),
  },
};

// Apollo server
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: {
    db: db,
    eok: createContext(db.sequelize),
  },
});

// Entry point
async function start() {
  await db.sequelize.sync({ force: true });

  // Setup dummy
  const userA = await db.user.create({ name: 'A' });
  const userB = await db.user.create({ name: 'B' });
  await userA.createEmail({ address: 'A1@e-mail.com' });
  await userA.createEmail({ address: 'A2@e-mail.com' });
  await userB.createEmail({ address: 'B1@e-mail.com' });

  server.listen().then(({ url }) => {
    console.log(`? Server ready at ${url}`);
  });
}

start();

这个非常简单,不需要解释的……

使用const typeDefs = …来定义GraphQL的模式。

const resolvers = …为GraphQl模式调用数据库并定义解析器。

在这段代码中,使用…创建了ApolloServer,并将数据库等数据提供给了context。

异步函数 start() 是入口点。在启动服务器之前,它会初始化数据库并添加数据。

执行

$ node server.js

进行操作。

image.png

如果没有问题的话,Graphql应该可以按照上述方式构建。

最后

我认为这件事做得相当简单,这真是太好了。

广告
将在 10 秒后关闭
bannerAds