Join Monster Versions Save

A GraphQL to SQL query execution layer for query planning and batch data fetching.

v2.0.0

6 years ago

New features:

  • LIMIT functionality, supported on all fields
  • Fetch columns from junction tables
  • For fields with junctions, you can now specify WHERE and ORDER BY clauses on the junction table or the main table, including paginated fields.
  • Ability to dynamically choose pagination implementation per-request.
  • Better ability to write where functions that depend on args and info from the parent/ancestors.

Breaking changes:

  • Fields with junctions have a new interface in order to support the new features.
  • Any where, orderBy, and sortKey on many-to-many paginated fields used to be applied to the junction table. This has changed, and will be applied to the main table instead in order to be consistent with non-paginated junctions. If the old behavior is desired, you can nest those properties inside the junction object, which is part of the new API.
  • Change 4th parameter of where and sqlExpr to the field's SQL AST Node, which is a lot more useful.
// this...
{
  type: new GraphQLList(User),
  junctionTable: 'relationships',
  sqlJoins: [
    (followers, relations) => `${followers}.id = ${relations}.follower_id`,
    (relations, followees) => `${relations}.followee_id = ${followees}.id`
  ]
}

// is now this...
{
  type: new GraphQLList(User),
  junction: {
    sqlTable: 'relationships',
    sqlJoins: [
      (followers, relations) => `${followers}.id = ${relations}.follower_id`,
      (relations, followees) => `${relations}.followee_id = ${followees}.id`
    ]
  }
}
// this...
{
  type: new GraphQLList(User),
  junctionTable: 'relationships',
  junctionTableKey: [ 'follower_id', 'followee_id' ],
  junctionBatch: {
    thisKey: 'follower_id',
    parentKey: 'id',
    sqlJoin: (relations, followees) => `${relations}.followee_id = ${followees}.id`
  }
}

// is now this...
{
  type: new GraphQLList(User),
  junction: {
    sqlTable: 'relationships',
    uniqueKey: [ 'follower_id', 'followee_id' ],
    sqlBatch: {
      thisKey: 'follower_id',
      parentKey: 'id',
      sqlJoin: (relations, followees) => `${relations}.followee_id = ${followees}.id`
    }
  }
}
// this...
{
  type: UserConnection,
  args: forwardConnectionArgs,
  sqlPaginate: true,
  orderBy: {
    created_at: 'DESC',
    followee_id: 'ASC'
  },
  junctionTable: 'relationships',
  sqlJoins: [
    (followers, relations) => `${followers}.id = ${relations}.follower_id`,
    (relations, followees) => `${relations}.followee_id = ${followees}.id`
  ]
}

// is now this...
{
  type: UserConnection,
  args: forwardConnectionArgs,
  sqlPaginate: true,
  junction: {
    sqlTable: 'relationships',
    sqlJoins: [
      (followers, relations) => `${followers}.id = ${relations}.follower_id`,
      (relations, followees) => `${relations}.followee_id = ${followees}.id`
    ],
    // the order now goes inside the `junction` if you want to sort on the junction table
    orderBy: {
      created_at: 'DESC',
      followee_id: 'ASC'
    }
  }
  // or you could apply the order on the user table by putting it out here
  //orderBy: {
  //  created_at: 'DESC',
  //  id: 'ASC'
  //}
  
  // you could also place a `where` at either
}

v1.2.0

7 years ago

v1.0.0-beta.1

7 years ago

More advanced query planning has arrived! One of the greatest criticisms of Join Monster has been the heavy use of JOINs, which can be an expensive database operation. One of the benefits of DataLoader was the ability to simply batch queries. In this release, Join Monster can do both!

You can plan queries that get all your data in a single request using joins, or you can get them in separate batches with queries that use WHERE IN to get the right data. You can mix these approaches together to find the optimal query plans for your application.

Breaking changes

  • getSQL method removed. No longer makes sense in he new multiple-query paradigm.
  • Offset pagination adds the total to the connection object instead of the pageInfo.

Deprecated

  • 'standard' dialect is deprecated because nothing really implements the standard. The new default is 'sqlite3'.
  • joinTable is deprecated. It was renamed to junctionTable to avoid over-use of the word "join".

v0.9.9

7 years ago

The v0 major version will be stable after this point.

The pre-release of v1.0.0 is coming soon. The most important new feature will be the option to use DataLoader-style batching instead of joins. Join Monster will have more advanced query planning in order to balance the optimizations on network latency due to roundtrips and duplicated data due to joins. Schemas can mix joins and batches to tune the query plans to the heuristics of their application. There will be a few breaking changes.

Q: Is support for Apollo server planned for the near future?

A: We do not use Apollo, so it is not a priority. However, we do want Join Monster to support it, as it is the most highly requested feature. How long this takes will depend largely on community engagement.