Пример #1
0
func init() {
	globalIDTestUserType = graphql.NewObject(graphql.ObjectConfig{
		Name: "User",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("User", nil),
			"name": &graphql.Field{
				Type: graphql.String,
			},
		},
		Interfaces: []*graphql.Interface{globalIDTestDef.NodeInterface},
	})
	photoIDFetcher := func(obj interface{}, info graphql.ResolveInfo) string {
		switch obj := obj.(type) {
		case *photo2:
			return fmt.Sprintf("%v", obj.PhotoId)
		}
		return ""
	}
	globalIDTestPhotoType = graphql.NewObject(graphql.ObjectConfig{
		Name: "Photo",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("Photo", photoIDFetcher),
			"width": &graphql.Field{
				Type: graphql.Int,
			},
		},
		Interfaces: []*graphql.Interface{globalIDTestDef.NodeInterface},
	})

	globalIDTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{
		Query: globalIDTestQueryType,
	})
}
Пример #2
0
func (api *ViewAPI) Start() error {
	api.Type = graphql.NewObject(graphql.ObjectConfig{
		Name: "View",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("View", nil),
			"createdAt": &graphql.Field{
				Description: "When the view was first created.",
				Type:        graphql.String,
			},
			"name": &graphql.Field{
				Description: "The name to display for the view.",
				Type:        graphql.String,
			},
			"searches": &graphql.Field{
				Type: graphql.NewList(api.SearchAPI.Type),
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					span := trace.FromContext(p.Context).NewChild("trythings.viewAPI.searches")
					defer span.Finish()

					v, ok := p.Source.(*View)
					if !ok {
						return nil, errors.New("expected view source")
					}

					ss, err := api.SearchService.ByView(p.Context, v)
					if err != nil {
						return nil, err
					}

					return ss, nil
				},
			},
		},
		Interfaces: []*graphql.Interface{
			api.NodeInterface,
		},
	})
	return nil
}
Пример #3
0
func (api *UserAPI) Start() error {
	api.Type = graphql.NewObject(graphql.ObjectConfig{
		Name:        "User",
		Description: "User represents a person who can interact with the app.",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("User", nil),
			"isAdmin": &graphql.Field{
				Description: "Whether or not the user is an Ellie's Pad admin.",
				Type:        graphql.Boolean,
			},
			"email": &graphql.Field{
				Description: "The user's email primary address.",
				Type:        graphql.String,
			},
			"name": &graphql.Field{
				Description: "The user's full name.",
				Type:        graphql.String,
			},
			"givenName": &graphql.Field{
				Description: "The user's given name.",
				Type:        graphql.String,
			},
			"familyName": &graphql.Field{
				Description: "The user's family name.",
				Type:        graphql.String,
			},
			"imageUrl": &graphql.Field{
				Description: "The user's profile picture URL.",
				Type:        graphql.String,
			},
			"space": &graphql.Field{
				Args: graphql.FieldConfigArgument{
					"id": &graphql.ArgumentConfig{
						Type:         graphql.String,
						DefaultValue: "",
						Description:  "id can be omitted, which will have space resolve to the user's default space.",
					},
				},
				Description: "space is a disjoint universe of views, searches and tasks.",
				Type:        api.SpaceAPI.Type,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					span := trace.FromContext(p.Context).NewChild("trythings.userAPI.space")
					defer span.Finish()

					id, ok := p.Args["id"].(string)
					if ok {
						resolvedID := relay.FromGlobalID(id)
						if resolvedID == nil {
							return nil, fmt.Errorf("invalid id %q", id)
						}

						sp, err := api.SpaceService.ByID(p.Context, resolvedID.ID)
						if err != nil {
							return nil, err
						}
						return sp, nil
					}

					u, ok := p.Source.(*User)
					if !ok {
						return nil, errors.New("expected user source")
					}

					sps, err := api.SpaceService.ByUser(p.Context, u)
					if err != nil {
						return nil, err
					}

					if len(sps) == 0 {
						return nil, errors.New("could not find default space for user")
					}

					return sps[0], nil
				},
			},
			"spaces": &graphql.Field{
				Type: graphql.NewList(api.SpaceAPI.Type),
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					span := trace.FromContext(p.Context).NewChild("trythings.userAPI.spaces")
					defer span.Finish()

					u, ok := p.Source.(*User)
					if !ok {
						return nil, errors.New("expected user source")
					}

					sps, err := api.SpaceService.ByUser(p.Context, u)
					if err != nil {
						return nil, err
					}

					return sps, nil
				},
			},
		},
		Interfaces: []*graphql.Interface{
			api.NodeInterface,
		},
	})
	return nil
}
Пример #4
0
func (api *TaskAPI) Start() error {
	api.Type = graphql.NewObject(graphql.ObjectConfig{
		Name:        "Task",
		Description: "Task represents a particular action or piece of work to be completed.",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("Task", nil),
			"createdAt": &graphql.Field{
				Description: "When the task was first added",
				Type:        graphql.String,
			},
			"title": &graphql.Field{
				Description: "A short summary of the task",
				Type:        graphql.String,
			},
			"description": &graphql.Field{
				Description: "A more detailed explanation of the task",
				Type:        graphql.String,
			},
			"isArchived": &graphql.Field{
				Description: "Whether this task requires attention",
				Type:        graphql.Boolean,
			},
		},
		Interfaces: []*graphql.Interface{
			api.NodeInterface,
		},
	})
	api.ConnectionType = relay.ConnectionDefinitions(relay.ConnectionConfig{
		Name:     api.Type.Name(),
		NodeType: api.Type,
	}).ConnectionType

	api.Mutations = map[string]*graphql.Field{
		"addTask": relay.MutationWithClientMutationID(relay.MutationConfig{
			Name: "AddTask",
			InputFields: graphql.InputObjectConfigFieldMap{
				"title": &graphql.InputObjectFieldConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
				"description": &graphql.InputObjectFieldConfig{
					Type: graphql.String,
				},
				"spaceId": &graphql.InputObjectFieldConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
			},
			OutputFields: graphql.Fields{
				"task": &graphql.Field{
					Type: api.Type,
					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
						payload, ok := p.Source.(map[string]interface{})
						if !ok {
							return nil, errors.New("could not cast payload to map")
						}
						id, ok := payload["taskId"].(string)
						if !ok {
							return nil, errors.New("could not cast taskId to string")
						}
						t, err := api.TaskService.ByID(p.Context, id)
						if err != nil {
							return nil, err
						}
						return t, nil
					},
				},
			},
			MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo, ctx context.Context) (map[string]interface{}, error) {
				title, ok := inputMap["title"].(string)
				if !ok {
					return nil, errors.New("could not cast title to string")
				}

				var desc string
				descOrNil := inputMap["description"]
				if descOrNil != nil {
					desc, ok = descOrNil.(string)
					if !ok {
						return nil, errors.New("could not cast description to string")
					}
				}

				spaceID, ok := inputMap["spaceId"].(string)
				if !ok {
					return nil, errors.New("could not cast spaceId to string")
				}
				resolvedSpaceID := relay.FromGlobalID(spaceID)
				if resolvedSpaceID == nil {
					return nil, fmt.Errorf("invalid id %q", spaceID)
				}

				t := &Task{
					Title:       title,
					Description: desc,
					SpaceID:     resolvedSpaceID.ID,
				}
				err := api.TaskService.Create(ctx, t)
				if err != nil {
					return nil, err
				}

				return map[string]interface{}{
					"taskId": t.ID,
				}, nil
			},
		}),
		"editTask": relay.MutationWithClientMutationID(relay.MutationConfig{
			Name: "EditTask",
			InputFields: graphql.InputObjectConfigFieldMap{
				"id": &graphql.InputObjectFieldConfig{
					Type: graphql.NewNonNull(graphql.ID),
				},
				"title": &graphql.InputObjectFieldConfig{
					Type: graphql.String,
				},
				"description": &graphql.InputObjectFieldConfig{
					Type: graphql.String,
				},
				"isArchived": &graphql.InputObjectFieldConfig{
					Type: graphql.Boolean,
				},
			},
			OutputFields: graphql.Fields{
				"task": &graphql.Field{
					Type: api.Type,
					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
						payload, ok := p.Source.(map[string]interface{})
						if !ok {
							return nil, errors.New("could not cast payload to map")
						}
						id, ok := payload["id"].(string)
						if !ok {
							return nil, errors.New("could not cast id to string")
						}
						t, err := api.TaskService.ByID(p.Context, id)
						if err != nil {
							return nil, err
						}
						return t, nil
					},
				},
			},
			MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo, ctx context.Context) (map[string]interface{}, error) {
				id, ok := inputMap["id"].(string)
				if !ok {
					return nil, errors.New("could not cast id to string")
				}

				resolvedID := relay.FromGlobalID(id)
				if resolvedID == nil {
					return nil, fmt.Errorf("invalid id %q", id)
				}

				t, err := api.TaskService.ByID(ctx, resolvedID.ID)
				if err != nil {
					return nil, err
				}

				title, ok := inputMap["title"].(string)
				if ok {
					t.Title = title
				}

				description, ok := inputMap["description"].(string)
				if ok {
					t.Description = description
				}

				isArchived, ok := inputMap["isArchived"].(bool)
				if ok {
					t.IsArchived = isArchived
				}

				err = api.TaskService.Update(ctx, t)
				if err != nil {
					return nil, err
				}

				return map[string]interface{}{
					"id": t.ID,
				}, nil
			},
		}),
	}

	return nil
}
Пример #5
0
func init() {

	/**
	 * We get the node interface and field from the relay library.
	 *
	 * The first method is the way we resolve an ID to its object. The second is the
	 * way we resolve an object that implements node to its type.
	 */
	nodeDefinitions = relay.NewNodeDefinitions(relay.NodeDefinitionsConfig{
		IDFetcher: func(id string, info graphql.ResolveInfo) interface{} {
			// resolve id from global id
			resolvedID := relay.FromGlobalID(id)

			// based on id and its type, return the object
			if resolvedID.Type == "Faction" {
				return GetFaction(resolvedID.ID)
			} else {
				return GetShip(resolvedID.ID)
			}
		},
		TypeResolve: func(value interface{}, info graphql.ResolveInfo) *graphql.Object {
			// based on the type of the value, return GraphQLObjectType
			switch value.(type) {
			case *Faction:
				return factionType
			default:
				return shipType
			}
		},
	})

	/**
	 * We define our basic ship type.
	 *
	 * This implements the following type system shorthand:
	 *   type Ship : Node {
	 *     id: String!
	 *     name: String
	 *   }
	 */
	shipType = graphql.NewObject(graphql.ObjectConfig{
		Name:        "Ship",
		Description: "A ship in the Star Wars saga",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("Ship", nil),
			"name": &graphql.Field{
				Type:        graphql.String,
				Description: "The name of the ship.",
			},
		},
		Interfaces: []*graphql.Interface{
			nodeDefinitions.NodeInterface,
		},
	})

	/**
	 * We define a connection between a faction and its ships.
	 *
	 * connectionType implements the following type system shorthand:
	 *   type ShipConnection {
	 *     edges: [ShipEdge]
	 *     pageInfo: PageInfo!
	 *   }
	 *
	 * connectionType has an edges field - a list of edgeTypes that implement the
	 * following type system shorthand:
	 *   type ShipEdge {
	 *     cursor: String!
	 *     node: Ship
	 *   }
	 */
	shipConnectionDefinition := relay.ConnectionDefinitions(relay.ConnectionConfig{
		Name:     "Ship",
		NodeType: shipType,
	})

	/**
	 * We define our faction type, which implements the node interface.
	 *
	 * This implements the following type system shorthand:
	 *   type Faction : Node {
	 *     id: String!
	 *     name: String
	 *     ships: ShipConnection
	 *   }
	 */
	factionType = graphql.NewObject(graphql.ObjectConfig{
		Name:        "Faction",
		Description: "A faction in the Star Wars saga",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("Faction", nil),
			"name": &graphql.Field{
				Type:        graphql.String,
				Description: "The name of the faction.",
			},
			"ships": &graphql.Field{
				Type: shipConnectionDefinition.ConnectionType,
				Args: relay.ConnectionArgs,
				Resolve: func(p graphql.ResolveParams) interface{} {
					// convert args map[string]interface into ConnectionArguments
					args := relay.NewConnectionArguments(p.Args)

					// get ship objects from current faction
					ships := []interface{}{}
					if faction, ok := p.Source.(*Faction); ok {
						for _, shipId := range faction.Ships {
							ships = append(ships, GetShip(shipId))
						}
					}
					// let relay library figure out the result, given
					// - the list of ships for this faction
					// - and the filter arguments (i.e. first, last, after, before)
					return relay.ConnectionFromArray(ships, args)
				},
			},
		},
		Interfaces: []*graphql.Interface{
			nodeDefinitions.NodeInterface,
		},
	})

	/**
	 * This is the type that will be the root of our query, and the
	 * entry point into our schema.
	 *
	 * This implements the following type system shorthand:
	 *   type Query {
	 *     rebels: Faction
	 *     empire: Faction
	 *     node(id: String!): Node
	 *   }
	 */
	queryType := graphql.NewObject(graphql.ObjectConfig{
		Name: "Query",
		Fields: graphql.Fields{
			"rebels": &graphql.Field{
				Type: factionType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return GetRebels()
				},
			},
			"empire": &graphql.Field{
				Type: factionType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return GetEmpire()
				},
			},
			"node": nodeDefinitions.NodeField,
		},
	})

	/**
	 * This will return a GraphQLField for our ship
	 * mutation.
	 *
	 * It creates these two types implicitly:
	 *   input IntroduceShipInput {
	 *     clientMutationID: string!
	 *     shipName: string!
	 *     factionId: ID!
	 *   }
	 *
	 *   input IntroduceShipPayload {
	 *     clientMutationID: string!
	 *     ship: Ship
	 *     faction: Faction
	 *   }
	 */
	shipMutation := relay.MutationWithClientMutationID(relay.MutationConfig{
		Name: "IntroduceShip",
		InputFields: graphql.InputObjectConfigFieldMap{
			"shipName": &graphql.InputObjectFieldConfig{
				Type: graphql.NewNonNull(graphql.String),
			},
			"factionId": &graphql.InputObjectFieldConfig{
				Type: graphql.NewNonNull(graphql.ID),
			},
		},
		OutputFields: graphql.Fields{
			"ship": &graphql.Field{
				Type: shipType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					if payload, ok := p.Source.(map[string]interface{}); ok {
						return GetShip(payload["shipId"].(string))
					}
					return nil
				},
			},
			"faction": &graphql.Field{
				Type: factionType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					if payload, ok := p.Source.(map[string]interface{}); ok {
						return GetFaction(payload["factionId"].(string))
					}
					return nil
				},
			},
		},
		MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo) map[string]interface{} {
			// `inputMap` is a map with keys/fields as specified in `InputFields`
			// Note, that these fields were specified as non-nullables, so we can assume that it exists.
			shipName := inputMap["shipName"].(string)
			factionId := inputMap["factionId"].(string)

			// This mutation involves us creating (introducing) a new ship
			newShip := CreateShip(shipName, factionId)
			// return payload
			return map[string]interface{}{
				"shipId":    newShip.ID,
				"factionId": factionId,
			}
		},
	})

	/**
	 * This is the type that will be the root of our mutations, and the
	 * entry point into performing writes in our schema.
	 *
	 * This implements the following type system shorthand:
	 *   type Mutation {
	 *     introduceShip(input IntroduceShipInput!): IntroduceShipPayload
	 *   }
	 */

	mutationType := graphql.NewObject(graphql.ObjectConfig{
		Name: "Mutation",
		Fields: graphql.Fields{
			"introduceShip": shipMutation,
		},
	})

	/**
	 * Finally, we construct our schema (whose starting query type is the query
	 * type we defined above) and export it.
	 */
	var err error
	Schema, err = graphql.NewSchema(graphql.SchemaConfig{
		Query:    queryType,
		Mutation: mutationType,
	})
	if err != nil {
		// panic if there is an error in schema
		panic(err)
	}
}
Пример #6
0
func init() {
	DbMap, err = InitDB("development")

	Me = entities.GetPerson(DbMap, 1).(entities.Person)

	House = graphql.NewObject(
		graphql.ObjectConfig{
			Name: "House",
			Fields: graphql.Fields{
				"id": relay.GlobalIDField("House", nil),
				"name": &graphql.Field{
					Type: graphql.String,
				},
			},
		},
	)

	Person = graphql.NewObject(
		graphql.ObjectConfig{
			Name: "Person",
			Fields: graphql.Fields{
				"id": relay.GlobalIDField("Person", nil),
				"name": &graphql.Field{
					Type: graphql.String,
				},
				"email": &graphql.Field{
					Type: graphql.String,
				},
				"updated_at": &graphql.Field{
					Type: graphql.String,
				},
				"house": &graphql.Field{
					Type: House,
					Resolve: func(p graphql.ResolveParams) interface{} {
						return entities.GetHouse(DbMap, p.Source.(entities.Person).HouseId)
					},
				},
			},
		},
	)

	Person.AddFieldConfig("roommates", &graphql.Field{
		Type: graphql.NewList(Person),
		Resolve: func(p graphql.ResolveParams) interface{} {
			return entities.GetPersonsRoommates(DbMap, p.Source.(entities.Person))
		},
	})

	//Debt = graphql.NewObject(
	//graphql.ObjectConfig{
	//Name: "Debt",
	//},
	//)

	Expense = graphql.NewObject(
		graphql.ObjectConfig{
			Name: "Expense",
			Fields: graphql.Fields{
				"id": relay.GlobalIDField("Expense", nil),
				"name": &graphql.Field{
					Type: graphql.String,
				},
			},
		},
	)

	queryType := graphql.NewObject(graphql.ObjectConfig{
		Name: "Query",
		Fields: graphql.Fields{
			"me": &graphql.Field{
				Type: Person,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return Me
				},
			},
		},
	})

	Schema, _ = graphql.NewSchema(graphql.SchemaConfig{
		Query: queryType,
	})
}
Пример #7
0
func (api *SpaceAPI) Start() error {
	api.Type = graphql.NewObject(graphql.ObjectConfig{
		Name:        "Space",
		Description: "Space represents an access-controlled universe of tasks.",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("Space", nil),
			"createdAt": &graphql.Field{
				Description: "When the space was first created.",
				Type:        graphql.String,
			},
			"name": &graphql.Field{
				Description: "The name to display for the space.",
				Type:        graphql.String,
			},
			"savedSearch": &graphql.Field{
				Args: graphql.FieldConfigArgument{
					"id": &graphql.ArgumentConfig{
						Type: graphql.String,
					},
				},
				Type: api.SearchAPI.Type,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					span := trace.FromContext(p.Context).NewChild("trythings.spaceAPI.savedSearch")
					defer span.Finish()

					id, ok := p.Args["id"].(string)
					if !ok {
						return nil, errors.New("id is required")
					}
					resolvedID := relay.FromGlobalID(id)
					if resolvedID == nil {
						return nil, fmt.Errorf("invalid id %q", id)
					}

					se, err := api.SearchService.ByClientID(p.Context, resolvedID.ID)
					if err != nil {
						return nil, err
					}
					return se, nil
				},
			},
			"querySearch": &graphql.Field{
				Args: graphql.FieldConfigArgument{
					"query": &graphql.ArgumentConfig{
						Type:         graphql.String,
						DefaultValue: "",
						Description:  "query filters the result to only tasks that contain particular terms in their title or description",
					},
				},
				Type: api.SearchAPI.Type,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					span := trace.FromContext(p.Context).NewChild("trythings.spaceAPI.querySearch")
					defer span.Finish()

					sp, ok := p.Source.(*Space)
					if !ok {
						return nil, errors.New("expected a space source")
					}

					q, ok := p.Args["query"].(string)
					if !ok {
						q = "" // Return all tasks.
					}

					return &Search{
						Query:   q,
						SpaceID: sp.ID,
					}, nil
				},
			},
			"view": &graphql.Field{
				Args: graphql.FieldConfigArgument{
					"id": &graphql.ArgumentConfig{
						Type:         graphql.String,
						DefaultValue: "",
						Description:  "id can be omitted, which will have view resolve to the space's default view.",
					},
				},
				Type: api.ViewAPI.Type,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					span := trace.FromContext(p.Context).NewChild("trythings.spaceAPI.view")
					defer span.Finish()

					id, ok := p.Args["id"].(string)
					if ok {
						resolvedID := relay.FromGlobalID(id)
						if resolvedID == nil {
							return nil, fmt.Errorf("invalid id %q", id)
						}

						v, err := api.ViewService.ByID(p.Context, resolvedID.ID)
						if err != nil {
							return nil, err
						}
						return v, nil
					}

					sp, ok := p.Source.(*Space)
					if !ok {
						return nil, errors.New("expected space source")
					}

					vs, err := api.ViewService.BySpace(p.Context, sp)
					if err != nil {
						return nil, err
					}

					if len(vs) == 0 {
						return nil, errors.New("could not find default view for space")
					}

					return vs[0], nil
				},
			},
			"views": &graphql.Field{
				Type: graphql.NewList(api.ViewAPI.Type),
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					span := trace.FromContext(p.Context).NewChild("trythings.spaceAPI.views")
					defer span.Finish()

					sp, ok := p.Source.(*Space)
					if !ok {
						return nil, errors.New("expected space source")
					}

					vs, err := api.ViewService.BySpace(p.Context, sp)
					if err != nil {
						return nil, err
					}

					return vs, nil
				},
			},
		},
		Interfaces: []*graphql.Interface{
			api.NodeInterface,
		},
	})

	return nil
}
Пример #8
0
func init() {

	/**
	 * We get the node interface and field from the Relay library.
	 *
	 * The first method defines the way we resolve an ID to its object.
	 * The second defines the way we resolve an object to its GraphQL type.
	 */
	nodeDefinitions = relay.NewNodeDefinitions(relay.NodeDefinitionsConfig{
		IDFetcher: func(id string, info graphql.ResolveInfo, ct context.Context) (interface{}, error) {
			resolvedID := relay.FromGlobalID(id)
			if resolvedID.Type == "User" {
				return GetUser(resolvedID.ID), nil
			}
			if resolvedID.Type == "Widget" {
				return GetWidget(resolvedID.ID), nil
			}
			return nil, nil
		},
		TypeResolve: func(value interface{}, info graphql.ResolveInfo) *graphql.Object {
			switch value.(type) {
			case *User:
				return userType
			case *Widget:
				return widgetType
			}
			return nil
		},
	})

	/**
	 * Define your own types here
	 */
	widgetType = graphql.NewObject(graphql.ObjectConfig{
		Name:        "Widget",
		Description: "A shiny widget'",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("Widget", nil),
			"name": &graphql.Field{
				Description: "The name of the widget",
				Type:        graphql.String,
			},
		},
		Interfaces: []*graphql.Interface{
			nodeDefinitions.NodeInterface,
		},
	})
	widgetConnection = relay.ConnectionDefinitions(relay.ConnectionConfig{
		Name:     "WidgetConnection",
		NodeType: widgetType,
	})

	userType = graphql.NewObject(graphql.ObjectConfig{
		Name:        "User",
		Description: "A person who uses our app",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("User", nil),
			"widgets": &graphql.Field{
				Type:        widgetConnection.ConnectionType,
				Description: "A person's collection of widgets",
				Args:        relay.ConnectionArgs,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					args := relay.NewConnectionArguments(p.Args)
					dataSlice := WidgetsToInterfaceSlice(GetWidgets()...)
					return relay.ConnectionFromArray(dataSlice, args), nil
				},
			},
		},
		Interfaces: []*graphql.Interface{
			nodeDefinitions.NodeInterface,
		},
	})

	/**
	 * This is the type that will be the root of our query,
	 * and the entry point into our schema.
	 */
	queryType := graphql.NewObject(graphql.ObjectConfig{
		Name: "Query",
		Fields: graphql.Fields{
			"node": nodeDefinitions.NodeField,

			// Add you own root fields here
			"viewer": &graphql.Field{
				Type: userType,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					return GetViewer(), nil
				},
			},
		},
	})

	/**
	 * This is the type that will be the root of our mutations,
	 * and the entry point into performing writes in our schema.
	 */
	//	mutationType := graphql.NewObject(graphql.ObjectConfig{
	//		Name: "Mutation",
	//		Fields: graphql.Fields{
	//			// Add you own mutations here
	//		},
	//	})

	/**
	* Finally, we construct our schema (whose starting query type is the query
	* type we defined above) and export it.
	 */
	var err error
	Schema, err = graphql.NewSchema(graphql.SchemaConfig{
		Query: queryType,
	})
	if err != nil {
		panic(err)
	}
}
Пример #9
0
func init() {

	nodeDefinitions = relay.NewNodeDefinitions(relay.NodeDefinitionsConfig{
		IDFetcher: func(id string, info graphql.ResolveInfo) interface{} {
			resolvedID := relay.FromGlobalID(id)
			if resolvedID.Type == "Todo" {
				return GetTodo(resolvedID.ID)
			}
			if resolvedID.Type == "User" {
				return GetUser(resolvedID.ID)
			}
			return nil
		},
		TypeResolve: func(value interface{}, info graphql.ResolveInfo) *graphql.Object {
			switch value.(type) {
			case *Todo:
				return todoType
			case *User:
				return userType
			default:
				return userType
			}
		},
	})

	todoType = graphql.NewObject(graphql.ObjectConfig{
		Name: "Todo",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("Todo", nil),
			"text": &graphql.Field{
				Type: graphql.String,
			},
			"complete": &graphql.Field{
				Type: graphql.Boolean,
			},
		},
		Interfaces: []*graphql.Interface{nodeDefinitions.NodeInterface},
	})

	todosConnection = relay.ConnectionDefinitions(relay.ConnectionConfig{
		Name:     "Todo",
		NodeType: todoType,
	})

	userType = graphql.NewObject(graphql.ObjectConfig{
		Name: "User",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("User", nil),
			"todos": &graphql.Field{
				Type: todosConnection.ConnectionType,
				Args: relay.NewConnectionArgs(graphql.FieldConfigArgument{
					"status": &graphql.ArgumentConfig{
						Type:         graphql.String,
						DefaultValue: "any",
					},
				}),
				Resolve: func(p graphql.ResolveParams) interface{} {
					status, _ := p.Args["status"].(string)
					args := relay.NewConnectionArguments(p.Args)
					todos := TodosToSliceInterface(GetTodos(status))
					return relay.ConnectionFromArray(todos, args)
				},
			},
			"totalCount": &graphql.Field{
				Type: graphql.Int,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return len(GetTodos("any"))
				},
			},
			"completedCount": &graphql.Field{
				Type: graphql.Int,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return len(GetTodos("completed"))
				},
			},
		},
		Interfaces: []*graphql.Interface{nodeDefinitions.NodeInterface},
	})

	rootType := graphql.NewObject(graphql.ObjectConfig{
		Name: "Root",
		Fields: graphql.Fields{
			"viewer": &graphql.Field{
				Type: userType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return GetViewer()
				},
			},
			"node": nodeDefinitions.NodeField,
		},
	})

	addTodoMutation := relay.MutationWithClientMutationID(relay.MutationConfig{
		Name: "AddTodo",
		InputFields: graphql.InputObjectConfigFieldMap{
			"text": &graphql.InputObjectFieldConfig{
				Type: graphql.NewNonNull(graphql.String),
			},
		},
		OutputFields: graphql.Fields{
			"todoEdge": &graphql.Field{
				Type: todosConnection.EdgeType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					payload, _ := p.Source.(map[string]interface{})
					todoId, _ := payload["todoId"].(string)
					todo := GetTodo(todoId)
					return relay.EdgeType{
						Node:   todo,
						Cursor: relay.CursorForObjectInConnection(TodosToSliceInterface(GetTodos("any")), todo),
					}
				},
			},
			"viewer": &graphql.Field{
				Type: userType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return GetViewer()
				},
			},
		},
		MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo) map[string]interface{} {
			text, _ := inputMap["text"].(string)
			todoId := AddTodo(text, false)
			return map[string]interface{}{
				"todoId": todoId,
			}
		},
	})

	changeTodoStatusMutation := relay.MutationWithClientMutationID(relay.MutationConfig{
		Name: "ChangeTodoStatus",
		InputFields: graphql.InputObjectConfigFieldMap{
			"id": &graphql.InputObjectFieldConfig{
				Type: graphql.NewNonNull(graphql.ID),
			},
			"complete": &graphql.InputObjectFieldConfig{
				Type: graphql.NewNonNull(graphql.Boolean),
			},
		},
		OutputFields: graphql.Fields{
			"todo": &graphql.Field{
				Type: todoType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					payload, _ := p.Source.(map[string]interface{})
					todoId, _ := payload["todoId"].(string)
					todo := GetTodo(todoId)
					return todo
				},
			},
			"viewer": &graphql.Field{
				Type: userType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return GetViewer()
				},
			},
		},
		MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo) map[string]interface{} {
			id, _ := inputMap["id"].(string)
			complete, _ := inputMap["complete"].(bool)
			resolvedId := relay.FromGlobalID(id)
			ChangeTodoStatus(resolvedId.ID, complete)
			return map[string]interface{}{
				"todoId": resolvedId.ID,
			}
		},
	})

	markAllTodosMutation := relay.MutationWithClientMutationID(relay.MutationConfig{
		Name: "MarkAllTodos",
		InputFields: graphql.InputObjectConfigFieldMap{
			"complete": &graphql.InputObjectFieldConfig{
				Type: graphql.NewNonNull(graphql.Boolean),
			},
		},
		OutputFields: graphql.Fields{
			"changedTodos": &graphql.Field{
				Type: graphql.NewList(todoType),
				Resolve: func(p graphql.ResolveParams) interface{} {
					payload, _ := p.Source.(map[string]interface{})
					todoIds, _ := payload["todoIds"].([]string)
					todos := []*Todo{}
					for _, todoId := range todoIds {
						todo := GetTodo(todoId)
						if todo != nil {
							todos = append(todos, todo)
						}
					}
					return todos
				},
			},
			"viewer": &graphql.Field{
				Type: userType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return GetViewer()
				},
			},
		},
		MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo) map[string]interface{} {
			complete, _ := inputMap["complete"].(bool)
			todoIds := MarkAllTodos(complete)
			return map[string]interface{}{
				"todoIds": todoIds,
			}
		},
	})

	removeCompletedTodosMutation := relay.MutationWithClientMutationID(relay.MutationConfig{
		Name: "RemoveCompletedTodos",
		OutputFields: graphql.Fields{
			"deletedTodoIds": &graphql.Field{
				Type: graphql.NewList(graphql.String),
				Resolve: func(p graphql.ResolveParams) interface{} {
					payload, _ := p.Source.(map[string]interface{})
					return payload["todoIds"]
				},
			},
			"viewer": &graphql.Field{
				Type: userType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return GetViewer()
				},
			},
		},
		MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo) map[string]interface{} {
			todoIds := RemoveCompletedTodos()
			return map[string]interface{}{
				"todoIds": todoIds,
			}
		},
	})

	removeTodoMutation := relay.MutationWithClientMutationID(relay.MutationConfig{
		Name: "RemoveTodo",
		InputFields: graphql.InputObjectConfigFieldMap{
			"id": &graphql.InputObjectFieldConfig{
				Type: graphql.NewNonNull(graphql.ID),
			},
		},
		OutputFields: graphql.Fields{
			"deletedTodoId": &graphql.Field{
				Type: graphql.ID,
				Resolve: func(p graphql.ResolveParams) interface{} {
					payload, _ := p.Source.(map[string]interface{})
					return payload["todoId"]
				},
			},
			"viewer": &graphql.Field{
				Type: userType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return GetViewer()
				},
			},
		},
		MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo) map[string]interface{} {
			id, _ := inputMap["id"].(string)
			resolvedId := relay.FromGlobalID(id)
			RemoveTodo(resolvedId.ID)
			return map[string]interface{}{
				"todoId": resolvedId.ID,
			}
		},
	})
	renameTodoMutation := relay.MutationWithClientMutationID(relay.MutationConfig{
		Name: "RenameTodo",
		InputFields: graphql.InputObjectConfigFieldMap{
			"id": &graphql.InputObjectFieldConfig{
				Type: graphql.NewNonNull(graphql.ID),
			},
			"text": &graphql.InputObjectFieldConfig{
				Type: graphql.NewNonNull(graphql.String),
			},
		},
		OutputFields: graphql.Fields{
			"todo": &graphql.Field{
				Type: todoType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					payload, _ := p.Source.(map[string]interface{})
					todoId, _ := payload["todoId"].(string)
					return GetTodo(todoId)
				},
			},
			"viewer": &graphql.Field{
				Type: userType,
				Resolve: func(p graphql.ResolveParams) interface{} {
					return GetViewer()
				},
			},
		},
		MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo) map[string]interface{} {
			id, _ := inputMap["id"].(string)
			resolvedId := relay.FromGlobalID(id)
			text, _ := inputMap["text"].(string)
			RenameTodo(resolvedId.ID, text)
			return map[string]interface{}{
				"todoId": resolvedId.ID,
			}
		},
	})
	mutationType := graphql.NewObject(graphql.ObjectConfig{
		Name: "Mutation",
		Fields: graphql.Fields{
			"addTodo":              addTodoMutation,
			"changeTodoStatus":     changeTodoStatusMutation,
			"markAllTodos":         markAllTodosMutation,
			"removeCompletedTodos": removeCompletedTodosMutation,
			"removeTodo":           removeTodoMutation,
			"renameTodo":           renameTodoMutation,
		},
	})

	var err error
	Schema, err = graphql.NewSchema(graphql.SchemaConfig{
		Query:    rootType,
		Mutation: mutationType,
	})
	if err != nil {
		panic(err)
	}
}
Пример #10
0
func (api *SearchAPI) Start() error {
	api.Type = graphql.NewObject(graphql.ObjectConfig{
		Name: "Search",
		Fields: graphql.Fields{
			"id": relay.GlobalIDField("Search", func(obj interface{}, info graphql.ResolveInfo, ctx context.Context) (string, error) {
				se, ok := obj.(*Search)
				if !ok {
					return "", fmt.Errorf("Search's GlobalIDField() was called with a non-Search")
				}

				cid, err := se.ClientID()
				if err != nil {
					return "", fmt.Errorf("Failed to create a ClientID for %v", se)
				}
				return cid, nil
			}),
			"createdAt": &graphql.Field{
				Description: "When the search was first saved.",
				Type:        graphql.String,
			},
			"name": &graphql.Field{
				Description: "The name to display for the search.",
				Type:        graphql.String,
			},
			// TODO#Perf: Consider storing the search results on the context or ResolveInfo to avoid computing them twice (numResults and results).
			"numResults": &graphql.Field{
				Description: "The total number of results that match the query",
				Type:        graphql.Int,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					span := trace.FromContext(p.Context).NewChild("trythings.searchAPI.numResults")
					defer span.Finish()

					se, ok := p.Source.(*Search)
					if !ok {
						return nil, errors.New("expected search source")
					}

					sp, err := api.SearchService.Space(p.Context, se)
					if err != nil {
						return nil, err
					}

					// TODO#Perf: Run a count query instead of fetching all of the matches.
					ts, err := api.TaskService.Search(p.Context, sp, se.Query)
					if err != nil {
						return nil, err
					}

					return len(ts), nil
				},
			},
			"query": &graphql.Field{
				Description: "The query used to search for tasks.",
				Type:        graphql.String,
			},
			"results": &graphql.Field{
				Description: "The tasks that match the query",
				Type:        api.TaskAPI.ConnectionType,
				Args:        relay.ConnectionArgs,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					span := trace.FromContext(p.Context).NewChild("trythings.searchAPI.results")
					defer span.Finish()

					se, ok := p.Source.(*Search)
					if !ok {
						return nil, errors.New("expected search source")
					}

					sp, err := api.SearchService.Space(p.Context, se)
					if err != nil {
						return nil, err
					}

					ts, err := api.TaskService.Search(p.Context, sp, se.Query)
					if err != nil {
						return nil, err
					}

					objs := []interface{}{}
					for _, t := range ts {
						objs = append(objs, *t)
					}

					// TODO#Performance: Run a limited query instead of filtering after the query.
					args := relay.NewConnectionArguments(p.Args)
					return relay.ConnectionFromArray(objs, args), nil
				},
			},
		},
		Interfaces: []*graphql.Interface{
			api.NodeInterface,
		},
	})
	return nil
}