Skip to content

Commit

Permalink
Update docs to reflect new extensions configuration setup
Browse files Browse the repository at this point in the history
  • Loading branch information
airhorns committed Jun 19, 2020
1 parent f35e345 commit 67ba3c8
Show file tree
Hide file tree
Showing 15 changed files with 536 additions and 291 deletions.
9 changes: 7 additions & 2 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
### v3.0.0 (unreleased)

**Breaking changes:**
- Update GraphQL requirement to version 15, which supports a new `extensions` property where join-monster config lives. The config keys and values are unchanged, but they must be nested under an `extensions: { joinMonster: ... }}` property on the GraphQLObjectTypes and fields using join-monster. For more information, see the upgrade guide:

### v2.1.2 (May 25, 2020)
#### Fixed
#### Fixed
- Connections inside union fragments [#407](https://github.com/join-monster/join-monster/pull/407)

### v2.1.1 (Nov. 21, 2019)
#### Fixed
#### Fixed
- Updated vulnerable version of lodash (`eed0264`)

### v2.1.0 (Aug. 25, 2018)
Expand Down
21 changes: 15 additions & 6 deletions docs/aggregation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ const Post = new GraphQLObjectType({
description: 'The number of comments on this post',
type: GraphQLInt,
// use a correlated subquery in a raw SQL expression to do things like aggregation
sqlExpr: postTable => `(SELECT count(*) FROM comments WHERE post_id = ${postTable}.id AND archived = FALSE)`
},
extensions: {
joinMonster: {
sqlExpr: postTable =>
`(SELECT count(*) FROM comments WHERE post_id = ${postTable}.id AND archived = FALSE)`
}
}
}
})
})
```
Expand Down Expand Up @@ -57,8 +62,13 @@ const Post = new GraphQLObjectType({
fields: () => ({
commentsWithoutJoin: {
type: new GraphQLList(SimpleComment),
sqlExpr: postTable => `(SELECT json_agg(comments) FROM comments WHERE comments.post_id = ${postTable}.id AND comments.archived = FALSE)`
},
extensions: {
joinMonster: {
sqlExpr: postTable =>
`(SELECT json_agg(comments) FROM comments WHERE comments.post_id = ${postTable}.id AND comments.archived = FALSE)`
}
}
}
})
})
```
Expand All @@ -76,7 +86,7 @@ This should work without any additional data munging if you're using `knex`, as
commentsWithoutJoin {
id
body
authorId
authorId
}
}
}
Expand All @@ -98,4 +108,3 @@ FROM accounts AS "user"
LEFT JOIN posts AS "posts" ON "user".id = "posts".author_id
WHERE "user".id = 2
```

66 changes: 51 additions & 15 deletions docs/arbitrary-depth.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ const Post = new GraphQLObjectType({
author: {
description: 'The user that created the post',
type: User,
sqlJoin: (postTable, userTable, args, context) => `${postTable}.author_id = ${userTable}.id`
extensions: {
joinMonster: {
sqlJoin: (postTable, userTable, args, context) =>
`${postTable}.author_id = ${userTable}.id`
}
}
}
})
})
Expand All @@ -31,12 +36,22 @@ const Comment = new GraphQLObjectType({
post: {
description: 'The post that the comment belongs to',
type: Post,
sqlJoin: (commentTable, postTable) => `${commentTable}.post_id = ${postTable}.id`
extensions: {
joinMonster: {
sqlJoin: (commentTable, postTable) =>
`${commentTable}.post_id = ${postTable}.id`
}
}
},
author: {
description: 'The user who wrote the comment',
type: User,
sqlJoin: (commentTable, userTable) => `${commentTable}.author_id = ${userTable}.id`
extensions: {
joinMonster: {
sqlJoin: (commentTable, userTable) =>
`${commentTable}.author_id = ${userTable}.id`
}
}
}
})
})
Expand All @@ -46,14 +61,22 @@ Now you can get the comments the user has written, the post on which each commen

```graphql
{
users {
id, email, fullName
users {
id
email
fullName
comments {
id, body
author { fullName }
id
body
author {
fullName
}
post {
id, body
author { fullName }
id
body
author {
fullName
}
}
}
}
Expand All @@ -71,11 +94,21 @@ const User = new GraphQLObjectType({
//...
posts: {
type: new GraphQLList(Post),
sqlJoin: (userTable, postTable, args) => `${userTable}.id = ${postTable}.author_id`
extensions: {
joinMonster: {
sqlJoin: (userTable, postTable, args) =>
`${userTable}.id = ${postTable}.author_id`
}
}
},
comments: {
type: new GraphQLList(Comment),
sqlJoin: (userTable, commentTable, args) => `${userTable}.id = ${commentTable}.author_id`
extensions: {
joinMonster: {
sqlJoin: (userTable, commentTable, args) =>
`${userTable}.id = ${commentTable}.author_id`
}
}
}
})
})
Expand All @@ -91,15 +124,18 @@ const Post = new GraphQLObjectType({
comments: {
description: 'The comments on this post',
type: new GraphQLList(Comment),
// the JOIN condition also checks that the comment is not archived
sqlJoin: (postTable, commentTable) => `${postTable}.id = ${commentTable}.post_id AND ${commentTable}.archived = FALSE`,
extensions: {
joinMonster: {
// the JOIN condition also checks that the comment is not archived
sqlJoin: (postTable, commentTable) =>
`${postTable}.id = ${commentTable}.post_id AND ${commentTable}.archived = FALSE`
}
}
}
})
})

