README.md in graphql-relay-0.10.0 vs README.md in graphql-relay-0.11.0

- old
+ new

@@ -3,12 +3,13 @@ [![Gem Version](https://badge.fury.io/rb/graphql-relay.svg)](http://badge.fury.io/rb/graphql-relay) [![Build Status](https://travis-ci.org/rmosolgo/graphql-relay-ruby.svg?branch=master)](https://travis-ci.org/rmosolgo/graphql-relay-ruby) [![Code Climate](https://codeclimate.com/github/rmosolgo/graphql-relay-ruby/badges/gpa.svg)](https://codeclimate.com/github/rmosolgo/graphql-relay-ruby) [![Test Coverage](https://codeclimate.com/github/rmosolgo/graphql-relay-ruby/badges/coverage.svg)](https://codeclimate.com/github/rmosolgo/graphql-relay-ruby/coverage) -Helpers for using [`graphql`](https://github.com/rmosolgo/graphql-ruby) with Relay. +Helpers for using [`graphql`](https://github.com/rmosolgo/graphql-ruby) with Relay. Includes support for serving Relay connections from `Array`s, `ActiveRecord::Relation`s and `Sequel::Dataset`s. + [API Documentation](http://www.rubydoc.info/github/rmosolgo/graphql-relay-ruby) ## Installation ```ruby gem "graphql-relay" @@ -113,11 +114,11 @@ `graphql-relay` will use those procs for interacting with global ids. ### Connections -Connections provide pagination and `pageInfo` for `Array`s or `ActiveRecord::Relation`s. +Connections provide pagination and `pageInfo` for `Array`s, `ActiveRecord::Relation`s or `Sequel::Dataset`s. #### Connection fields To define a connection field, use the `connection` helper. For a return type, get a type's `.connection_type`. For example: @@ -134,10 +135,13 @@ You can also define custom arguments and a custom resolve function for connections, just like other fields: ```ruby connection :featured_comments, CommentType.connection_type do + # Use a name to disambiguate this from `CommentType.connection_type` + name "CommentConnectionWithSince" + # Add an argument: argument :since, types.String # Return an Array or ActiveRecord::Relation resolve -> (post, args, ctx) { @@ -163,21 +167,124 @@ #### Connection types You can customize a connection type with `.define_connection`: ```ruby -PostType.define_connection do +PostConnectionWithTotalCountType = PostType.define_connection do field :totalCount do type types.Int # `obj` is the Connection, `obj.object` is the collection of Posts resolve -> (obj, args, ctx) { obj.object.count } end end + ``` -Now, `PostType.connection_type` will include a `totalCount` field. +Now, you can use `PostConnectionWithTotalCountType` to define a connection with the "totalCount" field: +```ruby +AuthorType = GraphQL::ObjectType.define do + # Use the custom connection type: + connection :posts, PostConnectionWithTotalCountType +end +``` + +#### Custom edge types + +If you need custom fields on `edge`s, you can define an edge type and pass it to a connection: + +```ruby +# Person => Membership => Team +MembershipSinceEdgeType = BaseType.define_edge do + name "MembershipSinceEdge" + field :memberSince, types.Int, "The date that this person joined this team" do + resolve -> (obj, args, ctx) { + obj # => GraphQL::Relay::Edge instnce + person = obj.parent + team = obj.node + membership = Membership.where(person: person, team: team).first + membership.created_at.to_i + } + end +end +``` + +Then, pass the edge type when defining the connection type: + +```ruby +TeamMembershipsConnectionType = TeamType.define_connection(edge_type: MembershipSinceEdgeType) do + # Use a name so it doesn't conflict with "TeamConnection" + name "TeamMembershipsConnection" +end +``` + +Now, you can query custom fields on the `edge`: + +```graphql +{ + me { + teams { + edge { + memberSince # <= Here's your custom field + node { + teamName: name + } + } + } + } +} +``` + +#### Custom Edge classes + +For more robust custom edges, you can define a custom edge class. It will be `obj` in the edge type's resolve function. For example, to define a membership edge: + +```ruby +# Make sure to familiarize yourself with GraphQL::Relay::Edge -- +# you have to avoid naming conflicts here! +class MembershipSinceEdge < GraphQL::Relay::Edge + # Cache `membership` to avoid multiple DB queries + def membership + @membership ||= begin + # "parent" and "node" are passed in from the surrounding Connection, + # See `Edge#initialize` for details + person = self.parent + team = self.node + Membership.where(person: person, team: team).first + end + end + + def member_since + membership.created_at.to_i + end + + def leader? + membership.leader? + end +end +``` + +Then, hook it up with custom edge type and custom connection type: + +```ruby +# Person => Membership => Team +MembershipSinceEdgeType = BaseType.define_edge do + name "MembershipSinceEdge" + field :memberSince, types.Int, "The date that this person joined this team", property: :member_since + field :isPrimary, types.Boolean, "Is this person the team leader?". property: :primary? + end +end + +TeamMembershipsConnectionType = TeamType.define_connection( + edge_class: MembershipSinceEdge, + edge_type: MembershipSinceEdgeType, + ) do + # Use a name so it doesn't conflict with "TeamConnection" + name "TeamMembershipsConnection" +end +``` + #### Connection objects Maybe you need to make a connection object yourself (for example, to return a connection type from a mutation). You can create a connection object like this: ```ruby @@ -235,11 +342,10 @@ field = GraphQL::Field.new # ... define the field connection_field = GraphQL::Relay::ConnectionField.create(field) ``` - ### Mutations Mutations allow Relay to mutate your system. They conform to a strict API which makes them predictable to the client. ### Mutation root @@ -340,10 +446,9 @@ 2. http://mgiroux.me/2015/getting-started-with-rails-graphql-relay/ 3. http://mgiroux.me/2015/uploading-files-using-relay-with-rails/ ## Todo -- Allow custom edge fields (per connection type) - `GlobalNodeIdentification.to_global_id` should receive the type name and _object_, not `id`. (Or, maintain the "`type_name, id` in, `type_name, id` out" pattern?) - Make GlobalId a property of the schema, not a global - Reduce duplication in ArrayConnection / RelationConnection - Improve API for creating edges (better RANGE_ADD support) - If the new edge isn't a member of the connection's objects, raise a nice error