forked from maxcoto/graphoid
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create pagination query generators and resolvers hook (#23)
## Summary * Pagination: Adds a new Pagination module for paginated query results, along with the corresponding paginated_type object for each model. The default page size is now configurable through the PAGE_SIZE environment variable. * Custom resolvers: Allows users to define custom resolvers for the find, filter, create, and update actions. This enables more granular control over how objects are retrieved, created, and updated. * Dynamic attribute handling: Properly handles dynamic attributes from models that include Mongoid::Attributes::Dynamic. Also adds utility functions for underscore and camelize transformations. * Bug fixes: Fixes a bug where the _id field was being ignored in input arguments, and another where the field names were not being properly camelized. # Overview 🔍 ## How to use the new features in the GraphQL library This guide will walk you through using the new features introduced in the GraphQL library, including pagination, custom resolvers, and dynamic attribute handling. ### Pagination The new pagination feature allows you to fetch a specific page of results with a specified number of items per page. To use it, follow these steps: 1. In your GraphQL query, use the pluralized form of the model name, which will return a paginated type. 2. Provide the `limit` and `skip` arguments to specify the number of items per page and the number of items to skip, respectively. Example query for fetching paginated results: ```graphql query { products(limit: 10, skip: 20) { count pageSize pages skip data { id name price } } } ``` ### Custom Resolvers You can now define custom resolvers for `find`, `filter`, `create`, and `update` actions. Here's how to do it: 1. In your model, define a class method for the action you want to customize, such as `resolve_find`, `resolve_filter`, `resolve_one`, or `resolve_many`. The method should take the necessary arguments based on the action. 2. Implement the custom logic for the resolver within the method. Example of defining a custom `resolve_find` resolver in the `Product` model: ```ruby class Product # ... def self.resolve_find(context, id) # Custom logic for finding a product by ID find_by(custom_id: id) end end ``` ### Dynamic Attribute Handling The library now properly handles dynamic attributes for models that include `Mongoid::Attributes::Dynamic`. To work with dynamic attributes, simply use them in your queries and mutations as you would with regular attributes. Example of querying a model with dynamic attributes: ```graphql query { product(id: "123") { id name dynamicAttribute } } ``` That's it! You're now ready to use the new features in the GraphQL library. Enjoy the enhanced flexibility and customization options in your GraphQL API. # Checks ☑️ - Updates readme to reflect latest changes - Query with pagination skip, limit, pages - Generate grapho builds during initializer - Enable dynamic defined fields in mongoid with dynamic enabled - Enabling back updateMany and deleteMany - Fix embeds many values transformation on update - Allow to hook before creation - Allow to filter objects before deletemany - Fix dynamic attributes for mongoid criterias - Allowing to hook data before create - Enable lookahead feature for pagination data - Converting input objects to hash
- Loading branch information
1 parent
7ab4f9b
commit f71c976
Showing
26 changed files
with
566 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# frozen_string_literal: true | ||
|
||
module Graphoid | ||
module Queries::Pagination | ||
PAGE_SIZE = (ENV['PAGE_SIZE'] || 100).to_i | ||
|
||
def self.generate(*models) | ||
models.each { |model| Graphoid::Queries::Pagination.build(model) } | ||
end | ||
|
||
def self.build(model) | ||
Graphoid.initialize | ||
grapho = Graphoid.build(model) | ||
query_type = ::Types::QueryType | ||
|
||
query_type.field name: grapho.name, type: grapho.type, null: true do | ||
argument :id, GraphQL::Types::ID, required: false | ||
argument :where, grapho.filter, required: false | ||
end | ||
|
||
paginated_type = Class.new(GraphQL::Schema::Object) do | ||
graphql_name("#{model.name}Pagination") | ||
description('Pagination Type') | ||
|
||
# https://www.rubydoc.info/github/rmosolgo/graphql-ruby/GraphQL/Field | ||
# Syntax => name, type, description | ||
field :count, GraphQL::Types::Int, null: true | ||
field :page_size, GraphQL::Types::Int, null: true | ||
field :pages, GraphQL::Types::Int, null: true | ||
field :skip, GraphQL::Types::Int, null: true | ||
field :data, [grapho.type], null: true, extras: [:lookahead] | ||
|
||
def data(lookahead:) | ||
object ||= @object | ||
# Mongoid::Criteria uses method_missing to send the method to the underlying Model | ||
# Just implement def self.lookahead(object, lookahead) in your model to manage | ||
# eager loading | ||
obj = object.lookahead(object, lookahead) if object.respond_to? :lookahead | ||
object = obj if obj | ||
return object.eager_load if object.respond_to? :eager_load | ||
object | ||
end | ||
|
||
def page_size | ||
return PAGE_SIZE if object.options[:limit].nil? or object.options[:limit] > PAGE_SIZE | ||
|
||
object.options[:limit] | ||
end | ||
|
||
def skip | ||
object.options[:skip] || 0 | ||
end | ||
|
||
def pages | ||
return 1 if object.options[:limit].nil? | ||
|
||
(object.count / object.options[:limit].to_f).ceil | ||
end | ||
end | ||
|
||
query_type.field name: grapho.plural, type: paginated_type, null: true do | ||
argument :where, grapho.filter, required: false | ||
argument :order, grapho.order, required: false | ||
argument :limit, GraphQL::Types::Int, required: false, default_value: PAGE_SIZE, | ||
prepare: lambda { |limit, _ctx| | ||
limit = PAGE_SIZE if limit > PAGE_SIZE | ||
return limit | ||
} | ||
argument :skip, GraphQL::Types::Int, required: false | ||
end | ||
|
||
Graphoid::Queries.define_resolvers(query_type, model, grapho.name, grapho) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# frozen_string_literal: true | ||
|
||
class Level | ||
include Mongoid::Document | ||
include Mongoid::Timestamps | ||
|
||
field :name, type: String | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# frozen_string_literal: true | ||
|
||
class Player | ||
include Mongoid::Document | ||
include Mongoid::Timestamps | ||
|
||
field :name, type: String | ||
field :email, type: String | ||
field :active, type: Boolean, default: true | ||
|
||
def self.resolve_many(resolver, where_args, order, limit, skip) | ||
w = where_args.to_h | ||
w[:active] = true | ||
result = Graphoid::Queries::Processor.execute(self, w) | ||
order = Graphoid::Queries::Processor.parse_order(self, order.to_h) | ||
result = result.order(order).limit(limit) | ||
Graphoid.driver.skip(result, skip) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# frozen_string_literal: true | ||
|
||
class ValueNested | ||
include Mongoid::Document | ||
include Mongoid::Timestamps | ||
|
||
field :text, type: String | ||
field :name, type: String | ||
|
||
embedded_in :value | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.