```

Again, the data is all fetched in a single query thanks to `JOIN`s.
However, doing all these joins can be cumbersome on the database.
We can split it into two, or perhaps more, separate queries to reduce the number of joins in the next section.

30 changes: 17 additions & 13 deletions docs/batch-many-many.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,23 @@ const User = new GraphQLObjectType({
following: {
description: 'Users that this user is following',
type: new GraphQLList(User),
// batching many-to-many is supported too
junction: {
sqlTable: 'relationships',
// this table has no primary key, but the combination of these two columns is unique
uniqueKey: [ 'follower_id', 'followee_id' ],
sqlBatch: {
// the matching column in the junction table
thisKey: 'follower_id',
// the column to match in the user table
parentKey: 'id',
// how to join the related table to the junction table
sqlJoin: (junctionTable, followeeTable) => `${junctionTable}.followee_id = ${followeeTable}.id`
extensions: {
joinMonster: {
// batching many-to-many is supported too
junction: {
sqlTable: 'relationships',
// this table has no primary key, but the combination of these two columns is unique
uniqueKey: ['follower_id', 'followee_id'],
sqlBatch: {
// the matching column in the junction table
thisKey: 'follower_id',
// the column to match in the user table
parentKey: 'id',
// how to join the related table to the junction table
sqlJoin: (junctionTable, followeeTable) =>
`${junctionTable}.followee_id = ${followeeTable}.id`
}
}
}
}
}
Expand All @@ -37,4 +42,3 @@ In addition to the changes made on the previous page, the plan now has 3 databas
![query-plan-3](img/query-plan-3.png)

Requests for the followees and for the comments are independent, and are sent concurrently.

27 changes: 15 additions & 12 deletions docs/batch-one-many.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,21 @@ const Post = new GraphQLObjectType({
comments: {
description: 'The comments on this post',
type: new GraphQLList(Comment),
// instead of doing yet another JOIN, we'll get these comments in a separate batch
// sqlJoin: (postTable, commentTable) => `${postTable}.id = ${commentTable}.post_id AND ${commentTable}.archived = FALSE`,
sqlBatch: {
// which column to match up to the users
thisKey: 'post_id',
// the other column to compare to
parentKey: 'id'
},
// sqlBatch works with the `where` function too. get only non-archived comments
where: table => `${table}.archived = FALSE`
},
extensions: {
joinMonster: {
// instead of doing yet another JOIN, we'll get these comments in a separate batch
// sqlJoin: (postTable, commentTable) => `${postTable}.id = ${commentTable}.post_id AND ${commentTable}.archived = FALSE`,
sqlBatch: {
// which column to match up to the users
thisKey: 'post_id',
// the other column to compare to
parentKey: 'id'
},
// sqlBatch works with the `where` function too. get only non-archived comments
where: table => `${table}.archived = FALSE`
}
}
}
})
})
```
Expand Down Expand Up @@ -91,4 +95,3 @@ Two database queries are made regardless of the number of posts, another way to

