项目介绍

join-monster/join-monster-graphql-tools-adapter 是一个托管在 GitHub 上的开源项目,主要使用 JavaScript 编写,目前获得 142 个 Star、17 次 Fork。

仓库全名
join-monster/join-monster-graphql-tools-adapter
Star 数
142
Fork 数
17
未关闭 Issue
7

README 摘要

Join Monster GraphQL Tools Adapter Use Join Monster's SQL generation and query batching powers with the Apollo graphql-tools server package. What's this package for? Suppose you have a GraphQL schema for a forum website, defined with the Schema Language like so: When using graphql-js, the reference implementation, you tag the Type constructors with extra metadata to configure Join Monster. The schema language does…

完整内容见 GitHub 原始 README 或本页 。

常见问题

join-monster-graphql-tools-adapter 用什么语言开发?

主要使用 JavaScript 编写,目前有 142 个 Star。

如何获取 join-monster-graphql-tools-adapter 的源码?

可以直接克隆仓库:git clone https://github.com/join-monster/join-monster-graphql-tools-adapter.git,默认分支为 master;安装与运行步骤见仓库 README。

join-monster-graphql-tools-adapter 最近还在维护吗?

仓库最近一次更新为 2023年1月7日,当前有 7 个未关闭 Issue;Star 数为 142,可作为社区活跃度的参考。

关于

GitHub 原始描述(英文)

Use Join Monster to fetch your data with Apollo Server.

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
184
价值分
90
活跃状态
活跃

语言占比

JavaScript

Release

README

Join Monster GraphQL Tools Adapter

Use Join Monster’s SQL generation and query batching powers with the Apollo graphql-tools server package.

What’s this package for?

Suppose you have a GraphQL schema for a forum website, defined with the Schema Language like so:

const typeDefs = `
type Comment {
  id: Int!,
  body: String!,
  postId: Int,
  authorId: Int,
  archived: Boolean
}

type Post {
  id: Int!,
  body: String!,
  authorId: Int,
  numComments: Int!,
  comments: [Comment]
}

type User {
  id: Int!,
  email: String!,
  fullName: String!,
  favNums: [Int],
  posts: [Post]
}

type Query {
  user(id: Int!): User
}
`

module.exports = typeDefs

When using graphql-js, the reference implementation, you tag the Type constructors with extra metadata to configure Join Monster. The schema language does not allow adding arbitrary properties to the type definitions.

This package let’s you add those tags without messing with the internals of the built schema object. Once you familiarize yourself with Join Monster’s API, you can use all the same properties by passing it to this function.

const joinMonsterAdapt = require('join-monster-graphql-tools-adapter')
const typeDefs = require('../path/to/types')

const joinMonster = require('join-monster').default
// node drivers for talking to SQLite
const db = require('sqlite')
const { makeExecutableSchema } = require('graphql-tools')

const resolvers = {
  Query: {
    // call joinMonster in the "user" resolver, and all child fields that are tagged with "sqlTable" are handled!
    user(parent, args, ctx, resolveInfo) {
      return joinMonster(resolveInfo, ctx, sql => {
        return db.all(sql)
      }, { dialect: 'sqlite3' })
    }
  },
  User: {
    // the only field that needs a resolver, joinMonster hydrates the rest!
    fullName(user) {
      return user.first_name + ' ' + user.last_name
    }
  }
}

const schema = makeExecutableSchema({
  typeDefs,
  resolvers
})

// tag the schema types with the extra join monster metadata
// Note the change in JoinMonster API (v3) - extensions: {} block
joinMonsterAdapt(schema, {
  Query: {
    fields: {
      // add a function to generate the "where condition"
      user: {
        extensions: {
          joinMonster: {
            where: (table, args) => `${table}.id = ${args.id}`
          }
        }
      }
    }
  },
  User: {
    // map the User object type to its SQL table
    extensions: {
      joinMonster: {
        sqlTable: 'accounts',
        uniqueKey: 'id',
      }
    },
    // tag the User's fields
    fields: {
      email: {
        extensions: {
          joinMonster: {
            sqlColumn: 'email_address'
          }
        }
      },
      fullName: {
        extensions: {
          joinMonster: {
            sqlDeps: [ 'first_name', 'last_name' ]
          }
        }
      },
      posts: {
        extensions: {
          joinMonster: {
            sqlJoin: (userTable, postTable) => `${userTable}.id = ${postTable}.author_id`,
          }
        }
      }
    }
  },
  Post: {
    extensions: {
      joinMonster: {
        sqlTable: 'posts',
        uniqueKey: 'id',
      }
    },
    fields: {
      numComments: {
        extensions: {
          joinMonster: {
        // count with a correlated subquery
            sqlExpr: table => `(SELECT count(*) FROM comments where ${table}.id = comments.post_id)`
          }
        }
      },
      comments: {
        // fetch the comments in another batch request instead of joining
        extensions: {
          joinMonster: {
            sqlBatch: {
              thisKey: 'post_id',
              parentKey: 'id'
            }
          }
        }
      }
    }
  },
  Comment: {
    extensions: {
      joinMonster: {
        sqlTable: 'comments',
        uniqueKey: 'id',
      }
    },
    fields: {
      postId: {
        extensions: {
          joinMonster: {
            sqlColumn: 'post_id'
            }
          }
      },
      authorId: {
        extensions: {
          joinMonster: {
            sqlColumn: 'author_id'
          }
        }
      }
    }
  }
})

Now that our schema is Join-monsterized, we are ready to start executing some queries!

const { graphql } = require('graphql')

const query = `{
  user(id: 1) {
    id
    fullName
    email
    posts {
      id
      body
      numComments
      comments {
        id
        body
        authorId
        archived
      }
    }
  }
}`
graphql(schema, query).then(doSomethingCrazy)

Advisory

There is a known issue (see #4) that passing the logger in graphql-tools makeExecutableSchema breaks automatic fetching of default column values. For the time being, it is suggested to remove the logger or add sqlColumn to every field.

评论

暂无评论