Although this also works perfectly fine for a one-to-one relation, it is not recommended.
Not much is gained by batching on a one-to-one since using a simple `JOIN` would not burden the database greatly.

43 changes: 31 additions & 12 deletions docs/field-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@ const User = new GraphQLObjectType({
},
email: {
type: GraphQLString,
// if the column name is different, it must be specified
sqlColumn: 'email_address'
extensions: {
joinMonster: {
// if the column name is different, it must be specified
sqlColumn: 'email_address'
}
}
},
idEncoded: {
description: 'The ID base-64 encoded',
type: GraphQLString,
sqlColumn: 'id',
extensions: {
joinMonster: {
sqlColumn: 'id'
}
},
// this field uses a sqlColumn and applies a resolver function on the value
// if a resolver is present, the `sqlColumn` MUST be specified even if it is the same name as the field
resolve: user => toBase64(user.id)
Expand Down Expand Up @@ -52,11 +60,15 @@ const User = new GraphQLObjectType({
//...
fields: () => ({
fullName: {
description: 'A user\'s first and last name',
description: "A user's first and last name",
type: GraphQLString,
// perhaps there is no 1-to-1 mapping of field to column
// this field depends on multiple columns
sqlDeps: [ 'first_name', 'last_name' ],
extensions: {
joinMonster: {
// perhaps there is no 1-to-1 mapping of field to column
// this field depends on multiple columns
sqlDeps: ['first_name', 'last_name']
}
},
resolve: user => `${user.first_name} ${user.last_name}`
}
})
Expand All @@ -71,15 +83,22 @@ const User = new GraphQLObjectType({
fields: () => ({
capitalizedLastName: {
type: GraphQLString,
// do a computed column in SQL with raw expression
sqlExpr: (table, args) => `UPPER(${table}.last_name)`
extensions: {
joinMonster: {
// do a computed column in SQL with raw expression
sqlExpr: (table, args) => `UPPER(${table}.last_name)`
}
}
},
fullNameAnotherWay: {
description: 'Another way we can get the full name.',
type: GraphQLString,
sqlExpr: table => `${table}.first_name || ' ' || ${table}.last_name`
},
extensions: {
joinMonster: {
sqlExpr: table => `${table}.first_name || ' ' || ${table}.last_name`
}
}
}
})
})
```

20 changes: 16 additions & 4 deletions docs/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,32 @@ const User = new GraphQLObjectType({
fields: () => ({
id: {
type: GraphQLInt,
sqlColumn: 'id'
extensions: {
joinMonster: {
sqlColumn: 'id'
}
}
},
email: {
type: GraphQLString,
sqlColumn: 'email_address'
extensions: {
joinMonster: {
sqlColumn: 'email_address'
}
}
},
immortal: {
type: graphQLBoolean,
resolve: () => false
},
posts: {
type: new GraphQLList(Post),
sqlJoin: (userTable, postTable) => `${userTable}.id = ${postTable}.author_id`
extensions: {
joinMonster: {
sqlJoin: (userTable, postTable) =>
`${userTable}.id = ${postTable}.author_id`
}
}
}
})
})
Expand Down Expand Up @@ -76,4 +89,3 @@ users: {
}
}
```

0 comments on commit 67ba3c8

Please sign in to comment.