pax_global_header 0000666 0000000 0000000 00000000064 14764346352 0014530 g ustar 00root root 0000000 0000000 52 comment=efbbdae81c7a18fc13424a7aae60c52c312f38c5
graphql-ruby-2.2.17/ 0000775 0000000 0000000 00000000000 14764346352 0014236 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/.codeclimate.yml 0000664 0000000 0000000 00000000415 14764346352 0017310 0 ustar 00root root 0000000 0000000 version: "2"
exclude_patterns:
- "spec/"
- "lib/graphql/language/lexer.rb"
- "lib/graphql/language/parser.rb"
# plugin - duplication - is failing on these
- "spec/graphql/language/printer_spec.rb"
- "lib/graphql/compatibility/query_parser_specification.rb"
graphql-ruby-2.2.17/.gitattributes 0000664 0000000 0000000 00000000064 14764346352 0017131 0 ustar 00root root 0000000 0000000 *.snap linguist-generated
*.lock linguist-generated
graphql-ruby-2.2.17/.github/ 0000775 0000000 0000000 00000000000 14764346352 0015576 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14764346352 0017761 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/.github/ISSUE_TEMPLATE/bug_report.md 0000664 0000000 0000000 00000002651 14764346352 0022457 0 ustar 00root root 0000000 0000000 ---
name: Bug report
about: Create a report to help us improve graphql-ruby
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Versions**
`graphql` version:
`rails` (or other framework):
other applicable versions (`graphql-batch`, etc)
**GraphQL schema**
Include relevant types and fields (in Ruby is best, in GraphQL IDL is ok). Any custom extensions, etc?
```ruby
class Product < GraphQL::Schema::Object
field :id, ID, hash_key: :id
# …
end
class ApplicationSchema < GraphQL::Schema
query QueryType
# …
end
```
**GraphQL query**
Example GraphQL query and response (if query execution is involved)
```graphql
query {
products { id title }
}
```
```json
{
"data": {
"products": […]
}
}
```
**Steps to reproduce**
Steps to reproduce the behavior
**Expected behavior**
A clear and concise description of what you expected to happen.
**Actual behavior**
What specifically went wrong?
Place full backtrace here (if a Ruby exception is involved):
Click to view exception backtrace
```
Something went wrong
2.6.0/gems/graphql-1.9.17/lib/graphql/subscriptions/instrumentation.rb:34:in `after_query'
… don't hesitate to include all the rows here: they will be collapsed
```
**Additional context**
Add any other context about the problem here.
With these details, we can efficiently hunt down the bug!
graphql-ruby-2.2.17/.github/ISSUE_TEMPLATE/feature_request.md 0000664 0000000 0000000 00000001127 14764346352 0023507 0 ustar 00root root 0000000 0000000 ---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
graphql-ruby-2.2.17/.github/contributing.md 0000664 0000000 0000000 00000002651 14764346352 0020633 0 ustar 00root root 0000000 0000000 # Contributing
Thanks for getting involved! I hope the information below will help you contribute to graphql-ruby.
## Issues
When reporting a bug, please include these details when applicable:
- `graphql` version and other applicable versions (Rails, `graphql-batch`, etc)
- Definitions of schema or relevant types and fields (in Ruby is best, in GraphQL IDL is ok)
- Example GraphQL query and response (if query execution is involved)
- Full backtrace (if a Ruby exception is involved)
With these details, we can efficiently hunt down the bug!
## Code
It's important for code to fit in with design and maintenance goals of the project. For this reason, consider an issue to discuss new features or large refactors. That way we can work together to find suitable solution!
## Legal
By submitting a Pull Request, you disavow any rights or claims to any changes submitted to `graphql-ruby` and assign the copyright of those changes to Robert Mosolgo, the author and maintainer of `graphql-ruby`. If you cannot or don't want to reassign those rights (your employment contract for your employer may not allow this), don't submit a PR. Instead, open an issue so that someone else can give it a try.
In short, contributing code means that the code belongs to the maintainer. That's generally what you want, since the burden of upkeep, support and distribution falls on the maintainer anyways. I hope this doesn't prohibit you from contributing!
graphql-ruby-2.2.17/.github/dependabot.yml 0000664 0000000 0000000 00000000166 14764346352 0020431 0 ustar 00root root 0000000 0000000 version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
graphql-ruby-2.2.17/.github/workflows/ 0000775 0000000 0000000 00000000000 14764346352 0017633 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/.github/workflows/apidocs.yaml 0000664 0000000 0000000 00000003055 14764346352 0022144 0 ustar 00root root 0000000 0000000 name: Publish API docs
on:
# For some reason, `on: release: ...` didn't work with `nektos/act`
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
# for re-running on old tags
workflow_dispatch:
inputs:
publish_version:
required: true
type: string
permissions: {}
jobs:
build:
permissions:
contents: write # for git push (s0/git-publish-subdir-action)
name: Publish API Docs
runs-on: ubuntu-latest
steps:
- name: Checkout release tag
uses: actions/checkout@v4
with:
ref: ${{ env.GITHUB_REF }}
- name: Checkout GitHub pages branch
uses: actions/checkout@v4
with:
path: gh-pages
ref: gh-pages
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
- name: Build API docs
run: |
bundle exec rake site:fetch_latest apidocs:gen_version["${{ inputs.publish_version || env.GITHUB_REF }}"]
- name: Commit changes as last committer
run: |
git config --global user.name rmosolgo
git config --global user.email rdmosolgo@github.com
git status
bundle exec rake site:commit_changes
git status
- name: Deploy to GitHub pages via gh-pages branch
uses: s0/git-publish-subdir-action@master
env:
REPO: self
BRANCH: gh-pages
FOLDER: gh-pages
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
graphql-ruby-2.2.17/.github/workflows/ci.yaml 0000664 0000000 0000000 00000007234 14764346352 0021120 0 ustar 00root root 0000000 0000000 name: CI Suite
on:
- pull_request
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
- run: bundle exec rake rubocop
system_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
- run: bundle exec rake compile
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
env:
BUNDLE_GEMFILE: ./spec/dummy/Gemfile
- run: bundle exec rails test:system
working-directory: ./spec/dummy
# Some coverage goals of these tests:
# - Test once without Rails at all
# - Test postgres, to make sure that the ActiveRecord
# stuff works on that (as well as the default sqlite)
# - Test mongoid -- and several versions, since they're quite different
# - Run the JS unit tests once
# - Test each major version of Rails we support
# - Test the min/max minor Ruby version we support (and others?)
test:
strategy:
fail-fast: false
matrix:
include:
- gemfile: Gemfile
ruby: 3.2
# Rails 6.1 is tested with Postgresql below
- gemfile: gemfiles/rails_7.0.gemfile
ruby: 3.1
- gemfile: gemfiles/rails_master.gemfile
ruby: 3.1
- gemfile: gemfiles/rails_7.0.gemfile
ruby: 3.2
- gemfile: gemfiles/rails_7.1.gemfile
ruby: 3.3
- gemfile: gemfiles/rails_master.gemfile
ruby: 3.3
runs-on: ubuntu-latest
steps:
- run: echo BUNDLE_GEMFILE=${{ matrix.gemfile }} > $GITHUB_ENV
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
bundler: ${{ matrix.bundler || 'default' }}
- run: bundle exec rake compile
- run: bundle exec rake test
javascript_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: '21'
- run: npm ci
working-directory: ./javascript_client
- run: npm test
working-directory: ./javascript_client
postgres_test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- run: echo BUNDLE_GEMFILE='gemfiles/rails_6.1_postgresql.gemfile' > $GITHUB_ENV
- run: echo DATABASE='POSTGRESQL' > $GITHUB_ENV
- run: echo PGPASSWORD='postgres' > $GITHUB_ENV
- run: echo GRAPHQL_CPARSER=1 > $GITHUB_ENV
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
- run: bundle exec rake compile test
mongodb_test:
strategy:
fail-fast: false
matrix:
gemfile:
- gemfiles/mongoid_6.gemfile
- gemfiles/mongoid_7.gemfile
runs-on: ubuntu-latest
services:
mongodb:
image: mongo
ports:
- 27017:27017
steps:
- run: echo BUNDLE_GEMFILE=${{ matrix.gemfile }} > $GITHUB_ENV
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
- run: bundle exec rake compile test
graphql-ruby-2.2.17/.github/workflows/website.yaml 0000664 0000000 0000000 00000002714 14764346352 0022165 0 ustar 00root root 0000000 0000000 name: Publish Website
on:
# For some reason, `on: release: ...` didn't work with `nektos/act`
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
workflow_dispatch:
permissions: {}
jobs:
build:
permissions:
contents: write # for git push (s0/git-publish-subdir-action)
name: Publish Website
runs-on: ubuntu-latest
steps:
- name: Checkout master
uses: actions/checkout@v4
- name: Checkout GitHub pages branch
uses: actions/checkout@v4
with:
path: gh-pages
ref: gh-pages
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.1'
bundler-cache: true
- name: Build HTML, reindex
env:
ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }}
run: |
bundle exec rake site:fetch_latest site:build_doc site:update_search_index site:clean_html site:build_html
- name: Commit changes as last committer
run: |
git config --global user.name "$(git log --format="%aN" -n 1)"
git config --global user.email "$(git log --format="%aE" -n 1)"
bundle exec rake site:commit_changes
- name: Deploy to GitHub pages via gh-pages branch
uses: s0/git-publish-subdir-action@master
env:
REPO: self
BRANCH: gh-pages
FOLDER: gh-pages
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
graphql-ruby-2.2.17/.gitignore 0000664 0000000 0000000 00000001277 14764346352 0016235 0 ustar 00root root 0000000 0000000 .ruby-version
doc/
.yardoc/
guides/yardoc/
pkg/
Gemfile.lock
gemfiles/*.lock
# Test database
*.db
.bundle/
vendor/
.idea/
_site
.sass-cache
.jekyll-metadata
.jekyll-cache
gh-pages/
tmp/*
__*.db
node_modules/
yarn.lock
OperationStoreClient.js
spec/integration/tmp
.vscode/
*.swp
*.swo
.DS_Store
# These are generated for distribution, but shouldn't be
# versioned with the typescript source (which is in javascript_client/src):
javascript_client/__tests__
javascript_client/subscriptions
javascript_client/sync
javascript_client/cli*
javascript_client/index*
# Don't commit compiled extension files:
*.bundle
*.so
# Ragel generates Ruby type hints which is great, but I'm not ready to support them
*.ri
graphql-ruby-2.2.17/.rubocop.yml 0000664 0000000 0000000 00000005103 14764346352 0016507 0 ustar 00root root 0000000 0000000 require:
- ./cop/development/none_without_block_cop
- ./cop/development/no_eval_cop
- ./cop/development/no_focus_cop
- ./lib/graphql/rubocop/graphql/default_null_true
- ./lib/graphql/rubocop/graphql/default_required_true
- ./cop/development/context_is_passed_cop
AllCops:
DisabledByDefault: true
SuggestExtensions: false
TargetRubyVersion: 2.4
Exclude:
- 'lib/graphql/language/lexer.rb'
- 'lib/graphql/language/parser.rb'
- 'gemfiles/**/*'
- 'tmp/**/*'
- 'vendor/**/*'
- 'spec/integration/tmp/**/*'
- 'spec/fixtures/cop/*.rb'
Development/ContextIsPassedCop:
Exclude:
- 'spec/**/*'
- 'cop/**/*'
# Legacy-related:
- 'lib/graphql/*_type.rb'
- 'lib/graphql/define/**/*.rb'
- 'lib/graphql/relay/**/*'
- 'lib/graphql/function.rb'
- 'lib/graphql/directive.rb'
- 'lib/graphql/field.rb'
- 'lib/graphql/schema/traversal.rb'
- 'lib/graphql/schema/possible_types.rb'
- 'lib/graphql/schema/validation.rb'
- 'lib/graphql/compatibility/**/*'
- 'lib/graphql/static_validation/literal_validator.rb'
- 'lib/graphql/static_validation/rules/**/*.rb'
- 'lib/graphql/internal_representation/**/*.rb'
# AST-related:
- 'lib/graphql/schema/build_from_definition.rb'
- 'lib/graphql/language/printer.rb'
- 'lib/graphql/language/nodes.rb'
# Build-time, not runtime:
- 'lib/graphql/schema/addition.rb'
- 'lib/graphql/schema/introspection_system.rb'
# Methods from generators
- 'lib/generators/graphql/type_generator.rb'
Development/NoneWithoutBlockCop:
Include:
- "lib/**/*"
- "spec/**/*"
Development/NoEvalCop:
Include:
- "lib/**/*"
Development/NoFocusCop:
Include:
- "spec/**/*"
# def ...
# end
Layout/DefEndAlignment:
EnforcedStyleAlignWith: def
# value = if
# # ...
# end
Layout/EndAlignment:
EnforcedStyleAlignWith: variable
Lint/UselessAssignment:
Enabled: true
Lint/DuplicateMethods:
Enabled: true
Metrics/ParameterLists:
Max: 7
CountKeywordArgs: false
Style/ClassAndModuleChildren:
EnforcedStyle: nested
Layout/EmptyLineBetweenDefs:
AllowAdjacentOneLineDefs: true
NumberOfEmptyLines: [0, 1, 2]
Style/FrozenStringLiteralComment:
Enabled: true
Layout/IndentationWidth:
Width: 2
Style/LambdaCall:
EnforcedStyle: call
Layout/LeadingCommentSpace:
Enabled: true
Naming/MethodName:
EnforcedStyle: snake_case
Style/WordArray:
EnforcedStyle: brackets
# ->(...) { ... }
Layout/SpaceInLambdaLiteral:
Enabled: true # Default is "require_no_space"
GraphQL/DefaultNullTrue:
Enabled: true
GraphQL/DefaultRequiredTrue:
Enabled: true
graphql-ruby-2.2.17/.yardopts 0000664 0000000 0000000 00000000162 14764346352 0016103 0 ustar 00root root 0000000 0000000 --no-private
--markup=markdown
--readme=readme.md
--title='GraphQL Ruby API Documentation'
'lib/**/*.rb' - '*.md'
graphql-ruby-2.2.17/CHANGELOG-enterprise.md 0000664 0000000 0000000 00000006553 14764346352 0020236 0 ustar 00root root 0000000 0000000 # graphql-enterprise
### Breaking Changes
### Deprecations
### New Features
### Bug Fix
# 1.3.4 (18 Mar 2024)
- ObjectCache: use new `trace_with` API for instrumentation
# 1.3.3 (30 Jan 2024)
- ObjectCache: fix compatibility with `run_graphql_field` test helper #4816
# 1.3.2 (15 Jan 2024)
### Bug Fix
- Limiters: Migrate to new `trace_with` instrumentation API, requires GraphQL-Ruby 2.0.18+
# 1.3.1 (12 June 2023)
### Bug Fix
- Add missing `require "graphql"` #4511
# 1.3.0 (29 May 2023)
### New Features
- Changesets: Add `added_in: ...` and `removed_in: ...` for inline definition changes
# 1.2.0 (10 February 2023)
### New Features
- Support the `redis-client` gem as `redis:` (requires graphql-pro 1.24.0+)
# 1.1.14 (3 November 2022)
### New Features
- Limiters: Support `dashboard_charts: false` to disable built-in instrumentation
- Limiters: Support `assign_as:` to use a different accessor method for storing limiter instances on schema classes (add a corresponding `class << self; attr_accessor ...; end` to the schema class to use it)
- Limiters: Support `context_key:` to put runtime info in a different key in query context
- Runtime Limiter: Add `window_ms:` to runtime info
# 1.1.13 (21 October 2022)
### Bug Fix
- Limiter: handle missing fields in MutationLimiter
# 1.1.12 (18 October 2022)
### New Features
- Limiters: add MutationLimiter
### Bug Fix
- ObjectCache: Update Redis calls to support redis-rb 5.0
# 1.1.11 (25 August 2022)
### Bug Fix
- ObjectCache: also update `delete` to handle more than 1000 objects in Lua
# 1.1.10 (19 August 2022)
### Bug Fix
- ObjectCache: read and write objects 1000-at-a-time to avoid overloading Lua scripts in Redis
# 1.1.9 (3 August 2022)
### New Features
- ObjectCache: Add a message to context when a type or field causes a query to be treated as "private"
### Bug Fix
- ObjectCache: skip the query analyzer when `context[:skip_object_cache]` is present
# 1.1.8 (1 August 2022)
### New Features
- ObjectCache: Add `ObjectType.cache_dependencies_for(object, context)` to customize dependencies for an object
### Bug Fix
- ObjectCache: Fix to make `context[:object_cache][:objects]` a Set
# 1.1.7 (28 July 2022)
### Bug Fix
- ObjectCache: remove needless `resolve_type` calls
# 1.1.6 (28 July 2022)
### Bug Fix
- ObjectCache: persist the type names of cached objects, pass them to `Schema.resolve_type` when validating cached responses.
# 1.1.5 (22 July 2022)
### New Features
- ObjectCache: add `cache_introspection: { ttl: ... }` for setting an expiration (in seconds) on introspection fields.
# 1.1.4 (19 March 2022)
### Bug Fix
- ObjectCache: don't create a cache fingerprint if the query is found to be uncacheable during analysis.
# 1.1.3 (3 March 2022)
### Bug Fix
- Changesets: Return an empty set when a schema doesn't use changesets #3972
# 1.1.2 (1 March 2022)
### New Features
- Changesets: Add introspection methods `Schema.changesets` and `Changeset.changes`
# 1.1.1 (14 February 2021)
### Bug Fix
- Changesets: don't require `context.schema` for plain-Ruby calls to introspection methods #3929
# 1.1.0 (24 November 2021)
### New Features
- Changesets: Add `GraphQL::Enterprise::Changeset`
# 1.0.1 (9 November 2021)
### Bug Fix
- Object Cache: properly handle invalid queries #3703
# 1.0.0 (13 October 2021)
### New Features
- Rate limiters: first release
- Object cache: first release
graphql-ruby-2.2.17/CHANGELOG-pro.md 0000664 0000000 0000000 00000074327 14764346352 0016662 0 ustar 00root root 0000000 0000000 # graphql-pro
### Breaking Changes
### Deprecations
### New Features
# 1.26.5 (1 Mar 2024)
- OperationStore::AddOperationBatch: remove rescue for StatementInvalid inside transaction
# 1.26.4 (27 Feb 2024)
- RelationConnection: Don't quote table names that weren't quoted in original SQL, fixes #4508 (comment)
# 1.26.3 (19 Feb 2024)
- OperationStore: fix `sync` endpoint for Rack 3+ #4829
- Improve error message handling on Rails 7.1
# 1.26.2 (30 Jan 2024)
- `@defer` / `@stream`: Write delimiters at the end of each patch so that clients respond to payloads more quickly. (Previously, delimiters were added at the start of each patch, so clients had to wait for the _next_ patch before they knew the current one was complete.)
# 1.26.1 (23 Jan 2024)
- Pundit integration: improve error message when a `Scope` class is missing
# 1.26.0 (19 Jan 2024)
### Breaking Changes
- Pundit integration: when the integration encounters an Array, it tries to find a configured policy class. If it can't, it raises an error.
Previously, the integration silently permitted all items in the array; this default has been changed. See #4726 for more discussion of this change.
If you encounter this error:
- add `scope: false` to any fields that return arrays to get the previous behavior (no authorization applied to the array; each item authorized on its own)
- Or, apply [scoping](https://graphql-ruby.org/authorization/scoping.html) by manually configuring a `pundit_policy_class` in the field's return type, then adding a `class Scope ...` inside that policy class. See the Pundit docs for the scope class API: https://github.com/varvet/pundit#scopes.
If you want to continue passing _all_ arrays through without scoping (for example, if you know they've already been authorized another way, or if you're OK with them being authorized one-at-a-time later), you can implement this in your base `Scope` class, for example:
```ruby
class BasePolicy
class Scope
def initialize(user, items)
@user = user
@items = items
end
def resolve
if items.is_a?(Array)
items
else
raise "Implement #{self.class}#resolve to filter these items: #{items.inspect}"
end
end
end
# Pass this scope class along to subclasses:
def self.inherited(child_class)
child_class.const_set(:Scope, Class.new(BasePolicy::Scope))
super
end
end
```
Alternatively, you could implement `def self.scope_items(items, context)` to skip arrays, for example:
```ruby
module SkipScopingOnArrays
def scope_items(items, context)
if items.is_a?(Array)
items # return these as-is
else
super
end
end
end
# Then, in type definitions which should skip scoping on arrays:
extend SkipScopingOnArrays
```
# 1.25.2 (29 Dec 2023)
### New Features
- Subscriptions: send `more: false` when the server calls `unsubscribe`
# 1.25.1 (21 Dec 2023)
### Bug Fix
- Ably subscriptions: update webhook handler for `presence.message` events
# 1.25.0 (7 Dec 2023)
### Bug Fix
- OperationStore: `.dup` the given `context` to avoid leaking state between queries when indexing
- Subscriptions: use the schema or query logger to output debug messages
# 1.24.15 (17 Nov 2023)
### Bug Fix
- OperationStore: don't sort directives when normalizing, properly retain directives on Operation and Fragment definitions #4703
# 1.24.14 (16 Nov 2023)
### Bug Fix
- OperationStore: also pass `context:` for ActiveRecord backend batches
# 1.24.13 (13 Nov 2023)
### New Features
- OperationStore: accept `context:` for `AddOperationBatch.call` #4697
# 1.24.12 (13 Nov 2023)
### New Features
- OperationStore: accept `context:` to `Validate.validate` #4697
### Bug Fix
- OperationStore: don't rescue application-raised `KeyError`s #4699
# 1.24.11 (8 Nov 2023)
### Bug Fix
- OperationStore: fix compatibility with 1.12.x #4696
# 1.24.10 (2 Nov 2023)
### Bug Fix
- Improve compatibility with GraphQL-Ruby 1.12.x
# 1.24.9 (4 Oct 2023)
### Bug Fix
- OperationStore: Preserve variable default values of `false` when normalizing queries
# 1.24.8 (29 Aug 2023)
### Bug Fix
- OperationStore: search for operation during `Query#initialize` to avoid races with other instrumentation. Add `use ... trace: true` to get the old behavior.
# 1.24.7 (16 June 2023)
### Bug Fix
- Stable relation connections: quote table names and column names in `WHERE` clauses #4508
# 1.24.6 (24 May 2023)
### New Features
- Defer: Add `incremental: true` for new proposed wire format, add example for working with GraphQL-Batch #4477
# 1.24.5 (24 May 2023)
### Bug Fix
- Stable relation connection: Quote table names and column names in selects and orders #4485
# 1.24.4 (18 April 2023)
### Bug Fix
- `@defer`: update `context[:current_path]` usage to fix `path:` on deferred errors
# 1.24.3 (14 April 2023)
### Bug Fix
- `OperationStore`: fix when used with Changesets (or other ways of defining arguments with the same name) #4440
# 1.24.2 (20 Mar 2023)
### Bug Fix
- Remove debug output, oops
# 1.24.1 (20 Mar 2023)
### Bug Fix
- Fix `OperationStore` with new module-based execution traces (#4389)
# 1.24.0 (10 Feb 2023)
### New Features
- Support the `redis-client` gem as `redis:`
# 1.23.9 (2 Feb 2023)
### Bug Fix
- Dashboard: Support Ruby 3.2.0
# 1.23.8 (27 Jan 2023)
### New Features
- OperationStore: Support `Changeset-Version` header for syncing with changesets #4304
# 1.23.7 (25 Jan 2023)
### Bug Fix
- Stable Relation Connections: Fix handling of Postgres JSON accesses
# 1.23.6
### New Features
- Subscriptions: accept `connection_pool:` instead of `redis:` for use with the `connection_pool` gem
### Bug Fix
- Stable connections: rescue `ActiveRecord::StatementInvalid` when loading nodes and return a client-facing error instead
# 1.23.5 (29 December 2022)
### New Features
- Ably subscriptions: Also listen for `presence.leave` webhooks to clean up subscriptions more quickly
# 1.23.4 (20 December 2022)
### Bug Fix
- Dashboard: nicely render subscriptions that are not found or cleaned up by `read_subscription_failed_error`
# 1.23.3 (19 December 2022)
### New Features
- Add `GraphQL::Pro::Subscriptions#read_subscription_failed_error` for handling errors that are raised when reloading queries from storage
# 1.23.2 (18 October 2022)
### New Features
- Add dashboard component for Enterprise mutation limiter
# 1.23.1 (25 August 2022)
### Bug Fix
- Redis: update redis usage to be forward-compatible with redis 5.x #4167
# 1.23.0 (2 August 2022)
### New Features
- Stable connections: support SQL queries that sort by `IS NOT NULL` #4153
# 1.22.3 (26 July 2022)
### Bug Fix
- Stable connections: handle `edges {...}` when an invalid cursor is given #4148
# 1.22.2 (20 April 2022)
### Bug Fix
- Use `deprecated_accepts_definitions` to stop warnings when loading this gem on 1.13.x
# 1.22.1 (22 March 2022)
### Bug Fix
- Pusher subscriptions: don't try to send empty trigger batches to Pusher
# 1.22.0 (19 March 2022)
### New Features
- Pusher subscriptions: it now sends updates in groups of 10 by default, pass `use ..., batch_size: 1` to revert to the previous behavior.
- OperationStore: when using ActiveRecord for storage, it now batches updates to `last_used_at` every 5 seconds. Pass `use ..., update_last_used_at_every: 0` to update that column synchronously, instead, as before.
# 1.21.6 (16 March 2022)
### Bug Fix
- OperationStore: Fix no method error in Redis pipeline usage
# 1.21.5 (7 March 2022)
### Bug Fix
- Postgres stable connection: support more complex aliased selects #3976
# 1.21.4 (15 February 2022)
### Bug Fix
- Encoders: don't extend `DeprecatedDefine` if it's not present (graphql-ruby < 1.12)
# 1.21.3 (9 February 2022)
### New Features
- Future-proof for GraphQL-Ruby 2.0
# 1.21.2 (27 January 2022)
### New Features
- Dashboard, Routes: support lazy-loading the schema with `Routes::Lazy` #3868
- OperationStore: Update deprecated usage of `@redis.pipelined` to address warning
# 1.21.1 (20 January 2022)
### Bug Fix
- Stream, Defer: Include `hasNext: true|false` in patches
# 1.21.0 (20 January 2022)
### New Features
- Stream: Add `@stream` directive for evaluating list items one-at-a-time
# 1.20.4 (4 December 2021)
### Bug Fix
- Stable connections: Fix using startCursor / endCursor without nodes #3752
# 1.20.3 (27 November 2021)
### Bug Fix
- Stable Connections: Properly handle cursors containing invalid JSON #3735
# 1.20.2 (15 November 2021)
### New Features
- Operation Store sync: ActiveRecord backend performance improvements: when syncing operations, only validate newly-added operations, reduce allocations when normalizing incoming query strings
# 1.20.1 (8 November 2021)
### Bug Fix
- Operation Store sync: fix when operations are re-synced with new aliases
# 1.20.0 (5 November 2021)
### New Features
- Operation Store: Use Rails `insert_all` for better performance when adding new operations
# 1.19.2 (26 October 2021)
### New Features
- Pundit and CanCan integrations: Add `ResolverIntegration` modules for plain resolvers #3392
### Bug Fix
- OperationStore Redis backend: pipeline updates to last_used_at values #3672
# 1.19.1 (15 October 2021)
### Bug Fix
- OperationStore: fix a stack overflow error on GraphQL 1.9 #3653
# 1.19.0 (13 October 2021)
### New Features
- Dashboard: add a component for GraphQL-Enterprise rate limiters
# 1.18.3 (1 Sept 2021)
### Breaking Changes
- Stable cursors: raise an error on unrecognized orderings instead of ignoring them #3605
### Bug Fix
- Stable cursors: Handle `Arel::Attributes::Attribute` and `Arel::SqlLiteral` #3605
# 1.18.2 (16 August 2021)
### Bug Fix
- Stable connections: nicely handle incoming cursors with too many sort values #3581
# 1.18.1 (20 July 2021)
### Bug Fix
- Stable connections: improve handling of `SELECT` with `CASE` #3558
- Defer: fix to support runtime wrapper objects in graphql-ruby 1.12.13
# 1.18.0 (31 May 2021)
### New Features
- Ably subscriptions: send `quickAck: true` for a faster response from Ably
### Bug Fix
- Defer: support dataloader inside deferred blocks
# 1.17.15 (29 Apr 2021)
### New Features
- Defer: support `label:` argument which is returned in the patch for that deferral #3454
# 1.17.14 (14 Apr 2021)
- Dashboard: fix stack error when OperationStore isn't configured on a class-based schema
# 1.17.13 (14 Apr 2021)
- Stable Connections: When using aliases and GROUP BY, replace the alias when building a HAVING condition.
- Pundit integration: Add a `use_owner_role(true)` configuration option
# 1.17.12 (3 Apr 2021)
### Bug Fix
- Stable Connections: Re-select aliased fields that are referenced by ORDER BY. #3421
# 1.17.11 (12 Mar 2021)
### Bug Fix
- Pundit integration: properly halt when `unauthorized_by_pundit` returns errors-as-data after a mutation argument fails authorization #3384
# 1.17.10 (11 Mar 2021)
### Bug Fix
- Pundit, CanCan integrations: properly call configured auth hooks for arguments that are lists and input objects
# 1.17.9 (3 Mar 2021)
### Bug Fix
- Fix OperationStore assignment on GraphQL-Ruby 1.9
# 1.17.8 (23 Feb 2021)
### New Features
- Subscriptions: change the default `cleanup_delay_s:` to 5 seconds (use `cleanup_delay_s: 0` to get the old behavior)
### Bug Fix
- Subscriptions: Handle unsubscribe race condition #3357
# 1.17.7 (19 Feb 2021)
### New Features
- CanCan integration: support `can_can_subject:` config for overriding the use of `object` as the CanCan subject #3350
### Bug Fixes
- Subscriptions: Support `Redis::Namespace` without deprecation warnings for `script load` #3347
# 1.17.6 (18 Feb 2021)
### New Features
- Stable connections: implement `range_add_edge` to leverage GraphQL-Ruby 1.12.5's improved RangeAdd #2184
### Bug Fix
- Defer: Update to work with Dataloader
# 1.17.5 (13 Feb 2021)
### Bug Fix
- Subscriptions: Use `MULTI` instead of Lua for some operations
- Subscriptions: Use `EVAL_SHA` for duplicate scripts to reduce network overhead #3285
- Subscriptions: Don't use `redis.call`, which is unsupported in the `redis-namespace` gem #3322
# 1.17.4 (4 Feb 2021)
## Bug Fix
- Stable Relation Connection: Don't emit `OR ... IS NULL` for columns that are known to be `null: false` (this improves index utilization)
## 1.17.3 (2 Feb 2021)
### New Features
- Pusher subscriptions: `context[:compress_pusher_payload] = true` will cause the payload to be gzipped before being sent to Pusher
## 1.17.2 (30 Jan 2021)
### Bug Fix
- Subscriptions: don't generate keys inside Lua scripts (for redis-namespace compatibility, and probably better support for Redis cluster) #3307
## 1.17.1 (25 Jan 2021)
### New Features
- OperationStore: add `OperationStore::AddOperationBatch.call` for adding data directly
- Subscriptions: use Lua scripts for more efficient Redis access
## 1.17.0 (20 Jan 2021)
### New Features
- Updates for 1.12.0 compatibility
### Bug Fix
- OperationStore: improve performance by batching reads and writes during updates
## 1.16.2 (21 Dec 2020)
### New Features
- Subscriptions: Add `stale_ttl_s:` and `cleanup_delay_s:` to customize persistence in Redis #3252
## 1.16.1 (3 Dec 2020)
### Bug Fix
- Fix duplicate calls to `Argument#authorized?` in CanCan and Pundit integrations #3242
## 1.16.0 (10 Nov 2020)
### New Features
- Ably Subscriptions: `cipher_base:` sets up end-to-end encryption
## 1.15.7 (29 Sept 2020)
### Bug Fix
- Encoder: fix Ruby 2.7 warning #3161
- Stable connections: Handle `ARRAY[...]` selections and cursors on Postgres #3166
- Pundit: properly lookup policies for list inputs #3146
## 1.15.6 (17 Sept 2020)
### Bug Fix
- Stable Connections: Use method access to get `.cursor_#{idx}` values instead of `.attributes[:cursor_#{idx}]`, fixes #3149
## 1.15.5
### New Features
- Stable Connections: use `.to_sql` to handle orderings that use complex Arel expressions (#3109)
## 1.15.4 (28 July 2020)
### New Features
- Pundit: add `pundit_policy_class_for(object, context)` and `pundit_role_for(object, context)` for custom runtime lookups
## 1.15.3 (17 July 2020)
### Bug Fix
- Subscriptions: don't send empty updates when subscriptions return `:no_update`
## 1.15.2 (16 July 2020)
### New Features
- OperationStore: improve handling of archived operations in index views
## 1.15.1 (16 July 2020)
(Oops, bad release!)
## 1.15.0 (15 July 2020)
- OperationStore: Store & display `last_used_at` for operation store clients and operations. To upgrade, add the column to your ActiveRecord table:
```ruby
add_column :graphql_client_operations, :last_used_at, :datetime
```
(It works out-of-the-box with the Redis backend.)
You can opt out of this feature by adding `use GraphQL::Pro::OperationStore, ... default_touch_last_used_at: false` to your schema setup.
- OperationStore: Add archive/unarchive workflow for operations. To upgrade, add the column to your table:
```ruby
add_column :graphql_client_operations, :is_archived, :boolean, index: true
```
(It works out-of-the-box with the Redis backend.)
- OperationStore: Fix indexing of enum values
## 1.14.1 (29 June 2020)
- CanCan: Accept `can_can_attribute:` configuration, which is passed as the third input to `.can?(...)`
## 1.14.0 (13 June 2020)
### New Features
- Add PubnubSubscriptions
- Update subscription implementations to support `broadcast: true` when available
### Bug Fix
- More Ruby 2.7 warning fixes
## 1.13.6 (8 June 2020)
### Bug Fix
- Return the proper `pageInfo` values when it's requested before `edges` or `nodes` (#2972)
## 1.13.5 (11 May 2020)
### Bug Fix
- Fix some warnings on Ruby 2.7
## 1.13.4 (17 Apr 2020)
### Bug Fix
- StableRelationConnection: properly return `hasNextPage: true` when `before` and `max_page_size` are used.
## 1.13.3 (2 Apr 2020)
### New Features
- `GraphQL::Pro::OperationStore::Migration` can be used to copy persisted operations from one backend to another (eg, ActiveRecord to Redis). See the source file, `lib/graphql/pro/operation_store/migration.rb` for docs.
## 1.13.2 (28 Mar 2020)
### Deprecations
- `GraphQL::Pro::Subscriptions` is deprecated; use `GraphQL::Pro::PusherSubscriptions` instead which works the same, but better (see below). This new name avoids confusion with the later-added `AblySubscriptions`.
### New Features
- `GraphQL::Pro::PusherSubscriptions` replaces `GraphQL::Pro::Subscriptions` and adds orphaned record cleanup. (No more dangling records in Redis.)
## 1.13.1 (12 Mar 2020)
- Use `nonce: true` when working with cursors in new stable connections
## 1.13.0 (10 Feb 2020)
### New Features
- OperationStore supports a `redis:` backend
- OperationStore supports an arbitrary `backend_class:` for persistence operations
### Bug Fix
- Use a loop when clearing Redis subscription state to avoid large stack traces #2701
- Handle empty subscription keys when publishing updates #2061
## 1.12.2 (22 Jan 2020)
### Bug Fix
- Improve backwards compat with OperationStore (Improve adding `.tracer`, use `.graphql_name` when indexing)
## 1.12.1 (20 Jan 2020)
### Bug Fix
- Fix OperationStore on class-based schemas with query instrumenters that use the query string
## 1.12.0 (20 Jan 2020)
### Deprecations
- `GraphQL::Pro::Monitoring` is deprecated; see Tracing for a replacement: https://graphql-ruby.org/queries/tracing.html
- `GraphQL::Pro::Repository` is deprecated; see OperationStore for a replacement: https://graphql-ruby.org/operation_store/overview.html
### New Features
- New stable connection support based on GraphQL-Ruby 1.10's new pagination implementation. New classes provide better handling of `NULL` values in order-by columns and they can be applied on a field-by-field basis(`GraphQL::Pro::SqliteStableRelationConnection`, `GraphQL::Pro::MySQLStableRelationConnection`, `GraphQL::Pro::PostgresStableRelationConnection`).
### Bug Fix
- Add the Access query analyzer to class-based schemas
## 1.11.0 (10 Oct 2019)
### New Features
- Forwards-compatibility for graphql 1.10.0
- Support 1.10.0.pre1's input object argument `loads:` authorization
## 1.10.8 (8 Oct 2019)
### Bug Fix
- Continue authorizing input object arguments
- Use millisecond-aware string format for datetimes in cursors
## 1.10.7 (22 Jul 2019)
### Bug Fix
- Support multiple subscriptions in one document
## 1.10.6 (27 Jun 2019)
### New Features
- Support custom `#can_can_ability` methods on query context for CanCanIntegration
- Support custom `#pundit_user` method on query context for PunditIntegration
### Bug Fix
- Fix off-by-one error when paginating backwards from the last item in a stable relation connection
## 1.10.5 (11 May 2019)
### New Features
- Include expected HMAC digest in OperationStore debug output
## 1.10.4 (26 Mar 2019)
### Bug Fix
- Include content-length and content-type headers in OperationStore JSON responses
## 1.10.3 (13 Mar 2019)
### Bug Fix
- Support stable connections ordered by Arel SQL literals
## 1.10.2 (11 Mar 2019)
### Bug Fix
- Support stable connections on realized views (which don't have primary keys)
## 1.10.1 (8 Mar 2019)
### Bug Fix
- Pundit integration: support `pundit_policy_class` String names when scoping connections
## 1.10.0 (5 Mar 2019)
### New Features
- Add `GraphQL::Pro::Defer`, implementing `@defer` for streaming responses
## 1.9.13 (4 Mar 2019)
### Bug Fix
- Pundit integration: correctly authorize fields when Query root is nil
## 1.9.12 (22 Feb 2019)
### Bug Fix
- Pundit integration: use overriden `pundit_policy_class` for scoping and mutation authorization
## 1.9.11 (20 Feb 2019)
### Bug Fix
- Pundit integration: Fields use the owner's configured `pundit_policy_class` if there is one
- Pundit integration: avoid conflicts with `#initialize` for schema classes that don't need it
## 1.9.10 (19 Feb 2019)
### Bug Fix
- Support inheritance with `pundit_policy_class(...)`
## 1.9.9 (13 Feb 2019)
### New Features
- Support `pundit_policy_class(...)` and `pundit_policy_class:` to manually specify a class or class name.
## 1.9.8 (30 Jan 2019)
### New Features
- Inject `context` into policy lookup hooks instead of just the user
## 1.9.7 (30 Jan 2019)
### New Features
- Extract `pundit_policy` and `scope_by_pundit_policy` hooks for user override
## 1.9.6 (18 Jan 2019)
### Bug Fix
- Properly render subscription context in dashboard
## 1.9.5 (14 Jan 2019)
## Bug Fix
- Don't pass arrays to Pundit scopes (fixes https://github.com/rmosolgo/graphql-ruby/issues/2008)
## 1.9.4 (11 Jan 2019)
## Bug Fix
- Prepare for future compat with graphql-ruby 1.9
## 1.9.3 (3 Dec 2018)
### Bug Fix
- Include table name when adding a default order-by-id to ActiveRecord Relations
- Raise if a required cursor attribute is missing
- Improve `rake routes` output for operation store endpoint
- Support already-parsed queries in subscription RedisStorage
## 1.9.2 (2 Nov 2018)
### Bug Fix
- Derp, remove the dummy app's `.log` files from the gem bundle
- Fix ordering bug when a SQL function call doesn't have an explicit order
## 1.9.1 (1 Nov 2018)
### Bug Fix
- Fix Pusher reference in AblySubscriptions
## 1.9.0 (27 Oct 2018)
### New Features
- Add `GraphQL::Pro::AblySubscriptions` for GraphQL subscriptions over Ably.io transport
## 1.8.2 (22 Oct 2018)
### Bug Fix
- Support `NULLS LAST` in stable cursors
## 1.8.1 (16 Oct 2018)
### Bug Fix
- Improve operation store models to work when `config.active_record.primary_key_prefix_type` is set
## 1.8.0 (11 Oct 2018)
### New Features
- Support Rails 3.2 with OperationStore
- Use `.select` to filter items in CanCanIntegration
### Bug Fix
- Properly send an _ability_ and the configured `can_can_action` to `.accessible_by`
- Use a string (not integer) for `Content-Length` header in the dashboard
## 1.7.13 (2 Oct 2018)
### Breaking Change
- `PunditIntegration`: instead of raising `MutationAuthorizationFailed` when an argument fails authorization, it will send a `GraphQL::UnauthorizedError` to your `Schema.unauthorized_object` hook. (This is what all other authorization failures do.) To retain the previous behavior, in your base mutation, add:
```ruby
def unauthorized_by_pundit(owner, value)
# Raise a runtime error to halt query execution
raise "#{value} failed #{owner}'s auth check"
end
```
Otherwise, customize the handling of this behavior with `Schema.unauthorized_object`.
### Bug Fix
- Auth: mutation arguments which have authorization constraints but _don't_ load an object from the database will have _mutation instance_ passed to the auth check, not the input value.
## 1.7.12 (29 Aug 2018)
### New Features
- Add `GraphQL::Pro::CanCanIntegration` which leverages GraphQL-Ruby's built-in auth
## 1.7.11 (21 Aug 2018)
### Bug Fix
- `PunditIntegration`: Don't try to authorize loaded objects when they're `nil`
## 1.7.10 (10 Aug 2018)
### New Features
- Update `PunditIntegration` for arguments, unions, interfaces and mutations
## 1.7.9 (9 Aug 2018)
### New Features
- Add a new `PunditIntegration` which leverages the built-in authorization methods
## 1.7.8 (10 July 2018)
### Bug Fix
- Authorization: fix scoping lists of abstract type when there's no `#scope` method on the strategy
## 1.7.7 (10 May 2018)
### Bug Fix
- Fix ordering of authorization field instrumenter (put it at the end, not the beginning of the list)
## 1.7.6 (2 May 2018)
### New Features
- Authorization: Add `view`/`access`/`authorize` methods to `GraphQL::Schema::Mutation`
## 1.7.5 (19 Apr 2018)
### New Features
- Authorization: when a `fallback:` configuration is given, apply it to each field which doesn't have a configuration of its own or from its return type. _Don't_ apply that configuration at schema level (it's applied to each otherwise uncovered field instead).
## 1.7.4 (16 Apr 2018)
### New Features
- Support Mongoid::Criteria in authorization scoping
## 1.7.3 (12 Apr 2018)
### Bug Fix
- Fix authorization code for when `ActiveRecord` is not defined
## 1.7.2 (10 Apr 2018)
### Bug Fix
- Use a more permissive regexp (`/^\s*((?:[a-z._]+)\(.*\))\s*(asc|desc)?\s*$/im`) to parse SQL functions
## 1.7.1 (4 Apr 2018)
### Bug Fix
- Fix route helpers to support class-based schemas
## 1.7.0 (25 Mar 2018)
### New Features
- Support `1.8-pre` versions of GraphQL-Ruby
### Bug Fix
- Fix OperationStore when other query instrumenters need `.query_string`
## 1.6.5 (7 Feb 2018)
### Bug Fix
- Support `LEAST(...)` in stable cursors
## 1.6.4 (7 Feb 2018)
### Bug Fix
- Support `CASE ... END` in stable cursors
## 1.6.3 (26 Jan 2018)
### Bug Fix
- Support `FIELD(...)` in stable cursors
## 1.6.2 (13 Jan 2018)
### Bug Fix
- Improve detection of `OperationStore` for the dashboard
- Serve `Content-Type` and `Content-Length` headers with dashboard pages
- Better `Dashboard#inspect` for Rails routes output
- Use a string to apply order-by-primary-key for better Rails 3 support
## 1.6.1 (22 Nov 2017)
### New Features
- Support `composite_primary_keys` gem
## 1.6.0 (13 Nov 2017)
### Breaking Changes
- `GraphQL::Pro::UI` renamed to `GraphQL::Pro::Dashboard`
### Deprecations
- Routing method `.ui` was renamed to `.dashboard`
### New Features
- Added `GraphQL::Pro::Subscriptions`
- Added subscriptions component to Dashboard
## 1.5.9 (10 Oct 2017)
### Bug Fix
- Don't crash when scoping lists of abstract types with Pundit
## 1.5.8 (2 Oct 2017)
### New Features
- Use `authorize(:pundit, namespace: )` to lookup policies in a namespace instead of the global namespace.
### Bug Fix
- Introspection data is allowed through `fallback:` `authorize:` and `access:` filters. (It can be hidden with a `view:` filter.)
## 1.5.7 (20 Sept 2017)
### Bug Fix
- Properly return `nil` when a list of authorized objects returns `nil`
## 1.5.6 (19 Sept 2017)
### New Features
- Add `authorization(..., operation_store:)` option for authorizing operation store requests
## 1.5.5 (18 Sept 2017)
### New Features
- Support `ConnectionType.bidrectional_pagination?` in stable RelationConnection
## 1.5.4 (18 Sept 2017)
### Bug Fix
- Fix load issue when Rails is not present
## 1.5.3 (4 Sept 2017)
### Bug Fix
- Fix OperationStore views on PostgresQL
- Fix stable cursors when joined tables have the same column names
__Note:__ This is implemented by adding extra fields to the `SELECT`
clause with aliases like `cursor_#{idx}`, so you'll notice this in your
SQL logs.
## 1.5.2 (4 Aug 2017)
### Bug Fix
- Bump `graphql` dependency to `1.6`
## 1.5.1 (2 Aug 2017)
### New Features
- Routing extensions moved to `using GraphQL::Pro::Routes`
### Deprecations
- Deprecate `using GraphQL::Pro`, move extensions to `GraphQL::Pro::Routes`
## 1.5.0 (31 Jul 2017)
### New Features
- Add `GraphQL::Pro::OperationStore` for persisted queries with Rails
## 1.4.8 (14 Jul 2017)
### Bug Fix
- Update `authorization` to use type-level `resolve_type` hooks
## 1.4.7 (13 Jul 2017)
### Bug Fix
- Update authorization instrumentation for `graphql >= 1.6.5`
## 1.4.6 (6 Jul 2017)
### Bug Fix
- Fix typo in RelationConnection source
## 1.4.5 (6 Jul 2017)
### Bug Fix
- Correctly fall back to offset-based cursors with `before:` argument
## 1.4.4 (15 Jun 2017)
### New Features
- Add `Schema#unauthorized_object(obj, ctx)` hook for failed runtime checks
### Bug Fix
- Prevent usage of `parent_role:` with `view:` or `access:` (since parent role requires a runtime check)
- Fix versioned, encrypted cursors with 16-byte legacy cursors
## 1.4.3 (13 Jun 2017)
### New Features
- `OrderedRelationConnection` supports ordering by joined fields
### Bug Fix
- Update auth plugin for new Relay instrumenters
- `Pro::Encoder` supports `encoder(...)` as documented
## 1.4.2 (2 May 2017)
### Bug Fix
- Fix compatibility of `RelationConnection` and `RangeAdd` helper
## 1.4.1 (19 Apr 2017)
### New Features
- Add `:datadog` monitoring
## 1.4.0 (19 Apr 2017)
### New Features
- `ActiveRecord::Relation`s can be scoped by Pundit `Scope`s, CanCan `accessible_by`, or custom strategy's `#scope(gate, relation)` methods
- Default authorization configuration can be provided with `authorization(..., fallback: { ... })`
- Authorization's `:current_user` key can be customized with `authorization(..., current_user: ...)`
## 1.3.0 (7 Mar 2017)
### New Features
- Serve static, persisted queries with `GraphQL::Pro::Repository`
## 1.2.3 (2 May 2017)
### Bug Fix
- Fix compatibility of `RelationConnection` and `RangeAdd` helper
## 1.2.2 (6 Mar 2017)
### Bug Fix
- Raise `GraphQL::Pro::RelationConnection::InvalidRelationError` when a grouped, unordered relation is returned from a field. (This relation can't be stably paginated.)
## 1.2.1 (3 Mar 2017)
### New Features
- Formally support ActiveRecord `>= 4.1.0`
### Bug Fix
- Support grouped relations in `GraphQL::Pro::RelationConnection`
## 1.2.0 (1 Mar 2017)
### New Features
- Authorize fields based on their parent object, for example:
```ruby
AccountType = GraphQL::ObjectType.define do
name "Account"
# This field is visible to all users:
field :name, types.String
# This is only visible when the current user is an `:owner`
# of this account
field :account_balance, types.Int, authorize: { parent_role: :owner }
end
```
## 1.1.1 (22 Feb 2017)
### Bug Fixes
- Fix monitoring when `Query#selected_operation` is nil
## 1.1.0 (9 Feb 2017)
### New Features
- Add AppSignal monitoring platform
- Add type- and field-level opting in and opting out of monitoring
- Add `monitor_scalars: false` to skip monitoring on scalars
### Bug Fixes
- Fix `OrderedRelationConnection` when neither `first` nor `last` are provided (use `max_page_size` or don't limit)
## 1.0.4 (23 Jan 2017)
### Bug Fixes
- `OrderedRelationConnection` exposes more metadata methods: `parent`, `field`, `arguments`, `max_page_size`, `first`, `after`, `last`, `before`
## 1.0.3 (23 Jan 2017)
### Bug Fixes
- When an authorization check fails on a non-null field, propagate the null and add a response to the errors key (as if the field had returned null). It previously leaked the internal symbol `__graphql_pro_access_not_allowed__`.
- Apply a custom Pundit policy even when the value isn't `nil`. (It previously fell back to `Pundit.policy`, skipping a `pundit_policy_name` configuration.)
## 1.0.2
### Bug Fixes
- `OrderedRelationConnection` exposes the underlying relation as `#nodes` (like `RelationConnection` does), supporting custom connection fields.
## 1.0.1
### New Features
- CanCan integration now supports a custom `Ability` class with the `ability_class:` option:
```ruby
authorize :cancan, ability_class: CustomAbility
```
## 1.0.0
- `GraphQL::Pro` released
graphql-ruby-2.2.17/CHANGELOG-relay.md 0000664 0000000 0000000 00000006677 14764346352 0017201 0 ustar 00root root 0000000 0000000 # graphql-relay
### Breaking Changes
### Deprecations
### New Features
### Bug Fix
## 0.12.0 (21 Jul 2016)
### Breaking Changes
- Don't cache a global node identification config #51
To migrate, assign your node identification helper to the schema:
```ruby
NodeIdentification = GraphQL::Relay::GlobalNodeIdentification.define { ... }
MySchema.node_identification = NodeIdentification
```
### New Features
- Support lazy definition blocks from graphql-ruby 0.17
- Add `startCursor` and `endCursor` to `PageInfo` #60
### Bug Fix
- Support `field:` keyword for connection helper #58
## 0.11.2 (6 Jul 2016)
### New Features
- Include description for built-in objects #55
## 0.11.1 (24 Jun 2016)
### Bug Fix
- Correctly pass parent object to Connections #53
## 0.11.0 (19 Jun 2016)
### Breaking Changes
- `BaseType.define_connection` no longer caches the result to use as the default `BaseType.connection_type`. Now, store the result of `.define_connection` in a variable and pass that variable into the schema:
```ruby
# Capture the returned type:
SomethingCustomConnectionType = SomethingType.define_connection { ... }
DifferentThingType = GraphQL::ObjectType.define do
# And pass it to the connection helper:
connection :somethings, SomethingCustomConnectionType
end
```
### New Features
- Support for custom edge types / classes #50
- Support for multiple connection classes #50
## 0.10.0 (31 May 2016)
### New Feature
- Support `graphql` 0.14.0 #47
### Bug Fix
- Use strings as argument names, not symbols #47
## 0.9.5
### New Feature
- Root `id` field may have a description #43
## 0.9.4 (29 Apr 2016)
### Bug Fix
- Fix Node interface to support GraphQL 0.13.0+
## 0.9.2 (29 Apr 2016)
### Bug Fix
- Fix Node interface when type_from_object returns nil
## 0.9.1 (6 Apr 2016)
### Bug Fix
- Respond to connection fields without any pagination arguments
- Limit by `max_page_size` even when no arguments are present
## 0.9.0 (30 Mar 2016)
### Breaking change
- Remove the `order` argument from connection fields. This isn't part of the spec and shouldn't have been there in the first place!
You can implement this behavior with a custom argument, for example:
```ruby
field :cities, CityType.connection_type do
argument :order, types.String, default_value: "name"
resolve ->(obj, args, ctx) {
obj.order(args[:order])
}
end
```
### Bug Fix
- Include the MIT license in the project's source
## 0.8.1 (22 Mar 2016)
### Bug Fix
- Accept description for Mutations
## 0.8.0 (20 Mar 2016)
### New Feature
- Accept configs for `to_global_id` and `from_global_id`
- Support `graphql` 0.12+
## 0.7.1 (29 Feb 2016)
### Bug Fix
- Limit the `count(*)` when testing next page with ActiveRecord #28
## 0.7.0 (20 Feb 2016)
### New Feature
- `max_page_size` option for connections
- Support ActiveSupport 5.0.0.beta2
## 0.6.2 (11 Feb 2016)
### Bug Fix
- Correctly cast values from connection cursors #21
- Use class _name_ instead of class _object_ when finding a connection implementation (to support Rails autoloading) #16
## 0.6.1 (14 Dec 2015)
### Bug Fix
- Stringify `id` when passed into `to_global_id`
## 0.6.0 (11 Dec 2015)
### Breaking Change
- `GlobalNodeIdentification#object_from_id(id, ctx)` now accepts context as the second argument #9
## 0.5.1 (11 Dec 2015)
### Feature
- Allow custom UUID join string #15
### Bug Fix
- Remove implicit ActiveSupport dependency #14
graphql-ruby-2.2.17/CHANGELOG.md 0000664 0000000 0000000 00000456426 14764346352 0016070 0 ustar 00root root 0000000 0000000 # Changelog
[Versioning guidelines](https://graphql-ruby.org/development.html#versioning)
### Breaking changes
### Deprecations
### New features
### Bug fixes
# 2.2.17 (12 Mar 2025)
- Security: fix CVE-2025-27407
# 2.2.16 (17 Jul 2024)
- Fix path on errors raised in Dataloader Sources #5026
# 2.2.15 (20 May 2024)
### Bug fixes
- Directives: correctly handle runtime directives in deeply nested fragments #4962
# 2.2.14 (18 Mar 2024)
### Bug fixes
- Parser: properly handle stray hyphens in query strings #4879
# 2.2.13 (11 Mar 2024)
### Bug fixes
- Tracing: when a new base `:default` trace class is added, merge already-configured trace modules into it #4875
# 2.2.12 (6 Mar 2024)
### Deprecations
- `Schema.{query|mutation|subscription}_execution_strategy` methods are deprecated without replacement #4867
### Breaking Changes
- Connections: Revert changes to `hasNextPage` returning `false` when no `first` is given (previously changed in 2.2.6) #4866
### Bug fixes
- Complexity: handle unauthorized argument errors better #4868
- Pass `context` when fetching argument for `loads: ...` #4870
# 2.2.11 (27 Feb 2024)
### New features
- Sentry: support transaction names in tracing #4853
### Bug fixes
- Tracing: handle unknown trace modes at runtime #4856
# 2.2.10 (20 Feb 2024)
### New features
- Parser: support directives on variable definitions #4847
### Bug fixes
- Fix compatibility with Ruby 3.4 #4846
- Tracing: Fix applying default options to non-default modes #4849, #4850
# 2.2.9 (15 Feb 2024)
### New features
- Complexity: Treat custom Connection fields as metadata (like `totalCount`), not as if they were evaluated for each item in the list #4842
- Subscriptions: Serialize `ActiveRecord::Relation`s given to `.trigger` #4840
### Bug fixes
- Complexity: apply configured `complexity ...` to connection fields #4841
- Authorization: properly handle Resolver arguments that return `false` for `#authorized?` #4839
# 2.2.8 (7 Feb 2024)
### New features
- Responses have `"errors"` before `"data"`, as recommended by the GraphQL spec #4823
### Bug fixes
- Sentry: fix integration with other trace modules #4830
- Sentry: fix when child span is `nil` (test environments) #4828
- Remove needless Base64 backport #4820
- Fix module arrangement to support RDoc #4819
# 2.2.7 (29 Jan 2024)
### Deprecations
- Deprecate returning `.resolve` dataloader requests (use `.load` instead) #4807
- Deprecate `error_bubbling(true)`, no replacement. Please open an issue if you need this option. #4813
### Bug fixes
- Remove unused `racc` dependency #4814
- Fix `backtrace: true` when used with `@defer` and batch-loaded lists #4815
- Accept input objects when required arguments aren't provided but have default values #4811
# 2.2.6 (25 Jan 2024)
### Deprecations
- `instrument(:query | :multiplex, ...)` was deprecated, use a `trace_with` module instead. #4771
- Legacy `PlatformTracing` classes are deprecated, use a `PlatformTrace` module instead #4779
### New features
- `FieldUsage` analyzer: returns a `used_deprecated_enum_values: ...` array in its result Hash #4805
- `validate_timeout` applies to query analysis as well as static validation #4800
- `SentryTrace` is added for instrumenting with Sentry #4775
### Bug fixes
- `FieldUsage` analyzer: properly find deprecated arguments in non-null input objects #4805
- DataDog: replace usage of `span_type` setter with `span` setter #4776
- Fix coercion error handing with given `null` values #4799
- Raise a better error when variables are defined with non-input types #4791
- Fix `hasNextPage` when `max_page_size` is set #4780
# 2.2.5 (10 Jan 2024)
### Bug fixes
- Parser: fix enum values named `type` #4772
- GraphQL::Deprecation: remove this unused helper module #4769
# 2.2.4 (3 Jan 2024)
### Bug fixes
- AsyncDataloader: don't resolve fields with event loop #4757
- Parser: properly parse some fields and args named after keywords #4759
- Performance: use `all?` to check classes directly #4760
# 2.2.3 (28 Dec 2023)
### Bug fixes
- AsyncDataloader: avoid leftover `suspended` Fibers #4754
- Generators: fix path and constant name of BaseResolver #4755
# 2.2.2 (27 Dec 2023)
### Bug fixes
- Dataloader: remove `Fiber#transfer` support because Ruby's control flow is unpredictable (#4748, #4752, #4743)
- Parser: fix handling of single-token document
- QueryComplexity: improve performance
# 2.2.1 (20 Dec 2023)
### Bug fixes
- `AsyncDataloader`: re-raise errors from fields and sources #4736
- Parser: fix parsing directives on interfaces in SDL #4738
# 2.2.0 (18 Dec 2023)
### Breaking changes
- `loads:` now requires a schema's `self.resolve_type` method to be implemented so that loaded objects can be verified to be of the expected type #4678
- Tracing: the new Ruby-based parser doesn't emit a "lex" event. (`graphql/c_parser` still does.)
### New features
- `GraphQL::Dataloader::AsyncDataloader`: a Dataloader class that uses the `async` gem to run I/O from fields and Dataloader sources in parallel #4727
- Parser: use a heavily-optimized lexer and a hand-written parser for better performance #4718
- `run_graphql_field`: a helper method for running fields in tests #4732
# 2.1.10 (27 Dec 2023)
- Dataloader: remove Fiber#transfer support because of unpredictable Ruby control flow #4753
# 2.1.9 (21 Dec 2023)
### Bug fixes
- Dataloader: fix some fiber scheduling bugs #4744
# 2.1.8 (18 Dec 2023)
### New features
- Rails generators: generate a base resolver class by default #4513
- Dataloader: add some support for transfer-based Fiber schedulers, simplify algorithm #4625 #4729
- `prepare`: check for the named method on the argument owner, too #4717
# 2.1.7 (4 Dec 2023)
### New features
- Make `NullContext` inherit from `Context`, to make typechecking easier #4709
- Accept a custom `Schema.query_class` to use for executing queries #4679
### Bug fixes
- Default `reauthorize_scoped_objects` to false #4720
- Fix `subscriptions.trigger` with custom enum values #4713
- Fix `backtrace: true` with GraphQL-Pro `@defer` #4708
- Omit `to_h` from Input Object validation error message #4701
- When trimming whitespace from block strings, remove first and last lines that contain only whitespace #4704
# 2.1.6 (2 Nov 2023)
### Breaking Changes
- The parser cache is now opt-in. Add `config.graphql.parser_cache = true` to your Rails environment setup to enable it. #4648
### New features
- New `ISO8601Duration` scalar #4688
### Bug fixes
- Trace: fix custom trace mode inheritance #4693
# 2.1.5 (25 Oct 2023)
### Bug fixes
- Logger: Fix `Schema.default_logger` when Rails is present but doesn't have a logger #4686
# 2.1.4 (24 Oct 2023)
### New features
- Add `Query#logger` #4674
- Lookahead: Add `with_alias:` option #2912
- Improve support for `load_application_object_failed` #4667
### Bug fixes
- Execution: Fix runtime loop in some cases with fragments #4684
- Fix `Connection#initialize` outside of execution #4675
- Fix ParseError in `Subscriptions#trigger` #4673
- Mongo: don't load all records in hasNextPage #4671
- Interfaces: fix `definition_methods` when interfaces implement other interfaces #4670
- Migrate `NullContext` to use the built-in Singleton module #4669
- Speed up type lookup #4664
- Fix `ScopeExtension#after_resolve` outside of execution #4685
- Speed up `one_of?` checks #4680
# 2.1.3 (12 Oct 2023)
### Bug fixes
- Tracing: fix legacy tracers added to `GraphQL::Schema` #4663
- Add `racc` as a dependency because it's not included by default in Ruby 3.3 #4661
- Connections: don't add automatic connection behaviors for types named "Connection" #4668
# 2.1.2 (11 Oct 2023)
### New features
- Depth: accept `count_introspection_fields: false` #4658
- Dataloader: add `get_fiber_variables` and `set_fiber_variables` #4593
- Trace: Add `Schema.default_trace_mode` #4642
### Bug fixes
- Fix merging results after calling directives #4639 #4660
- Visibility: don't reveal implementors of hidden abstract types #4589
- Bump required Ruby version to 2.7 since numbered block arguments are used #4659
- `hash_key:`: use the configured hash key when the underlying Hash has a default value Proc #4656
# 2.1.1 (2 Oct 2023)
### New features
- Mutations: `HasSingleInput` provides Relay Classic-like `input: ...` argument behavior #4581
- Add `@specifiedBy` default directive #4633
- Analysis: support `visit?` hook to skip visit but still return a value
- Add `context.scoped` for a long-lived reference to the current scoped context #4605
### Bug fixes
- Sanitized printer: Correctly print enum variable defaults #4652
- Schema printer: use `extend schema` when the schema has directives #4647
- Performance: pass runtime state through interpreter code #4621
- Performance: add `StaticVisitor` for faster AST visits #4645
- Performance: faster field lookup #4626
- Improve generator templates #4627
- Dataloader: clear cache between root mutation fields #4617
- Performance: Improve argument checks #4622
- Remove unused legacy connection code #4606
# 2.1.0 (30 Aug 2023)
### Breaking changes
- Visitor: legacy-style proc-based visitors are no longer supported #4577 #4583
- Deprecated `GraphQL::Filter` is removed #4325
- Language::Printer has been re-written to append to a buffer; custom printers will need to be updated #4394
### New features
- Authorization: Items in a list can skip object-level `.authorized?` checks if the type is configured with `reauthorize_scoped_objects(false)` #3994
- Subscriptions: `unsubscribe(...)` accepts a value to be used to return a result along with unsubscribing #4283
- Language::Printer is much faster #4394
# 2.0.27 (30 Aug 2023)
### New features
- Validators: Support `%{value}` in custom messages #4601
### Bug fixes
- Resolvers: Support `return false, nil` from `ready?` and `authorized?` #4585
- Enums: properly load directives from Schema IDL #4596
- Language: faster scanner #4576
- Language: support fields and arguments named `"null"` #4586
- Language: fix block string quote unescaping #4580
- Generator: use generated node type in Relay-related fields #4598
# 2.0.26 (8 Aug 2023)
### Bug fixes
- Datadog Tracing: fix LocalJumpError #4579
# 2.0.25 (7 Aug 2023)
### New features
- Tracing: add trace modes #4571
- Dataloader: add `Source#result_key_for` for customizing cache keys in sources #4569
### Bug fixes
- Tracing: Support multiple tracing platforms at once #4543
# 2.0.24 (27 Jun 2023)
### New features
- `Schema::Object.wrap` can be used to customize how objects are (or aren't) wrapped by `GraphQL::Schema::Object` instances at runtime #4524
- `Query`: accept a `static_validator:` option in `#initialize` to use instead of the default validation configuration.
### Bug fixes
- Performance: Reduce memory usage when adding types to a schema #4533
- Performance, `Dataloader`: when loading specific keys, only run dataloader until those specific keys are resolved #4519
# 2.0.23 (19 Jun 2023)
### New features
- Printer: print extensions in SDL #4516
- Trace: accept trace instances during query execution #4497
- AlwaysVisible: Make a way to bypass type visibility #4442, #4491
### Bug fixes
- Tests: fix assertion for Ruby 3.3.0-dev #4515
- Performance: improve fragment possible type lookup #4506
- Docs: document Timeout can handle floats #4505
- Performance: use a dedicated object for field extension state #4401
- Backtrace: fix `backtrace: true` with other trace modules #4505
- Handle `context.warden` being nil #4503
- Dev: disable Minitest::Reporters for RubyMin #4494
- Trace: fix compatibility with inheritance #4487
- Context: fix NullContext compatibility with fetch, dig and key? #4483
# 2.0.22 (17 May 2023)
### New features
- Warden: manually instantiating doesn't require a `filter` instance #4462
### Bug fixes
- Enum: fix procs for enum values #4474
- Lexer: force UTF-8 encoding #4467
- Trace: inherit superclass `trace_options` #4470
- Dataloader: properly run mutations in sequence #4461
- NotificationsTrace: Add `execute_multiplex.graphql` event #4460
- Fix `Context#dig` when called with one key #4458
- Performance: Use a plain hash for selection sets at runtime #4453
- Performance: Memoize current trace #4450, #4452
- Performance: Pass is_non_null to runtime check #4449
- Performance: Use `compare_by_identity` on some runtime caches
- Properly support nested queries (fix `Thread.current` clash) #4445
# 2.0.21 (11 April 2023)
### Deprecations
- Deprecate `GraphQL::Filter` (use `visible?` methods instead) #4424
### New features
- PrometheusTracing: support histograms #4418
### Bug fixes
- Backtrace: improve compatibility with `trace_with` #4437
- Consolidate internally-used empty value constants #4434
- Fix some warnings #4422
- Performance: improve runtime speed #4436 #4433 #4428 #4430 #4427 #4399
- Validation: fix inline fragment selection on scalar #4429
- `@oneOf`: print definition in the SDL when it's used
- SDL: load schema directives when they're used
- Appsignal tracing: Fix `resolve_type` definition
# 2.0.20 (30 March 2023)
### Bug fixes
- `.resolve_type`: fix returning `[Type, false]` from resolve_type #4412
- Parsing: improve usage of `GraphQL.default_parser` #4411
- AppsignalTrace: implement missing methods #4390
- Runtime: Fix `current_depth` method in some lazy lists #4386
- Performance: improve `Object` object shape #4365
- Tracing: return execution errors raised from field resolution to `execute_field` hooks #4398
# 2.0.19 (14 March 2023)
### Bug fixes
- Scoped context: fix `context.scoped_context.current_path` #4376
- Tracing: fix `tracer` inheritance in Schema classes #4379
- Timeout: fix `Timeout` plugin when other tracers are used #4383
- Performance: use Arrays instead of `GraphQL::Language::Token`s when scanning #4366
# 2.0.18 (9 March 2023)
### Breaking Changes
- Tracing: `"execute_field"` events on fields defined on interface types will now receive the _interface_ type as `data[:owner]` instead of the current object type. To get the old behavior, use `data[:object].class` instead. #4292
### New features
- Add `TypeKind#leaf?` #4352
### Bug fixes
- Tracing: use the interface type as `data[:owner]` instead of the object type #4292
- Performance: improve Shape compatibility of `GraphQL::Schema::Field` #4360
- Performance: improve Shape compatibility of `GraphQL::Schema::Warden` #4361
- Performance: rewrite the token scanner in plain Ruby #4369
- Performance: make `deprecation_reason` faster #4356
- Performance: improve lazy value resolution in execution #4333
- Performance: create `current_path` only when the application needs it #4342
- Performance: add `GraphQL::Tracing::Trace` as a lower-overhead tracing API #4344
- Connections: fix `hasNextPage` for already-loaded ActiveRecord Relations #4349
# 2.0.17.2 (29 March 2023)
### Bug fixes
- Unions and Interfaces: support returning `[type_module, false]` from `resolve_type` #4413
# 2.0.17.1 (27 March 2023)
### Bug fixes
- Tracing: restore behavior returning execution errors raised during field resolution #4402
# 2.0.17 (14 February 2023)
### Breaking changes
- Enums: require at least one value in a definition #4278
### New features
- Enums: support `nil` as a Ruby value #4311
### Bug fixes
- Don't re-encode ASCII strings as UTF-8 #4319, #4343
- Fix `handle_or_reraise` with arguments validation #4341
- Performance: Remove error handling from `Lazy#value` (unused) #4335
- Performance: Use codegen instead of dynamic dispatch in `Language::Visitor` and `Analysis::AST::Visitor` #4338
- Performance: reduce indirection in `#introspection?` and `#graphql_name` #4327
- Clean up thread-based state after running queries #4329
- JSON types: don't pass raw NullValue AST nodes to `coerce_input` #4324, #4320
- Performance: reduce `.is_a?` calls at runtime #4318
- Performance: cache interface type memberships #4311
- Performance: eagerly define some type instance variables for Shape friendliness #4300 #4295 #4297
- Performance: reduce argument overhead, don't scope introspection by default, reduce duplicate call to Field#type #4317
- Fix anonymous `eval` usage #4288
- Authorization: fix field auth fail call after lazy #4289
- Subscriptions: fix `loads:`/`as:`
# 2.0.16 (19 December 2022)
### Breaking changes
- `Union`: Only accept Object types in `possible_types` (previously, other types were also accepted, but this was against the spec) #4269
### New features
- Rake: support introspection query options in the `RakeTask` #4247
- Subscriptions: Merge `.trigger(... context: { ... })` into the query context when running updates #4242
### Bug fixes
- Make BaseEdge and subclasses return true for `.default_relay?` #4272
- Validation: return a proper error for duplicate-named fragments when used indirectly #4268
- Don't re-apply `scope_items` to `nodes { ... }` or `edges { ... }` arrays #4263
- Fix `Concurrent::Map` initialization to prevent race conditions
- Speed up scoped context lookup #4245
- Support overriding built-in context keys #4239
- Context: properly `dig` into `:current_arguments` #4249
# 2.0.15 (22 October 2022)
### New features
- SDL: support extensions on the schema itself #4203
- SDL: recognize `.graphqls` files in `.from_definition` #4204
- Schema: add a reader method of `TypeMembership#options` #4209
### Bug fixes
- Node Behaviors: call the id-from-object hook with the type definition, not the type instance #4233
- RelayClassicMutation: add a period to the generated description of the payload type #4229
- Dataloader: make scoped context work with Dataloader #4220
- SDL: fix parsing repeatable directives #4218
- Lookahead: reduce more allocations in `.selects?` #4212
- Introspection Query: strip blank lines from generated query strings #4208
- Enums: Add error handling to result coercion #4206
- Lookahead: add `selected_type:` to `.selects?` #4194
- Lookahead: fix `.selects?` on unions #4193
- Fields: use field-local `connection:` config over resolver config #4191
# 2.0.14 (8 September 2022)
### New features
- Input Objects: support `one_of` for input objects that allow exactly one argument #4184
- Dataloader: add `source.merge({ ... })` for adding objects to dataloader source caches #4186
- Validation: generate new schemas with a suggested `validate_max_errors` of 100 #4179
### Bug fixes
- Lookahead: improve performance when field names are given as symbols #4189
- Runtime: simplify some internal code #4183
- Datadog tracing: remove deprecated options #4159
# 2.0.13 (12 August 2022)
### New features
- Fields: add configuration methods for `default_value` and `prepare` #4156
- Static validation: merge directive errors when they're on the same location or directive
### Bug fixes
- Subscriptions: properly use the given `.trigger(... context: )` for determining subscription root field visibility #4160
- Fix fields that use `hash_key:` and have a falsy value for that key #4132
- Variable validation: respect `validate_max_error` limit
- Performance: use `Array#+` to add objects during execution #4142
# 2.0.12 (19 July 2022)
### New features
- Support returning `[Type, nil]` from `resolve_type` #4130
### Bug fixes
- SDL: Don't print empty braces for input objects with no arguments #4138
- Arguments: always call `prepare` before loading objects based on ID (`loads:`) #4128
- Don't support re-assigning `Query#validate=` after validation has run #4127
# 2.0.11 (20 June 2022)
### New features
- Support full unicode range #4090
### Bug fixes
- Subscriptions: support overriding subscriptions in subclasses #4108
- Schema: support types with duplicate names and cyclical references #4107
- Connections: don't exceed application-applied `LIMIT` with `max_page_size` #4104
- Field: add `Field#relay_nodes_field` config reader #4103
- Remove partial `opentelementry` implementation, oops #4086
- Remove unused method `Lazy.resolve`
# 2.0.10 (20 June 2022)
Oops, this version was accidentally released to RubyGems as "2.10.0". I yanked it. See 2.0.11 instead.
# 2.0.9 (31 May 2022)
### New features
- Connections: use `Schema.default_page_size`, `Field#default_page_size`, or `Resolver.default_page_size` when one of them is available and no `first` or `last` is given #4081
- Tracing: Add `OpenTelementryTracing` #4077
### Bug fixes
- Field usage analyzer: don't crash on null input objects #4078
- Complexity: properly handle `ExecutionError`s raised in `prepare:` hooks #4079
# 2.0.8 (24 May 2022)
### New Features
- Fields: return `fallback_value:` when method or hash key field resolution fails #4069
- Support `hash_key:` lookups on Hash-like objects #4072
- Datadog tracing: support `prepare_span` hook for adding custom tags #4067
### Bug fixes
- Fields: When `hash_key:` is given, populate `#method_str` based on it #4072
- Errors: rescue errors raised when calling `.each` on list values #4052
- Date type: continue accepting dates without hyphens #4061
- Parser: properly parse empty type definitions #4046
# 2.0.7 (25 April 2022)
### New Features
- Subscriptions: support `validate_update: false` to disable validation when running subscription updates #4039
- Expose duplicated name on `DuplicateNamesError` #4022
### Bug Fixes
- Datadog: improve tracer #4038
- `hash_key:` try stringified hash key when resolving fields (this restores previous behavior) #4043
- Printer: Don't print empty field set when types have no fields (`{\n}`) #4042
- Dataloader: improve handoff between lazy resolution and dataloader resolution #4036
- Remove unused `Lazy::Resolve` module from legacy execution code #4035
# 2.0.6 (14 April 2022)
### Bug fixes
- Dataloader: make multiplexes use custom dataloaders #4026
- ISO8601Date: properly accept `nil` as input #4025
- Mutation: fix error message when `ready?` returns an invalid result #4029
- ISO8601 scalars: add `specified_by_url` configs #4014
- Array connection: don't return all items when `before` is the first cursor #4012
- Introspection: fix typo `specifiedByUrl` -> `specifiedByURL`
- Fields: fix `hash_key` to take priority over method lookup #4015
# 2.0.5 (28 March 2022)
### Bug Fixes
- Resolvers: fix inheriting arguments when parent classes aren't hooked up directly to the schema #4006
# 2.0.4 (21 March 2022)
### Bug fixes
- Fields: make sure `null:` config overrides a default from a resolver #4000
# 2.0.3 (21 March 2022)
### Bug fixes
- Fields: make sure field configs override resolver defaults #3975
- Fix `Field#scoped?` when the field uses a resolver #3990
- Allow schema members to have multiple of `repeatable` directives #3986
- Remove some legacy code #3979 #9995
- SDL: fix indirect interface implementation when loading a schema #3982
- Datadog tracing: Support ddtrace 1.0 #3978
- Fix `Node` implementation when connection types include built-in behavior modules #3967
- Small stack trace size reduction #3957
# 2.0.2 (1 March 2022)
### New features
- Reduce schema memory footprint #3959
### Bug fixes
- Mutation: Correctly use a configured `type(...)` #3965
- Interfaces: De-duplicate indirectly implemented interfaces #3932
- Remove an unnecessary require #3961
# 2.0.1 (21 February 2022)
### Breaking changes
- Resolvers: refactored so that, instead of _copying_ configurations to `field ...` instances, `GraphQL::Schema::Field`s reference their provided `resolver: ...`, `mutation: ...`, or `subscription: ...` classes for many properties. This _shouldn't_ break anything -- all of graphql-ruby's own tests passed just fine -- but it's mentioned here in case you notice anything out-of-sorts in your own application #3916
- Remove deprecated field options `field:`, `function:`, and `resolve:` (these were already no-ops, but they were overlooked in 2.0.0) #3917
### Bug fixes
- Scoped context: fix usage with dataloader #3950
- Subscriptions: support multiple definitions for subscription root fields with `.trigger` #3897 #3935
- Improve some error messages #3920 #3923
- Clean up scalar validation code #3982
# 2.0.0 (9 February 2022)
### Breaking Changes
- __None, ideally.__ If you have an application that ran without warnings on v1.13, you should be able to update to 2.0.0 without a hitch. If this isn't the case, please [open an issue](https://github.com/rmosolgo/graphql-ruby/issues/new?template=bug_report.md&title=[2.0%20update]%20describe%20your%20problem) and let me know what happened! I plan to maintain 1.13 for a while in order to ensure a smooth transition.
- But, many legacy code components were removed, so if there are any more references to those, there will be name errors! See #3729 for a list of removed components.
# 1.13.19 (2 February 2023)
### Bug fixes
- Performance: don't re-encode schema member names #4323
- Performance: fix a duplicate field.type call #4316
- Performance: use `scope: false` for introspection types #4315
- Performance: improve argument coercion and validation #4312
- Performance: improve interface type membership lookup #4309
# 1.13.18 (10 January 2023)
### New Features
- `hash_key:`: perform `[...]` lookups even when the underlying object isn't a Hash #4286
# 1.13.17 (17 November 2022)
### Bug fixes
- Handle ExecutionErrors from prepare hooks when calculating complexity #4248
# 1.13.16 (31 August 2022)
### New Features
- Make variable validation respect `validate_max_errors` #4178
# 1.13.15 (30 June 2022)
### Bug fixes
- Remove partial OpenTelementry tracing #4086
- Properly use `Query#validate` to skip static validation #3881
# 1.13.14 (20 June 2022)
### New Features
- Add `Field#relay_nodes_field` reader #4103
- Datadog: detect tracing module #4100
# 1.13.13 (31 May 2022)
### New features
- Datadog: update tracer for ddtrace 1.0 #4038
- Datadog: Add `#prepare_span` hook for custom tags #4067
- Tracing: Add `OpenTelementry` tracing #4077
# 1.13.12 (14 April 2022)
- Pass `context[:dataloader]` to multiplex context #4026
- Add a deprecation warning to `.accepts_definitions` #4002
# 1.13.11 (21 March 2022)
### Deprecations
- `RangeAdd` warns when `context:` isn't provided (it's required in GraphQL-Ruby 2.0) #3996
# 1.13.10
### Breaking changes
- `id` fields: #3914 Previously, when a field was created with `global_id_field`, it would pass a _legacy-style_ type definition (an instance of `GraphQL::ObjectType`) to `Schema.id_from_object(...)`. Now, it passes a class-based definition instead. If your `id_from_object(...)` method was using any methods from those legacy definitions, they should be migrated. (Most notably, uses of `type.name` should be migrated to `type.graphql_name`.)
### Deprecations
- Connections: deprecation warnings were added to configuration methods `.bidirectional_pagination = ...` and `.default_nodes_field = ...`. These two configurations don't apply to the new pagination implementation, so they can be removed. #3918
# 1.13.9 (9 February 2022)
### Breaking changes
- Authorization: #3903 In graphql-ruby v1.12.17-1.13.8, when input objects used `prepare: -> { ... }` , the returned values were not authorized at all. However, this release goes back to the behavior from 1.12.16 and before, where a returned `Hash` is validated just like an input object that didn't have a `prepare:` hook. To get the previous behavior, you can implement `def self.authorized?` in the input object you want to skip authorization in:
```ruby
class Types::BaseInputObject < GraphQL::Schema::InputObject
def self.authorized?(obj, value, ctx)
if value.is_a?(self)
super
else
true # graphql-ruby skipped auth in this case for v1.12.17-v1.13.8
end
end
end
```
### Bug fixes
- Support re-setting `query.validate = ...` after a query is initialized #3881
- Handle validation errors in connection complexity calculations #3906
- Input Objects: try to authorize values when `prepare:` returns a Hash (this was default < v1.12.16) #3903
- SDL: fix when a type has two directives
# 1.13.8 (1 February 2022)
### Bug fixes
- Introspection query: hide newly-supported fields behind arguments, maintain backwards-compatible INTROSPECTION_QUERY #3877
# 1.13.7 (28 January 2022)
### New Features
- Arguments: `replace_null_with_default: true` replaces incoming `null`s with the configured `default_value:` #3871
- Arguments: support `dig: [key1, key2, ...]` for nested hash key access #3856
- Generators: support more Postgresql field types #3577
- Generators: support downcased generator argument types #3577
- Generators: add an input type generator #3577
- Generators: support namespaces in generators #3577
### Bug Fixes
- Field: better error for nil `owner` #3870
- ISO8601DateTime: don't accept inputs with partial time parts #3862
- SDL: fix for base connection classes that implement interfaces #3859
- Cops: find `required: true` on `f.argument` calls (with explicit receiver) #3858
- Analysis: handle undefined or hidden fields with `nil` in `visitor.field_definition` #3857
# 1.13.6 (20 January 2022)
### New features
- Introspection: support `__Schema.description`, `__Directive.isRepeatable`, `__Type.specifiedByUrl`, and `__DirectiveLocation.VARIABLE_DEFINITION` #3854
- Directives: Call `Directive.resolve_each` for list items #3853
- Dataloader: Run each list item in its own fiber (to support batching across list items) #3841
### Bug fixes
- RelationConnection: Preserve `OFFSET` when it's already set on the relation #3846
- `Types::ISO8601Date`: Accept default values as Ruby date objects #3563
# 1.13.5 (13 January 2022)
### New features
- Directives: support `repeatable` directives #3837
- Tracing: use `context[:fallback_transaction_name]` when operations aren't named #3778
### Bug fixes
- Performance: improve performance of queries with directives #3835
- Fix crash on undefined constant `NodeField` #3832
- Fix crash on partially-required `ActiveSupport` #3829
# 1.13.4 (7 January 2022)
### Bug fixes
- Connections: Fix regression in 1.13.3 on unbounded Relation connections #3822
# 1.13.3 (6 January 2022)
### Deprecations
- `GraphQL::Relay::NodeField` and `GraphQL::Relay::NodesField` are deprecated; use `GraphQL::Types::Relay::HasNodesField` or `GraphQL::Types::Relay::HasNodeField` instead. (The underlying field instances require a reference to their owner type, but `NodeField` and `NodesField` can't do that, since they're shared instances) #3791
### New features
- Arguments: support `required: :nullable` to make an argument required to be _present_, even if it's `null` #3784
- Connections: When paginating an AR::Relation, use already-loaded results if possible #3790
- Tracing: Support DRY::Notifications #3776
- Improve the error when a Ruby method doesn't support the defined GraphQL arguments #3785
- Input Objects: call `.authorized?` on them at runtime #3786
- Field extensions: add `extras(...)` for extension-related extras with automatic cleanup #3787
### Bug fixes
- Validation: accept nullable variable types for arguments with default values #3819
- Validation: raise a better error when a schema receives a `query { ... }` but has no query root #3815
- Improve the error message when `Schema.get_field` can't make sense of the arguments #3815
- Subscriptions: losslessly serialize Rails 7 TimeWithZone #3774
- Field Usage analyzer: handle errors from `prepare:` hooks #3794
- Schema from definition: fix default values with camelized arguments #3780
# 1.13.2 (15 December 2021)
### Bug fixes
- Authorization: only authorize arguments _once_, after they've been loaded with `loads:` #3782
- Execution: always provide an `Interpreter::Arguments` instance as `context[:current_arguments]` #3783
# 1.13.1 (13 December 2021)
### Deprecations
- `.to_graphql` and `.graphql_definition` are deprecated and will be removed in GraphQL-Ruby 2.0. All features using those legacy definitions are already removed and all behaviors should have been ported to class-based definitions. So, you should be able to remove those calls entirely. Please open an issue if you have trouble with it! #3750 #3765
### New features
- `context.response_extensions[...] = ...` adds key-value pairs to the `"extensions" => {...}` hash in the final response #3770
- Connections: `node_type` and `edge_type` accept `field_options:` to pass custom options to generated fields #3756
- Field extensions: Support `default_argument ...` configuration for adding arguments if the field doesn't already have them #3751
### Bug fixes
- fix `rails destroy graphql:install` #3739
- ActionCable subscriptions: close channel when unsubscribing from server #3737
- Mutations: call `.authorized?` on arguments from `input_object_class`, `input_type`, too #3738
- Prevent blank strings with `validates: { length: ... }, allow_blank: false` #3747
- Lexer: return mutable strings when strings are empty #3741
- Errors: don't send execution errors to schema-defined handlers from inside lazies #3749
- Complexity: don't multiple `edges` and `nodes` fields by page size #3758
- Performance: fix validation performance degradation from 1.12.20 #3762
# 1.13.0 (24 November 2021)
Since this version, GraphQL-Ruby is tested on Ruby 2.4+ and Rails 4+ only.
### Breaking changes
- ActionCable Subscriptions: No update is delivered if all subscriptions return `NO_UPDATE` #3713
- Subscription classes: If a subscription has a `scope ...` configuration, then a `scope:` option is required in `.trigger(...)`. Use `scope ..., optional: true` to get the old behavior. #3692
- Arguments whose default values are used aren't checked for authorization #3665
- Complexity: Connection fields have a default complexity implementation based on `first`/`last`/`max_page_size` #3609
- Arguments: if arguments are configured to return `false` for `.visible?(context)`, their default values won't be applied
### New features
- Visibility: A schema may contain multiple members with the same name. For each name, GraphQL-Ruby will use the one that returns true for `.visible?(context)` for each query (and raise an error if multiple objects with the same name are visible). #3651 #3716 #3725
- Dataloader: `nonblocking: true` will make GraphQL::Dataloader use `Fiber.scheduler` to run fields and load data with sources, supporting non-blocking IO. #3482
- `null: true` and `required: true` are now default. GraphQL-Ruby includes some RuboCop cops, `GraphQL/DefaultNullTrue` and `GraphQL/DefaultRequiredTrue`, which identify and remove those needless configurations. #3612
- Interfaces may `implement ...` other interfaces #3613
### Bug fixes
- Enum `value(...)` and Input Object `argument(...)` methods return the defined object #3727
- When a field returns an array of mixed errors and values, the result will contain `nil` where there were errors in the list #3656
# 1.12.24 (4 February 2022)
### Bug fixes
- SDL: fix parsing schemas where types have multiple directives #3886
# 1.12.23 (20 December 2021)
### Bug fixes
- FieldUsage analyzer: handle arguments that raise an error during `prepare:` #3795
# 1.12.22 (8 December 2021)
### Bug fixes
- Static validation: fix regression and improve performance of fields_will_merge validation #3761
# 1.12.21 (23 November 2021)
### Bug fixes
- Validators: Fix `format:`/`allow_blank: true` to correctly accept a blank string #3726
- Generators: generate a correct `Schema.type_error` hook #3722
# 1.12.20 (17 November 2021)
### New Features
- Static validation: improve error messages when fields won't merge #3698
- Generators: improve id_from_object and type_error suggested implementations #3710
- Connections: make the new connections module fall back to old connections #3704
### Bug fixes
- Dataloader: re-enqueue sources when one call to `yield` didn't satisfy their pending requests #3707
- Subscriptions: Fix when JSON-typed arguments are used #3705
# 1.12.19 (5 November 2021)
### New Features
- Argument validation: Make `allow_null` and `allow_blank` work standalone #3671
- Add field and path info to Encoding errors #3697
- Add `Resolver#unauthorized_object` for handling loaded but unauthorized objects #3689
### Bug fixes
- Properly hook up `Schema.validate_max_errors` at runtime #3691
# 1.12.18 (2 November 2021)
### New features
- Subscriptions: Add `NO_UPDATE` constant for skipping subscription updates #3664
- Validation: Add `Schema.validate_max_errors(integer)` for halting validation when it reaches a certain number #3683
- Call `self.load_...` methods on Input objects for loading arguments #3682
- Use `import_methods` in Refinements when available #3674
- `AppsignalTracing`: Add `set_action_name` #3659
### Bug fixes
- Authorize objects returned from custom `def load_...` methods #3682
- Fix `context[:current_field]` when argument `prepare:` hooks raise an error #3666
- Raise a helpful error when a Resolver doesn't have a configured `type(...)` #3679
- Better error message when subscription clients are using ActionCable #3668
- Dataloader: Fix dataloading of input object arguments #3666
- Subscriptions: Fix parsing time zones #3667
- Subscriptions: Fix parsing with non-null arguments #3620
- Authorization: Call `schema.unauthorized_field` for unauthorized resolvers
- Fix when literal `null` is used as a value for a list argument #3660
# 1.12.17 (15 October 2021)
### New features
- Support `extras: [:parent]` #3645
- Support ranges in `NumericalityValidator` #3635
- Add some Dataloader methods for testing #3335
### Bug fixes
- Support input object arguments called `context` #3654
- Support single-item default values for list arguments #3652
- Ensure query strings are strings before running a query #3628
- Fix empty hash kwargs for Ruby 3 #3610
- Fix wrongly detecting Ipnut objects in authorization #3606
# 1.12.16 (31 August 2021)
### New features
- Connections: automatically support Mongoid 7.3 #3599
- Support `def self.topic_for` in Subscription classes for server-filtered streams #3597
- When a list item or object field has an invalid null, stop executing that list or
### Bug fixes
- Perf: don't refine String when unnecessary #3593
- BigInt: always parse as base 10 #3586
- Errors: only return one error when a node in a non-null connection has an invalid null #3601
# 1.12.15 (23 August 2021)
### New Features
- Subscriptions: add support for multi-tenant setups when deserializing context #3574
- Analyzers: also track deprecated arguments #3549
# 1.12.14 (22 July 2021)
### Bug fixes
- SDL: support directive arguments referencing overridden built-in scalars #3564
- Use `"_"` as the name for `field :_, ...` fields #3560
- Support `sanitized_printer(...)` in the schema definition for `Query#sanitized_query_string`
- `GraphQL::Backtrace`: fix multiplex support
# 1.12.13 (20 June 2021)
### Breaking changes
- Add a trailing newline to the `Schema.to_definition` output string #3541
### Bug fixes
- Properly handled list results in GraphQL::Backtrace #3540
- Return plain `Hash`es and `Array`s from queries instead of customized subclasses #3533
- Fix errors raised from non-null fields #3537
- Resolver: don't pass frozen array of extensions when none were configured #3515
- Configure the right `owner` for `node` and `nodes` fields #3509
- Improve error message for invalid enum value #3507
- Properly halt on lazily-returned `context.skip`s #3514
- Fix: call overridden `to_h` methods on InputObject classes #3539
- Halt execution when a runtime directive argument raises a `GraphQL::ExecutionError` #3542
# 1.12.12 (31 May 2021)
### Bug fixes
- Directives on inline fragments and fragment spreads receive `.resolve(...)` calls #3499
# 1.12.11 (28 May 2021)
### Bug fixes
- Validate argument default values when adding them to the schema #3496
- Resolvers inherit extensions from superclasses #3500
- Greatly reduce runtime overhead #3494, #3505
- Remove hidden directives from introspection #3488
# 1.12.10 (18 May 2021)
### New features
- Use `GlobalID::Locator.locate_many` for arrays of global Ids #3481
- Support runtime directives (call `.resolve`) on `QUERY` #3474
### Bug fixes
- Don't override Resolver `#load_*` methods when they're inherited #3486
- Fix validation of runtime directive arguments that have input objects #3485
- Add a final newline to rake task output
- Don't add connection arguments to fields loaded from introspection responses #3470
- Fix `rescue_from` on loading arguments #3471
# 1.12.9 (7 May 2021)
### New features
- Overriding `.authorized_new(...)` to call `.new(...)` effectively skips object authorization #3446
- Dataloader copies Fiber-local values from `Thread.current[...]` when initializing new Fibers #3461
### Bug fixes
- Fix introspection of default value input objects #3456
- Add `StandardError => ...` condition to the generated GraphqlController #3460
- Fix `Dataloader::Source` on Ruby 3 with keyword arguments
- Respect directive visibility at runtime #3450
- ActionCable subscriptions: only deserialize the broadcast payload once #3443
- Don't re-add `graphiql-rails` when `generate graphql:install` is run twice #3441
- Allow differing selections on mutually exclusive interfaces #3063
- Respect `max_page_size: nil` override in fields #3438
# 1.12.8 (12 Apr 2021)
### Bug fixes
- Fix loading single-key hashes in Subscriptions #3428
- Fix looking up `rescue_from` handlers inherited from parent schema classes #3431
# 1.12.7 (7 Apr 2021)
### Breaking changes
- `Execution::Errors` (which implements `rescue_from`) was refactored so that, when an error matches more than one registered handler, it picks the _most specific_ handler instead of the _first match_ in the underlying Hash. This might "break" your code if your application registered a handler for a parent class and a child class, but expects instances of the child class to be handled by the handler for the parent class. (This seems very unlikely -- I consider the change to be a "breaking fix.") #3404
### New features
- Errors: pick the most specific error handlers (instead of an order-dependent selection) #3404
- Add `node_nullable(...)` connection configuration options #3389
- Add `has_nodes_field(true|false)` connection configuration option #3388
- Store more metadata in argument-related static validation errors #3406
### Bug fixes
- Fix connection nullability settings to properly handle `false` #3386
- Fix returning `RawValue`s as part of a list #3403
- Fix introspection for deprecated directive arguments #3416
- Optimize `has_next_page` for ActiveRecord::Relation connections #3414
- Tracing: consistent event sequencing when queries are executed with `Query#result` #3408
# 1.12.6 (11 March 2021)
### Breaking changes
- Static validation: previously, variables passed as arguments to input objects were not properly type-checked. #3370 fixed type checking in this case, but may case existing (invalid) queries to break.
### New features
- Connection types: support `edges_nullable(false)` and `edge_nullable(false)` for non-null fields #3376
- Connections: add `.arguments` reader to new `Pagination::Connection` classes #3360
### Bug fixes
- Relation connection: Remove extra `COUNT` query from some scenarios #3373
- Add a Bootsnap-style parsing cache when Bootsnap is detected #3156
- Fix input validation for input object variables #3370
# 1.12.5 (18 February 2021)
### New features
- Resolvers: support `max_page_size` config #3338
- RangeAdd: call `range_add_edge` (if supported) to improve stable connection support #3341
### Bug fixes
- Backtrace: fix new tracer when analyzing multiplex without executing it #3342
- Dataloader: pass along `throw`s #3333
- Skip possible_types filtering for non-interface types #3336
- Improve debugging message for ListResultFailedError #3339
# 1.12.4 (8 February 2021)
### Bug fixes
- Allow prepended modules to add fields #3325
- Fix ConnectionExtension when another extension short-circuits `resolve` #3326
- Backtrace: Fix GraphQL::Backtrace with static validation (used by graphql-client) #3324
- Dataloader: Fix yield from root fiber when accessing arguments from analyzers. Fix arguments sometimes containing unresolved `Execution::Lazy`s #3320
- Dataloader: properly pass raised errors to `handle_error` handlers #3319
- Fix NameError in validation error #3303
- Dataloader: properly batch when parent fields were not batched #3312
# 1.12.3 (27 January 2021)
### Bug fixes
- Fix constant names for legacy scalar types
# 1.12.2 (26 January 2021)
### New features
- `GraphQL::Deprecation.warn` is used for GraphQL-Ruby 2.0 deprecation warnings (and calls through to `ActiveSupport::Deprecation.warn` if it's available) #3292
# 1.12.1 (25 January 2021)
### Bug fixes
- `GraphQL::Dataloader`: properly support selections with multiple fields #3297
# 1.12.0 (20 January 2021)
### Breaking changes
- `GraphQL::Schema` defaults to `GraphQL::Execution::Interpreter`, `GraphQL::Analysis::AST`, `GraphQL::Pagination::Connections`, and `GraphQL::Execution::Errors`. (#3145) To get the previous (deprecated) behaviors:
```ruby
# Revert to deprecated execution behaviors:
use GraphQL::Execution::Execute
use GraphQL::Analysis
# Disable the new connection implementation:
self.connections = nil
```
- `GraphQL::Execution::Interpreter::Arguments` instances are frozen (#3138). (Usually, GraphQL code doesn't interact with these objects, but they're used some places under the hood.)
### Deprecations
- Many, many legacy classes and methods were deprecated. #3275 Deprecation errors include links to migration documentation. For a full list, see: https://github.com/rmosolgo/graphql-ruby/issues/3056
### New features
- Rails-like argument validations (#3207)
- Fiber-based `GraphQL::Dataloader` for batch-loading data #3264
- Connection and edge behaviors are available as mixins #3071
- Schema definition supports schema directives #3224
### Bug fixes
# 1.11.10 (5 Nov 2021)
### Bug fixes
- Properly hook up `Schema.max_validation_errors` at query runtime #3690
# 1.11.9 (1 Nov 2021)
### New Features
- `Schema.max_validation_errors(val)` limits the number of errors that can be added during static validation #3675
# 1.11.8 (12 Feb 2021)
### Bug fixes
- Improve performance of `Schema.possible_types(t)` for object types #3172
# 1.11.7 (18 January 2021)
### Breaking changes
- Incoming integer values are properly bound (as per the spec) #3206 To continue receiving out-of-bound integer values, add this to your schema's `def self.type_error(err, ctx)` hook:
```ruby
def self.type_error(err, ctx)
if err.is_a?(GraphQL::IntegerDecodingError)
return err.integer_value # return it anyways, since this is how graphql-ruby used to work
end
# ...
end
```
### New features
- Support Ruby 3.0 #3278
- Add validation timeout option #3234
- Support Prometheus custom_labels in GraphQLCollector #3215
### Bug fixes
- Handle `GraphQL::UnauthorizedError` in interpreter in from arguments #3276
- Set description for auto-generated `input:` argument #3141
- Improve performance of fields will merge validation #3228
- Use `Float` graphql type for ActiveRecord decimal columns #3246
- Add some custom methods to ArrayConnection #3238
- Fix generated fields for types ending Connection #3223
- Improve runtime performance #3217
- Improve argument handling when extensions shortcut the defined resolve #3212
- Bind scalar ints as per the spec #3206
- Validate that input object names are unique #3205
## 1.11.6 (29 October 2020)
### Breaking changes
FieldExtension: pass extended values instead of originals to `after_resolve` #3168
### Deprecations
### New features
- Accept additional options in `global_id_field` macro #3196
### Bug fixes
- Use `graphql_name` in `UnauthorizedError` default message (fixes #3174) #3176
- Improve error handling for base 64 decoding (in `UniqueWithinType`) #3179
- Fix `.valid_isolated_input?` on parsed schemas (fixes #3181) #3182
- Fix fields nullability in subscriptions documentation #3194
- Update `RangeAdd` to use new connections when available #3195
## 1.11.5 (30 September 2020)
### New features
- SanitizedPrinter: accept `inline_variables: false` option and add `#redact_argument_value?` and `#redacted_argument_value` hooks #3167
- GraphQL::Schema::Timeoout#max_seconds(query) can provide a per-query timeout duration #3167
- Implement Interpreter::Arguments#fetch
- Assign `current_{path,field,arguments,object}` in `query.context` #3139. The values at these keys change while the query is running.
- ActionCableSubscriptions: accept `use(..., namespace: "...")` for running multiple schemas in the same application #3076
- Add `deprecation_reason:` to arguments #3015
### Bug fixes
- SanitizedPrinter: Fix lists and JSON scalars #3171
- Improve retained memory in Schema.from_definition #3153
- Make it easier to cache schema parsing #3153
- Make sure deprecated arguments aren't required #3137
- Use `.empty?` instead of `.length.zero?` in lexer #3134
- Return a proper error when a stack error happens #3129
- Assert valid input types on arguments #3120
- Improve Validator#validate performance #3125
- Don't wrap `RawValue` in ConnectionExtension #3122
- Fix interface possible types visibility #3124
## 1.11.4 (24 August 2020)
### Breaking changes
### New features
- Add `node_nullable` option for `edge_type` #3083
- Use module namespacing for template generators #3098
### Bug fixes
- Rescue `SystemStackError`s during validation #3107
- Add `require 'digest/sha2'` for fingerprint #3103
- Optimize `GraphQL::Query::Context#dig` #3090
- Check if new connections before calling method on it (fixes #3059) #3100
- Thread field owner type through interpreter runtime (fixes #3086) #3099
- Check for visible interfaces on the type in warden #3096
- Update `AppOpticsTracing` with latest changes in `PlatformTracing` #3097
- Use throw instead of raise to halt subscriptions early #3084
- Optimize `GraphQL::Query::Context#fetch` #3081
## 1.11.3 (13 August 2020)
### Breaking changes
- Reverted the `required` and `default_value` argument behaviour change in 1.11.2 since it was not spec compliant #3066
### New features
- Improve resolver method conflict warning #3069, #3062
- Store arguments on `Mutation` instances after they're loaded #3073
### Bug fixes
- Fix connection wrappers on lazy lists #3070
## 1.11.2 (1 August 2020)
### Breaking changes
- Previously, GraphQL-Ruby allowed _both_ `default_value: ...` and `required: true` in argument definitions. However, this definition doesn't make sense -- a default value is never used for a `required: true` argument. This configuration now raises an error. Remove the `default_value:` to get rid of the error. #3011
### New features
- Support Date, Time and OpenStruct in Subscription::Serialize #3057
### Bug fixes
- Speed up `DELETE_NODE` check #3053
- Reject invalid enum values during definition #3055
- Fix `.trigger` from unsubscribed ActionCable channel #3051
- Fix error message from VariablesAreUsedAndDefined for anonymous queries #3050
- Fix renaming variable identifiers in AST visitor #3045
- Reject `default_value: ...` used with `required: true` during definition #3011
- Use the configured `edge_class:` with new connections #3036
- Don't call visible for unused arguments #3030, #3031
- Properly load directives from introspection results #3021
- Reject interfaces as members of unions #3024
- Load deprecation reason from introspection results #3014
- Fix arguments caching when extension modify arguments #3009
## 1.11.1 (17 June 2020)
### New Features
- Add `StatsdTracing` #2996
### Bug Fixes
- Raise the proper `InvalidNullError` when a mutation field returns an invalid `nil` #2997
## 1.11.0 (13 June 2020)
### Breaking changes
- Global tracers are removed (deprecated since 1.7.4) #2936
- Fields defined in camel case (`field :doStuff`) will not line up to methods that are underscore case (`def do_stuff`). Instead, the given symbol is used _verbatim_. #2938 To work around this:
- Change the name of the method to match the field (eg, `def doStuff`)
- Change the name of the field to match the method (eg, `field :do_stuff`, let graphql-ruby camelize it for you)
- Or, add `resolver_method: :do_stuff` to explicitly map the field to a method on the object type definition
You can probably find instances of this in your application with a regexp like `/field :[a-z]+[A-Z]/`, and review them.
### New features
- `extend SubscriptionRoot` is no longer necessary #2770
- Add `broadcast: true` option to subscriptions #2959
- Add `Edge#parent` to new connection classes #2961
### Bug fixes
- Use the field name as configured for hash key or method name #2906
## 1.10.12 (13 June 2020)
### Bug fixes
- Fix compatibility of `YYYY-mm-dd` with `Types::ISO8601DateTime` #2989
- Remove unused ivar in InputObject #2987
## 1.9.21 (12 June 2020)
### Bug fixes
- Fix `extras:` on subscription fields #2983
## 1.10.11 (11 June 2020)
### New features
- Scout tracer adds transaction name to traces #2969
- `resolve_type` can optionally return a resolved object #2976
- DateTime scalar returns a `Time` for better timezone handling #2973
- Interpreter memory improvements #2980, #2978
- Support lazy values from field-level authorization hooks #2977
- Object generator infers fields from model classes #2954
- Add type-specific runtime errors #2957
### Bug fixes
- Fix for error when using `extras:` with subscription fields #2984
- Improve Schema.error_handler inheritance #2975
- Add raw_value to conflict warning list #2958
- Arguments#each_value yields ArgumentValues #2956
## 1.10.10 (20 May 2020)
### Bug Fixes
- Fix lazy `loads:` with list arguments #2949
- Show object fields even when inherited ones are hidden #2950
- Use `reverse_each` in instrumenters #2945
- Fix underscored names in introspection loader #2941
- Fix array input to Date/DateTime types #2927
- Fix method conflict warnings on schema loader #2934
- Fix some Ruby 2.7 warnings #2925
## 1.9.20 (20 May 2020)
### Bug fixes
- Fix `default_value: {}` on Ruby 2.7
## 1.10.9 (4 May 2020)
### New features
- Add `Interpreter::Arguments#dig` #2912
## 1.10.8 (27 April 2020)
### Breaking changes
- With the interpreter, `Query#arguments_for` returns `Interpreter::Arguments` instances instead of plain hashes. (They should work mostly the same, though.) #2881
### New features
- `Schema::Field#introspection?` returns true for built-in introspection-related fields
### Bug fixes
- Fix Ruby 2.7 warning on `Schema.to_json` #2905
- Pass `&block` to nested method calls to reduce stack depths #2900
- Fix lazy `loads:` with list arguments #2894
- Fix `loads:` on nested input object #2895
- Rescue base64 encoding errors in the encoder #2896
## 1.10.7 (16 April 2020)
### Breaking changes
- `Schema.from_introspection(...)` builds class-based schemas #2876
### New features
- `Date` and `DateTime` types also accept well-formatted strings #2848
- `Schema.from_introspection(...)` builds class-based schemas #2876
- `Schema#to_definition` now dumps all directives that were part of the original IDL, if the schema was parsed with `.from_definition` #2879
### Bug fixes
- Fix memory leak in legacy runtime #2884
- Fix interface inheritance in legacy runtime #2882
- Fix description on `List` and `NonNull` types (for introspection) #2875
- Fix over-rescue of NoMethodError when building list responses #2887
## 1.10.6 (6 April 2020)
### New features
- Add options to `implements(...)` and inteface type visibility #2791
- Add `Query#fingerprint` for logging #2859
- Add `--playground` option to install generator #2839
- Support lazy-loaded objects from input object `loads:` #2834
### Bug fixes
- Fix `Language::Nodes` equality: move `eql?` to `==` #2861
- Make rake task properly detect rails `environment` task #2862
- Fix `nil` override for `max_page_size` #2843
- Fix `pageInfo` methods when they're called before `nodes` #2845
- Make the default development error match a normal GraphQL error #2825
- Fix `loads:` with `require: false` #2833
- Fix typeerror for `BigInt` given `nil` #2827
## 1.10.5 (12 March 2020)
### New features
- Add `#field_complexity` hook to `AST::QueryComplexity` analyzer #2807
### Bug fixes
- Pass `nonce: true` when encoding cursors #2821
- Ignore empty-string cursors #2821
- Properly pass along `Analysis::AST` to schema instances #2820
- Support filtering unreachable types in schemas from IDL #2816
- Use `Query#arguments_for` for lookahead arguments #2811
- Fix pagination bug on old connections #2799
- Support new connection system on old runtime #2798
- Add details to raise CoercionErrors #2796
## 1.10.4 (3 March 2020)
### Breaking changes
- When an argument is defined with a symbol (`argument :my_arg, ...`), that symbol is used _verbatim_ to build Ruby keyword arguments. Previously it was converted to underscore-case, but this autotransform was confusing and wrong in some cases. You may have to change the symbol in your `argument(...)` configuration if you were depending on that underscorization. #2792
- Schemas from `.from_definition` previously had half-way connection support. It's now completely removed, so you have to add connection wrappers manually. See #2782 for migration notes.
### New features
- Add `Appoptics` tracing #2789
- Add `Query#sanitized_query_string` #2785
- Improved duplicate type error message #2777
### Bug fixes
- Fix arguments ending in numbers, so they're injected with the same name that they're configured with #2792
- Improve `Query#arguments_for` with interpreter #2781
- Fix visitor replacement of variable definitions #2752
- Remove half-broken connection handling from `Schema.from_definition` #2782
## 1.10.3 (17 Feb 2020)
### New features
- Support `loads:` with plain field arguments #2720
- Support `raw_value(...)` to halt execution with a certain value #2699
- `.read_subscription` can return `nil` to bypass executing a subscription #2741
### Bug fixes
- Connection wrappers are properly inherited #2750
- `prepare(...)` is properly applied to default values in subscription fields #2748
- Code tidying for RSpec warnings #2741
- Include new analysis module when generating a schema #2734
- Include directive argument types in printed schemas #2733
- Use `module_parent_name` in Rails #2713
- Fix overriding default scalars in build_from_definition #2722
- Fix some non-null errors in lists #2651
## 1.10.2 (31 Jan 2020)
### Bug fixes
- Properly wrap nested input objects in instances #2710
## 1.10.1 (28 Jan 2020)
### Bug fixes
- Include Interface-level `orphan_types` when building a schema #2705
- Properly re-enter selections in complexity analyzer #2595
- Fix input objects with null values #2690
- Fix default values of `{}` in `.define`-based schemas #2703
- Fix field extension presence check #2689
- Make new relation connections more efficient #2697
- Don't include fields `@skip(if: true)` or `@include(if: false)` in lookahead #2700
## 1.9.19 (28 Jan 2020)
### Bug Fixes
- Fix argument default value of `{}` with Ruby 2.7 argument handling #2704
## 1.10.0 (20 Jan 2020)
### Breaking Changes
- Class-based schemas using the new interpreter will now use _definition classes_ at runtime. #2363 (Previously, `.to_graphql` methods were used to generate singletons which were used at runtime.) This means:
- Methods that used to receive types at runtime will now receive classes instead of those singletons.
- `.name` will now call `Class#name`, which will give the class name. Use `.graphql_name` to get the name of a GraphQL type. (Fields, arguments and directives have `.graphql_name` too, so you can use it everywhere.)
- Some methods that return hashes are slow because they merge hashes according to class inheritance, for example `MySchema.types` and `MyObjectType.fields`. Instead:
- If you only need one item out of the Hash, use `.get_type(type_name)` or `.get_field(field_name)` instead. Those methods find a match without performing Hash merges.
- If you need the whole Hash, get a cached value from `context.warden` (an instance of `GraphQL::Schema::Warden`) at runtime. Those values reflect the types and fields which are permitted for the current query, and they're cached for life of the query. Check the API docs to see methods on the `warden`.
- Class-based schemas using the interpreter _must_ add `use GraphQL::Analysis::AST` to their schema (and update their custom analyzers, see https://graphql-ruby.org/queries/ast_analysis.html) #2363
- ActiveSupport::Notifications events are correctly named in event.library format #2562
- Field and Argument `#authorized?` methods now accept _three_ arguments (instead of 2). They now accept `(obj, args, ctx)`, where `args` is the arguments (for a field) or the argument value (for an argument). #2520
- Double-null `!!` is disallowed by the parser #2397
- (Non-interpreter only) The return value of subscription fields is passed along to execute the subscription. Return `nil` to get the previous behavior. #2536
- `Schema.from_definition` builds a _class-based schema_ from the definition string #2178
- Only integers are accepted for `Int` type #2404
- Custom scalars now call `.coerce_input` on all input values - previously this call was skipped for `null` values.
### Deprecations
- `.define` is deprecated; class-based schema definitions should be used instead. If you're having trouble or you can't find information about an upgrade path, please open an issue on GitHub!
### New Features
- Add tracing events for `.authorized?` and `.resolve_type` calls #2660
- `Schema.from_definition` accepts `using:` for installing plugins (equivalent to `use ...` in class-based schemas) #2307
- Add `$` to variable names in error messages #2531
- Add invalid value to argument error message #2531
- Input object arguments with `loads:` get the loaded object in their `authorized?` hook, as `arg` in `authorized?(obj, args, ctx)`. #2536
- `GraphQL::Pagination` auto-pagination system #2143
- `Schema.from_definition` builds a _class-based schema_ from the definition string #2178
### Bug Fixes
- Fix warnings on Ruby 2.7 #2668
- Fix Ruby keyword list to support Ruby 2.7 #2640
- Reduce memory of class-based schema #2636
- Improve runtime performance of interpreter #2630
- Big numbers (ie, greater than Ruby's `Infinity`) no longer :boom: when being reserialized #2320
- Fix `hasNextPage`/`hasPrevious` page when max_page_size limits the items returned #2608
- Return parse errors for empty documents and empty argument lists #2344
- Properly serialize `defaultValue` of input objects containing enum values #2439
- Don't crash when a query contains `!!`. #2397
- Resolver `loads:` assign the value to argument `@loads` #2364
- Only integers are accepted for `Int` type #2404
## 1.9.18 (15 Jan 2020)
### New features
- Support disabling `__type` or `__schema` individually #2657
- Support Ruby 2.7, and turn on CI for it :tada: #2665
### Bug fixes
- Fix Ruby 2.7 warnings #2653 #2669
- Properly build camelized names for directive classes #2666
- Use schema-defined context class for SDL generation #2656
- Apply visibility checks when generating SDL #2637
## 1.9.17 (17 Dec 2019)
### New features
- Scoped context for propagating values to child fields #2634
- Add `type_membership_class` with possible_type visibility #2391
### Bug fixes
- Don't return unreachable types in introspection response #2596
- Wrap more of execution with error handling #2632
- Fix InputObject `.prepare` for the interpreter #2624
- Fix Ruby keyword list to support Ruby 2.7 #2640
- Fix performance of urlsafe_encode64 backport #2643
## 1.9.16 (2 Dec 2019)
### Breaking changes
- `GraphQL::Schema::Resolver#initialize` accepts a new keyword argument, `field:`. If you have overriden this method, you'll have to add that keyword to your argument list (and pass it along to `super`.) #2605
### Deprecations
- `SkylightTracing` is disabled; the Skylight agent contains its own GraphQL support. See Skylight's docs for migration. #2601
### New features
### Bug fixes
- Fix multiplex max_depth calculation #2613
- Use monotonic time in TimeoutMiddleware #2622
- Use underscored names in Mutation generator #2617
- Fix lookahead when added to mutations in their `field(...)` definitions #2605
- Handle returned lists of errors from Mutations #2567
- Fix lexer error on block strings containing only newlines #2598
- Fix mutation generator to reference the new base class #2580
- Use the right camelization configuration when generating subscription topics #2552
## 1.9.15 (30 Oct 2019)
### New features
- Improve parser performance #2572
- Add `def prepare` API for input objects #1869
- Support `extensions` config in Resolver classes #2570
- Support custom `.connection_extension` in field classes #2561
- Warn when a field name is a Ruby keyword #2559
- Improve performance for ActiveRecord connection #2547
### Bug fixes
- Fix errantly generated `def resolve_field` method in `BaseField` #2578
- Comment out the `null_session` handling in the generated controller, for better compat with Rails API mode #2557
- Fix validation error with duplicate, self-referencing fragment #2577
- Revert the `.authorized?` behavior of InputObjects to handle cyclical references. See 1.10.0.pre1 for a better behavior. #2576
- Replace `NotImplementedError` (which is meant for operating system APIs) with `GraphQL::RequiredImplementationMissingError` #2543
## 1.9.14 (14 Oct 2019)
### New features
- Add `null_session` CSRF handing in `install` generator #2524
- Correctly report InputObjects without arguments and Objects without fields as invalid #2539 #2462
### Bug fixes
- Fix argument incompatibility #2541
- Add a `require` for `Types::ISO8691Date` #2528
- Fix errors re-raised after lazy fields #2525
## 1.9.13 (8 Oct 2019)
### Breaking changes
- Enum values were (erroneously) accepted as ID or String values, but they aren't anymore. #2505
### New features
- Add `Query#executed?` #2486
- Add `Types::ISO8601Date` #2471
### Bug fixes
- Don't accept Enums as IDs or Strings #2505
- Call `.authorized?` hooks on arguments that belong to input objects #2519
- Fix backslash parsing edge case #2510
- Improve performance #2504 #2498
- Properly stringify keys in error extensions #2508
- Fix `extras:` handling in RelayClassicMutation #2484
- Use `Types::BaseField` in scaffold #2470
## 1.9.12 (9 Sept 2019)
### Breaking Changes
- AST Analyzers follow fragments spreads as if they were inline fragments. #2463
### New Features
- `use GraphQL::Execution::Errors` provides error handling for the new interpreter. #2458
### Bug Fixes
- Fix false positive on enum value validation #2454
## 1.9.11 (29 Aug 2019)
### Breaking Changes
- Introspection fields are now considered for query depth validations, so you'll need at least `max_depth: 13` to run the introspection query #2437
### New features
- Add `extras` setter to `GraphQL::Schema::Field` #2450
- Add extensions in `CoercionError` #2431
### Bug fixes
- Make `extensions` kwarg on field on more flexible for extensions with options #2443
- Fix list validation error handling #2441
- Include introspective fields in query depth calculations #2437
- Correct the example for using 'a class method to generate fields' #2435
- Enable multiple execution errors for Fields defined to return a list #2433
## 1.9.10 (20 Aug 2019)
### New features
- Support required arguments with default values #2416
### Bug fixes
- Properly disable `max_complexity` and `max_depth` when `nil` is passed #2409
- Fix printing class-based schemas #2406
- Improve field method naming conflict check #2420
## 1.9.9 (30 July 2019)
### New features
- Memoize generated strings in `.to_query_string` #2400
- Memoize generated strings in platform tracing #2401
### Bug fixes
- Support class-based subscription type in `.define`-based schema #2403
## 1.9.8 (24 July 2019)
### New features
- Schema classes pass their configuration to subclasses #2384
- Improve memory consumption of lexer and complexity validator #2389
- The `install` generator creates a BaseArgument #2379
- When a field name conflicts with a built-in method name, give a warning #2376
### Bug fixes
- When a resolver argument uses `loads:`, the argument definition will preserve the type in `.loads` #2365
- When an required argument is hidden, it won't add a validation error #2393
- Fix handling of invalid UTF-8 #2372, #2377
- Empty block strings are parsed correctly #2381
- For resolvers, only authorize arguments once #2378
## 1.9.7 (25 June 2019)
### Breaking changes
- `Analysis::AST::Visitor#argument_definition` no longer returns the _previous_ argument definition. Instead, it returns the _current_ argument definition and `#previous_argument_definition` returns the previous one. You might have to replace calls to `.argument_definition` with `.previous_argument_definition` for compatibility. #2226
### New features
- Accept a `subscription_scope` configuration in Subscription classes #2297
- Add a `disable_introspection_entry_points` configuration in Schema classes #2327
- Add `Analysis::AST::Visitor#argument_definition` which returns the _current_ argument definition, `#previous_argument_definition` returns the _previous_ one #2226
- Run CI on Ruby 2.6 #2328
- Autogenerate base field class #2216
- Add timeout support with interpreter #2220
### Bug fixes
- Fix Stack overflow when calling `.to_json` on input objects #2343
- Fix off-by-one error with hasNextPage and ArrayConnections #2349
- Fix GraphQL-Pro operation store compatibility #2350
- Fix class-based transformer when multiple mutations are in one file #2309
- Use `default_graphql_name` for Edge classes #2224
- Support nested `loads:` with input objects #2323
- Support `max_complexity` with multiplex & AST analysis #2306
## 1.9.6 (23 May 2019)
### Bug fixes
- Backport `String#-@` for Ruby 2.2 support #2305
## 1.9.5 (22 May 2019)
### New features
- Support `rescue_from` returning `GraphQL::ExecutionError` #2140
- Accept `context:` in `Schema.validate` #2256
- Include `query:` in interpreter tracing for `execute_field` and `execute_field_lazy` #2236
- Add `Types::JSON` #2227
- Add `null:` option to `BaseEdge.node_type` #2249
### Bug fixes
- Fix Ruby 2.2 compatibility #2302
- Distinguish aliased selections in lookahead #2266
- Properly show list enum default values in introspection #2263
- Performance improvements: #2289, #2244, #2258, #2257, #2240
- Don't recursively unwrap inputs for RelayClassicMutation #2236
- Fix `Schema::Field#scoped?` when no return type #2255
- Properly forward more authorization errors #2165
- Raise `ParseError` for `.parse(nil)` #2238
## 1.9.4 (5 Apr 2019)
### Breaking Changes
- `GraphQL::Schema::Resolver::LoadApplicationObjectFailedError` was renamed to `GraphQL::LoadApplicationObjectFailedError`. (This will only break if you're referencing the class by name and running Ruby 2.5+) #2080
### New features
- Add `Types::BigInt` #2150
- Add auto-loading arguments support in Input Object types #2080
- Add analytics tag to Datadog tracing #2154
### Bug fixes
- Fix `Query#execute` when no explicit query string is passed in #2142
- Fix when a root type returns nil because unauthorized #2144
- Fix tracing `node` by threading `owner:` through field tracing #2156
- Fix interpreter handling of exceptions raised during argument preparation #2198
- Fix ActionCableLink when there are errors but no data #2176
- Provide empty hash as default option for field resolvers #2189
- Prevent argument names from overwriting Arguments methods #2171
- Include array indices in error paths #2162
- Handle non-node arrays in AST visitor #2161
## 1.9.3 (20 Feb 2019)
### Bug fixes
- Fix `Schema::Subscription` when it has no arguments #2135
- Don't try to scope `nil`, just skip scoping altogether #2134
- Fix when a root `.authorized?` returns `false` and there's no `root_value` #2136
- Fix platform tracing with interpreter & introspection #2137
- Support root Subscription types with name other than `Subscription` #2102
- Fix nested list-type input object nullability validation #2123
## 1.9.2 (15 Feb 2019)
### Bug fixes
- Properly support connection fields with resolve procs #2115
## 1.9.1 (14 Feb 2019)
### Bug fixes
- Properly pass errors to Resolver `load_application_object_failed` methods #2110
## 1.9.0 (13 Feb 2019)
### Breaking Changes
- AST nodes are immutable. To modify a parsed GraphQL query, see `GraphQL::Language::Visitor` for its mutation API, which builds a new AST with the specified mutations applied. #1338, #1740
- Cursors use urlsafe Base64. This won't break your clients (it's backwards-compatible), but it might break your tests, so it's listed here. #1698
- Add `field(..., resolver_method:)` for when GraphQL-Ruby should call a method _other than_ the one whose name matches the field name (#1961). This means that if you're using `method:` to call a different method _on the Schema::Object subclass_, you should update that configuration to `resolver_method:`. (`method:` is still used to call a different method on the _underlying application object_.)
- `Int` type now applies boundaries as [described in the spec](https://facebook.github.io/graphql/June2018/#sec-Int) #2101. To preserve the previous, unbounded behavior, handle the error in your schema's `.type_error(err, ctx)` hook, for example:
```ruby
class MySchema < GraphQL::Schema
def self.type_error(err, ctx)
if err.is_a?(GraphQL::IntegerEncodingError)
# Preserve the previous unbounded behavior
# by returning the out-of-bounds value
err.integer_value
else
super
end
end
end
```
- `field(...)` configurations don't create implicit method definitions (#1961). If one resolver method depended on the implicitly-created method from another field, you'll have to refactor that call or manually add a `def ...` for that field.
- Calling `super` in a field method doesn't work anymore (#1961)
- Error `"problems"` are now in `"extensions" : { "problems": ... }` #2077
- Change schema default to `error_bubbling false` #2069
### New Features
- Add class-based subscriptions with `GraphQL::Schema::Subscription` #1930
- Add `GraphQL::Execution::Interpreter` (#1394) and `GraphQL::Analysis::AST` (#1824) which together cut GraphQL overhead by half (time and memory)
- Add `Schema.unauthorized_field(err)` for when `Field#authorized?` checks fail (#1994)
- Add class-based custom directives for the interpreter (#2055)
- Add `Schema::FieldExtension` for customizing field execution with class-based fields #1795
- Add `Query#lookahead` for root-level selection info #1931
- Validation errors have `"extensions": { ... }` which includes metadata about that error #1970
### Bug fixes
- Fix list-type arguments passed with a single value #2085
- Support `false` as an Enum value #2050
- Support `hash_key:` fields when the key isn't a valid Ruby method name #2016
## 1.8.15 (13 Feb 2019)
### Bug fixes
- Fix unwrapping inputobject types when turning arguments to hashes #2094
- Support lazy objects from `.resolve_type` hooks #2108
## 1.8.14 (9 Feb 2019)
### Bug Fixes
- Fix single-item list inputs that aren't passed as lists #2095
## 1.8.13 (4 Jan 2019)
### Bug fixes
- Fix regression in block string parsing #2032
## 1.8.12 (3 Jan 2019)
### Breaking changes
- When an input object's argument has a validation error, that error is reported on the _argument_ instead of its parent input object. #2013
### New features
- Add `error_bubbling false` Schema configuration for nicer validation of compound inputs #2013
- Print descriptions as block strings in SDL #2011
- Improve string-to-constant resolution #1810
- Add `Query::Context#to_hash` for splatting #1955
- Add `#dig` to `Schema::InputObject` and `Query::Arguments` #1968
- Add `.*_execution_strategy` methods to class-based schemas #1914
- Accept multiple errors when adding `.rescue_from` handlers #1991
### Bug fixes
- Fix scalar tracing in NewRelic and Skylight #1954
- Fix lexer for multiple block strings #1937
- Add `unscope(:order)` when counting relations #1911
- Improve build-from-definition error message #1998
- Fix regression in legacy compat #2000
## 1.8.11 (16 Oct 2018)
### New features
- `extras: [:lookahead]` injects a `GraphQL::Execution::Lookahead`
### Bug fixes
- Fix type printing in Printer #1902
- Rescue `GraphQL::ExecutionError` in `.before_query` hooks #1898
- Properly load default values that are lists of input objects from the IDL #1874
## 1.8.10 (21 Sep 2018)
### Bug fixes
- When using `loads:` with a nullable mutation input field, allow `null` values to be provided. #1851
- When an invalid Base64 encoded cursor is provided, raise a `GraphQL::ExecutionError` instead of `ArgumentError`. #1855
- Fix an issue with `extras: [:path]` would use the field's `path` instead of the `context`. #1859
### New features
- Add scalar type generator `rails g graphql:scalar` #1847
- Add `#dig` method to `Query::Context` #1861
## 1.8.9 (13 Sep 2018)
### Breaking changes
- When `field ... ` is called with a block and the block has one argument, the field is yielded, but `self` inside the block is _not_ changed to the field. #1843
### New features
- `extras: [...]` can inject values from the field instance #1808
- Add `ISO8601DateTime.time_precision` for customization #1845
- Fix input objects with default values of enum #1827
- `Schema.sync_lazy(value)` hook for intercepting lazy-resolved objects #1784
### Bug fixes
- When a field block is provided with an arity of `1`, yield the field #1843
## 1.8.8 (27 Aug 2018)
### Bug fixes
- When using `RelayClassicMutation`, `client_mutation_id` will no longer be passed to `authorized?` method #1771
- Fix issue in schema upgrader script which would cause `.to_non_null_type` calls in type definition to be ignored #1783
- Ensure enum values respond to `graphql_name` #1792
- Fix infinite resolution bug that could occur when an exception not inheriting from `StandardError` is thrown #1804
### New features
- Add `#path` method to schema members #1766
- Add `as:` argument to allow overriding the name of the argument when using `loads:` #1773
- Add support for list of IDs when using `loads:` in an argument definition #1797
## 1.8.7 (9 Aug 2018)
### Breaking changes
- Some mutation authorization hooks added in 1.8.5 were changed, see #1736 and #1737. Roughly:
- `before_prepare` was changed to `#ready?`
- `validate_*` hooks were replaced with a single `#authorized?` method
### Bug fixes
- Argument default values include nested default values #1728
- Clean up duplciate method defs #1739
### New features
- Built-in support for Mongoid 5, 6, 7 #1754
- Mutation `#ready?` and `#authorized?` may halt flow and/or return data #1736, #1737
- Add `.scope_items(items, ctx)` hook for filtering lists
- Add `#default_graphql_name` for overriding default logic #1729
- Add `#add_argument` for building schemas #1732
- Cursors are decoded using `urlsafe_decode64` to future-proof for urlsafe cursors #1748
## 1.8.6 (31 July 2018)
### Breaking changes
- Only allow Objects to implement actual Interfaces #1715. Use `include` instead for plain Ruby modules.
- Revert extending interface methods onto Objects #1716. If you were taking advantage of this feature, you can create a plain Ruby module with the functionality and include it in both the interface and object.
### Deprecations
### New features
- Support string descriptions (from June 2018 GraphQL spec) #1725
- Add some accessors to Schema members #1722
- Yield argument for definition block with arity of one #1714
- Yield field for definition blocks with arity of one #1712
- Support grouping by "endpoint" with skylight instrumentation #1663
- Validation: Don't traverse irep if no handlers are registered #1696
- Add `nodes_field` option to `edge_type` to hide nodes field #1693
- Add `GraphQL::Types::ISO8601DateTime` to documentation #1694
- Conditional Analyzers #1690
- Improve error messages in `ActionCableSubscriptions` #1675
- Add Prometheus tracing #1672
- Add `map` to `InputObject` #1669
### Bug fixes
- Improve the mutation generator #1718
- Fix method inheritance for interfaces #1709
- Fix Interface inheritance chain #1686
- Fix require in `tracing.rb` #1685
- Remove delegate for `FieldResolutionContext#schema` #1682
- Remove duplicated `object_class` method #1667
## 1.8.5 (10 July 2018)
### Breaking changes
- GraphQL validation errors now include `"filename"` if the parsed document had a `filename` #1618
### Deprecations
- `TypeKind#resolves?` is deprecated in favor of `TypeKind#abstract?` #1619
### New features
- Add Mutation loading/authorization system #1609
- Interface `definition_methods` are inherited by object type classes #1635
- include `"filename"` in GraphQL errors if the parsed document has a filename #1618
- Add `Schema::InputObject#empty?` #1651
- require `ISO8601DateTime` by default #1660
- Support `extend` in the parser #1620
- Improve generator to have nicer error handling in development
### Bug fixes
- Fix `@skip`/`@include` with default value of `false` #1617
- Fix lists of abstract types with promises #1613
- Don't check the type of `nil` when it's in a list #1610
- Fix NoMethodError when `variables: nil` is passed to `execute(...)` #1661
- Objects returned from `Schema.unauthorized_objects` are properly wrapped by their type proxies #1662
## 1.8.4 (21 June 2018)
### New features
- Add class-based definitions for Relay types #1568
- Add a built-in auth system #1494
### Bug fixes
- Properly rescue coercion errors in variable values #1602
## 1.8.3 (14 June 2018)
### New features
- Add an ISO 8601 DateTime scalar: `Types::ISO8601DateTime`. #1566
- Use classes under the hood for built-in scalars. These are now accessible via `Types::` namespace. #1565
- Add `possible_types` helpers to abstract types #1580
### Bug fixes
- Fix `Language::Visitor` when visiting `InputObjectTypeDefinition` nodes to include child `Directive` nodes. #1584
- Fix an issue preventing proper subclassing of `TimeoutMiddleware`. #1579
- Fix `graphql:interface` generator such that it generates working code. #1577
- Update the description of auto-generated `before` and `after` arguments to better describe their input type. #1572
- Add `Language::Nodes::DirectiveLocation` AST node to represent directive locations in directive definitions. #1564
## 1.8.2 (6 June 2018)
### Breaking changes
- `Schema::InputObject#to_h` recursively transforms hashes to underscorized, symbolized keys. #1555
### New features
- Generators create class-based types #1562
- `Schema::InputObject#to_h` returns a underscorized, symbolized hash #1555
### Bug fixes
- Support `default_mask` in class-based schemas #1563
- Fix null propagation for list types #1558
- Validate unique arguments in queries #1557
- Fix `RelayClassicMutation`s with no arguments #1543
## 1.8.1 (1 June 2018)
### Breaking changes
- When filtering items out of a schema, Unions will now be hidden if their possible types are all hidden or if all fields returning it are hidden. #1515
### New features
- `GraphQL::ExecutionError.new` accepts an `extensions:` option which will be merged into the `"extensions"` key in that error's JSON #1552
### Bug fixes
- When filtering items out of a schema, Unions will now be hidden if their possible types are all hidden or if all fields returning it are hidden. #1515
- Require that fields returning interfaces have selections made on them #1551
- Correctly mark introspection types and fields as `introspection?` #1535
- Remove unused introspection objects #1534
- use `object`/`context` in the upgrader instead of `@object`/`@context` #1529
- (Development) Don't require mongodb for non-mongo tests #1548
- Track position of union member nodes in the parser #1541
## 1.8.0 (17 May 2018)
`1.8.0` has been in prerelease for 6 months. See the prerelease changelog for change-by-change details. Here's a high-level changelog, followed by a detailed list of changes since the last prerelease.
### High-level changes
#### Breaking Changes
- GraphQL-Ruby is not tested on Ruby 2.1. #1070 Because Ruby 2.1 doesn't garbage collect Symbols, it's possible that GraphQL-Ruby will introduce a OOM vulnerability where unique symbols are dynamically created, for example, turning user input into Symbols. No instances of this are known in GraphQL-Ruby ... yet!
- `GraphQL::Delegate`, a duplicate of Ruby's `Forwardable`, was removed. Use `Forwardable` instead, and update your Ruby if you're on `2.4.0`, due to a performance regression in `Forwardable` in that version.
- `MySchema.subscriptions.trigger` asserts that its inputs are valid arguments #1400. So if you were previously passing invalid options there, you'll get an error. Remove those options.
#### New Features
- A new class-based API for schema definition. The old API is completely supported, but the new one is much nicer to use. If you migrate, some schema extensions may require a bit of extra work.
- Built-in support for Mongoid-backed Relay connections
- `.execute(variables: ...)` and `subscriptions.trigger` both accept Symbol-keyed hashes
- Lots of other small things around SDL parsing, tracing, runtime ... everything. Read the details below for a full list.
#### Bug Fixes
- Many, many bug fixes. See the detailed list if you're curious about specific bugs.
### Changes since `1.8.0.pre11`:
#### Breaking Changes
- `GraphQL::Schema::Field#initialize`'s signature changed to accept keywords and a block only. `type:`, `description:` and `name:` were moved to keywords. See `Field.from_options` for how the `field(...)` helper's arguments are merged to go to `Field.new`. #1508
#### New Features
- `Schema::Resolver` is a replacement for `GraphQL::Function` #1472
- Fix subscriptions with class-based schema #1478
- `Tracing::NewRelicTracing` accepts `set_transaction_name:` to use the GraphQL operation name as the NewRelic transaction name #1430
#### Bug fixes
- Backported `accepts_definition`s are inherited #1514
- Fix Schema generator's `resolve_type` method #1481
- Fix constant assignment warnings with interfaces including multiple other interfaces #1465
- InputObject types loaded from SDL have the proper AST node assigned to them #1512
## 1.8.0.pre11 (3 May 2018)
### Breaking changes
- `Schema::Mutation.resolve_mutation` was moved to an instance method; see changes to `Schema::RelayClassicMutation` in #1469 for an example refactor
- `GraphQL::Delegate` was removed, use Ruby's `Forwardable` instead (warning: bad performance on Ruby 2.4.0)
- `GraphQL::Schema::Interface` is a module, not a class #1372. To refactor, use a base module instead of a base class:
```ruby
module BaseInterface
include GraphQL::Schema::Interface
end
```
And include that in your interface types:
```ruby
module Reservable
include BaseInterface
field :reservations, ...
end
```
In object types, no change is required; use `implements` as before:
```ruby
class EventVenue < BaseObject
implements Reservable
end
```
### New features
- `GraphQL::Schema::Interface` is a module
- Support `prepare:` and `as:` argument options #1469
- First-class support for Mongoid connections #1452
- More type inspection helpers for class-based types #1446
- Field methods may call `super` to get the default behavior #1437
- `variables:` accepts symbol keys #1401
- Reprint any directives which were parsed from SDL #1417
- Support custom JSON scalars #1398
- Subscription `trigger` accepts symbol, underscored arguments and validates their presence #1400
- Mutations accept a `null(true | false)` setting to affect field nullability #1406
- `RescueMiddleware` uses inheritance to match errors #1393
- Resolvers may return a list of errors #1231
### Bug fixes
- Better error for anonymous class names #1459
- Input Objects correctly inherit arguments #1432
- Fix `.subscriptions` for class-based Schemas #1391
## 1.8.0.pre10 (4 Apr 2018)
### New features
- Add `Schema::Mutation` and `Schema::RelayClassicMutation` base classes #1360
### Bug fixes
- Fix using anonymous classes for field types #1358
## 1.8.0.pre9 (19 Mar 2018)
- New version number. (I needed this because I messed up build tooling for 1.8.0.pre8).
## 1.8.0.pre8 (19 Mar 2018)
### New Features
- Backport `accepts_definition` for configurations #1357
- Add `#owner` method to Schema objects
- Add `Interface.orphan_types` config for orphan types #1346
- Add `extras: :execution_errors` for `add_error` #1313
- Accept a block to `Schema::Argument#initialize` #1356
### Bug Fixes
- Support `cursor_encoder` #1357
- Don't double-count lazy/eager field time in Tracing #1321
- Fix camelization to support single leading underscore #1315
- Fix `.resolve_type` for Union and Interface classes #1342
- Apply kwargs before block in `Argument.from_dsl` #1350
## 1.8.0.pre7 (27 Feb 2018)
### New features
- Upgrader improvements #1305
- Support `global_id_field` for interfaces #1299
- Add `camelize: false` #1300
- Add readers for `context`, `object` and `arguments` #1283
- Replace `Schema.method_missing` with explicit whitelist #1265
## 1.8.0.pre6 (1 Feb 2018)
### New features
- Custom enum value classes #1264
### Bug fixes
- Properly print SDL type directives #1255
## 1.8.0.pre5 (1 Feb 2018)
### New features
- Upgrade argument access with the upgrader #1251
- Add `Schema#find(str)` for finding schema members by name #1232
### Bug fixes
- Fix `Schema.max_complexity` #1246
- Support cyclical connections/edges #1253
## 1.8.0.pre4 (18 Jan 2018)
### Breaking changes
- `Type.fields`, `Field.arguments`, `Enum.values` and `InputObject.arguments` return a Hash instead of an Array #1222
### New features
- By default, fields try hash keys which match their name, as either a symbol or a string #1225
- `field do ... end` instance_evals on the Field instance, not a FieldProxy #1227
- `[T, null: true]` creates lists with nullable items #1229
- Upgrader improvements #1223
### Bug fixes
- Don't require `parser` unless the upgrader is run #1218
## 1.8.0.pre3 (12 Jan 2018)
### New Features
- Custom `Context` classes for class-based schemas #1161
- Custom introspection for class-based schemas #1170
- Improvements to upgrader tasks and internals #1151, #1178, #1212
- Allow description inside field blocks #1175
## 1.8.0.pre2 (29 Nov 2017)
### New Features
- Add `rake graphql:upgrade[app/graphql]` for automatic upgrade #1110
- Automatically camelize field names and argument names #1143, #1126
- Improved error message when defining `name` instead of `graphql_name` #1104
### Bug fixes
- Fix list wrapping when value is `nil` #1117
- Fix ArgumentError typo #1098
## 1.8.0.pre1 (14 Nov 2017)
### Breaking changes
- Stop official support for Ruby 2.1 #1070
### New features
- Add class-based schema definition API #1037
## 1.7.14 (4 Apr 2018)
### New features
- Support new IDL spec for `&` for interfaces #1304
- Schema members built from IDL have an `#ast_node` #1367
### Bug fixes
- Fix paging backwards with `hasNextPage` #1319
- Add hint for `orphan_types` in error message #1380
- Use an empty hash for `result` when a query has unhandled errors #1382
## 1.7.13 (28 Feb 2018)
### Bug fixes
- `Schema#as_json` returns a hash, not a `GraphQL::Query::Result` #1288
## 1.7.12 (13 Feb 2018)
### Bug fixes
- `typed_children` should always return a Hash #1278
## 1.7.11 (13 Feb 2018)
### Bug fixes
- Fix compatibility of `irep_node.typed_children` on leaf nodes #1277
## 1.7.10 (13 Feb 2018)
### Breaking Changes
- Empty selections (`{ }`) are invalid in the GraphQL spec, but were previously allowed by graphql-ruby. They now return a parse error. #1268
### Bug fixes
- Fix error when inline fragments are spread on scalars #1268
- Fix printing SDL when types have interfaces and directives #1255
## 1.7.9 (1 Feb 2018)
## New Features
- Support block string inputs #1219
## Bug fixes
- Fix deprecation regression in schema printer #1250
- Fix resource names in DataDog tracing #1208
- Fix passing `context` to multiplex in `Query#result` #1200
## 1.7.8 (11 Jan 2018)
### New features
- Refactor `Schema::Printer` to use `Language::Printer` #1159
- Add `ArgumentValue#default_used?` and `Arguments#default_used?` #1152
### Bug fixes
- Fix Scout Tracing #1187
- Call `#inspect` for `EnumType::UnresolvedValueError` #1179
- Parse empty field sets in IDL parser #1145
## 1.7.7 (29 Nov 2017)
### New features
- `Schema#to_document` returns a `Language::Nodes::Document` #1134
- Add `trace_scalars` and `trace: true|false` to monitoring #1103
- Add `Tracing::DataDogPlatform` monitoring #1129
- Support namespaces in `rails g graphql:function` and `:loader` #1127
- Support `serializer:` option for `ActionCableSubscriptions` #1085
### Bug fixes
- Properly count the column after a closing quote #1136
- Fix default value input objects in `Schema.from_definition` #1135
- Fix `rails destroy graphql:mutation` #1119
- Avoid unneeded query in RelationConnection with Sequel #1101
- Improve & document instrumentation stack behavior #1101
## 1.7.6 (13 Nov 2017)
### Bug fixes
- Serialize symbols in with `GraphQL::Subscriptions::Serialize` #1084
## 1.7.5 (7 Nov 2017)
### Breaking changes
- Rename `Backtrace::InspectResult#inspect` to `#inspect_result` #1022
### New features
- Improved website search with Algolia #934
- Support customized generator directory #1047
- Recursively serialize `GlobalID`-compliant objects in Arrays and hashes #1030
- Add `Subscriptions#build_id` helper #1046
- Add `#non_null?` and `#list?` helper methods to type objects #1054
### Bug fixes
- Fix infinite loop in query instrumentation when error is raised #1074
- Don't try to trace error when it's not raised during execution
- Improve validation of query variable definitions #1073
- Fix Scout tracing module load order #1064
## 1.7.4 (9 Oct 2017)
### Deprecations
- `GraphQL::Tracing.install` is deprecated, use schema-local or query-local tracers instead #996
### New features
- Add monitoring plugins for AppSignal, New Relic, Scout and Skylight #994, #1013
- Custom coercion errors for custom scalars #988
- Extra `options` for `GraphQL::ExecutionError` #1002
- Use `GlobalID` for subscription serialization when available #1004
- Schema- and query-local, threadsafe tracers #996
### Bug fixes
- Accept symbol-keyed arguments to `.trigger` #1009
## 1.7.3 (20 Sept 2017)
### Bug fixes
- Fix arguments on `Query.__type` field #978
- Fix `Relay::Edge` objects in `Backtrace` tables #975
## 1.7.2 (20 Sept 2017)
### Bug fixes
- Correctly skip connections that return `ctx.skip` #972
## 1.7.1 (18 Sept 2017)
### Bug fixes
- Properly release changes from 1.7.0
## 1.7.0 (18 Sept 2017)
### Breaking changes
- `GraphQL::Result` is the returned from GraphQL execution. #898 `Schema#execute` and `Query#result` both return a `GraphQL::Result`. It implements Hash-like methods to preserve compatibility.
### New features
- `puts ctx.backtrace` prints out a GraphQL backtrace table #946
- `GraphQL::Backtrace.enable` wraps unhandled errors with GraphQL backtraces #946
- `GraphQL::Relay::ConnectionType.bidrectional_pagination = true` turns on _true_ bi-directional pagination checks for `hasNextPage`/`hasPreviousPage` fields. This will become the default behavior in a future version. #960
- Field arguments may be accessed as methods on the `args` object. This is an alternative to `#[]` syntax which provides did-you-mean behavior instead of returning `nil` on a typo. #924 For example:
```ruby
# using hash syntax:
args[:limit] # => 10
args[:limittt] # => nil
# using method syntax:
args.limit # => 10
args.limittt # => NoMethodError
```
The old syntax is _not_ deprecated.
- Improvements to schema filters #919
- If a type is not referenced by anything, it's hidden
- If a type is an abstract type, but has no visible members, it's hidden
- `GraphQL::Argument.define` builds re-usable arguments #948
- `GraphQL::Subscriptions` provides hooks for subscription platforms #672
- `GraphQL::Subscriptions::ActionCableSubscriptions` implements subscriptions over ActionCable #672
- More runtime values are accessble from a `ctx` object #923 :
- `ctx.parent` returns the `ctx` from the parent field
- `ctx.object` returns the current `obj` for that field
- `ctx.value` returns the resolved GraphQL value for that field
These can be used together, for example, `ctx.parent.object` to get the parent object.
- `GraphQL::Tracing` provides more hooks into gem internals for performance monitoring #917
- `GraphQL::Result` provides access to the original `query` and `context` after executing a query #898
### Bug fixes
- Prevent passing _both_ query string and parsed document to `Schema#execute` #957
- Prevent invalid names for types #947
## 1.6.8 (8 Sept 2017)
### Breaking changes
- Validate against EnumType value names to match `/^[_a-zA-Z][_a-zA-Z0-9]*$/` #915
### New features
- Use stdlib `forwardable` when it's not Ruby 2.4.0 #926
- Improve `UnresolvedTypeError` message #928
- Add a default field to the Rails generated mutation type #922
### Bug fixes
- Find types via directive arguments when traversing the schema #944
- Assign `#connection?` when building a schema from IDL #941
- Initialize `@edge_class` to `nil` #942
- Disallow invalid enum values #915
- Disallow doubly-nested non-null types #916
- Fix `Query#selected_operation_name` when no selections are present #899
- Fix needless `COUNT` query for `hasNextPage` #906
- Fix negative offset with `last` argument #907
- Fix line/col for `ArgumentsAreDefined` validation #890
- Fix Sequel error when limit is `0` #892
## 1.6.7 (11 Aug 2017)
### New features
- Add `GraphQL.parse_file` and `AbstractNode#filename` #873
- Support `.graphql` filepaths with `Schema.from_definition` #872
### Bug fixes
- Fix variable usage inside non-null list #888
- Fix unqualified usage of ActiveRecord::Relation #885
- Fix `FieldsWillMerge` handling of equivalent input objects
- Fix to call `prepare:` on nested input types
## 1.6.6 (14 Jul 2017)
### New features
- Validate `graphql-pro` downloads with `rake graphql:pro:validate[$VERSION]` #846
### Bug fixes
- Remove usage of Rails-only `Array.wrap` #840
- Fix `RelationConnection` to count properly when relation contains an alias #838
- Print name of Enum type when a duplicate value is added #843
## 1.6.5 (13 Jul 2017)
### Breaking changes
- `Schema#types[](type_name)` returns `nil` when there's no type named `type_name` (it used to raise `RuntimeError`). To get an error for missing types, use `.fetch` instead, for example:
```ruby
# Old way:
MySchema.types[type_name] # => may raise RuntimeError
# New way:
MySchema.types.fetch(type_name) # => may raise KeyError
```
- Schema build steps happen in one pass instead of two passes #819 . This means that `instrument(:field)` hooks may not access `Schema#types`, `Schema#possible_types` or `Schema#get_field`, since the underlying data hasn't been prepared yet. There's not really a clear upgrade path here. It's a bit of a mess. If you're affected by this, feel free to open an issue and we'll try to find something that works!
### Deprecations
- `Schema#resolve_type` is now called with `(abstract_type, obj, ctx)` instead of `(obj, ctx)` #834 . To update, add an unused parameter to the beginning of your `resolve_type` hook:
```ruby
MySchema = GraphQL::Schema.define do
# Old way:
resolve_type ->(obj, ctx) { ... }
# New way:
resolve_type ->(type, obj, ctx) { ... }
end
```
### New features
- `rails g graphql:mutation` will add Mutation boilerplate if it wasn't added already #812
- `InterfaceType` and `UnionType` both accept `resolve_type ->(obj, ctx) { ... }` functions for type-specific resolution. This function takes precedence over `Schema#resolve_type` #829 #834
- `Schema#resolve_type` is called with three arguments, `(abstract_type, obj, ctx)`, so you can distinguish object type based on interface or union.
- `Query#operation_name=` may be assigned during query instrumentation #833
- `query.context.add_error(err)` may be used to add query-level errors #833
### Bug fixes
- `argument(...)` DSL accepts custom keywords #809
- Use single-query `max_complexity` overrides #812
- Return a client error when `InputObjectType` receives an array as input #803
- Properly handle raised errors in `prepare` functions #805
- Fix using `as` and `prepare` in `argument do ... end` blocks #817
- When types are added to the schema with `instrument(:field, ...)`, make sure they're in `Schema#types` #819
- Raise an error when duplicate `EnumValue` is created #831
- Properly resolve all query levels breadth-first when using `lazy_resolve` #835
- Fix tests to run on PostgresQL; Run CI on PostgresQL #814
- When no query string is present, return a client error instead of raising `ArgumentError` #833
- Properly validate lists containing variables #824
## 1.6.4 (20 Jun 2017)
### New features
- `Schema.to_definition` sorts fields and arguments alphabetically #775
- `validate: false` skips static validations in query execution #790
### Bug fixes
- `graphql:install` adds `operation_name: params[:operationName]` #786
- `graphql:install` skips `graphiql-rails` for API-only apps #772
- `SerialExecution` calls `.is_a?(Skip)` to avoid user-defined `#==` methods #794
- `prepare:` functions which return `ExecutionError` are properly handled when default values are present #801
## 1.6.3 (7 Jun 2017)
### Bug fixes
- Run multiplex instrumentation when running a single query with a legacy execution strategy #766
- Check _each_ strategy when looking for overridden execution strategy #765
- Correctly wrap `Method`s with BackwardsCompatibility #763
- Various performance improvements #764
- Don't call `#==(other)` on user-provided objects (use `.is_a?` instead) #761
- Support lazy object from custom connection `#edge_nodes` #762
- If a lazy field returns an invalid null, stop evaluating its siblings #767
## 1.6.2 (2 Jun 2017)
### New features
- `Schema.define { default_max_page_size(...) }` provides a Connection `max_page_size` when no other is provided #752
- `Schema#get_field(type, field)` accepts a string type name #756
- `Schema.define { rescue_from(...) }` accepts multiple error classes for the handler #758
### Bug fixes
- Use `*_execution_strategy` when executing a single query (doesn't support `Schema#multiplex`) #755
- Fix NameError when `ActiveRecord` isn't loaded #747
- Fix `Query#mutation?` etc to support lazily-loaded AST #754
## 1.6.1 (28 May 2017)
### New Features
- `Query#selected_operation_name` returns the operation to execute, even if it was inferred (not provided as `operation_name:`) #746
### Bug fixes
- Return `nil` from `Query#operation_name` if no `operation_name:` was provided #746
## 1.6.0 (27 May 2017)
### Breaking changes
- `InternalRepresentation::Node#return_type` will now return the wrapping type. Use `return_type.unwrap` to access the old value #704
- `instrument(:query, ...)` instrumenters are applied as a stack instead of a queue #735. If you depend on queue-based behavior, move your `before_query` and `after_query` hooks to separate instrumenters.
- In a `Relay::Mutation`, Raising or returning a `GraphQL::Execution` will nullify the mutation field, not the field's children. #731
- `args.to_h` returns a slightly different hash #714
- keys are always `String`s
- if an argument is aliased with `as:`, the alias is used as the key
- `InternalRepresentation::Node#return_type` includes the original "wrapper" types (non-null or list types), call `.unwrap` to get the inner type #20
```ruby
# before
irep_node.return_type
# after
irep_node.return_type.unwrap
```
### Deprecations
- Argument `prepare` functions which take one argument are deprecated #730
```ruby
# before
argument :id, !types.ID, prepare: ->(val) { ... }
# after
argument :id, !types.ID, prepare: ->(val, ctx) { ... }
```
### New features
- `Schema#multiplex(queries)` runs multiple queries concurrently #691
- `GraphQL::RakeTask` supports dumping the schema to IDL or JSON #687
- Improved support for `Schema.from_definition` #699 :
- Custom scalars are supported with `coerce_input` and `coerce_result` functions
- `resolve_type` function will be used for abstract types
- Default resolve behavior is to check `obj` for a method and call it with 0, 1, or 2 arguments.
- `ctx.skip` may be returned from field resolve functions to exclude the field from the response entirely #688
- `instrument(:field, ..., after_built_ins: true)` to apply field instrumentation after Relay wrappers #740
- Argument `prepare` functions are invoked with `(val, ctx)` (previously, it was only `(val)`) #730
- `args.to_h` returns stringified, aliased arguments #714
- `ctx.namespace(:my_namespace)` provides namespaced key-value storage #689
- `GraphQL::Query` can be initialized without a query_string; it can be added after initialization #710
- Improved filter support #713
- `Schema.execute(only:, except:)` accept a callable _or_ an array of callables (multiple filters)
- Filters can be added to a query via `Query#merge_filters(only:, except:)`. You can add a filter to every query by merging it in during query instrumentation.
### Bug fixes
- Correctly apply cursors and `max_page_size` in `Relay::RelationConnection` and `Relay::ArrayConnection` #728
- Nullify a mutation field when it raises or returns an error #731
## 1.5.14 (27 May 2017)
### New features
- `UniqueWithinType` Relay ID generator supports `-` in the ID #742
- `assign_metadata_key` assigns `true` when the definition method is called without arguments #724
- Improved lexer performance #737
### Bug fixes
- Assign proper `parent` when a `connection` resolve returns a promise #736
## 1.5.13 (11 May 2017)
- Fix raising `ExecutionError` inside mutation resolve functions (it nullifies the field) #722
## 1.5.12 (9 May 2017)
- Fix returning `nil` from connection resolve functions (now they become `null`) #719
- Fix duplicate AST nodes when merging fragments #721
## 1.5.11 (8 May 2017)
### New features
- `Schema.from_definition` accepts a `parser:` option (to work around lack of schema parser in `graphql-libgraphqlparser`) #712
- `Query#internal_representation` exposes an `InternalRepresentation::Document` #701
- Update generator usage of `graphql-batch` #697
### Bug fixes
- Handle fragments with the same name as operations #706
- Fix type generator: ensure type name is camelized #718
- Fix `Query#operation_name` to return the operation name #707
- Fix pretty-print of non-null & list types #705
- Fix single input objects passed to list-type arguments #716
## 1.5.10 (25 Apr 2017)
### New features
- Support Rails 5.1 #693
- Fall back to `String#encode` for non-UTF-8/non-ASCII strings #676
### Bug Fixes
- Correctly apply `Relay::Mutation`'s `return_field ... property:` argument #692
- Handle Rails 5.1's `ActionController::Parameters` #693
## 1.5.9 (19 Apr 2017)
### Bug Fixes
- Include instrumentation-related changes in introspection result #681
## 1.5.8 (18 Apr 2017)
### New features
- Use Relay PageInfo descriptions from graphql-js #673
### Bug Fixes
- Allow fields with different arguments when fragments are included within inline fragments of non-overlapping types #680
- Run `lazy_resolve` instrumentation for `connection` fields #679
## 1.5.7 (14 Apr 2017)
### Bug fixes
- `InternalRepresentation::Node#definition` returns `nil` instead of raising NoMethodError for operation fields #675
- `Field#function` is properly populated for fields derived from `GraphQL::Function`s #674
## 1.5.6 (9 Apr 2017)
## Breaking Changes
- Returned strings which aren't encoded as UTF-8 or ASCII will raise `GraphQL::StringEncodingError` instead of becoming `nil` #661
To preserve the previous behavior, Implement `Schema#type_error` to return `nil` for this error, eg:
```ruby
GraphQL::Schema.define do
type_error ->(err, ctx) {
case err
# ...
when GraphQL::StringEncodingError
nil
end
}
```
- `coerce_non_null_input` and `validate_non_null_input` are private #667
## Deprecations
- One-argument `coerce_input` and `coerce_result` functions for custom scalars are deprecated. #667 Those functions now accept a second argument, `ctx`.
```ruby
# From
->(val) { val.to_i }
# To:
->(val, ctx) { val.to_i }
```
- Calling `coerce_result`, `coerce_input`, `valid_input?` or `validate_input` without a `ctx` is deprecated. #667 Use `coerce_isolated_result` `coerce_isolated_input`, `valid_isolated_input?`, `validate_input` to explicitly bypass `ctx`.
## New Features
- Include `#types` in `GraphQL::Function` #654
- Accept `prepare:` function for arguments #646
- Scalar coerce functions receive `ctx` #667
## Bug Fixes
- Properly apply default values of `false` #658
- Fix application of argument options in `GraphQL::Relay::Mutation` #660
- Support concurrent-ruby `>1.0.0` #663
- Only raise schema validation errors on `#execute` to avoid messing with Rails constant loading #665
## 1.5.5 (31 Mar 2017)
### Bug Fixes
- Improve threadsafety of `lazy_resolve` cache, use `Concurrent::Map` if it's available #631
- Properly handle unexpeced input objects #638
- Handle errors during definition by preseriving the definition #632
- Fix `nil` input for nullable list types #637, #639
- Handle invalid schema IDL with a validation error #647
- Properly serialize input object default values #635
- Fix `as:` on mutation `input_field` #650
- Fix null propagation for `nil` members of non-null list types #649
## 1.5.4 (22 Mar 2017)
### Breaking Changes
- Stop supporting deprecated one-argument schema masks #616
### Bug Fixes
- Return a client error for unknown variable types when default value is provided or when directives are present #627
- Fix validation performance regression on nested abstract fragment conditions #622, #624
- Put back `InternalRepresentation::Node#parent` and fix it for fragment fields #621
- Ensure enum names are strings #619
## 1.5.3 (20 Mar 2017)
### Bug Fixes
- Fix infinite loop triggered by user input. #620 This query would cause an infinite loop:
```graphql
query { ...frag }
fragment frag on Query { __typename }
fragment frag on Query { ...frag }
```
- Validate fragment name uniqueness #618
## 1.5.2 (16 Mar 2017)
### Breaking Changes
- Parse errors are no longer raised to the application. #607 Instead, they're returned to the client in the `"errors"` key. To preserve the previous behavior, you can implement `Schema#parse_error` to raise the error:
```ruby
MySchema = GraphQL::Schema.define do
# ...
parse_error ->(err, ctx) { raise(err) }
end
```
### New Features
- Add `graphq:enum` generator #611
- Parse errors are returned to the client instead of raised #607
### Bug Fixes
- Handle negative cursor pagination args as `0` #612
- Properly handle returned `GraphQL::ExecutionError`s from connection resolves #610
- Properly handle invalid nulls in lazy scalar fields #609
- Properly handle invalid input objects passed to enum arguments #604
- Fix introspection response of enum default values #605
- Allow `Schema.from_definition` default resolver hashes to have defaults #608
## 1.5.1 (12 Mar 2017)
### Bug fixes
- Fix rewrite performance regressions from 1.5.0 #599
- Remove unused `GraphQL::Execution::Lazy` initialization API #597
## 1.5.0 (10 Mar 2017), yanked
### Breaking changes
- _Only_ UTF-8-encoded strings will be returned by `String` fields. Strings with other encodings (or objects whose `#to_s` method returns a string with a different encoding) will return `nil` instead of that string. #517
To opt into the _previous_ behavior, you can modify `GraphQL::STRING_TYPE`:
```ruby
# app/graphql/my_schema.rb
# Restore previous string behavior:
GraphQL::STRING_TYPE.coerce_result = ->(value) { value.to_s }
MySchema = GraphQL::Schema.define { ... }
```
- Substantial changes to the internal query representation (#512, #536). Query analyzers may notice some changes:
- Nodes skipped by directives are not visited
- Nodes are always on object types, so `Node#owner_type` always returns an object type. (Interfaces and Unions are replaced with concrete object types which are valid in the current scope.)
See [changes to `Analysis::QueryComplexity`](https://github.com/rmosolgo/graphql-ruby/compare/v1.4.5...v1.5.0#diff-8ff2cdf0fec46dfaab02363664d0d201) for an example migration. Here are some other specific changes:
- Nodes are tracked on object types only, not interface or union types
- Deprecated, buggy `Node#children` and `Node#path` were removed
- Buggy `#included` was removed
- Nodes excluded by directives are entirely absent from the rewritten tree
- Internal `InternalRepresentation::Selection` was removed (no longer needed)
- `Node#spreads` was replaced by `Node#ast_spreads` which returns a Set
### New features
- `Schema#validate` returns a list of errors for a query string #513
- `implements ...` adds interfaces to object types _without_ inherit-by-default #548, #574
- `GraphQL::Relay::RangeAdd` for implementing `RANGE_ADD` mutations #587
- `use ...` definition method for plugins #565
- Rails generators #521, #580
- `GraphQL::Function` for reusable resolve behavior with arguments & return type #545
- Support for Ruby 2.4 #475
- Relay `node` & `nodes` field can be extended with a custom block #552
- Performance improvements:
- Resolve fragments only once when validating #504
- Reuse `Arguments` objects #500
- Skip needless `FieldResult`s #482
- Remove overhead from `ensure_defined` #483
- Benchmark & Profile tasks for gem maintenance #520, #579
- Fetch `has_next_page` while fetching items in `RelationConnection` #556
- Merge selections on concrete object types ahead of time #512
- Support runnable schemas with `Schema.from_definition` #567, #584
### Bug fixes
- Support different arguments on non-overlapping typed fragments #512
- Don't include children of `@skip`ped nodes when parallel branches are not skipped #536
- Fix offset in ArrayConnection when it's larger than the array #571
- Add missing `frozen_string_literal` comments #589
## 1.4.5 (6 Mar 2017)
### Bug Fixes
- When an operation name is provided but no such operation is present, return an error (instead of executing the first operation) #563
- Require unique operation names #563
- Require selections on root type #563
- If a non-null field returns `null`, don't resolve any more sibling fields. #575
## 1.4.4 (17 Feb 2017)
### New features
- `Relay::Node.field` and `Relay::Node.plural_field` accept a custom `resolve:` argument #550
- `Relay::BaseConnection#context` provides access to the query context #537
- Allow re-assigning `Field#name` #541
- Support `return_interfaces` on `Relay::Mutation`s #533
- `BaseType#to_definition` stringifies the type to IDL #539
- `argument ... as:` can be used to alias an argument inside the resolve function #542
### Bug fixes
- Fix negative offset from cursors on PostgresQL #510
- Fix circular dependency issue on `.connection_type`s #535
- Better error when `Relay::Mutation.resolve` doesn't return a Hash
## 1.4.3 (8 Feb 2017)
### New features
- `GraphQL::Relay::Node.plural_field` finds multiple nodes by UUID #525
### Bug fixes
- Properly handle errors from lazy mutation results #528
- Encode all parsed strings as UTF-8 #516
- Improve error messages #501 #519
## 1.4.2 (23 Jan 2017)
### Bug fixes
- Absent variables aren't present in `args` (_again_!) #494
- Ensure definitions were executed when accessing `Field#resolve_proc` #502 (This could have caused errors when multiple instrumenters modified the same field in the schema.)
## 1.4.1 (16 Jan 2017)
### Bug fixes
- Absent variables aren't present in `args` #479
- Fix grouped ActiveRecord relation with `last` only #476
- `Schema#default_mask` & query `only:`/`except:` are combined, not overriden #485
- Root types can be hidden with dynamic filters #480
## 1.4.0 (8 Jan 2017)
### Breaking changes
### Deprecations
- One-argument schema filters are deprecated. Schema filters are now called with _two_ arguments, `(member, ctx)`. #463 To update, add a second argument to your schema filter.
- The arity of middleware `#call` methods has changed. Instead of `next_middleware` being the last argument, it is passed as a block. To update, call `yield` to continue the middleware chain or use `&next_middleware` to capture `next_middleware` into a local variable.
```ruby
# Previous:
def call(*args, next_middleware)
next_middleware.call
end
# Current
def call(*args)
yield
end
# Or
def call(*args, &next_middleware)
next_middleware.call
end
```
### New features
- You can add a `nodes` field directly to a connection. #451 That way you can say `{ friends { nodes } }` instead of `{ freinds { edges { node } } }`. Either pass `nodes_field: true` when defining a custom connection type, for example:
```ruby
FriendsConnectionType = FriendType.define_connection(nodes_field: true)
```
Or, set `GraphQL::Relay::ConnectionType.default_nodes_field = true` before defining your schema, for example:
```ruby
GraphQL::Relay::ConnectionType.default_nodes_field = true
MySchema = GraphQL::Schema.define { ... }
```
- Middleware performance was dramatically improved by reducing object allocations. #462 `next_middleware` is now passed as a block. In general, [`yield` is faster than calling a captured block](https://github.com/JuanitoFatas/fast-ruby#proccall-and-block-arguments-vs-yieldcode).
- Improve error messages for wrongly-typed variable values #423
- Cache the value of `resolve_type` per object per query #462
- Pass `ctx` to schema filters #463
- Accept whitelist schema filters as `only:` #463
- Add `Schema#to_definition` which accepts `only:/except:` to filter the schema when printing #463
- Add `Schema#default_mask` as a default `except:` filter #463
- Add reflection methods to types #473
- `#introspection?` marks built-in introspection types
- `#default_scalar?` marks built-in scalars
- `#default_relay?` marks built-in Relay types
- `#default_directive?` marks built-in directives
### Bug fixes
- Fix ArrayConnection: gracefully handle out-of-bounds cursors #452
- Fix ArrayConnection & RelationConnection: properly handle `last` without `before` #362
## 1.3.0 (8 Dec 2016)
### Deprecations
- As per the spec, `__` prefix is reserved for built-in names only. This is currently deprecated and will be invalid in a future version. #427, #450
### New features
- `Schema#lazy_resolve` allows you to define handlers for a second pass of resolution #386
- `Field#lazy_resolve` can be instrumented to track lazy resolution #429
- `Schema#type_error` allows you to handle `InvalidNullError`s and `UnresolvedTypeErrors` in your own way #416
- `Schema#cursor_encoder` can be specified for transforming cursors from built-in Connection implementations #345
- Schema members `#dup` correctly: they shallowly copy their state into new instances #444
- `Query#provided_variables` is now public #430
### Bug fixes
- Schemas created from JSON or strings with custom scalars can validate queries (although they still can't check if inputs are valid for those custom scalars) #445
- Always use `quirks_mode: true` when serializing values (to support non-stdlib `JSON`s) #449
- Calling `#redefine` on a Schema member copies state outside of previous `#define` blocks (uses `#dup`) #444
## 1.2.6 (1 Dec 2016)
### Bug fixes
- Preserve connection behaviors after `redefine` #421
- Implement `respond_to_missing?` on `DefinedObjectProxy` (which is `self` inside `.define { ... }`) #414
## 1.2.5 (22 Nov 2016)
### Breaking changes
- `Visitor` received some breaking changes, though these are largely-private APIs (#401):
- Global visitor hooks (`Visitor#enter` and `Visitor#leave`) have been removed
- Returning `SKIP` from a visitor hook no longer skips sibling nodes
### New features
- `Schema#instrument` may be called outside of `Schema.define` #399
- Validation: assert that directives on a node are unique #409
- `instrument(:query)` hooks are executed even if the query raises an error #412
### Bug fixes
- `Mutation#input_fields` should trigger lazy definition #392
- `ObjectType#connection` doesn't modify the provided `GraphQL::Field` #411
- `Mutation#resolve` may return a `GraphQL::ExecutionError` #405
- `Arguments` can handle nullable arguments passed as `nil` #410
## 1.2.4 (14 Nov 2016)
### Bug fixes
- For invalid enum values, print the enum name in the error message (not a Ruby object dump) #403
- Improve detection of invalid UTF-8 escapes #394
## 1.2.3 (14 Nov 2016)
### Bug fixes
- `Lexer` previous token should be a local variable, not a method attribute #396
- `Arguments` should wrap values according to their type, not their value #398
## 1.2.2 (7 Nov 2016)
### New features
- `Schema.execute` raises an error if `variables:` is a string
### Bug fixes
- Dynamic fields `__schema`, `__type` and `__typename` are properly validated #391
## 1.2.1 (7 Nov 2016)
### Bug fixes
- Implement `Query::Context#strategy` and `FieldResolutionContext#strategy` to support GraphQL::Batch #382
## 1.2.0 (7 Nov 2016)
### Breaking changes
- A breaking change from 1.1.0 was reverted: two-character `"\\u"` _is_ longer treated as the Unicode escape character #372
- Due to the execution bug described below, the internal representation of a query has changed. Although `Node` responds to the same methods, tree is built differently and query analyzers visit it differently. #373, #379
The difference is in cases like this:
```graphql
outer {
... on A { inner1 { inner2 } }
... on B { inner1 { inner3 } }
}
```
Previously, visits would be:
- `outer`, which has one child:
- `inner1`, which has two definitions (one on `A`, another on `B`), then visit its two `children`:
- `inner2` which has one definition (on the return type of `inner1`)
- `inner3` which has one definition (on the return type of `inner1`)
This can be wrong for some cases. For example, if `A` and `B` are mutually exclusive (both object types, or union types with no shared members), then `inner2` and `inner3` will never be executed together.
Now, the visit goes like this:
- `outer` which has two entries in `typed_children`, one on `A` and another on `B`. Visit each `typed_chidren` branch:
- `inner1`, then its one `typed_children` branch:
- `inner2`
- `inner1`, then its one `typed_children` branch:
- `inner3`
As you can see, we visit `inner1` twice, once for each type condition. `inner2` and `inner3` are no longer visited as siblings. Instead they're visited as ... cousins? (They share a grandparent, not a parent.)
Although `Node#children` is still present, it may not contain all children actually resolved at runtime, since multiple `typed_children` branches could apply to the same runtime type (eg, two branches on interface types can apply to the same object type). To track all children, you have to do some bookkeeping during visitation, see `QueryComplexity` for an example.
You can see PR #373 for how built-in analyzers were changed to reflect this.
### Deprecations
- `InternalRepresentation::Node#children` and `InternalRepresentation::Node#definitions` are deprecated due to the bug described below and the breaking change described above. Instead, use `InternalRepresentation::Node#typed_children` and `InternalRepresentation::Node#defininition`. #373
### New features
- `null` support for the whole library: as a query literal, variable value, and argument default value. To check for the presence of a nullable, use `Arguments#key?` #369
- `GraphQL::Schema::UniqueWithinType.default_id_separator` may be assigned to a custom value #381
- `Context#add_error(err)` may be used to add a `GraphQL::ExecutionError` to the response's `"errors"` key (and the resolve function can still return a value) #367
- The third argument of `resolve` is now a `FieldResolutionContext`, which behaves just like a `Query::Context`, except that it is not modified during query execution. This means you can capture a reference to that context and access some field-level details after the fact: `#path`, `#ast_node`, `#irep_node`. (Other methods are delegated to the underlying `Query::Context`) #379
- `TimeoutMiddleware`'s second argument is a _proxied_ query object: it's `#context` method returns the `FieldResolutionContext` (see above) for the timed-out field. Other methods are delegated to the underlying `Query` #379
### Bug fixes
- Fix deep selection merging on divergently-typed fragments. #370, #373, #379 Previously, nested selections on different fragments were not distinguished. Consider a case like this:
```graphql
... on A { inner1 { inner2 } }
... on B { inner1 { inner3 } }
```
Previously, an object of type `A` would resolve `inner1`, then the result would receive _both_ `inner2` and `inner3`. The same was true for an object of type `B`.
Now, those are properly distinguished. An object of type `A` resolves `inner1`, then its result receives `inner2`. An object of type `B` receives `inner1`, then `inner3`.
## 1.1.0 (1 Nov 2016)
### Breaking changes
- Two-character `"\\u"` is no longer treated as the Unicode escape character, only the Unicode escape character `"\u"` is treated that way. (This behavior was a bug, the migration path is to use the Unicode escape character.) #366
- `GraphQL::Language::ParserTests` was removed, use `GraphQL::Compatibility` instead. #366
- Non-null arguments can't be defined with default values, because those values would never be used #361
### New features
- `Schema.from_definition(definition_string)` builds a `GraphQL::Schema` out of a schema definition. #346
- Schema members (types, fields, arguments, enum values) can be hidden on a per-query basis with the `except:` option #300
- `GraphQL::Compatibility` contains `.build_suite` functions for testing user-provided parsers and execution strategies with GraphQL internals. #366
- Schema members respond to `#redefine { ... }` for making shallow copies with extended definitions. #357
- `Schema#instrument` provides an avenue for observing query and field resolution with no overhead.
- Some `SerialExecution` objects were converted to functions, resulting in a modest performance improvement for query resolution.
### Bug fixes
- `NonNullType` and `ListType` have no name (`nil`), as per the spec #355
- Non-null arguments can't be defined with default values, because those values would never be used #361
## 1.0.0 (25 Oct 2016)
### Breaking changes
- `validate: false` option removed from `Schema.execute` (it didn't work anyways) #338
- Some deprecated methods were removed: #349
- `BaseConnection#object` was removed, use `BaseConnection#nodes`
- `BaseConnection.connection_for_items` was removed, use `BaseConnection#connection_for_nodes`
- Two-argument resolve functions for `Relay::Mutation`s are not supported, use three arguments instead: `(root_obj, input, ctx)`
- `Schema.new` no longer accepts initialization options, use `Schema.define` instead
- `GraphQL::ObjectType::UnresolvedTypeError` was removed, use `GraphQL::UnresolvedTypeError` instead
- Fragment type conditions should be parsed as `TypeName` nodes, not strings. (Users of `graphql-libgraphqlparser` should update to `1.0.0` of that gem.) #342
### New Features
- Set `ast_node` and `irep_node` on query context before sending it to middleware #348
- Enum values can be extended with `.define` #341
### Bug Fixes
- Use `RelationConnection` for Rails 3 relations (which also extend `Array`) #343
- Fix schema printout when arguments have comments #335
## 0.19.4 (18 Oct 2016)
### Breaking changes
- `Relay::BaseConnection#order` was removed (it always returned `nil`) #313
- In the IDL, Interface names & Union members are parsed as `TypeName` nodes instead of Strings #322
### New features
- Print and parse descriptions in the IDL #305
- Schema roots from IDL are omitted when their names match convention #320
- Don't add `rescue_middleware` to a schema if it's not using `rescue_from` #328
- `Query::Arguments#each_value` yields `Query::Argument::ArgumentValue` instances which contain key, value and argument definition #331
### Bug fixes
- Use `JSON.generate(val, quirks_mode: true)` for compatibility with other JSON implementations #316
- Improvements for compatibility with 1.9.3 branch #315 #314 #313
- Raise a descriptive error when calculating a `cursor` for a node which isn't present in the connection's members #327
## 0.19.3 (13 Oct 2016)
### Breaking Changes
- `GraphQL::Query::Arguments.new` requires `argument_definitions:` of type `{String => GraphQL::Argument }` #304
### Deprecations
- `Relay::Mutation#resolve` has a new signature. #301
Previously, it was called with two arguments:
```ruby
resolve ->(inputs, ctx) { ... }
```
Now, it's called with three inputs:
```ruby
resolve ->(obj, inputs, ctx) { ... }
```
`obj` is the value of `root_value:` given to `Schema#execute`, as with other root-level fields.
Two-argument resolvers are still supported, but they are deprecated and will be removed in a future version.
### New features
- `Relay::Mutation` accepts a user-defined `return_type` #310
- `Relay::Mutation#resolve` receives the `root_value` passed to `Schema#execute` #301
- Derived `Relay` objects have descriptions #303
### Bug fixes
- Introspection query is 7 levels deep instead of 3 #308
- Unknown variable types cause validation errors, not runtime errors #310
- `Query::Arguments` doesn't wrap hashes from parsed scalars (fix for user-defined "JSONScalar") #304
## 0.19.2 (6 Oct 2016)
### New features
- If a list entry has a `GraphQL::ExecutionError`, replace the entry with `nil` and return the error #295
### Bug fixes
- Support graphql-batch rescuing `InvalidNullError`s #296
- Schema printer prints Enum names, not Ruby values for enums #297
## 0.19.1 (4 Oct 2016)
### Breaking changes
- Previously-deprecated `InterfaceType#resolve_type` hook has been removed, use `Schema#resolve_type` instead #290
### New features
- Eager-load schemas at definition time, validating types & schema-level hooks #289
- `InvalidNullError`s contain the type & field name that returned null #293
- If an object is resolved with `Schema#resolve_type` and the resulting type is not a member of the expected possible types, raise an error #291
### Bug fixes
- Allow `directive` as field or argument name #288
## 0.19.0 (30 Sep 2016)
### Breaking changes
- `GraphQL::Relay::GlobalNodeIdentification` was removed. Its features were moved to `GraphQL::Schema` or `GraphQL::Relay::Node`. The new hooks support more robust & flexible global IDs. #243
- Relay's `"Node"` interface and `node(id: "...")` field were both moved to `GraphQL::Relay::Node`. To use them in your schema, call `.field` and `.interface`. For example:
```ruby
# Adding a Relay-compliant `node` field:
field :node, GraphQL::Relay::Node.field
```
```ruby
# This object type implements Relay's `Node` interface:
interfaces [GraphQL::Relay::Node.interface]
```
- UUID hooks were renamed and moved to `GraphQL::Schema`. You should define `id_from_object` and `object_from_id` in your `Schema.define { ... }` block. For example:
```ruby
MySchema = GraphQL::Schema.define do
# Fetch an object by UUID
object_from_id ->(id, ctx) {
MyApp::RelayLookup.find(id)
}
# Generate a UUID for this object
id_from_object ->(obj, type_defn, ctx) {
MyApp::RelayLookup.to_id(obj)
}
end
```
- The new hooks have no default implementation. To use the previous default, use `GraphQL::Schema::UniqueWithinType`, for example:
```ruby
MySchema = GraphQL::Schema.define do
object_from_id ->(id, ctx) {
# Break the id into its parts:
type_name, object_id = GraphQL::Schema::UniqueWithinType.decode(id)
# Fetch the identified object
# ...
}
id_from_object ->(obj, type_defn, ctx) {
# Provide the type name & the object's `id`:
GraphQL::Schema::UniqueWithinType.encode(type_defn.name, obj.id)
}
end
```
If you were using a custom `id_separator`, it's now accepted as an input to `UniqueWithinType`'s methods, as `separator:`. For example:
```ruby
# use "---" as a ID separator
GraphQL::Schema::UniqueWithinType.encode(type_name, object_id, separator: "---")
GraphQL::Schema::UniqueWithinType.decode(relay_id, separator: "---")
```
- `type_from_object` was previously deprecated and has been replaced by `Schema#resolve_type`. You should define this hook in your schema to return a type definition for a given object:
```ruby
MySchema = GraphQL::Schema.define do
# ...
resolve_type ->(obj, ctx) {
# based on `obj` and `ctx`,
# figure out which GraphQL type to use
# and return the type
}
end
```
- `Schema#node_identification` has been removed.
- `Argument` default values have been changed to be consistent with `InputObjectType` default values. #267
Previously, arguments expected GraphQL values as `default_value`s. Now, they expect application values. (`InputObjectType`s always worked this way.)
Consider an enum like this one, where custom values are provided:
```ruby
PowerStateEnum = GraphQL::EnumType.define do
name "PowerState"
value("ON", value: 1)
value("OFF", value: 0)
end
```
__Previously__, enum _names_ were provided as default values, for example:
```ruby
field :setPowerState, PowerStateEnum do
# Previously, the string name went here:
argument :newValue, default_value: "ON"
end
```
__Now__, enum _values_ are provided as default values, for example:
```ruby
field :setPowerState, PowerStateEnum do
# Now, use the application value as `default_value`:
argument :newValue, default_value: 1
end
```
Note that if you __don't have custom values__, then there's no change, because the name and value are the same.
Here are types that are affected by this change:
- Custom scalars (previously, the `default_value` was a string, now it should be the application value, eg `Date` or `BigDecimal`)
- Enums with custom `value:`s (previously, the `default_value` was the name, now it's the value)
If you can't replace `default_value`s, you can also use a type's `#coerce_input` method to translate a GraphQL value into an application value. For example:
```ruby
# Using a custom scalar, "Date"
# PREVIOUSLY, provide a string:
argument :starts_on, DateType, default_value: "2016-01-01"
# NOW, transform the string into a Date:
argument :starts_on, DateType, default_value: DateType.coerce_input("2016-01-01")
```
### New features
- Support `@deprecated` in the Schema language #275
- Support `directive` definitions in the Schema language #280
- Use the same introspection field descriptions as `graphql-js` #284
### Bug fixes
- Operation name is no longer present in execution error `"path"` values #276
- Default values are correctly dumped & reloaded in the Schema language #267
## 0.18.15 (20 Sep 2016)
### Breaking changes
- Validation errors no longer have a `"path"` key in their JSON. It was renamed to `"fields"` #264
- `@skip` and `@include` over multiple selections are handled according to the spec: if the same field is selected multiple times and _one or more_ of them would be included, the field will be present in the response. Previously, if _one or more_ of them would be skipped, it was absent from the response. #256
### New features
- Execution errors include a `"path"` key which points to the field in the response where the error occurred. #259
- Parsing directives from the Schema language is now supported #273
### Bug fixes
- `@skip` and `@include` over multiple selections are now handled according to the spec #256
## 0.18.14 (20 Sep 2016)
### Breaking changes
- Directives are no longer considered as "conflicts" in query validation. This is in conformity with the spec, but a change for graphql-ruby #263
### Features
- Query analyzers may emit errors by raising `GraphQL::AnalysisError`s during `#call` or returning a single error or an array of errors from `#final_value` #262
### Bug fixes
- Merge fields even when `@skip` / `@include` are not identical #263
- Fix possible infinite loop in `FieldsWillMerge` validation #261
## 0.18.13 (19 Sep 2016)
### Bug fixes
- Find infinite loops in nested contexts, too #258
## 0.18.12 (19 Sep 2016)
### New features
- `GraphQL::Analysis::FieldUsage` can be used to check for deprecated fields in the query analysis phase #245
### Bug fixes
- If a schema receives a query on `mutation` or `subscription` but that root doesn't exist, return a validation error #254
- `Query::Arguments#to_h` only includes keys that were provided in the query or have a default value #251
## 0.18.11 (11 Sep 2016)
### New features
- `GraphQL::Language::Nodes::Document#slice(operation_name)` finds that operation and its dependencies and puts them in a new `Document` #241
### Bug fixes
- Validation errors for non-existent fields have the location of the field usage, not the parent field #247
- Properly `require "forwardable"` #242
- Remove `ALLOWED_CONSTANTS` for boolean input, use a plain comparison #240
## 0.18.10 (9 Sep 2016)
### New features
- Assign `#mutation` on objects which are derived from a `Relay::Mutation` #239
## 0.18.9 (6 Sep 2016)
### Bug fixes
- fix backward compatibility for `type_from_object` #238
## 0.18.8 (6 Sep 2016)
### New features
- AST nodes now respond to `#eql?(other)` to test value equality #231
### Bug fixes
- The `connection` helper no longer adds a duplicate field #235
## 0.18.7 (6 Sep 2016)
### New features
- Support parsing nameless fragments (but not executing them) #232
### Bug fixes
- Allow `__type(name: "Whatever")` to return null, as per the spec #233
- Include a Relay mutation's description with a mutation field #225
## 0.18.6 (29 Aug 2016)
### New features
- ` GraphQL::Schema::Loader.load(schema_json)` turns an introspection result into a `GraphQL::Schema` #207
- `.define` accepts plural definitions for: object fields, interface fields field arguments, enum values #222
## 0.18.5 (27 Aug 2016)
### Deprecations
- `Schema.new` is deprecated; use `Schema.define` instead.
Before:
```ruby
schema = GraphQL::Schema.new(
query: QueryType,
mutation: MutationType,
max_complexity: 100,
types: [ExtraType, OtherType]
)
schema.node_identification = MyGlobalID
schema.rescue_from(ActiveRecord::RecordNotFound) { |err| "..." }
```
After:
```ruby
schema = GraphQL::Schema.define do
query QueryType
mutation MutationType
max_complexity 100
node_identification MyGlobalID
rescue_from(ActiveRecord::RecordNotFound) { |err| "..." }
# Types was renamed to `orphan_types` to avoid conflict with the `types` helper
orphan_types [ExtraType, OtherType]
end
```
This unifies the disparate methods of configuring a schema and provides new, more flexible design space. It also adds `#metadata` to schemas for user-defined storage.
- `UnionType#resolve_type`, `InterfaceType#resolve_type`, and `GlobalNodeIdentification#type_from_object` are deprecated, unify them into `Schema#resolve_type` instead.
Before:
```ruby
GraphQL::Relay::GlobalNodeIdentification.define do
type_from_object ->(obj) { ... }
end
GraphQL::InterfaceType.define do
resolve_type ->(obj, ctx) { ... }
end
```
After:
```ruby
GraphQL::Schema.define do
resolve_type ->(obj, ctx) { ... }
end
```
This simplifies type inference and prevents unexpected behavior when different parts of the schema resolve types differently.
### New features
- Include expected type in Argument errors #221
- Define schemas with `Schema.define` #208
- Define a global object-to-type function with `Schema#resolve_type` #216
### Bug fixes
## 0.18.4 (25 Aug 2016)
### New features
- `InvalidNullError`s expose a proper `#message` #217
### Bug fixes
- Return an empty result for queries with no operations #219
## 0.18.3 (22 Aug 2016)
### Bug fixes
- `Connection.new(:field)` is optional, not required #215
- 0.18.2 introduced a more restrictive approach to resolving interfaces & unions; revert that approach #212
## 0.18.2 (17 Aug 2016)
### New features
- Connection objects expose the `GraphQL::Field` that created them via `Connection#field` #206
## 0.18.1 (7 Aug 2016)
### Deprecations
- Unify `Relay` naming around `nodes` as the items of a connection:
- `Relay::BaseConnection.connection_for_nodes` replaces `Relay::BaseConnection.connection_for_items`
- `Relay::BaseConnection#nodes` replaces `Relay::BaseConnection#object`
### New features
- Connection fields' `.resolve_proc` is an instance of `Relay::ConnectionResolve` #204
- Types, fields and arguments can store arbitrary values in their `metadata` hashes #203
## 0.18.0 (4 Aug 2016)
### Breaking changes
- `graphql-relay` has been merged with `graphql`, you should remove `graphql-relay` from your gemfile. #195
### Deprecations
### New features
- `GraphQL.parse` can turn schema definitions into a `GraphQL::Language::Nodes::Document`. The document can be stringified again with `Document#to_query_string` #191
- Validation errors include a `path` to the part of the query where the error was found #198
- `.define` also accepts keywords for each helper method, eg `GraphQL::ObjectType.define(name: "PostType", ...)`
### Bug fixes
- `global_id_field`s have default complexity of 1, not `nil`
- Relay `pageInfo` is correct for connections limited by `max_page_size`
- Rescue invalid variable errors & missing operation name errors during query analysis
## 0.17.2 (26 Jul 2016)
### Bug fixes
- Correctly spread fragments when nested inside other fragments #194
## 0.17.1 (26 Jul 2016)
### Bug fixes
- Fix `InternalRepresentation::Node#inspect`
## 0.17.0 (21 Jul 2016)
### Breaking changes
- `InternalRepresentation::Node` API changes:
- `#definition_name` returns the field name on field nodes (while `#name` may have an alias)
- `#definitions` returns `{type => field}` pairs for possible fields on this node
- `#definition` is gone, it is equivalent to `node.definitions.values.first`
- `#on_types` is gone, it is equivalent to `node.definitions.keys`
### New features
- Accept `hash_key:` field option
- Call `.define { }` block lazily, so `-> { }` is not needed for circular references #182
### Bug fixes
- Support `on` as an Enum value
- If the same field is requested on multiple types, choose the maximum complexity among them (not the first)
## 0.16.1 (20 Jul 2016)
### Bug fixes
- Fix merging fragments on Union types (see #190, broken from #180)
## 0.16.0 (14 Jul 2016)
### Breaking changes & deprecations
- I don't _know_ that this breaks anything, but `GraphQL::Query::SerialExecution` now iterates over a tree of `GraphQL::InternalRepresentation::Node`s instead of an AST (`GraphQL::Language::Nodes::Document`).
### New features
- Query context keys can be assigned with `Context#[]=` #178
- Cancel further field resolution with `TimeoutMiddleware` #179
- Add `GraphQL::InternalRepresentation` for normalizing queries from AST #180
- Analyze the query before running it #180
- Assign complexity cost to fields, enforce max complexity before running it #180
- Log max complexity or max depth with `MaxComplexity` or `MaxDepth` analyzers #180
- Query context exposes `#irep_node`, the internal representation of the current node #180
### Bug fixes
- Non-null errors are propagated to the next nullable field, all the way up to `data` #174
## 0.15.3 (28 Jun 2016)
### New features
- `EnumValue`s can receive their properties after instantiation #171
## 0.15.2 (16 Jun 2016)
### New features
- Support lazy type arguments in Object's `interfaces` and Union's `possible_types` #169
### Bug fixes
- Support single-member Unions, as per the spec #170
## 0.15.1 (15 Jun 2016)
### Bug fixes
- Whitelist operation types in `lexer.rb`
## 0.15.0 (11 Jun 2016)
### Breaking changes & deprecations
- Remove `debug:` option, propagate all errors. #161
## 0.14.1 (11 Jun 2016)
### Breaking changes & deprecations
- `debug:` is deprecated (#165). Propagating errors (`debug: true`) will become the default behavior. You can get a similar implementation of error gobbling with `CatchallMiddleware`. Add it to your schema:
```ruby
MySchema.middleware << GraphQL::Schema::CatchallMiddleware
```
### New features
### Bug fixes
- Restore previous introspection fields on DirectiveType as deprecated #164
- Apply coercion to input default values #162
- Proper Enum behavior when a value isn't found
## 0.14.0 (31 May 2016)
### Breaking changes & deprecations
### New features
- `GraphQL::Language::Nodes::Document#to_query_string` will re-serialize a query AST #151
- Accept `root_value:` when running a query #157
- Accept a `GraphQL::Language::Nodes::Document` to `Query.new` (this allows you to cache parsed queries on the server) #152
### Bug fixes
- Improved parse error messages #149
- Improved build-time validation #150
- Raise a meaningful error when a Union or Interface can't be resolved during query execution #155
## 0.13.0 (29 Apr 2016)
### Breaking changes & deprecations
- "Dangling" object types are not loaded into the schema. The must be passed in `GraphQL::Schema.new(types: [...])`. (This was deprecated in 0.12.1)
### New features
- Update directive introspection to new spec #121
- Improved schema validation errors #113
- 20x faster parsing #119
- Support inline fragments without type condition #123
- Support multiple schemas composed of the same types #142
- Accept argument `description` and `default_value` in the block #138
- Middlewares can send _new_ arguments to subsequent middlewares #129
### Bug fixes
- Don't leak details of internal errors #120
- Default query `context` to `{}` #133
- Fixed list nullability validation #131
- Ensure field names are strings #128
- Fix `@skip` and `@include` implementation #124
- Interface membership is not shared between schemas #142
## 0.12.1 (26 Apr 2016)
### Breaking changes & deprecations
- __Connecting object types to the schema _only_ via interfaces is deprecated.__ It will be unsupported in the next version of `graphql`.
Sometimes, object type is only connected to the Query (or Mutation) root by being a member of an interface. In these cases, bugs happen, especially with Rails development mode. (And sometimes, the bugs don't appear until you deploy to a production environment!)
So, in a case like this:
```ruby
HatInterface = GraphQL::ObjectType.define do
# ...
end
FezType = GraphQL::ObjectType.define do
# ...
interfaces [HatInterface]
end
QueryType = GraphQL::ObjectType.define do
field :randomHat, HatInterface # ...
end
```
`FezType` can only be discovered by `QueryType` _through_ `HatInterface`. If `fez_type.rb` hasn't been loaded by Rails, `HatInterface.possible_types` will be empty!
Now, `FezType` must be passed to the schema explicitly:
```ruby
Schema.new(
# ...
types: [FezType]
)
```
Since the type is passed directly to the schema, it will be loaded right away!
### New features
### Bug fixes
## 0.12.0 (20 Mar 2016)
### Breaking changes & deprecations
- `GraphQL::DefinitionConfig` was replaced by `GraphQL::Define` #116
- Many scalar types are more picky about which inputs they allow (#115). To get the previous behavior, add this to your program:
```ruby
# Previous coerce behavior for scalars:
GraphQL::BOOLEAN_TYPE.coerce = ->(value) { !!value }
GraphQL::ID_TYPE.coerce = ->(value) { value.to_s }
GraphQL::STRING_TYPE.coerce = ->(value) { value.to_s }
# INT_TYPE and FLOAT_TYPE were unchanged
```
- `GraphQL::Field`s can't be renamed because `#resolve` may depend on that name. (This was only a problem if you pass the _same_ `GraphQL::Field` instance to `field ... field:` definitions.)
- `GraphQL::Query::DEFAULT_RESOLVE` was removed. `GraphQL::Field#resolve` handles that behavior.
### New features
- Can override `max_depth:` from `Schema#execute`
- Base `GraphQL::Error` for all graphql-related errors
### Bug fixes
- Include `""` for String default values (so it's encoded as a GraphQL string literal)
## 0.11.1 (6 Mar 2016)
### New features
- Schema `max_depth:` option #110
- Improved validation errors for input objects #104
- Interfaces provide field implementations to object types #108
## 0.11.0 (28 Feb 2016)
### Breaking changes & deprecations
- `GraphQL::Query::BaseExecution` was removed, you should probably extend `SerialExecution` instead #96
- `GraphQL::Language::Nodes` members no longer raise if they don't get inputs during `initialize` #92
- `GraphQL.parse` no longer accepts `as:` for parsing partial queries. #92
### New features
- `Field#property` & `Field#property=` can be used to access & modify the method that will be sent to the underlying object when resolving a field #88
- When defining a field, you can pass a string for as `type`. It will be looked up in the global namespace.
- `Query::Arguments#to_h` unwraps `Arguments` objects recursively
- If you raise `GraphQL::ExecutionError` during field resolution, it will be rescued and the message will be added to the response's `errors` key. #93
- Raise an error when non-null fields are `nil` #94
### Bug fixes
- Accept Rails params as input objects
- Don't get a runtime error when input contains unknown key #100
## 0.10.9 (15 Jan 2016)
### Bug fixes
- Handle re-assignment of `ObjectType#interfaces` #84
- Fix merging queries on interface-typed fields #85
## 0.10.8 (14 Jan 2016)
### Bug fixes
- Fix transform of nested lists #79
- Fix parse & transform of escaped characters #83
## 0.10.7 (22 Dec 2015)
### New features
- Support Rubinius
### Bug fixes
- Coerce values into one-item lists for ListTypes
## 0.10.6 (20 Dec 2015)
### Bug fixes
- Remove leftover `puts`es
## 0.10.5 (19 Dec 2015)
### Bug fixes
- Accept enum value description in definition #71
- Correctly parse empty input objects #75
- Correctly parse arguments preceded by newline
- Find undefined input object keys during static validation
## 0.10.4 (24 Nov 2015)
### New features
- Add `Arguments#to_h` #66
### Bug fixes
- Accept argument description in definition
- Correctly parse empty lists
## 0.10.3 (11 Nov 2015)
### New features
- Support root-level `subscription` type
### Bug fixes
- Require Set for Schema::Printer
## 0.10.2 (10 Nov 2015)
### Bug fixes
- Handle blank strings in queries
- Raise if a field is configured without a proper type #61
## 0.10.1 (22 Oct 2015)
### Bug fixes
- Properly merge fields on fragments within fragments
- Properly delegate enumerable-ish methods on `Arguments` #56
- Fix & refactor literal coersion & validation #53
## 0.10.0 (17 Oct 2015)
### New features
- Scalars can have distinct `coerce_input` and `coerce_result` methods #48
- Operations don't require a name #54
### Bug fixes
- Big refactors and fixes to variables and arguments:
- Correctly apply argument default values
- Correctly apply variable default values
- Raise at execution-time if non-null variables are missing
- Incoming values are coerced to their proper types before execution
## 0.9.5 (1 Oct 2015)
### New features
- Add `Schema#middleware` to wrap field access
- Add `RescueMiddleware` to handle errors during field execution
- Add `Schema::Printer` for printing the schema definition #45
### Bug fixes
## 0.9.4 (22 Sept 2015)
### New features
- Fields can return `GraphQL::ExecutionError`s to add errors to the response
### Bug fixes
- Fix resolution of union types in some queries #41
## 0.9.3 (15 Sept 2015)
### New features
- Add `Schema#execute` shorthand for running queries
- Merge identical fields in fragments so they're only resolved once #34
- An error during parsing raises `GraphQL::ParseError` #33
### Bug fixes
- Find nested input types in `TypeReducer` #35
- Find variable usages inside fragments during static validation
## 0.9.2, 0.9.1 (10 Sept 2015)
### Bug fixes
- remove Celluloid dependency
## 0.9.0 (10 Sept 2015)
### Breaking changes & deprecations
- remove `GraphQL::Query::ParallelExecution` (use [`graphql-parallel`](https://github.com/rmosolgo/graphql-parallel))
## 0.8.1 (10 Sept 2015)
### Breaking changes & deprecations
- `GraphQL::Query::ParallelExecution` has been extracted to [`graphql-parallel`](https://github.com/rmosolgo/graphql-parallel)
## 0.8.0 (4 Sept 2015)
### New features
- Async field resolution with `context.async { ... }`
- Access AST node during resolve with `context.ast_node`
### Bug fixes
- Fix for validating arguments returning up too soon
- Raise if you try to define 2 types with the same name
- Raise if you try to get a type by name but it doesn't exist
## 0.7.1 (27 Aug 2015)
### Bug fixes
- Merge nested results from different fragments instead of using the latest one only
## 0.7.0 (26 Aug 2015)
### Breaking changes & deprecations
- Query keyword argument `params:` was removed, use `variables:` instead.
### Bug fixes
- `@skip` has precedence over `@include`
- Handle when `DEFAULT_RESOVE` returns nil
## 0.6.2 (20 Aug 2015)
### Bug fixes
- Fix whitespace parsing in input objects
## 0.6.1 (16 Aug 2015)
### New features
- Parse UTF-8 characters & escaped characters
### Bug fixes
- Properly parse empty strings
- Fix argument / variable compatibility validation
## 0.6.0 (14 Aug 2015)
### Breaking changes & deprecations
- Deprecate `params` option to `Query#new` in favor of `variables`
- Deprecated `.new { |obj, types, fields, args| }` API was removed (use `.define`)
### New features
- `Query#new` accepts `operation_name` argument
- `InterfaceType` and `UnionType` accept `resolve_type` configs
### Bug fixes
- Gracefully handle blank-string & whitespace-only queries
- Handle lists in variable definitions and arguments
- Handle non-null input types
## 0.5.0 (12 Aug 2015)
### Breaking changes & deprecations
- Deprecate definition API that yielded a bunch of helpers #18
### New features
- Add new definition API #18
graphql-ruby-2.2.17/CNAME 0000664 0000000 0000000 00000000021 14764346352 0014775 0 ustar 00root root 0000000 0000000 graphql-ruby.org
graphql-ruby-2.2.17/Gemfile 0000664 0000000 0000000 00000001134 14764346352 0015530 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
source "https://rubygems.org"
gemspec
gem 'bootsnap' # required by the Rails apps generated in tests
gem 'stackprof', platform: :ruby
gem 'pry'
gem 'pry-stack_explorer', platform: :ruby
gem 'pry-byebug'
# For Ruby 3.2 compat:
gem "yard", github: "lsegal/yard", ref: "b51bf26"
if RUBY_VERSION >= "3.0"
gem "libev_scheduler"
gem "evt"
end
if RUBY_VERSION >= "3.1.1"
gem "async", "~>2.0"
end
# Required for running `jekyll algolia ...` (via `rake site:update_search_index`)
group :jekyll_plugins do
gem 'jekyll-algolia', '~> 1.0'
gem 'jekyll-redirect-from'
end
graphql-ruby-2.2.17/MIT-LICENSE 0000664 0000000 0000000 00000002036 14764346352 0015673 0 ustar 00root root 0000000 0000000 Copyright 2015 Robert Mosolgo
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
graphql-ruby-2.2.17/Rakefile 0000664 0000000 0000000 00000013136 14764346352 0015707 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require "bundler/gem_helper"
Bundler::GemHelper.install_tasks
require "rake/testtask"
require_relative "guides/_tasks/site"
require_relative "lib/graphql/rake_task/validate"
require 'rake/extensiontask'
Rake::TestTask.new do |t|
t.libs << "spec" << "lib" << "graphql-c_parser/lib"
exclude_integrations = []
['Mongoid', 'Rails'].each do |integration|
begin
Object.const_get(integration)
rescue NameError
exclude_integrations << integration.downcase
end
end
t.test_files = Dir['spec/**/*_spec.rb'].reject do |f|
next unless f.start_with?("spec/integration/")
excluded = exclude_integrations.any? do |integration|
f.start_with?("spec/integration/#{integration}/")
end
puts "+ #{f}" unless excluded
excluded
end
t.warning = false
end
require 'rubocop/rake_task'
RuboCop::RakeTask.new
default_tasks = [:test, :rubocop]
if ENV["SYSTEM_TESTS"]
task(default: ["test:system"] + default_tasks)
else
task(default: default_tasks)
end
def assert_dependency_version(dep_name, required_version, check_script)
version = `#{check_script}`
if !version.include?(required_version)
raise <<-ERR
build_parser requires #{dep_name} version "#{required_version}", but found:
$ #{check_script}
> #{version}
To fix this issue:
- Update #{dep_name} to the required version
- Update the assertion in `Rakefile` to match the current version
ERR
end
end
namespace :bench do
def prepare_benchmark
$LOAD_PATH << "./lib" << "./spec/support"
require_relative("./benchmark/run.rb")
end
desc "Benchmark parsing"
task :parse do
prepare_benchmark
GraphQLBenchmark.run("parse")
end
desc "Benchmark lexical analysis"
task :scan do
prepare_benchmark
GraphQLBenchmark.run("scan")
end
desc "Benchmark the introspection query"
task :query do
prepare_benchmark
GraphQLBenchmark.run("query")
end
desc "Benchmark validation of several queries"
task :validate do
prepare_benchmark
GraphQLBenchmark.run("validate")
end
desc "Profile a validation"
task :validate_memory do
prepare_benchmark
GraphQLBenchmark.validate_memory
end
desc "Generate a profile of the introspection query"
task :profile do
prepare_benchmark
GraphQLBenchmark.profile
end
desc "Run benchmarks on a very large result"
task :profile_large_result do
prepare_benchmark
GraphQLBenchmark.profile_large_result
end
desc "Run benchmarks on a small result"
task :profile_small_result do
prepare_benchmark
GraphQLBenchmark.profile_small_result
end
desc "Run introspection on a small schema"
task :profile_small_introspection do
prepare_benchmark
GraphQLBenchmark.profile_small_introspection
end
desc "Dump schema to SDL"
task :profile_to_definition do
prepare_benchmark
GraphQLBenchmark.profile_to_definition
end
desc "Compare GraphQL-Batch and GraphQL-Dataloader"
task :profile_batch_loaders do
prepare_benchmark
GraphQLBenchmark.profile_batch_loaders
end
desc "Run benchmarks on schema creation"
task :profile_boot do
prepare_benchmark
GraphQLBenchmark.profile_boot
end
desc "Check the memory footprint of a large schema"
task :profile_schema_memory_footprint do
prepare_benchmark
GraphQLBenchmark.profile_schema_memory_footprint
end
desc "Check the depth of the stacktrace during execution"
task :profile_stack_depth do
prepare_benchmark
GraphQLBenchmark.profile_stack_depth
end
desc "Run a very big introspection query"
task :profile_large_introspection do
prepare_benchmark
GraphQLBenchmark.profile_large_introspection
end
task :profile_small_query_on_large_schema do
prepare_benchmark
GraphQLBenchmark.profile_small_query_on_large_schema
end
desc "Run analysis on a big query"
task :profile_large_analysis do
prepare_benchmark
GraphQLBenchmark.profile_large_analysis
end
desc "Run analysis on parsing"
task :profile_parse do
prepare_benchmark
GraphQLBenchmark.profile_parse
end
end
namespace :test do
desc "Run system tests for ActionCable subscriptions"
task :system do
success = Dir.chdir("spec/dummy") do
system("bundle install")
system("bundle exec bin/rails test:system")
end
success || abort
end
task js: "js:test"
end
namespace :js do
client_dir = "./javascript_client"
desc "Run the tests for javascript_client"
task :test do
success = Dir.chdir(client_dir) do
system("yarn run test")
end
success || abort
end
desc "Install JS dependencies"
task :install do
Dir.chdir(client_dir) do
system("yarn install")
end
end
desc "Compile TypeScript to JavaScript"
task :build do
Dir.chdir(client_dir) do
system("yarn tsc")
end
end
task all: [:install, :build, :test]
end
task :build_c_lexer do
assert_dependency_version("Ragel", "7.0.4", "ragel -v")
`ragel -F1 graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl`
end
Rake::ExtensionTask.new("graphql_c_parser_ext") do |t|
t.ext_dir = 'graphql-c_parser/ext/graphql_c_parser_ext'
t.lib_dir = "graphql-c_parser/lib/graphql"
end
task :build_yacc_parser do
assert_dependency_version("Bison", "3.8", "yacc --version")
`yacc graphql-c_parser/ext/graphql_c_parser_ext/parser.y -o graphql-c_parser/ext/graphql_c_parser_ext/parser.c -Wyacc`
end
task :move_binary do
# For some reason my local env doesn't respect the `lib_dir` configured above
`mv graphql-c_parser/lib/*.bundle graphql-c_parser/lib/graphql`
end
desc "Build the C Extension"
task build_ext: [:build_c_lexer, :build_yacc_parser, "compile:graphql_c_parser_ext", :move_binary]
graphql-ruby-2.2.17/benchmark/ 0000775 0000000 0000000 00000000000 14764346352 0016170 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/benchmark/abstract_fragments.graphql 0000664 0000000 0000000 00000000674 14764346352 0023430 0 ustar 00root root 0000000 0000000 query AbstractFragments {
node(id: "1") {
...Frag1
}
}
fragment Frag1 on Commentable {
id
__typename
...Frag2
}
fragment Frag2 on Commentable {
id
__typename
...Frag3
}
fragment Frag3 on Commentable {
id
__typename
...Frag4
}
fragment Frag4 on Commentable {
id
__typename
...Frag5
}
fragment Frag5 on Commentable {
id
__typename
...Frag6
}
fragment Frag6 on Commentable {
comments {
body
}
}
graphql-ruby-2.2.17/benchmark/abstract_fragments_2.graphql 0000664 0000000 0000000 00000001230 14764346352 0023636 0 ustar 00root root 0000000 0000000 query AbstractFragments {
node(id: "1") {
...Frag1
}
}
fragment Frag1 on Commentable {
id
__typename
...Frag9
...Frag2
}
fragment Frag2 on Commentable {
id
__typename
...Frag9
...Frag3
}
fragment Frag3 on Commentable {
id
__typename
...Frag9
...Frag4
}
fragment Frag4 on Commentable {
id
__typename
...Frag9
...Frag5
}
fragment Frag5 on Commentable {
id
__typename
...Frag9
...Frag6
}
fragment Frag6 on Commentable {
...Frag7
...Frag9
name
id
comments {
...Frag8
...Frag7
id
}
}
fragment Frag7 on Node {
id
}
fragment Frag8 on Comment {
body
}
fragment Frag9 on Named {
name
}
graphql-ruby-2.2.17/benchmark/batch_loading.rb 0000664 0000000 0000000 00000006432 14764346352 0021300 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module BatchLoading
class GraphQLBatchSchema < GraphQL::Schema
DATA = [
{ id: "1", name: "Bulls", player_ids: ["2", "3"] },
{ id: "2", name: "Michael Jordan", team_id: "1" },
{ id: "3", name: "Scottie Pippin", team_id: "1" },
{ id: "4", name: "Braves", player_ids: ["5", "6"] },
{ id: "5", name: "Chipper Jones", team_id: "4" },
{ id: "6", name: "Tom Glavine", team_id: "4" },
]
class DataLoader < GraphQL::Batch::Loader
def initialize(column: :id)
@column = column
end
def perform(keys)
keys.each do |key|
record = DATA.find { |d| d[@column] == key }
fulfill(key, record)
end
end
end
class Team < GraphQL::Schema::Object
field :name, String, null: false
field :players, "[BatchLoading::GraphQLBatchSchema::Player]", null: false
def players
DataLoader.load_many(object[:player_ids])
end
end
class Player < GraphQL::Schema::Object
field :name, String, null: false
field :team, Team, null: false
def team
DataLoader.load(object[:team_id])
end
end
class Query < GraphQL::Schema::Object
field :team, Team do
argument :name, String
end
def team(name:)
DataLoader.for(column: :name).load(name)
end
end
query(Query)
use GraphQL::Batch
end
class GraphQLDataloaderSchema < GraphQL::Schema
class DataSource < GraphQL::Dataloader::Source
def initialize(options = {column: :id})
@column = options[:column]
end
def fetch(keys)
keys.map { |key|
d = GraphQLBatchSchema::DATA.find { |d| d[@column] == key }
# p [key, @column, d]
d
}
end
end
class Team < GraphQL::Schema::Object
field :name, String, null: false
field :players, "[BatchLoading::GraphQLDataloaderSchema::Player]", null: false
def players
dataloader.with(DataSource).load_all(object[:player_ids])
end
end
class Player < GraphQL::Schema::Object
field :name, String, null: false
field :team, Team, null: false
def team
dataloader.with(DataSource).load(object[:team_id])
end
end
class Query < GraphQL::Schema::Object
field :team, Team do
argument :name, String
end
def team(name:)
dataloader.with(DataSource, column: :name).load(name)
end
end
query(Query)
use GraphQL::Dataloader
end
class GraphQLNoBatchingSchema < GraphQL::Schema
DATA = GraphQLBatchSchema::DATA
class Team < GraphQL::Schema::Object
field :name, String, null: false
field :players, "[BatchLoading::GraphQLNoBatchingSchema::Player]", null: false
def players
object[:player_ids].map { |id| DATA.find { |d| d[:id] == id } }
end
end
class Player < GraphQL::Schema::Object
field :name, String, null: false
field :team, Team, null: false
def team
DATA.find { |d| d[:id] == object[:team_id] }
end
end
class Query < GraphQL::Schema::Object
field :team, Team do
argument :name, String
end
def team(name:)
DATA.find { |d| d[:name] == name }
end
end
query(Query)
end
end
graphql-ruby-2.2.17/benchmark/big_query.graphql 0000664 0000000 0000000 00000015561 14764346352 0021546 0 ustar 00root root 0000000 0000000 query Anc_inbox_layout($first_0:Int!,$first_5:Int!,$first_6:Int!,$first_a:Int!,$first_c:Int!,$order_by_1:ReportOrderInput!,$substate_2:ReportStateEnum!,$pre_submission_review_states_3:[ReportPreSubmissionReviewStateEnum]!,$size_4:ProfilePictureSizes!,$size_9:ProfilePictureSizes!,$not_types_7:[ActivityTypes]!,$order_by_8:ActivityOrderInput!,$order_by_b:TeamOrderInput!) {
query {
id,
...FE
}
}
fragment F0 on User {
username,
_profile_picturePkPpF:profile_picture(size:$size_4),
impact,
reputation,
signal,
id
}
fragment F1 on Report {
reporter {
username,
_profile_picturePkPpF:profile_picture(size:$size_4),
impact,
reputation,
signal,
_duplicate_users2Nhzxe:duplicate_users(first:$first_5) {
pageInfo {
hasNextPage,
hasPreviousPage
},
total_count,
edges {
node {
id,
...F0
},
cursor
}
},
id
},
id
}
fragment F2 on Report {
id
}
fragment F3 on Node {
id,
__typename
}
fragment F4 on ReportActivityInterface {
automated_response,
genius_execution_id,
report {
team {
handle,
id
},
id
},
__typename,
...F3
}
fragment F5 on Team {
url,
internet_bug_bounty,
_profile_pictureihzmG:profile_picture(size:$size_9),
name,
id
}
fragment F6 on User {
username,
url,
_profile_pictureihzmG:profile_picture(size:$size_9),
id
}
fragment F7 on ActivitiesBugDuplicate {
original_report_id,
id
}
fragment F8 on ActivitiesReferenceIdAdded {
reference,
reference_url,
id
}
fragment F9 on ActivitiesCveIdAdded {
cve_ids,
id
}
fragment Fa on ActivitiesAgreedOnGoingPublic {
first_to_agree,
id
}
fragment Fb on ActivitiesBugCloned {
original_report_id,
id
}
fragment Fc on ActivitiesUserAssignedToBug {
assigned_user {
url,
username,
id
},
id
}
fragment Fd on ActivitiesGroupAssignedToBug {
assigned_group {
name,
id
},
id
}
fragment Fe on ActivitiesExternalUserInvited {
email,
id
}
fragment Ff on ActivitiesExternalUserInvitationCancelled {
email,
id
}
fragment Fg on ActivitiesExternalUserRemoved {
removed_user {
id
},
id
}
fragment Fh on ActivitiesUserBannedFromProgram {
removed_user {
id
},
id
}
fragment Fi on ActivitiesBountyAwarded {
bounty_amount,
bounty_currency,
bonus_amount,
report {
reporter {
username,
url,
id
},
id
},
id
}
fragment Fj on ActivitiesBountySuggested {
bounty_amount,
bounty_currency,
bonus_amount,
id
}
fragment Fk on ActivitiesBugResolved {
report {
reporter {
username,
url,
id
},
id
},
id
}
fragment Fl on ActivitiesSwagAwarded {
report {
reporter {
username,
url,
id
},
id
},
id
}
fragment Fm on ActivitiesChangedScope {
old_scope {
asset_identifier,
id
},
new_scope {
asset_identifier,
id
},
id
}
fragment Fn on ActivityInterface {
_id,
internal,
i_can_edit,
__typename,
message,
markdown_message,
created_at,
updated_at,
actor {
__typename,
...F5,
...F6,
...F3
},
attachments {
_id,
file_name,
content_type,
expiring_url,
id
},
...F7,
...F8,
...F9,
...Fa,
...Fb,
...Fc,
...Fd,
...Fe,
...Ff,
...Fg,
...Fh,
...Fi,
...Fj,
...Fk,
...Fl,
...Fm,
...F3
}
fragment Fo on User {
username,
url,
__typename,
id
}
fragment Fp on TeamMemberGroup {
name,
__typename,
id
}
fragment Fq on Report {
_id,
url,
title,
state,
substate,
created_at,
assignee {
__typename,
...Fo,
...Fp,
...F3
},
cloned_from {
_id,
id
},
reporter {
username,
url,
id
},
team {
_id,
url,
handle,
name,
twitter_handle,
website,
about,
offers_bounties,
id
},
id
}
fragment Fr on Report {
state,
stage,
disclosed_at,
cve_ids,
singular_disclosure_disabled,
disclosed_at,
bug_reporter_agreed_on_going_public_at,
team_member_agreed_on_going_public_at,
comments_closed,
mediation_requested_at,
vulnerability_information,
vulnerability_information_html,
reporter {
disabled,
username,
url,
_profile_picture2g6hJa:profile_picture(size:$size_4),
id
},
weakness {
id,
name
},
original_report {
id,
url
},
attachments {
_id,
file_name,
expiring_url,
content_type,
id
},
allow_singular_disclosure_at,
allow_singular_disclosure_after,
singular_disclosure_allowed,
severity {
rating,
score,
author_type,
id
},
structured_scope {
_id,
asset_type,
asset_identifier,
max_severity,
id
},
_activities4z6spP:activities(first:$first_6,not_types:$not_types_7,order_by:$order_by_8) {
edges {
node {
__typename,
...F4,
...Fn,
...F3
},
cursor
},
pageInfo {
hasNextPage,
hasPreviousPage
}
},
id,
...Fq
}
fragment Fs on Report {
id,
...Fr
}
fragment Ft on Report {
title,
id
}
fragment Fu on Report {
_id,
pre_submission_review_state,
i_can_anc_review,
reporter {
username,
id
},
team {
handle,
id
},
id,
...F2
}
fragment Fv on Report {
team {
policy_html,
id
},
structured_scope {
asset_identifier,
asset_type,
instruction,
id
},
id
}
fragment Fw on Report {
weakness {
name,
id
},
id
}
fragment Fx on Report {
severity {
rating,
score,
id
},
id
}
fragment Fy on Report {
latest_activity_at,
created_at,
id,
...Fq
}
fragment Fz on Query {
me {
username,
_teamsWbVmT:teams(order_by:$order_by_b,first:$first_c) {
edges {
node {
name,
handle,
id
},
cursor
},
pageInfo {
hasNextPage,
hasPreviousPage
}
},
id
},
id
}
fragment FA on Query {
_reports1t04lE:reports(page:$first_0,first:$first_a,limit:$first_a,order_by:$order_by_1,substate:$substate_2,pre_submission_review_states:$pre_submission_review_states_3) {
total_count,
edges {
node {
_id,
id,
...Fy
},
cursor
},
pageInfo {
hasNextPage,
hasPreviousPage
}
},
id,
...Fz
}
fragment FB on Query {
id,
...Fz
}
fragment FC on Query {
id
}
fragment FD on Query {
me {
username,
_profile_pictureihzmG:profile_picture(size:$size_9),
id
},
id,
...FC
}
fragment FE on Query {
_reports3QQXft:reports(first:$first_0,order_by:$order_by_1,substate:$substate_2,pre_submission_review_states:$pre_submission_review_states_3) {
edges {
node {
id,
...F1,
...F2,
...Fs,
...Ft,
...Fu,
...Fv,
...Fw,
...Fx
},
cursor
},
pageInfo {
hasNextPage,
hasPreviousPage
}
},
id,
...FA,
...FB,
...FD
}
graphql-ruby-2.2.17/benchmark/big_schema.graphql 0000664 0000000 0000000 00000337223 14764346352 0021643 0 ustar 00root root 0000000 0000000 # Autogenerated input type of AcceptInvitation
input AcceptInvitationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
handle: String!
}
# Autogenerated return type of AcceptInvitation
type AcceptInvitationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
me: User
}
# Autogenerated input type of AcknowledgeProgramHealthAcknowledgementMutation
input AcknowledgeProgramHealthAcknowledgementMutationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
program_health_acknowledgement_id: ID!
}
# Autogenerated return type of AcknowledgeProgramHealthAcknowledgementMutation
type AcknowledgeProgramHealthAcknowledgementMutationPayload {
acknowledged_program_health_acknowledgement_id: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# A Activities::AgreedOnGoingPublic activity for a report
type ActivitiesAgreedOnGoingPublic implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
first_to_agree: Boolean!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BountyAwarded activity for a report
type ActivitiesBountyAwarded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
bonus_amount: String
bounty_amount: String
bounty_currency: String
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BountySuggested activity for a report
type ActivitiesBountySuggested implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
bonus_amount: String
bounty_amount: String
bounty_currency: String
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugCloned activity for a report
type ActivitiesBugCloned implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
original_report: Report
original_report_id: Int @deprecated(reason: "Deprecated in favor of .original_report")
report: Report
updated_at: String!
}
# A Activities::BugDuplicate activity for a report
type ActivitiesBugDuplicate implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
original_report: Report
original_report_id: Int @deprecated(reason: "Deprecated in favor of .original_report")
report: Report
updated_at: String!
}
# A Activities::BugFiled activity for a report
type ActivitiesBugFiled implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugInformative activity for a report
type ActivitiesBugInformative implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugNeedsMoreInfo activity for a report
type ActivitiesBugNeedsMoreInfo implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugNew activity for a report
type ActivitiesBugNew implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugNotApplicable activity for a report
type ActivitiesBugNotApplicable implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugReopened activity for a report
type ActivitiesBugReopened implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugResolved activity for a report
type ActivitiesBugResolved implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugSpam activity for a report
type ActivitiesBugSpam implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::BugTriaged activity for a report
type ActivitiesBugTriaged implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ChangedScope activity for a report
type ActivitiesChangedScope implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
new_scope: StructuredScope
old_scope: StructuredScope
report: Report
updated_at: String!
}
# A Activities::Comment activity for a report
type ActivitiesComment implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::CommentsClosed activity for a report
type ActivitiesCommentsClosed implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::CveIdAdded activity for a report
type ActivitiesCveIdAdded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
cve_ids: [String]
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalAdvisoryAdded activity for a report
type ActivitiesExternalAdvisoryAdded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalUserInvitationCancelled activity for a report
type ActivitiesExternalUserInvitationCancelled implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
email: String
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalUserInvited activity for a report
type ActivitiesExternalUserInvited implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
email: String
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalUserJoined activity for a report
type ActivitiesExternalUserJoined implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
duplicate_report: Report
duplicate_report_id: Int @deprecated(reason: "Deprecated in favor of .duplicate_report")
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ExternalUserRemoved activity for a report
type ActivitiesExternalUserRemoved implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
removed_user: User!
report: Report
updated_at: String!
}
# A Activities::GroupAssignedToBug activity for a report
type ActivitiesGroupAssignedToBug implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
assigned_group: TeamMemberGroup
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
group: TeamMemberGroup @deprecated(reason: "deprecated in favor of assigned group")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::HackerRequestedMediation activity for a report
type ActivitiesHackerRequestedMediation implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ManuallyDisclosed activity for a report
type ActivitiesManuallyDisclosed implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::MediationRequested activity for a report
type ActivitiesMediationRequested implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# An Activities::NobodyAssignedToBug activity for a report
type ActivitiesNobodyAssignedToBug implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::NotEligibleForBounty activity for a report
type ActivitiesNotEligibleForBounty implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReassignedToTeam activity for a report
type ActivitiesReassignedToTeam implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReferenceIdAdded activity for a report
type ActivitiesReferenceIdAdded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
reference: String
reference_url: String
report: Report
updated_at: String!
}
# A Activities::ReportBecamePublic activity for a report
type ActivitiesReportBecamePublic implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReportCollaboratorInvited activity for a report
type ActivitiesReportCollaboratorInvited implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReportCollaboratorJoined activity for a report
type ActivitiesReportCollaboratorJoined implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReportSeverityUpdated activity for a report
type ActivitiesReportSeverityUpdated implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::ReportTitleUpdated activity for a report
type ActivitiesReportTitleUpdated implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
new_title: String!
old_title: String!
report: Report
updated_at: String!
}
# A Activities::ReportVulnerabilityTypesUpdated activity for a report
type ActivitiesReportVulnerabilityTypesUpdated implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
new_weakness: Weakness
old_weakness: Weakness
report: Report
updated_at: String!
}
# A Activities::SwagAwarded activity for a report
type ActivitiesSwagAwarded implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
swag: Swag!
updated_at: String!
}
# A Activities::TeamPublished activity for a team
type ActivitiesTeamPublished implements ActivityInterface, Node {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
created_at: String!
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
updated_at: String!
}
# A Activities::UserAssignedToBug activity for a report
type ActivitiesUserAssignedToBug implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
assigned_user: User!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
report: Report
updated_at: String!
}
# A Activities::UserBannedFromProgram activity for a report
type ActivitiesUserBannedFromProgram implements ActivityInterface, Node, ReportActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
automated_response: Boolean
created_at: String!
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
removed_user: User!
report: Report
updated_at: String!
}
# A Activities::UserJoined activity for a user
type ActivitiesUserJoined implements ActivityInterface, Node {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
created_at: String!
i_can_edit: Boolean!
id: ID!
internal: Boolean
markdown_message: String
message: String
updated_at: String!
}
# The connection type for ActivityUnion.
type ActivityConnection {
# A list of edges.
edges: [ActivityUnionEdge]
max_updated_at: String
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# A interface for the common fields on an HackerOne Activity
interface ActivityInterface {
_id: ID!
actor: ActorUnion!
attachments: [Attachment]
created_at: String!
i_can_edit: Boolean!
internal: Boolean
markdown_message: String
message: String
updated_at: String!
}
# Fields on which a collection of activities can be ordered
enum ActivityOrderField {
created_at
updated_at
}
input ActivityOrderInput {
direction: OrderDirection!
field: ActivityOrderField!
}
# Possible types for an activity
enum ActivityTypes {
AgreedOnGoingPublic
BountyAwarded
BountySuggested
BugCloned
BugDuplicate
BugFiled
BugInformative
BugNeedsMoreInfo
BugNew
BugNotApplicable
BugReopened
BugResolved
BugSpam
BugTriaged
ChangedScope
Comment
CommentsClosed
CveIdAdded
ExternalAdvisoryAdded
ExternalUserInvitationCancelled
ExternalUserInvited
ExternalUserJoined
ExternalUserRemoved
GroupAssignedToBug
HackerRequestedMediation
ManuallyDisclosed
MediationRequested
NobodyAssignedToBug
NotEligibleForBounty
ReassignedToTeam
ReferenceIdAdded
ReportBecamePublic
ReportCollaboratorInvited
ReportCollaboratorJoined
ReportSeverityUpdated
ReportTitleUpdated
ReportVulnerabilityTypesUpdated
SwagAwarded
TeamPublished
UserAssignedToBug
UserBannedFromProgram
UserJoined
}
# Activities can be of multiple types
union ActivityUnion = ActivitiesAgreedOnGoingPublic | ActivitiesBountyAwarded | ActivitiesBountySuggested | ActivitiesBugCloned | ActivitiesBugDuplicate | ActivitiesBugFiled | ActivitiesBugInformative | ActivitiesBugNeedsMoreInfo | ActivitiesBugNew | ActivitiesBugNotApplicable | ActivitiesBugReopened | ActivitiesBugResolved | ActivitiesBugSpam | ActivitiesBugTriaged | ActivitiesChangedScope | ActivitiesComment | ActivitiesCommentsClosed | ActivitiesCveIdAdded | ActivitiesExternalAdvisoryAdded | ActivitiesExternalUserInvitationCancelled | ActivitiesExternalUserInvited | ActivitiesExternalUserJoined | ActivitiesExternalUserRemoved | ActivitiesGroupAssignedToBug | ActivitiesHackerRequestedMediation | ActivitiesManuallyDisclosed | ActivitiesMediationRequested | ActivitiesNobodyAssignedToBug | ActivitiesNotEligibleForBounty | ActivitiesReassignedToTeam | ActivitiesReferenceIdAdded | ActivitiesReportBecamePublic | ActivitiesReportCollaboratorInvited | ActivitiesReportCollaboratorJoined | ActivitiesReportSeverityUpdated | ActivitiesReportTitleUpdated | ActivitiesReportVulnerabilityTypesUpdated | ActivitiesSwagAwarded | ActivitiesTeamPublished | ActivitiesUserAssignedToBug | ActivitiesUserBannedFromProgram | ActivitiesUserJoined
# The connection type for ActivityUnion.
type ActivityUnionConnection {
# A list of edges.
edges: [ActivityUnionEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type ActivityUnionEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: ActivityUnion
}
# The actor of an activity can be multiple types
union ActorUnion = Team | User
# A HackerOne user's address used for submitting swag
type Address implements Node {
_id: ID!
city: String!
country: String!
created_at: String!
id: ID!
name: String!
phone_number: String
postal_code: String!
state: String!
street: String!
tshirt_size: TshirtSizeEnum @deprecated(reason: "Query tshirt size on User instead")
}
# Autogenerated input type of ArchiveStructuredScope
input ArchiveStructuredScopeInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
structured_scope_id: ID!
}
# Autogenerated return type of ArchiveStructuredScope
type ArchiveStructuredScopePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
query: Query
structured_scope: StructuredScope
}
# Report can be assigned to either a user or a team member group
union AssigneeUnion = TeamMemberGroup | User
# A HackerOne attachment for a report
type Attachment implements Node {
_id: ID!
content_type: String!
created_at: String!
expiring_url: String!
file_name: String!
file_size: Int!
id: ID!
}
# Types of authentication methods for users
enum AuthenticationServiceEnum {
database
saml
token
}
# A HackerOne badge
type Badge implements Node {
_id: ID!
description: String!
id: ID!
image_path: String!
name: String!
}
# Represents a badge earned by a user
type BadgesUsers implements Node {
_id: ID!
badge: Badge!
created_at: String!
id: ID!
user: User!
}
# The connection type for BadgesUsers.
type BadgesUsersConnection {
# A list of edges.
edges: [BadgesUsersEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type BadgesUsersEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: BadgesUsers
}
# Resources for setting up the Bank Transfer payment method
type BankTransferReference implements Node {
beneficiary_required_details(currency: String!, bank_account_country: String!, beneficiary_country: String!): BeneficiaryRequiredDetail
countries: [Country]
currencies: [Currency]
id: ID!
}
# A specification of information needed to create a bank transfer payment preference
type BeneficiaryRequiredDetail implements Node {
bank_account_country: String!
beneficiary_country: String!
beneficiary_required_details(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): BeneficiaryRequiredDetailsConnection
currency: String!
id: ID!
}
input BeneficiaryRequiredDetailInput {
field: String!
value: String!
}
# A specification of the possibilities for creating a bank transfer payout preference
type BeneficiaryRequiredDetails implements Node {
beneficiary_entity_type: String!
beneficiary_required_fields(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): BeneficiaryRequiredFieldConnection
description: String!
fee: String!
id: ID!
payment_type: String!
}
# The connection type for BeneficiaryRequiredDetails.
type BeneficiaryRequiredDetailsConnection {
# A list of edges.
edges: [BeneficiaryRequiredDetailsEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type BeneficiaryRequiredDetailsEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: BeneficiaryRequiredDetails
}
# A specification of the format of a field used to create a bank transfer payout preference
type BeneficiaryRequiredField implements Node {
description: String!
field: String!
id: ID!
regex: String!
}
# The connection type for BeneficiaryRequiredField.
type BeneficiaryRequiredFieldConnection {
# A list of edges.
edges: [BeneficiaryRequiredFieldEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type BeneficiaryRequiredFieldEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: BeneficiaryRequiredField
}
# A HackerOne bounty for a report
type Bounty implements Node {
_id: ID!
amount: String!
awarded_amount: String!
awarded_bonus_amount: String!
awarded_currency: String!
bonus_amount: String!
created_at: String!
id: ID!
report: Report!
status: BountyStatusEnum!
}
# The connection type for Bounty.
type BountyConnection {
# A list of edges.
edges: [BountyEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_amount: Float!
total_count: Int!
}
# An edge in a connection.
type BountyEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Bounty
}
# Status which reflect the state of a bounty
enum BountyStatusEnum {
cancelled
confirmed
failed
failed_ofac_check
needs_payout_method
needs_tax_form
no_mileage_account
no_status
no_tax_form
ofac_reject
pending
pending_ofac_check
rejected
sent
}
# A subset of weaknesses that share a common characteristic
type Cluster implements Node {
created_at: String!
description: String
id: ID!
name: String!
updated_at: String!
weaknesses(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: WeaknessOrder = {direction: ASC, field: name}
search: String = null
team_handle: String = null
team_weakness_state: [TeamWeaknessStates] = [enabled, disabled, hidden]
): ClusterWeaknessConnection
}
# The connection type for Cluster.
type ClusterConnection {
# A list of edges.
edges: [ClusterEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type ClusterEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Cluster
}
input ClusterOrder {
direction: OrderDirection!
field: ClusterOrderField!
}
# Fields on which a collection of Cluster can be ordered
enum ClusterOrderField {
BROWSING_FRIENDLY
}
# The connection type for Weakness.
type ClusterWeaknessConnection {
# A list of edges.
edges: [ClusterWeaknessEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type ClusterWeaknessEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Weakness
team_weakness(team_handle: String!): TeamWeakness
}
# A Coinbase Payout Preference
type CoinbasePayoutPreferenceType implements Node, PayoutPreferenceInterface {
_id: ID!
default: Boolean
email: String
id: ID!
}
# A common response
type CommonResponse implements Node {
# The primary key from the database
_id: ID!
created_at: String!
id: ID!
message: String!
team: Team!
title: String!
updated_at: String!
}
# The connection type for CommonResponse.
type CommonResponseConnection {
# A list of edges.
edges: [CommonResponseEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type CommonResponseEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: CommonResponse
}
input CommonResponseOrder {
direction: OrderDirection!
field: CommonResponseOrderField!
}
# Fields on which a collection of common responses can be ordered
enum CommonResponseOrderField {
title
}
# Will only return values for valid SeverityRatingEnum and null.
scalar CountBySeverity
# A country as specified in ISO 3166
type Country implements Node {
alpha2: String!
currency_code: String
id: ID!
name: String!
}
# Autogenerated input type of CreateActivityComment
input CreateActivityCommentInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
internal: Boolean!
message: String!
report_id: ID!
}
# Autogenerated return type of CreateActivityComment
type CreateActivityCommentPayload {
activities: ActivityUnionConnection
activity: ActivitiesComment
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
new_activity_edge: ActivityUnionEdge
report: Report
}
# Autogenerated input type of CreateBounty
input CreateBountyInput {
amount: Float
bonus_amount: Float
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String
report_id: ID!
}
# Autogenerated return type of CreateBounty
type CreateBountyPayload {
bounty: Bounty!
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated input type of CreateBountySuggestion
input CreateBountySuggestionInput {
amount: Float
bonus_amount: Float
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String
report_id: ID!
}
# Autogenerated return type of CreateBountySuggestion
type CreateBountySuggestionPayload {
activity: ActivitiesBountySuggested!
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated input type of CreateCoinbasePayoutPreference
input CreateCoinbasePayoutPreferenceInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
coinbase_email: String!
default_method: Boolean!
}
# Autogenerated return type of CreateCoinbasePayoutPreference
type CreateCoinbasePayoutPreferencePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
me: User
}
# Autogenerated input type of CreateCurrencycloudBankTransferPayoutPreference
input CreateCurrencycloudBankTransferPayoutPreferenceInput {
bank_account_country: String!
bank_account_holder_name: String!
beneficiary_entity_type: CurrencycloudBankTransferEntityType!
beneficiary_required_details: [BeneficiaryRequiredDetailInput]!
# A unique identifier for the client performing the mutation.
clientMutationId: String
currency: String!
default_method: Boolean!
payment_type: CurrencycloudBankTransferPaymentType!
}
# Autogenerated return type of CreateCurrencycloudBankTransferPayoutPreference
type CreateCurrencycloudBankTransferPayoutPreferencePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of CreateJiraOauthUrl
input CreateJiraOauthUrlInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
site: String!
team_id: ID!
}
# Autogenerated return type of CreateJiraOauthUrl
type CreateJiraOauthUrlPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
url: String
}
# Autogenerated input type of CreateJiraWebhookToken
input CreateJiraWebhookTokenInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_id: ID!
}
# Autogenerated return type of CreateJiraWebhookToken
type CreateJiraWebhookTokenPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team!
webhook_url: String!
}
# Autogenerated input type of CreateMailingAddress
input CreateMailingAddressInput {
city: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
country: String!
name: String!
phone_number: String!
postal_code: String!
state: String!
street: String!
}
# Autogenerated return type of CreateMailingAddress
type CreateMailingAddressPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of CreateOrUpdateHackeroneToJiraEventsConfiguration
input CreateOrUpdateHackeroneToJiraEventsConfigurationInput {
assignee_changes: Boolean
# A unique identifier for the client performing the mutation.
clientMutationId: String
comments: Boolean
public_disclosures: Boolean
rewards: Boolean
state_changes: Boolean
team_id: ID!
}
# Autogenerated return type of CreateOrUpdateHackeroneToJiraEventsConfiguration
type CreateOrUpdateHackeroneToJiraEventsConfigurationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team!
}
# Autogenerated input type of CreateOrUpdateJiraIntegration
input CreateOrUpdateJiraIntegrationInput {
assignee: String
base_url: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
custom: String
description: String!
generate_webhook_in_jira_if_does_not_exist: Boolean
issue_type: Int!
labels: String
pid: Int!
summary: String!
team_id: ID!
}
# Autogenerated return type of CreateOrUpdateJiraIntegration
type CreateOrUpdateJiraIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of CreatePaypalPreference
input CreatePaypalPreferenceInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
default_method: Boolean!
paypal_email: String!
}
# Autogenerated return type of CreatePaypalPreference
type CreatePaypalPreferencePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of CreateSlackPipeline
input CreateSlackPipelineInput {
channel: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
descriptive_label: String
notification_report_agreed_on_going_public: Boolean!
notification_report_assignee_changed: Boolean!
notification_report_became_public: Boolean!
notification_report_bounty_paid: Boolean!
notification_report_bounty_suggested: Boolean!
notification_report_bug_closed_as_spam: Boolean!
notification_report_bug_duplicate: Boolean!
notification_report_bug_informative: Boolean!
notification_report_bug_needs_more_info: Boolean!
notification_report_bug_new: Boolean!
notification_report_bug_not_applicable: Boolean!
notification_report_closed_as_resolved: Boolean!
notification_report_comments_closed: Boolean!
notification_report_created: Boolean!
notification_report_internal_comment_added: Boolean!
notification_report_manually_disclosed: Boolean!
notification_report_not_eligible_for_bounty: Boolean!
notification_report_public_comment_added: Boolean!
notification_report_reopened: Boolean!
notification_report_swag_awarded: Boolean!
notification_report_triaged: Boolean!
team_id: ID!
}
# Autogenerated return type of CreateSlackPipeline
type CreateSlackPipelinePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
new_slack_pipeline_edge: SlackPipelineEdge
slack_pipelines_connection: SlackPipelineConnection
team: Team!
}
# Autogenerated input type of CreateStructuredScope
input CreateStructuredScopeInput {
asset_identifier: String!
asset_type: StructuredScopedAssetTypeEnum
availability_requirement: String
# A unique identifier for the client performing the mutation.
clientMutationId: String
confidentiality_requirement: String
eligible_for_bounty: Boolean
eligible_for_submission: Boolean
instruction: String
integrity_requirement: String
reference: String
team_id: ID!
}
# Autogenerated return type of CreateStructuredScope
type CreateStructuredScopePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of CreateSurveyAnswer
input CreateSurveyAnswerInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
feedback: String
invitation_token: String
structured_response_ids: [ID]!
}
# Autogenerated return type of CreateSurveyAnswer
type CreateSurveyAnswerPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of CreateSwag
input CreateSwagInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String
report_id: ID!
}
# Autogenerated return type of CreateSwag
type CreateSwagPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
swag: Swag!
}
# Autogenerated input type of CreateTaxForm
input CreateTaxFormInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
type: TaxFormTypeEnum!
}
# Autogenerated return type of CreateTaxForm
type CreateTaxFormPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [String]
me: User
}
# Autogenerated input type of CreateUserBountiesReport
input CreateUserBountiesReportInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of CreateUserBountiesReport
type CreateUserBountiesReportPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of CreateUserLufthansaAccount
input CreateUserLufthansaAccountInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
first_name: String!
last_name: String!
number: String!
}
# Autogenerated return type of CreateUserLufthansaAccount
type CreateUserLufthansaAccountPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# A currency as defined by ISO 4217
type Currency implements Node {
code: String!
id: ID!
name: String!
}
# Possible currencies codes for bounties
enum CurrencyCode {
USD
XLA
}
# Different entity types for currencycloud payout preferences
enum CurrencycloudBankTransferEntityType {
company
individual
}
# Different payment types for currencycloud payout preferences
enum CurrencycloudBankTransferPaymentType {
priority
regular
}
# A CurrencyCloud Bank Transfer Payout Preference
type CurrencycloudBankTransferPayoutPreferenceType implements Node, PayoutPreferenceInterface {
_id: ID!
default: Boolean
id: ID!
name: String
}
# Autogenerated input type of DeleteBiDirectionalJiraIntegration
input DeleteBiDirectionalJiraIntegrationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_id: ID!
}
# Autogenerated return type of DeleteBiDirectionalJiraIntegration
type DeleteBiDirectionalJiraIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of DeleteJiraWebhook
input DeleteJiraWebhookInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
jira_webhook_id: ID!
}
# Autogenerated return type of DeleteJiraWebhook
type DeleteJiraWebhookPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of DeletePhabricatorIntegration
input DeletePhabricatorIntegrationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_id: ID!
}
# Autogenerated return type of DeletePhabricatorIntegration
type DeletePhabricatorIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of DeleteSlackPipeline
input DeleteSlackPipelineInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
slack_pipeline_id: String!
}
# Autogenerated return type of DeleteSlackPipeline
type DeleteSlackPipelinePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
deleted_slack_pipeline_id: String!
team: Team
}
# Autogenerated input type of DeleteTeamMember
input DeleteTeamMemberInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_member_id: ID!
}
# Autogenerated return type of DeleteTeamMember
type DeleteTeamMemberPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
deletedMembershipId: ID
errors: Hash
me: User
}
# Autogenerated input type of DeleteTeamSlackIntegration
input DeleteTeamSlackIntegrationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
slack_integration_id: ID!
}
# Autogenerated return type of DeleteTeamSlackIntegration
type DeleteTeamSlackIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of DeleteUserLufthansaAccount
input DeleteUserLufthansaAccountInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of DeleteUserLufthansaAccount
type DeleteUserLufthansaAccountPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of DisableTwoFactorAuthentication
input DisableTwoFactorAuthenticationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
password: String!
totp_code: String!
}
# Autogenerated return type of DisableTwoFactorAuthentication
type DisableTwoFactorAuthenticationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [String]
me: User
}
# Autogenerated input type of DismissProgramHealthAcknowledgementMutation
input DismissProgramHealthAcknowledgementMutationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
program_health_acknowledgement_id: ID!
}
# Autogenerated return type of DismissProgramHealthAcknowledgementMutation
type DismissProgramHealthAcknowledgementMutationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
dismissed_program_health_acknowledgement_id: String!
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of EnableTwoFactorAuthentication
input EnableTwoFactorAuthenticationInput {
backup_codes: [String]!
# A unique identifier for the client performing the mutation.
clientMutationId: String
password: String!
signature: String!
totp_code: String!
totp_secret: String!
}
# Autogenerated return type of EnableTwoFactorAuthentication
type EnableTwoFactorAuthenticationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [String]
me: User
}
# Autogenerated input type of EnableUser
input EnableUserInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of EnableUser
type EnableUserPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of EnrollForProgram
input EnrollForProgramInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_id: ID!
}
# Autogenerated return type of EnrollForProgram
type EnrollForProgramPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
deleted_recommended_program_edge: TeamEdge
query: Query!
teams_connection: TeamConnection
}
# An error
type Error implements Node {
field: String
id: ID!
message: String!
type: ErrorTypeEnum!
}
# Types of errors that can occur
enum ErrorTypeEnum {
ARGUMENT
AUTHORIZATION
}
# An External Program
type ExternalProgram implements Node {
# The primary key from the database
_id: ID!
about: String
handle: String!
# ID of the object.
id: ID!
name: String!
profile_picture(size: ProfilePictureSizes!): String!
}
# Autogenerated input type of GenerateMfaOtp
input GenerateMfaOtpInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of GenerateMfaOtp
type GenerateMfaOtpPayload {
backup_codes: [String]
# A unique identifier for the client performing the mutation.
clientMutationId: String
me: User
qrcode: Hash
signature: String
totp_secret: String
}
# Autogenerated input type of GenerateTaxFormUrl
input GenerateTaxFormUrlInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
}
# Autogenerated return type of GenerateTaxFormUrl
type GenerateTaxFormUrlPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# A HackeronePayroll Payout Preference
type HackeronePayrollPayoutPreferenceType implements Node, PayoutPreferenceInterface {
_id: ID!
default: Boolean
email: String
id: ID!
}
# Configuration for the events sent from HackerOne to JIRA
type HackeroneToJiraEventsConfiguration implements Node {
assignee_changes: Boolean!
comments: Boolean!
id: ID!
public_disclosures: Boolean!
rewards: Boolean!
state_changes: Boolean!
team: Team!
}
scalar Hash
# An interface for the common fields on a HackerOne Invitation
interface InvitationInterface {
_id: ID!
}
# User invitation preference type
enum InvitationPreferenceTypeEnum {
always
bounty_only
never
}
# Invitations can be of multiple types
union InvitationUnion = InvitationsSoftLaunch
# The connection type for InvitationUnion.
type InvitationUnionConnection {
# A list of edges.
edges: [InvitationUnionEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type InvitationUnionEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: InvitationUnion
}
# An invitation to join a private team as a hacker
type InvitationsSoftLaunch implements InvitationInterface, Node {
_id: ID!
expires_at: String
id: ID!
markdown_message: String
message: String
team: Team!
token: String
}
# A JIRA integration for a team
type JiraIntegration implements Node {
assignee: String
base_url: String!
created_at: String!
custom: String
description: String!
id: ID!
issue_type: Int!
labels: String
pid: Int!
summary: String!
team: Team!
updated_at: String!
}
# A JIRA Oauth for a team
type JiraOauth implements Node {
# Assignables for a project
assignables(project_id: Int!): [Hash]
configured: Boolean!
created_at: String!
id: ID!
issue_types: [Hash]
projects: [Hash]
site: String
team: Team!
updated_at: String!
}
# A JIRA webhook for a team
type JiraWebhook implements Node {
created_at: String!
id: ID!
last_event_received_at: String
last_token_issued_at: String
process_assignee_change: Boolean!
process_comment_add: Boolean!
process_priority_change: Boolean!
process_resolution_change: Boolean!
process_status_change: Boolean!
team: Team!
updated_at: String!
}
# Autogenerated input type of LeavePrivateProgram
input LeavePrivateProgramInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
handle: String!
}
# Autogenerated return type of LeavePrivateProgram
type LeavePrivateProgramPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of LockReport
input LockReportInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
report_id: ID!
}
# Autogenerated return type of LockReport
type LockReportPayload {
activities: ActivityUnionConnection
activity: ActivitiesComment
# A unique identifier for the client performing the mutation.
clientMutationId: String
new_activity_edge: ActivityUnionEdge
report: Report
}
# Settings for a user's Lufthansa Account
type LufthansaAccount implements Node {
created_at: String!
first_name: String!
id: ID!
last_name: String!
number: String!
updated_at: String!
}
# Autogenerated input type of MarkReportAsNeedsMoreInfo
input MarkReportAsNeedsMoreInfoInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String!
report_id: ID!
}
# Autogenerated return type of MarkReportAsNeedsMoreInfo
type MarkReportAsNeedsMoreInfoPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
query: Query
report: Report
report_id: ID!
was_successful: Boolean!
}
# Autogenerated input type of MarkReportAsNoise
input MarkReportAsNoiseInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String!
report_id: ID!
}
# Autogenerated return type of MarkReportAsNoise
type MarkReportAsNoisePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
query: Query
report: Report
was_successful: Boolean!
}
# Autogenerated input type of MarkReportAsSignal
input MarkReportAsSignalInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String
report_id: ID!
}
# Autogenerated return type of MarkReportAsSignal
type MarkReportAsSignalPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
query: Query
report: Report
was_successful: Boolean!
}
type Mutation {
acceptInvitation(input: AcceptInvitationInput!): AcceptInvitationPayload
acknowledgeProgramHealthAcknowledgement(input: AcknowledgeProgramHealthAcknowledgementMutationInput!): AcknowledgeProgramHealthAcknowledgementMutationPayload
archiveStructuredScope(input: ArchiveStructuredScopeInput!): ArchiveStructuredScopePayload
createActivityComment(input: CreateActivityCommentInput!): CreateActivityCommentPayload
createBounty(input: CreateBountyInput!): CreateBountyPayload
createBountySuggestion(input: CreateBountySuggestionInput!): CreateBountySuggestionPayload
createCoinbasePayoutPreference(input: CreateCoinbasePayoutPreferenceInput!): CreateCoinbasePayoutPreferencePayload
createCurrencycloudBankTransferPayoutPreference(input: CreateCurrencycloudBankTransferPayoutPreferenceInput!): CreateCurrencycloudBankTransferPayoutPreferencePayload
createJiraOauthUrl(input: CreateJiraOauthUrlInput!): CreateJiraOauthUrlPayload
createJiraWebhookToken(input: CreateJiraWebhookTokenInput!): CreateJiraWebhookTokenPayload
createMailingAddress(input: CreateMailingAddressInput!): CreateMailingAddressPayload
createOrUpdateHackeroneToJiraEventsConfiguration(input: CreateOrUpdateHackeroneToJiraEventsConfigurationInput!): CreateOrUpdateHackeroneToJiraEventsConfigurationPayload
createOrUpdateJiraIntegration(input: CreateOrUpdateJiraIntegrationInput!): CreateOrUpdateJiraIntegrationPayload
createPaypalPreference(input: CreatePaypalPreferenceInput!): CreatePaypalPreferencePayload
createSlackPipeline(input: CreateSlackPipelineInput!): CreateSlackPipelinePayload
createStructuredScope(input: CreateStructuredScopeInput!): CreateStructuredScopePayload
createSurveyAnswer(input: CreateSurveyAnswerInput!): CreateSurveyAnswerPayload
createSwag(input: CreateSwagInput!): CreateSwagPayload
createTaxForm(input: CreateTaxFormInput!): CreateTaxFormPayload
createUserBountiesReport(input: CreateUserBountiesReportInput!): CreateUserBountiesReportPayload
createUserLufthansaAccount(input: CreateUserLufthansaAccountInput!): CreateUserLufthansaAccountPayload
deleteBiDirectionalJiraIntegration(input: DeleteBiDirectionalJiraIntegrationInput!): DeleteBiDirectionalJiraIntegrationPayload
deleteJiraWebhook(input: DeleteJiraWebhookInput!): DeleteJiraWebhookPayload
deletePhabricatorIntegration(input: DeletePhabricatorIntegrationInput!): DeletePhabricatorIntegrationPayload
deleteSlackPipeline(input: DeleteSlackPipelineInput!): DeleteSlackPipelinePayload
deleteTeamMember(input: DeleteTeamMemberInput!): DeleteTeamMemberPayload
deleteTeamSlackIntegration(input: DeleteTeamSlackIntegrationInput!): DeleteTeamSlackIntegrationPayload
deleteUserLufthansaAccount(input: DeleteUserLufthansaAccountInput!): DeleteUserLufthansaAccountPayload
disableTwoFactorAuthentication(input: DisableTwoFactorAuthenticationInput!): DisableTwoFactorAuthenticationPayload
dismissProgramHealthAcknowledgement(input: DismissProgramHealthAcknowledgementMutationInput!): DismissProgramHealthAcknowledgementMutationPayload
enableTwoFactorAuthentication(input: EnableTwoFactorAuthenticationInput!): EnableTwoFactorAuthenticationPayload
enableUser(input: EnableUserInput!): EnableUserPayload
enrollForProgram(input: EnrollForProgramInput!): EnrollForProgramPayload
generateMfaOtp(input: GenerateMfaOtpInput!): GenerateMfaOtpPayload
generateTaxFormUrl(input: GenerateTaxFormUrlInput!): GenerateTaxFormUrlPayload
leavePrivateProgram(input: LeavePrivateProgramInput!): LeavePrivateProgramPayload
lockReport(input: LockReportInput!): LockReportPayload
markReportAsNeedsMoreInfo(input: MarkReportAsNeedsMoreInfoInput!): MarkReportAsNeedsMoreInfoPayload
markReportAsNoise(input: MarkReportAsNoiseInput!): MarkReportAsNoisePayload
markReportAsSignal(input: MarkReportAsSignalInput!): MarkReportAsSignalPayload
rejectInvitation(input: RejectInvitationInput!): RejectInvitationPayload
updateAutomaticInvites(input: UpdateAutomaticInvitesInput!): UpdateAutomaticInvitesPayload
updateBackupCodes(input: UpdateBackupCodesInput!): UpdateBackupCodesPayload
updateInvitationPreferences(input: UpdateInvitationPreferencesInput!): UpdateInvitationPreferencesPayload
updateJiraWebhook(input: UpdateJiraWebhookInput!): UpdateJiraWebhookPayload
updateMe(input: UpdateMeInput!): UpdateMePayload
updatePhabricatorIntegration(input: UpdatePhabricatorIntegrationInput!): UpdatePhabricatorIntegrationPayload
updateReportStateToNeedsMoreInfo(input: UpdateReportStateToNeedsMoreInfoInput!): UpdateReportStateToNeedsMoreInfoPayload
updateReportStructuredScope(input: UpdateReportStructuredScopeInput!): UpdateReportStructuredScopePayload
updateSlackPipeline(input: UpdateSlackPipelineInput!): UpdateSlackPipelinePayload
updateSlackUser(input: UpdateSlackUserInput!): UpdateSlackUserPayload
updateStructuredScope(input: UpdateStructuredScopeInput!): UpdateStructuredScopePayload
updateTeamFancySlackIntegration(input: UpdateTeamFancySlackIntegrationInput!): UpdateTeamFancySlackIntegrationPayload
updateTeamMemberVisibility(input: UpdateTeamMemberVisibilityInput!): UpdateTeamMemberVisibilityPayload
updateTeamSubmissionState(input: UpdateTeamSubmissionStateInput!): UpdateTeamSubmissionStatePayload
updateTeamSubscription(input: UpdateTeamSubscriptionInput!): UpdateTeamSubscriptionPayload
updateTeamWeakness(input: UpdateTeamWeaknessInput!): UpdateTeamWeaknessPayload
updateUserEmail(input: UpdateUserEmailInput!): UpdateUserEmailPayload
updateUserLufthansaAccount(input: UpdateUserLufthansaAccountInput!): UpdateUserLufthansaAccountPayload
updateUserPassword(input: UpdateUserPasswordInput!): UpdateUserPasswordPayload
}
# An object with an ID.
interface Node {
# ID of the object.
id: ID!
}
# Possible directions for sorting a collection
enum OrderDirection {
ASC
DESC
}
# Information about pagination in a connection.
type PageInfo {
# When paginating forwards, the cursor to continue.
endCursor: String
# When paginating forwards, are there more items?
hasNextPage: Boolean!
# When paginating backwards, are there more items?
hasPreviousPage: Boolean!
# When paginating backwards, the cursor to continue.
startCursor: String
}
# The connection type for User.
type ParticipantConnection {
# A list of edges.
edges: [ParticipantWithReputationEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
year_range: [Int]
}
# An edge in a connection.
type ParticipantWithReputationEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: User
# The participant's rank within the team
rank: Int
# The participant's reputation within the team
reputation: Int
}
# A interface for the common fields on an Payout Preference
interface PayoutPreferenceInterface {
_id: ID!
default: Boolean
id: ID!
}
# A user can have payout preferences for different payment services
union PayoutPreferenceUnion = CoinbasePayoutPreferenceType | CurrencycloudBankTransferPayoutPreferenceType | HackeronePayrollPayoutPreferenceType | PaypalPayoutPreferenceType
# A Paypal Payout Preference
type PaypalPayoutPreferenceType implements Node, PayoutPreferenceInterface {
_id: ID!
default: Boolean
email: String
id: ID!
}
# All available permissions
enum PermissionEnum {
program_management
}
# A Phabricator integration for a team
type PhabricatorIntegration implements Node {
base_url: String
created_at: String!
description: String
id: ID!
process_h1_comment_added: Boolean!
process_h1_status_change: Boolean!
process_phabricator_comment_added: Boolean!
process_phabricator_status_change: Boolean!
project_tags: String
team: Team!
title: String
updated_at: String!
}
# Different possible profile picture sizes
enum ProfilePictureSizes {
# 110x110
large
# 82x82
medium
# 62x62
small
# 260x260
xtralarge
}
# A program_health_acknowledgement for a team_member
type ProgramHealthAcknowledgement implements Node {
acknowledged: Boolean
created_at: String
dismissed: Boolean
id: ID!
reason: ProgramHealthAcknowledgementReasonEnum
team_member: TeamMember!
}
# The connection type for ProgramHealthAcknowledgement.
type ProgramHealthAcknowledgementConnection {
# A list of edges.
edges: [ProgramHealthAcknowledgementEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type ProgramHealthAcknowledgementEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: ProgramHealthAcknowledgement
}
# reason which reflect the state of a program health acknowledgement
enum ProgramHealthAcknowledgementReasonEnum {
failed
ok
paused
review
}
# Root entity of the Hackerone Schema
type Query implements Node {
bank_transfer_reference: BankTransferReference
clusters(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: ClusterOrder = {direction: ASC, field: BROWSING_FRIENDLY}
): ClusterConnection
external_program(handle: String!): ExternalProgram
id: ID!
me: User
# Fetches an object given its ID.
node(
# ID of the object.
id: ID!
): Node
query: Query!
report(id: Int!): Report @deprecated(reason: "Query for a Report node at the root level is not recommended.")
reports(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
database_id: Int = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
limit: Int = null
order_by: ReportOrderInput = {direction: DESC, field: id}
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
page: Int = null
pre_submission_review_states: [ReportPreSubmissionReviewStateEnum] = null
substate: ReportStateEnum
without_scope: Boolean = null
): ReportConnection
resource(url: URI): ResourceInterface
session: Session
severity_calculator: SeverityCalculator
surveys(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
category: SurveyCategoryEnum
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): SurveyConnectionType
team(handle: String!): Team @deprecated(reason: "Query for a Team node at the root level is not recommended. Ref T12456")
teams(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
enrollable: Boolean
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: TeamOrderInput
permissions: [PermissionEnum] = []
): TeamConnection
user(username: String!): User @deprecated(reason: "Query for a User node at the root level is not recommended. Ref T12456")
users(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): UserConnection
}
# Autogenerated input type of RejectInvitation
input RejectInvitationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
handle: String!
}
# Autogenerated return type of RejectInvitation
type RejectInvitationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
me: User
}
# A HackerOne report
type Report implements Node, ResourceInterface {
_id: ID!
activities(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
not_types: [ActivityTypes]
order_by: ActivityOrderInput
types: [ActivityTypes]
# A timestamp encoded as a string that. When provided, only activities with a
# updated_at greater than this value will be resolved. Example:
# activities(updated_at_after: "2017-11-30 13:37:12 UTC")
updated_at_after: String
): ActivityConnection
allow_singular_disclosure_after: String
allow_singular_disclosure_at: String
assignee: AssigneeUnion
attachments: [Attachment]
bounties: [Bounty]
bounty_awarded_at: String
bug_reporter_agreed_on_going_public_at: String
cloned_from: Report
closed_at: String
comments_closed: Boolean
created_at: String!
cve_ids: [String]
disclosed_at: String
first_program_activity_at: String
i_can_anc_review: Boolean
id: ID!
latest_activity_at: String
latest_public_activity_at: String
latest_public_activity_of_reporter_at: String
latest_public_activity_of_team_at: String
mediation_requested_at: String
original_report: Report
pre_submission_review_state: String
reference: ID
reference_link: String
reporter: User
severity: Severity
singular_disclosure_allowed: Boolean
singular_disclosure_disabled: Boolean
stage: String
stale: Boolean
state: String
structured_scope: StructuredScope
substate: String!
suggested_bounty: String
summaries: [Summary]
swag: [Swag]
swag_awarded_at: String
team: Team
team_member_agreed_on_going_public_at: String
title: String
triaged_at: String
# A pre-submission trigger that notified the hacker before submission. This
# field is only present for reports filed after February 14, 2016.
triggered_pre_submission_trigger: Trigger
url: URI!
vulnerability_information: String
vulnerability_information_html: String
weakness: Weakness
}
# A interface for the common fields on an HackerOne Report Activity
interface ReportActivityInterface {
attachments: [Attachment]
automated_response: Boolean
genius_execution_id: ID @deprecated(reason: "This is about to be replaced by .genius_execution")
report: Report
}
# The connection type for Report.
type ReportConnection {
# Groups and counts reports by the severity rating
count_by_severity: [CountBySeverity]!
# A list of edges.
edges: [ReportEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type ReportEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Report
}
# Filters which can be used to query reports
enum ReportFilterEnum {
assigned
assigned_to_me
bounty_awarded
going_public_team
going_public_user
hacker_requested_mediation
ineligible_for_bounty
needs_first_program_response
no_bounty_awarded
no_swag_awarded
not_public
public
reporter_is_active
stale
swag_awarded
unassigned
}
# Fields on which a collection of reports can be ordered
enum ReportOrderField {
created_at
id
latest_activity_at
}
input ReportOrderInput {
direction: OrderDirection!
field: ReportOrderField!
}
# Pre submission review states a report can be in
enum ReportPreSubmissionReviewStateEnum {
pre_submission_accepted
pre_submission_needs_more_info
pre_submission_pending
pre_submission_rejected
}
# States a report can be in
enum ReportStateEnum {
closed
duplicate
informative
needs_more_info
new
not_applicable
open
pre_submission
resolved
spam
triaged
}
# The connection type for User.
type ReporterConnection {
# A list of edges.
edges: [UserEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# Represents a type that can be retrieved by a URL.
interface ResourceInterface {
url: URI!
}
# A HackerOne session
type Session implements Node {
csrf_token: String! @deprecated(reason: "This token is used to support legacy operations in HackerOne's frontend")
id: ID!
}
# A HackerOne severity for a report
type Severity implements Node {
_id: ID!
attack_complexity: SeverityAttackComplexityEnum
attack_vector: SeverityAttackVectorEnum
author_type: SeverityAuthorEnum
availability: SeverityAvailabilityEnum
confidentiality: SeverityConfidentialityEnum
created_at: String
id: ID!
integrity: SeverityIntegrityEnum
privileges_required: SeverityPrivilegesRequiredEnum
rating: SeverityRatingEnum
scope: SeverityScopeEnum
score: Float
user_id: Int
user_interaction: SeverityUserInteractionEnum
}
# Severity attack complexity
enum SeverityAttackComplexityEnum {
high
low
}
# Severity attack vector
enum SeverityAttackVectorEnum {
adjacent
local
network
physical
}
# Severity author
enum SeverityAuthorEnum {
Team
User
}
# Severity availability
enum SeverityAvailabilityEnum {
high
low
none
}
# Calculate CVSS Severity score and rating
type SeverityCalculator implements Node {
calculated_max_severity(availability_requirement: SeveritySecurityRequirementEnum, confidentiality_requirement: SeveritySecurityRequirementEnum, integrity_requirement: SeveritySecurityRequirementEnum): SeverityRatingEnum
id: ID!
}
# Severity confidentiality
enum SeverityConfidentialityEnum {
high
low
none
}
# Severity integrity
enum SeverityIntegrityEnum {
high
low
none
}
# Severity privileges required
enum SeverityPrivilegesRequiredEnum {
high
low
none
}
# Severity rating
enum SeverityRatingEnum {
critical
high
low
medium
none
}
# Severity scope
enum SeverityScopeEnum {
changed
unchanged
}
# Severity security requirement rating
enum SeveritySecurityRequirementEnum {
high
low
medium
none
}
# Severity user interaction
enum SeverityUserInteractionEnum {
none
required
}
# SLA types
enum SlaTypeEnum {
first_program_response
report_triage
}
# Slack channel
type SlackChannel implements Node {
# ID of the object.
id: ID!
name: String!
}
# A Slack integration for a team
type SlackIntegration implements Node {
channel: String @deprecated(reason: "this field is not used in our new Slack integration")
channels: [SlackChannel]
id: ID!
should_fetch_slack_channels: Boolean!
should_fetch_slack_users: Boolean!
team: Team!
team_url: String!
users: [SlackUser]
}
# A Slack Pipeline Configuration for notifications
type SlackPipeline implements Node, ResourceInterface {
# The primary key from the database
_id: ID!
channel: String!
descriptive_label: String
id: ID!
notification_report_agreed_on_going_public: Boolean!
notification_report_assignee_changed: Boolean!
notification_report_became_public: Boolean!
notification_report_bounty_paid: Boolean!
notification_report_bounty_suggested: Boolean!
notification_report_bug_closed_as_spam: Boolean!
notification_report_bug_duplicate: Boolean!
notification_report_bug_informative: Boolean!
notification_report_bug_needs_more_info: Boolean!
notification_report_bug_new: Boolean!
notification_report_bug_not_applicable: Boolean!
notification_report_closed_as_resolved: Boolean!
notification_report_comments_closed: Boolean!
notification_report_created: Boolean!
notification_report_internal_comment_added: Boolean!
notification_report_manually_disclosed: Boolean!
notification_report_not_eligible_for_bounty: Boolean!
notification_report_public_comment_added: Boolean!
notification_report_reopened: Boolean!
notification_report_swag_awarded: Boolean!
notification_report_triaged: Boolean!
team: Team!
updated_at: String!
url: URI!
}
# The connection type for SlackPipeline.
type SlackPipelineConnection {
# A list of edges.
edges: [SlackPipelineEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type SlackPipelineEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: SlackPipeline
}
# Slack user
type SlackUser implements Node {
# The id provided by Slack
_id: String!
avatar_small: String!
deleted: Boolean!
email: String!
# ID of the object.
id: ID!
name: String!
real_name: String
}
# A static participant for a team
type StaticParticipant implements Node {
_id: ID!
avatar(size: ProfilePictureSizes!): String!
bio: String
external_url: String
id: ID!
name: String!
year: String
}
# The connection type for StaticParticipant.
type StaticParticipantConnection {
# A list of edges.
edges: [StaticParticipantEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type StaticParticipantEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: StaticParticipant
}
# A defined scope of a HackerOne program
type StructuredScope implements Node, ResourceInterface {
_id: ID!
archived_at: String
asset_identifier: String!
asset_type: StructuredScopedAssetTypeEnum
availability_requirement: SeveritySecurityRequirementEnum
confidentiality_requirement: SeveritySecurityRequirementEnum
created_at: String!
eligible_for_bounty: Boolean
eligible_for_submission: Boolean
id: ID!
instruction: String
integrity_requirement: SeveritySecurityRequirementEnum
max_severity: SeverityRatingEnum
reference: String
rendered_instruction: String
reports(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ReportConnection
structured_scope_versions(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): StructuredScopeVersionConnection
team: Team
updated_at: String
url: URI!
}
# An edge in a connection.
type StructuredScopeEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: StructuredScope
}
# A versioned log of a scope of a HackerOne program
type StructuredScopeVersion implements Node, ResourceInterface {
_id: ID!
archived_at: String
created_at: String!
id: ID!
instruction: String
max_severity: String
team: Team
url: URI!
}
# The connection type for StructuredScopeVersion.
type StructuredScopeVersionConnection {
# A list of edges.
edges: [StructuredScopeVersionEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type StructuredScopeVersionEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: StructuredScopeVersion
}
# Structured Scope asset type enum
enum StructuredScopedAssetTypeEnum {
APPLE_STORE_APP_ID
CIDR
DOWNLOADABLE_EXECUTABLES
GOOGLE_PLAY_APP_ID
HARDWARE
OTHER
OTHER_APK
OTHER_IPA
SOURCE_CODE
TESTFLIGHT
URL
WINDOWS_APP_STORE_APP_ID
}
# The connection type for StructuredScope.
type StructuredScopesConnection {
# A list of edges.
edges: [StructuredScopeEdge]
max_updated_at: String
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# Submission states
enum SubmissionStateEnum {
disabled
open
paused
}
# Team subscription action enum
enum SubscriptionActionEnum {
subscribe_to_all
unsubscribe_from_all
}
# A HackerOne summary for a report
type Summary implements Node {
_id: ID!
category: String! @deprecated(reason: "The implementation of this field contains hard to reason about polymorphism")
content: String!
created_at: String!
id: ID!
updated_at: String!
user: User!
}
# A HackerOne survey
type Survey implements Node, ResourceInterface {
category: String!
id: ID!
question: String!
structured_responses(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): SurveyStructuredResponseConnectionType
url: URI!
}
# Survey categories
enum SurveyCategoryEnum {
invitation_rejection
}
# The connection type for Survey.
type SurveyConnectionType {
# A list of edges.
edges: [SurveyEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type SurveyEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Survey
}
# Prepared survey response reasons
type SurveyStructuredResponse implements Node {
_id: ID!
enabled: Boolean!
helper_text: String
id: ID!
reason: String!
survey: Survey
}
# The connection type for SurveyStructuredResponse.
type SurveyStructuredResponseConnectionType {
# A list of edges.
edges: [SurveyStructuredResponseEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type SurveyStructuredResponseEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: SurveyStructuredResponse
}
# A HackerOne swag awarded for a report
type Swag implements Node {
_id: ID!
address: Address @deprecated(reason: "This field is deprecated. The preferred way to access this data is using swag.user.address.")
created_at: String
id: ID!
report: Report
sent: Boolean!
team: Team
user: User
}
# The connection type for Swag.
type SwagConnection {
# A list of edges.
edges: [SwagEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type SwagEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Swag
}
# A tax form for a user
type TaxForm implements Node {
created_at: String!
hello_sign_client_id: String
id: ID!
signed_at: String
status: TaxFormStateEnum!
type: TaxFormTypeEnum!
url: String
}
# Status of a tax form
enum TaxFormStateEnum {
expired
needs_review
rejected
requested
unavailable
valid
}
# Type of a tax form
enum TaxFormTypeEnum {
W8BEN
W8BENE
W9
W9Corporate
}
# A HackerOne team
type Team implements Node, ResourceInterface {
# The primary key from the database
_id: ID!
about: String
abuse: Boolean
activities(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
not_types: [ActivityTypes]
order_by: ActivityOrderInput
types: [ActivityTypes]
# A timestamp encoded as a string that. When provided, only activities with a
# updated_at greater than this value will be resolved. Example:
# activities(updated_at_after: "2017-11-30 13:37:12 UTC")
updated_at_after: String
): ActivityConnection
automatic_invites: Boolean
base_bounty: Int
bug_count: Int
child_teams(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): TeamConnection
common_responses(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: CommonResponseOrder = {direction: ASC, field: title}
): CommonResponseConnection
created_at: String
currency: String
fancy_slack_integration: Boolean
fancy_slack_integration_enabled: Boolean!
first_response_time: Float
hackerone_to_jira_events_configuration: HackeroneToJiraEventsConfiguration
handle: String!
has_avatar: Boolean
has_policy: Boolean
i_can_create_jira_webhook: Boolean
i_can_destroy_jira_webhook: Boolean!
i_can_view_base_bounty: Boolean
i_can_view_jira_integration: Boolean
i_can_view_jira_webhook: Boolean
i_can_view_phabricator_integration: Boolean
i_can_view_program_health: Boolean!
i_can_view_reports_resolved: Boolean
i_can_view_weaknesses: Boolean
i_cannot_create_jira_webhook_reasons: [TeamCannotCreateJiraWebhookReasons]!
id: ID!
inbox_views(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: TeamInboxViewOrder = {direction: ASC, field: position}
visible: Boolean
): TeamInboxViewConnection
internet_bug_bounty: Boolean
jira_integration: JiraIntegration
jira_oauth: JiraOauth
jira_phase_3_enabled: Boolean!
jira_webhook: JiraWebhook
maximum_number_of_team_mediation_requests: Float
name: String!
new_staleness_threshold: Int
offers_bounties: Boolean
offers_swag: Boolean
open_soft_launch_invitations(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): InvitationUnionConnection @deprecated(reason: "This should be a generic invitation connection.\n Used interim until generic invitation type is defined")
participants(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
limit: Int = null
year: Int = null
): ParticipantConnection
phabricator_integration: PhabricatorIntegration
policy_html: String
profile_picture(size: ProfilePictureSizes!): String!
report_submission_form_intro: String
report_template: String
reporters(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ReporterConnection
reports(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
database_id: Int = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
limit: Int = null
order_by: ReportOrderInput = {direction: DESC, field: id}
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
page: Int = null
pre_submission_review_states: [ReportPreSubmissionReviewStateEnum] = null
state: ReportStateEnum
substate: ReportStateEnum
violates_minimum_sla: SlaTypeEnum
without_scope: Boolean = null
): ReportConnection
review_requested_at: String
sla_failed_count: Int
sla_missed_count: Int
slack_integration: SlackIntegration
slack_pipelines(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): SlackPipelineConnection
state: TeamState!
static_participants(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): StaticParticipantConnection
structured_scopes(
# Returns the elements in the list that come after the specified cursor.
after: String
archived: Boolean = null
asset_type: String = null
# Returns the elements in the list that come before the specified cursor.
before: String
eligible_for_submission: Boolean = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
search: String = null
): StructuredScopesConnection
submission_state: SubmissionStateEnum!
target_signal: Float
team_member_groups(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): TeamMemberGroupConnection
team_members(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: TeamMemberOrder = {direction: ASC, field: username}
): TeamMemberConnection
triage_active: Boolean
triage_time: Float
triaged_staleness_threshold: Int
twitter_handle: String
updated_at: String
url: URI!
weaknesses(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
cluster_id: ID = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: WeaknessOrder = {direction: ASC, field: name}
search: String = null
team_weakness_state: [TeamWeaknessStates] = [enabled, disabled, hidden]
): TeamWeaknessConnection
website: String
whitelisted_hackers(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ReporterConnection
}
# Different reasons why a team cannot create a jira webhook
enum TeamCannotCreateJiraWebhookReasons {
CANNOT_VIEW
FEATURE_GATED
PROGRAM_PERMISSION_REQUIRED
}
# The connection type for Team.
type TeamConnection {
# A list of edges.
edges: [TeamEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type TeamEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Team
}
# A team report filter preset
type TeamInboxView implements Node {
_id: ID!
assigned_to_group_ids: [Int!]!
assigned_to_user_ids: [Int!]!
built_in: Boolean!
created_at: String!
filters: [ReportFilterEnum!]!
hackathons: [Int!]!
id: ID!
key: String!
name: String!
position: Int!
reporter_ids: [Int!]!
severities: [String!]!
substates: [ReportStateEnum!]!
team: Team!
text_query: String!
updated_at: String!
visible: Boolean!
}
# The connection type for TeamInboxView.
type TeamInboxViewConnection {
# A list of edges.
edges: [TeamInboxViewEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type TeamInboxViewEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: TeamInboxView
}
input TeamInboxViewOrder {
direction: OrderDirection!
field: TeamInboxViewOrderField!
}
# Fields on which a collection of team inbox views can be ordered
enum TeamInboxViewOrderField {
position
}
# A HackerOne team member
type TeamMember implements Node {
# The primary key from the database
_id: ID!
auto_subscribe: Boolean
concealed: Boolean
created_at: String!
i_can_leave_team: Boolean!
id: ID!
permissions: [String]!
slack_user_id: String
team: Team!
user: User!
}
# The connection type for TeamMember.
type TeamMemberConnection {
# A list of edges.
edges: [TeamMemberEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type TeamMemberEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: TeamMember
}
# A HackerOne team member group
type TeamMemberGroup implements Node {
_id: ID!
created_at: String
# ID of the object.
id: ID!
name: String!
permissions: [String]!
}
# The connection type for TeamMemberGroup.
type TeamMemberGroupConnection {
# A list of edges.
edges: [TeamMemberGroupEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
}
# An edge in a connection.
type TeamMemberGroupEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: TeamMemberGroup
}
input TeamMemberOrder {
direction: OrderDirection!
field: TeamMemberOrderField!
}
# Fields on which a collection of team members can be ordered
enum TeamMemberOrderField {
username
}
# Fields on which a collection of Teams can be ordered
enum TeamOrderField {
missing_pressure
name
}
input TeamOrderInput {
direction: OrderDirection!
field: TeamOrderField!
}
# Different possible team states
enum TeamState {
da_mode
inactive
public_mode
sandboxed
soft_launched
}
# Team configuration of a weakness
type TeamWeakness implements Node {
id: ID!
instruction: String
state: TeamWeaknessStates
team: Team!
weakness: Weakness!
}
# The connection type for Weakness.
type TeamWeaknessConnection {
# A list of edges.
edges: [TeamWeaknessEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type TeamWeaknessEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: Weakness
team_weakness: TeamWeakness
}
# Possible states of how a weakness can be configured for a team
enum TeamWeaknessStates {
disabled
enabled
hidden
}
# A HackerOne trigger
type Trigger implements Node {
_id: ID!
id: ID!
title: String!
}
# Tshirt size
enum TshirtSizeEnum {
M_Large
M_Medium
M_Small
M_XLarge
M_XXLarge
W_Large
W_Medium
W_Small
W_XLarge
W_XXLarge
}
# Represents a RFC compliant URI string. It is often used to fetch an object.
scalar URI
# Autogenerated input type of UpdateAutomaticInvites
input UpdateAutomaticInvitesInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
enabled: Boolean!
handle: String!
}
# Autogenerated return type of UpdateAutomaticInvites
type UpdateAutomaticInvitesPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of UpdateBackupCodes
input UpdateBackupCodesInput {
backup_codes: [String]!
# A unique identifier for the client performing the mutation.
clientMutationId: String
password: String!
signature: String!
totp_code: String!
totp_secret: String!
}
# Autogenerated return type of UpdateBackupCodes
type UpdateBackupCodesPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [String]
me: User
}
# Autogenerated input type of UpdateInvitationPreferences
input UpdateInvitationPreferencesInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
invitation_preference: InvitationPreferenceTypeEnum!
}
# Autogenerated return type of UpdateInvitationPreferences
type UpdateInvitationPreferencesPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of UpdateJiraWebhook
input UpdateJiraWebhookInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
jira_webhook_id: ID!
process_assignee_change: Boolean
process_comment_add: Boolean
process_priority_change: Boolean
process_resolution_change: Boolean
process_status_change: Boolean
}
# Autogenerated return type of UpdateJiraWebhook
type UpdateJiraWebhookPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
jira_webhook: JiraWebhook!
}
# Autogenerated input type of UpdateMe
input UpdateMeInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
tshirt_size: String!
}
# Autogenerated return type of UpdateMe
type UpdateMePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of UpdatePhabricatorIntegration
input UpdatePhabricatorIntegrationInput {
api_token: String
base_url: String
# A unique identifier for the client performing the mutation.
clientMutationId: String
description: String
process_h1_comment_added: Boolean
process_h1_status_change: Boolean
process_phabricator_comment_added: Boolean
process_phabricator_status_change: Boolean
team_id: ID!
title: String
}
# Autogenerated return type of UpdatePhabricatorIntegration
type UpdatePhabricatorIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of UpdateReportStateToNeedsMoreInfo
input UpdateReportStateToNeedsMoreInfoInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
message: String!
report_id: ID!
}
# Autogenerated return type of UpdateReportStateToNeedsMoreInfo
type UpdateReportStateToNeedsMoreInfoPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
report: Report
}
# Autogenerated input type of UpdateReportStructuredScope
input UpdateReportStructuredScopeInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
report_id: ID!
structured_scope_id: ID
}
# Autogenerated return type of UpdateReportStructuredScope
type UpdateReportStructuredScopePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
report: Report
}
# Autogenerated input type of UpdateSlackPipeline
input UpdateSlackPipelineInput {
channel: String!
# A unique identifier for the client performing the mutation.
clientMutationId: String
descriptive_label: String
notification_report_agreed_on_going_public: Boolean!
notification_report_assignee_changed: Boolean!
notification_report_became_public: Boolean!
notification_report_bounty_paid: Boolean!
notification_report_bounty_suggested: Boolean!
notification_report_bug_closed_as_spam: Boolean!
notification_report_bug_duplicate: Boolean!
notification_report_bug_informative: Boolean!
notification_report_bug_needs_more_info: Boolean!
notification_report_bug_new: Boolean!
notification_report_bug_not_applicable: Boolean!
notification_report_closed_as_resolved: Boolean!
notification_report_comments_closed: Boolean!
notification_report_created: Boolean!
notification_report_internal_comment_added: Boolean!
notification_report_manually_disclosed: Boolean!
notification_report_not_eligible_for_bounty: Boolean!
notification_report_public_comment_added: Boolean!
notification_report_reopened: Boolean!
notification_report_swag_awarded: Boolean!
notification_report_triaged: Boolean!
slack_pipeline_id: ID!
}
# Autogenerated return type of UpdateSlackPipeline
type UpdateSlackPipelinePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
slack_pipeline: SlackPipeline!
}
# Autogenerated input type of UpdateSlackUser
input UpdateSlackUserInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
slack_user_id: String!
team_member_id: ID!
}
# Autogenerated return type of UpdateSlackUser
type UpdateSlackUserPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_member: TeamMember!
}
# Autogenerated input type of UpdateStructuredScope
input UpdateStructuredScopeInput {
asset_identifier: String
availability_requirement: String
# A unique identifier for the client performing the mutation.
clientMutationId: String
confidentiality_requirement: String
eligible_for_bounty: Boolean
eligible_for_submission: Boolean
instruction: String
integrity_requirement: String
reference: String
structured_scope_id: ID!
}
# Autogenerated return type of UpdateStructuredScope
type UpdateStructuredScopePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
query: Query
structured_scope: StructuredScope
}
# Autogenerated input type of UpdateTeamFancySlackIntegration
input UpdateTeamFancySlackIntegrationInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
fancy_slack_integration: Boolean!
team_id: ID!
}
# Autogenerated return type of UpdateTeamFancySlackIntegration
type UpdateTeamFancySlackIntegrationPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
team: Team
}
# Autogenerated input type of UpdateTeamMemberVisibility
input UpdateTeamMemberVisibilityInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
concealed: Boolean!
team_member_id: ID!
}
# Autogenerated return type of UpdateTeamMemberVisibility
type UpdateTeamMemberVisibilityPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team_member: TeamMember
}
# Autogenerated input type of UpdateTeamSubmissionState
input UpdateTeamSubmissionStateInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
handle: String!
submission_state: SubmissionStateEnum!
}
# Autogenerated return type of UpdateTeamSubmissionState
type UpdateTeamSubmissionStatePayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team: Team
}
# Autogenerated input type of UpdateTeamSubscription
input UpdateTeamSubscriptionInput {
action: SubscriptionActionEnum
auto_subscribe: Boolean!
# A unique identifier for the client performing the mutation.
clientMutationId: String
team_member_id: ID!
}
# Autogenerated return type of UpdateTeamSubscription
type UpdateTeamSubscriptionPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
team_member: TeamMember
}
# Autogenerated input type of UpdateTeamWeakness
input UpdateTeamWeaknessInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
instruction: String
state: TeamWeaknessStates!
team_weakness_id: ID!
}
# Autogenerated return type of UpdateTeamWeakness
type UpdateTeamWeaknessPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
query: Query
team_weakness: TeamWeakness
}
# Autogenerated input type of UpdateUserEmail
input UpdateUserEmailInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
email: String!
password: String!
}
# Autogenerated return type of UpdateUserEmail
type UpdateUserEmailPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: [Error]
me: User
was_successful: Boolean!
}
# Autogenerated input type of UpdateUserLufthansaAccount
input UpdateUserLufthansaAccountInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
first_name: String!
last_name: String!
number: String!
}
# Autogenerated return type of UpdateUserLufthansaAccount
type UpdateUserLufthansaAccountPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# Autogenerated input type of UpdateUserPassword
input UpdateUserPasswordInput {
# A unique identifier for the client performing the mutation.
clientMutationId: String
current_password: String!
password: String!
password_confirmation: String!
}
# Autogenerated return type of UpdateUserPassword
type UpdateUserPasswordPayload {
# A unique identifier for the client performing the mutation.
clientMutationId: String
errors: Hash
me: User
}
# A HackerOne user
type User implements Node, ResourceInterface {
_id: ID!
address: Address
authentication_service: AuthenticationServiceEnum!
badges(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): BadgesUsersConnection
bio: String
bounties(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
currency: CurrencyCode = null
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): BountyConnection
created_at: String!
demo_hacker: Boolean!
disabled: Boolean!
duplicate_users(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): UserConnection
email: String
i_can_update_username: Boolean
id: ID!
impact: Float
impact_percentile: Float
invitation_preference: InvitationPreferenceTypeEnum
location: String
lufthansa_account: LufthansaAccount
member_of_verified_team: Boolean
membership(team_handle: String!): TeamMember
memberships(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): TeamMemberConnection
name: String
next_update_username_date: String
otp_backup_codes: [String]
payout_preferences: [PayoutPreferenceUnion]
profile_picture(size: ProfilePictureSizes!): String!
profile_pictures: Hash! @deprecated(reason: "Returns all the possible profile pictures instead of just the one you want use .profile_picture instead.")
program_health_acknowledgements(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ProgramHealthAcknowledgementConnection
rank: Int
remaining_reports(team_handle: String!): Int
reports(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
database_id: Int = null
# Returns the first _n_ elements from the list.
first: Int
handle: String
# Returns the last _n_ elements from the list.
last: Int
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
limit: Int = null
order_by: ReportOrderInput = {direction: DESC, field: id}
# Relay classic does not have support for starting paginationsomewhere in the
# middle, see https://github.com/facebook/relay/issues/1312 Workaround is to
# add a page argument till Relay supports this
page: Int = null
pre_submission_review_states: [ReportPreSubmissionReviewStateEnum] = null
substate: ReportStateEnum
without_scope: Boolean = null
): ReportConnection
reputation: Int
signal: Float
signal_percentile: Float
soft_launch_invitation(team_handle: String!): InvitationsSoftLaunch
swag(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): SwagConnection
tax_form: TaxForm
teams(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
enrollable: Boolean
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
order_by: TeamOrderInput
permissions: [PermissionEnum] = []
): TeamConnection
totp_enabled: Boolean
totp_supported: Boolean
triage_user: Boolean
tshirt_size: TshirtSizeEnum
unconfirmed_email: String
url: URI!
username: String!
website: String
whitelisted_teams(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): TeamConnection
}
# The connection type for User.
type UserConnection {
# A list of edges.
edges: [UserEdge]
# Information to aid in pagination.
pageInfo: PageInfo!
total_count: Int!
}
# An edge in a connection.
type UserEdge {
# A cursor for use in pagination.
cursor: String!
# The item at the end of the edge.
node: User
}
# The type of vulnerability on a HackerOne report
type Weakness implements Node {
_id: ID!
clusters(
# Returns the elements in the list that come after the specified cursor.
after: String
# Returns the elements in the list that come before the specified cursor.
before: String
# Returns the first _n_ elements from the list.
first: Int
# Returns the last _n_ elements from the list.
last: Int
): ClusterConnection
created_at: String!
description: String
external_id: String
id: ID!
name: String!
updated_at: String!
}
input WeaknessOrder {
direction: OrderDirection!
field: WeaknessOrderField!
}
# Fields on which a collection of weaknesses can be ordered
enum WeaknessOrderField {
name
}
graphql-ruby-2.2.17/benchmark/run.rb 0000664 0000000 0000000 00000045711 14764346352 0017331 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require "graphql"
require "jazz"
require "benchmark/ips"
require "stackprof"
require "memory_profiler"
require "graphql/batch"
module GraphQLBenchmark
QUERY_STRING = GraphQL::Introspection::INTROSPECTION_QUERY
DOCUMENT = GraphQL.parse(QUERY_STRING)
SCHEMA = Jazz::Schema
BENCHMARK_PATH = File.expand_path("../", __FILE__)
CARD_SCHEMA = GraphQL::Schema.from_definition(File.read(File.join(BENCHMARK_PATH, "schema.graphql")))
ABSTRACT_FRAGMENTS = GraphQL.parse(File.read(File.join(BENCHMARK_PATH, "abstract_fragments.graphql")))
ABSTRACT_FRAGMENTS_2_QUERY_STRING = File.read(File.join(BENCHMARK_PATH, "abstract_fragments_2.graphql"))
ABSTRACT_FRAGMENTS_2 = GraphQL.parse(ABSTRACT_FRAGMENTS_2_QUERY_STRING)
BIG_SCHEMA = GraphQL::Schema.from_definition(File.join(BENCHMARK_PATH, "big_schema.graphql"))
BIG_QUERY_STRING = File.read(File.join(BENCHMARK_PATH, "big_query.graphql"))
BIG_QUERY = GraphQL.parse(BIG_QUERY_STRING)
FIELDS_WILL_MERGE_SCHEMA = GraphQL::Schema.from_definition("type Query { hello: String }")
FIELDS_WILL_MERGE_QUERY = GraphQL.parse("{ #{Array.new(5000, "hello").join(" ")} }")
module_function
def self.run(task)
Benchmark.ips do |x|
case task
when "query"
x.report("query") { SCHEMA.execute(document: DOCUMENT) }
when "validate"
x.report("validate - introspection ") { CARD_SCHEMA.validate(DOCUMENT) }
x.report("validate - abstract fragments") { CARD_SCHEMA.validate(ABSTRACT_FRAGMENTS) }
x.report("validate - abstract fragments 2") { CARD_SCHEMA.validate(ABSTRACT_FRAGMENTS_2) }
x.report("validate - big query") { BIG_SCHEMA.validate(BIG_QUERY) }
x.report("validate - fields will merge") { FIELDS_WILL_MERGE_SCHEMA.validate(FIELDS_WILL_MERGE_QUERY) }
when "scan"
require "graphql/c_parser"
x.report("scan c - introspection") { GraphQL.scan_with_c(QUERY_STRING) }
x.report("scan - introspection") { GraphQL.scan_with_ruby(QUERY_STRING) }
x.report("scan c - fragments") { GraphQL.scan_with_c(ABSTRACT_FRAGMENTS_2_QUERY_STRING) }
x.report("scan - fragments") { GraphQL.scan_with_ruby(ABSTRACT_FRAGMENTS_2_QUERY_STRING) }
x.report("scan c - big query") { GraphQL.scan_with_c(BIG_QUERY_STRING) }
x.report("scan - big query") { GraphQL.scan_with_ruby(BIG_QUERY_STRING) }
when "parse"
# Uncomment this to use the C parser:
# require "graphql/c_parser"
x.report("parse - introspection") { GraphQL.parse(QUERY_STRING) }
x.report("parse - fragments") { GraphQL.parse(ABSTRACT_FRAGMENTS_2_QUERY_STRING) }
x.report("parse - big query") { GraphQL.parse(BIG_QUERY_STRING) }
else
raise("Unexpected task #{task}")
end
end
end
def self.profile_parse
# To profile the C parser instead:
# require "graphql/c_parser"
report = MemoryProfiler.report do
GraphQL.parse(BIG_QUERY_STRING)
GraphQL.parse(QUERY_STRING)
GraphQL.parse(ABSTRACT_FRAGMENTS_2_QUERY_STRING)
end
report.pretty_print
end
def self.validate_memory
FIELDS_WILL_MERGE_SCHEMA.validate(FIELDS_WILL_MERGE_QUERY)
report = MemoryProfiler.report do
FIELDS_WILL_MERGE_SCHEMA.validate(FIELDS_WILL_MERGE_QUERY)
nil
end
report.pretty_print
end
def self.profile
# Warm up any caches:
SCHEMA.execute(document: DOCUMENT)
# CARD_SCHEMA.validate(ABSTRACT_FRAGMENTS)
res = nil
result = StackProf.run(mode: :wall) do
# CARD_SCHEMA.validate(ABSTRACT_FRAGMENTS)
res = SCHEMA.execute(document: DOCUMENT)
end
StackProf::Report.new(result).print_text
end
def self.build_large_schema
Class.new(GraphQL::Schema) do
query_t = Class.new(GraphQL::Schema::Object) do
graphql_name("Query")
int_ts = 5.times.map do |i|
int_t = Module.new do
include GraphQL::Schema::Interface
graphql_name "Interface#{i}"
5.times do |n2|
field :"field#{n2}", String do
argument :arg, String
end
end
end
field :"int_field_#{i}", int_t
int_t
end
obj_ts = 100.times.map do |n|
input_obj_t = Class.new(GraphQL::Schema::InputObject) do
graphql_name("Input#{n}")
argument :arg, String
end
obj_t = Class.new(GraphQL::Schema::Object) do
graphql_name("Object#{n}")
implements(*int_ts)
20.times do |n2|
field :"field#{n2}", String do
argument :input, input_obj_t
end
end
field :self_field, self
field :int_0_field, int_ts[0]
end
field :"rootfield#{n}", obj_t
obj_t
end
10.times do |n|
union_t = Class.new(GraphQL::Schema::Union) do
graphql_name "Union#{n}"
possible_types(*obj_ts.sample(10))
end
field :"unionfield#{n}", union_t
end
end
query(query_t)
end
end
def self.profile_boot
Benchmark.ips do |x|
x.config(time: 10)
x.report("Booting large schema") {
build_large_schema
}
end
result = StackProf.run(mode: :wall, interval: 1) do
build_large_schema
end
StackProf::Report.new(result).print_text
retained_schema = nil
report = MemoryProfiler.report do
retained_schema = build_large_schema
end
report.pretty_print
end
SILLY_LARGE_SCHEMA = build_large_schema
def self.profile_small_query_on_large_schema
schema = Class.new(SILLY_LARGE_SCHEMA)
Benchmark.ips do |x|
x.report("Run small query") {
schema.execute("{ __typename }")
}
end
result = StackProf.run(mode: :wall, interval: 1) do
schema.execute("{ __typename }")
end
StackProf::Report.new(result).print_text
StackProf.run(mode: :wall, out: "tmp/small_query.dump", interval: 1) do
schema.execute("{ __typename }")
end
report = MemoryProfiler.report do
schema.execute("{ __typename }")
end
puts "\n\n"
report.pretty_print
end
def self.profile_large_introspection
schema = SILLY_LARGE_SCHEMA
Benchmark.ips do |x|
x.config(time: 10)
x.report("Run large introspection") {
schema.to_json
}
end
result = StackProf.run(mode: :wall) do
schema.to_json
end
StackProf::Report.new(result).print_text
report = MemoryProfiler.report do
schema.to_json
end
puts "\n\n"
report.pretty_print
end
def self.profile_large_analysis
query_str = "query {\n".dup
5.times do |n|
query_str << " intField#{n} { "
20.times do |o|
query_str << "...Obj#{o}Fields "
end
query_str << "}\n"
end
query_str << "}"
20.times do |o|
query_str << "fragment Obj#{o}Fields on Object#{o} { "
20.times do |f|
query_str << " field#{f}(arg: \"a\")\n"
end
query_str << " selfField { selfField { selfField { __typename } } }\n"
# query_str << " int0Field { ...Int0Fields }"
query_str << "}\n"
end
# query_str << "fragment Int0Fields on Interface0 { __typename }"
query = GraphQL::Query.new(SILLY_LARGE_SCHEMA, query_str)
analyzers = [
GraphQL::Analysis::AST::FieldUsage,
GraphQL::Analysis::AST::QueryDepth,
GraphQL::Analysis::AST::QueryComplexity
]
Benchmark.ips do |x|
x.report("Running introspection") {
GraphQL::Analysis::AST.analyze_query(query, analyzers)
}
end
StackProf.run(mode: :wall, out: "last-stackprof.dump", interval: 1) do
GraphQL::Analysis::AST.analyze_query(query, analyzers)
end
result = StackProf.run(mode: :wall, interval: 1) do
GraphQL::Analysis::AST.analyze_query(query, analyzers)
end
StackProf::Report.new(result).print_text
report = MemoryProfiler.report do
GraphQL::Analysis::AST.analyze_query(query, analyzers)
end
puts "\n\n"
report.pretty_print
end
# Adapted from https://github.com/rmosolgo/graphql-ruby/issues/861
def self.profile_large_result
schema = ProfileLargeResult::Schema
document = ProfileLargeResult::ALL_FIELDS
Benchmark.ips do |x|
x.config(time: 10)
x.report("Querying for #{ProfileLargeResult::DATA.size} objects") {
schema.execute(document: document)
}
end
result = StackProf.run(mode: :wall, interval: 1) do
schema.execute(document: document)
end
StackProf::Report.new(result).print_text
report = MemoryProfiler.report do
schema.execute(document: document)
end
report.pretty_print
end
def self.profile_small_result
schema = ProfileLargeResult::Schema
document = GraphQL.parse <<-GRAPHQL
query {
foos(first: 5) {
__typename
id
int1
int2
string1
string2
foos(first: 5) {
__typename
string1
string2
foo {
__typename
int1
}
}
}
}
GRAPHQL
Benchmark.ips do |x|
x.config(time: 10)
x.report("Querying for #{ProfileLargeResult::DATA.size} objects") {
schema.execute(document: document)
}
end
StackProf.run(mode: :wall, interval: 1, out: "tmp/small.dump") do
schema.execute(document: document)
end
result = StackProf.run(mode: :wall, interval: 1) do
schema.execute(document: document)
end
StackProf::Report.new(result).print_text
report = MemoryProfiler.report do
schema.execute(document: document)
end
report.pretty_print
end
def self.profile_small_introspection
schema = ProfileLargeResult::Schema
document = GraphQL.parse(GraphQL::Introspection::INTROSPECTION_QUERY)
Benchmark.ips do |x|
x.config(time: 5)
x.report("Introspection") {
schema.execute(document: document)
}
end
result = StackProf.run(mode: :wall, interval: 1) do
schema.execute(document: document)
end
StackProf::Report.new(result).print_text
report = MemoryProfiler.report do
schema.execute(document: document)
end
report.pretty_print
end
module ProfileLargeResult
def self.eager_or_proc(value)
ENV["EAGER"] ? value : -> { value }
end
DATA_SIZE = 1000
DATA = DATA_SIZE.times.map {
eager_or_proc({
id: SecureRandom.uuid,
int1: SecureRandom.random_number(100000),
int2: SecureRandom.random_number(100000),
string1: eager_or_proc(SecureRandom.base64),
string2: SecureRandom.base64,
boolean1: SecureRandom.random_number(1) == 0,
boolean2: SecureRandom.random_number(1) == 0,
int_array: eager_or_proc(10.times.map { eager_or_proc(SecureRandom.random_number(100000)) } ),
string_array: 10.times.map { SecureRandom.base64 },
boolean_array: 10.times.map { SecureRandom.random_number(1) == 0 },
})
}
module Bar
include GraphQL::Schema::Interface
field :string_array, [String], null: false
end
module Baz
include GraphQL::Schema::Interface
implements Bar
field :int_array, [Integer], null: false
field :boolean_array, [Boolean], null: false
end
class ExampleExtension < GraphQL::Schema::FieldExtension
end
class FooType < GraphQL::Schema::Object
implements Baz
field :id, ID, null: false, extensions: [ExampleExtension]
field :int1, Integer, null: false, extensions: [ExampleExtension]
field :int2, Integer, null: false, extensions: [ExampleExtension]
field :string1, String, null: false do
argument :arg1, String, required: false
argument :arg2, String, required: false
argument :arg3, String, required: false
argument :arg4, String, required: false
end
field :string2, String, null: false do
argument :arg1, String, required: false
argument :arg2, String, required: false
argument :arg3, String, required: false
argument :arg4, String, required: false
end
field :boolean1, Boolean, null: false do
argument :arg1, String, required: false
argument :arg2, String, required: false
argument :arg3, String, required: false
argument :arg4, String, required: false
end
field :boolean2, Boolean, null: false do
argument :arg1, String, required: false
argument :arg2, String, required: false
argument :arg3, String, required: false
argument :arg4, String, required: false
end
field :foos, [FooType], null: false, description: "Return a list of Foo objects" do
argument :first, Integer, default_value: DATA_SIZE
end
def foos(first:)
DATA.first(first)
end
field :foo, FooType
def foo
DATA.sample
end
end
class QueryType < GraphQL::Schema::Object
description "Query root of the system"
field :foos, [FooType], null: false, description: "Return a list of Foo objects" do
argument :first, Integer, default_value: DATA_SIZE
end
def foos(first:)
DATA.first(first)
end
end
class Schema < GraphQL::Schema
query QueryType
# use GraphQL::Dataloader
lazy_resolve Proc, :call
end
ALL_FIELDS = GraphQL.parse <<-GRAPHQL
query($skip: Boolean = false) {
foos {
id @skip(if: $skip)
int1
int2
string1
string2
boolean1
boolean2
stringArray
intArray
booleanArray
}
}
GRAPHQL
end
def self.profile_to_definition
require_relative "./batch_loading"
schema = ProfileLargeResult::Schema
schema.to_definition
Benchmark.ips do |x|
x.report("to_definition") { schema.to_definition }
end
result = StackProf.run(mode: :wall, interval: 1) do
schema.to_definition
end
StackProf::Report.new(result).print_text
report = MemoryProfiler.report do
schema.to_definition
end
report.pretty_print
end
def self.profile_batch_loaders
require_relative "./batch_loading"
include BatchLoading
document = GraphQL.parse <<-GRAPHQL
{
braves: team(name: "Braves") { ...TeamFields }
bulls: team(name: "Bulls") { ...TeamFields }
}
fragment TeamFields on Team {
players {
team {
players {
team {
name
}
}
}
}
}
GRAPHQL
batch_result = GraphQLBatchSchema.execute(document: document).to_h
dataloader_result = GraphQLDataloaderSchema.execute(document: document).to_h
no_batch_result = GraphQLNoBatchingSchema.execute(document: document).to_h
results = [batch_result, dataloader_result, no_batch_result].uniq
if results.size > 1
puts "Batch result:"
pp batch_result
puts "Dataloader result:"
pp dataloader_result
puts "No-batch result:"
pp no_batch_result
raise "Got different results -- fix implementation before benchmarking."
end
Benchmark.ips do |x|
x.report("GraphQL::Batch") { GraphQLBatchSchema.execute(document: document) }
x.report("GraphQL::Dataloader") { GraphQLDataloaderSchema.execute(document: document) }
x.report("No Batching") { GraphQLNoBatchingSchema.execute(document: document) }
x.compare!
end
puts "========== GraphQL-Batch Memory =============="
report = MemoryProfiler.report do
GraphQLBatchSchema.execute(document: document)
end
report.pretty_print
puts "========== Dataloader Memory ================="
report = MemoryProfiler.report do
GraphQLDataloaderSchema.execute(document: document)
end
report.pretty_print
puts "========== No Batch Memory =============="
report = MemoryProfiler.report do
GraphQLNoBatchingSchema.execute(document: document)
end
report.pretty_print
end
def self.profile_schema_memory_footprint
schema = nil
report = MemoryProfiler.report do
query_type = Class.new(GraphQL::Schema::Object) do
graphql_name "Query"
100.times do |i|
type = Class.new(GraphQL::Schema::Object) do
graphql_name "Object#{i}"
field :f, Integer
end
field "f#{i}", type
end
end
thing_type = Class.new(GraphQL::Schema::Object) do
graphql_name "Thing"
field :name, String
end
mutation_type = Class.new(GraphQL::Schema::Object) do
graphql_name "Mutation"
100.times do |i|
mutation_class = Class.new(GraphQL::Schema::RelayClassicMutation) do
graphql_name "Do#{i}"
argument :id, "ID"
field :thing, thing_type
field :things, thing_type.connection_type
end
field "f#{i}", mutation: mutation_class
end
end
schema = Class.new(GraphQL::Schema) do
query(query_type)
mutation(mutation_type)
end
end
report.pretty_print
end
class StackDepthSchema < GraphQL::Schema
class Thing < GraphQL::Schema::Object
field :thing, self do
argument :lazy, Boolean, default_value: false
end
def thing(lazy:)
if lazy
-> { :something }
else
:something
end
end
field :stack_trace_depth, Integer do
argument :lazy, Boolean, default_value: false
end
def stack_trace_depth(lazy:)
get_depth = -> {
graphql_caller = caller.select { |c| c.include?("graphql") }
graphql_caller.size
}
if lazy
get_depth
else
get_depth.call
end
end
end
class Query < GraphQL::Schema::Object
field :thing, Thing
def thing
:something
end
end
query(Query)
lazy_resolve(Proc, :call)
end
def self.profile_stack_depth
query_str = <<-GRAPHQL
query($lazyThing: Boolean!, $lazyStackTrace: Boolean!) {
thing {
thing(lazy: $lazyThing) {
thing(lazy: $lazyThing) {
thing(lazy: $lazyThing) {
thing(lazy: $lazyThing) {
stackTraceDepth(lazy: $lazyStackTrace)
}
}
}
}
}
}
GRAPHQL
eager_res = StackDepthSchema.execute(query_str, variables: { lazyThing: false, lazyStackTrace: false })
lazy_res = StackDepthSchema.execute(query_str, variables: { lazyThing: true, lazyStackTrace: false })
very_lazy_res = StackDepthSchema.execute(query_str, variables: { lazyThing: true, lazyStackTrace: true })
get_depth = ->(result) { result["data"]["thing"]["thing"]["thing"]["thing"]["thing"]["stackTraceDepth"] }
puts <<~RESULT
Result Depth
---------------------
Eager #{get_depth.call(eager_res)}
Lazy #{get_depth.call(lazy_res)}
Very Lazy #{get_depth.call(very_lazy_res)}
RESULT
end
end
graphql-ruby-2.2.17/benchmark/schema.graphql 0000664 0000000 0000000 00000003370 14764346352 0021013 0 ustar 00root root 0000000 0000000 # A big schema for testing
type Query {
node(id: ID!): Node
}
interface Node {
id: ID!
}
interface Node2 {
id: ID
}
interface Commentable {
id: ID!
comments: [Comment!]!
}
interface Named {
name: String!
}
type Comment implements Node {
author: Player
body: String!
id: ID!
}
type Card implements Node, Commentable, Node2, Named {
name: String!
converted_mana_cost: Int!
mana_cost: String!
colors: [Color!]!
power: Int
toughness: Int
rules_text: String!
id: ID!
comments: [Comment!]!
}
type Printing implements Node, Commentable, Node2 {
card: Card!
expansion: Expansion!
rarity: Rarity!
artist: Artist!
id: ID!
comments: [Comment!]!
}
type Expansion implements Node, Commentable, Named {
name: String!
code: String!
printings: [Printing!]!
block: Block!
id: ID!
comments: [Comment!]!
}
type Block implements Node, Commentable, Named {
name: String!
expansions: [Expansion!]!
id: ID!
comments: [Comment!]!
}
# Eg shard, guild, clan
type Watermark implements Node, Commentable, Named {
name: String!
cards: [Card!]!
colors: [Color!]!
id: ID!
comments: [Comment!]!
}
type Artist implements Node, Commentable, Named {
name: String!
printings: [Printing!]!
id: ID!
comments: [Comment!]!
}
type Player implements Node, Commentable, Named {
name: String!
decks: [Deck!]!
id: ID!
comments: [Comment!]!
}
type Deck implements Node, Commentable, Named {
name: String!
colors: [Color!]!
slots: [Slot!]!
id: ID!
comments: [Comment!]!
}
type Slot implements Node, Commentable {
deck: Deck!
card: Card!
id: ID!
comments: [Comment!]!
}
enum Color {
WHITE
BLUE
BLACK
RED
GREEN
COLORLESS
}
enum Rarity {
COMMON
UNCOMMON
RARE
MYTHIC_RARE
TIMESHIFTED
}
graphql-ruby-2.2.17/cop/ 0000775 0000000 0000000 00000000000 14764346352 0015017 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/cop/development/ 0000775 0000000 0000000 00000000000 14764346352 0017341 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/cop/development/context_is_passed_cop.rb 0000664 0000000 0000000 00000003037 14764346352 0024250 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'rubocop'
module Cop
module Development
class ContextIsPassedCop < RuboCop::Cop::Cop
MSG = <<-MSG
This method also accepts `context` as an argument. Pass it so that the returned value will reflect the current query, or use another method that isn't context-dependent.
MSG
# These are already context-aware or else not query-related
def_node_matcher :likely_query_specific_receiver?, "
{
(send _ {:ast_node :query :context :warden :ctx :query_ctx :query_context})
(lvar {:ast_node :query :context :warden :ctx :query_ctx :query_context})
(ivar {:@query :@context :@warden})
(send _ {:introspection_system})
}
"
def_node_matcher :method_doesnt_receive_second_context_argument?, <<-MATCHER
(send _ {:get_field :get_argument :get_type} _)
MATCHER
def_node_matcher :method_doesnt_receive_first_context_argument?, <<-MATCHER
(send _ {:fields :arguments :types :enum_values})
MATCHER
def_node_matcher :is_enum_values_call_without_arguments?, "
(send (send _ {:enum :enum_type (ivar {:@enum :@enum_type})}) {:values})
"
def on_send(node)
if (
method_doesnt_receive_second_context_argument?(node) ||
method_doesnt_receive_first_context_argument?(node) ||
is_enum_values_call_without_arguments?(node)
) && !likely_query_specific_receiver?(node.to_a[0])
add_offense(node)
end
end
end
end
end
graphql-ruby-2.2.17/cop/development/no_eval_cop.rb 0000664 0000000 0000000 00000001170 14764346352 0022151 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'rubocop'
module Cop
module Development
class NoEvalCop < RuboCop::Cop::Base
MSG_TEMPLATE = "Don't use `%{eval_method_name}` which accepts strings and may result evaluating unexpected code. Use `%{exec_method_name}` instead, and pass a block."
def on_send(node)
case node.method_name
when :module_eval, :class_eval, :instance_eval
message = MSG_TEMPLATE % { eval_method_name: node.method_name, exec_method_name: node.method_name.to_s.sub("eval", "exec").to_sym }
add_offense node, message: message
end
end
end
end
end
graphql-ruby-2.2.17/cop/development/no_focus_cop.rb 0000664 0000000 0000000 00000000742 14764346352 0022345 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'rubocop'
module Cop
module Development
# Make sure no tests are focused, from https://github.com/rubocop-hq/rubocop/issues/3773#issuecomment-420662102
class NoFocusCop < RuboCop::Cop::Cop
MSG = 'Remove `focus` from tests.'
def_node_matcher :focused?, <<-MATCHER
(send nil? :focus)
MATCHER
def on_send(node)
return unless focused?(node)
add_offense node
end
end
end
end
graphql-ruby-2.2.17/cop/development/none_without_block_cop.rb 0000664 0000000 0000000 00000001751 14764346352 0024427 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'rubocop'
module Cop
module Development
# A custom Rubocop rule to catch uses of `.none?` without a block.
#
# @see https://github.com/rmosolgo/graphql-ruby/pull/2090
class NoneWithoutBlockCop < RuboCop::Cop::Cop
MSG = <<-MD
Instead of `.none?` without a block:
- Use `.empty?` to check for an empty collection (faster)
- Add a block to explicitly check for `false` (more clear)
Run `-a` to replace this with `.empty?`.
MD
def on_block(node)
# Since this method was called with a block, it can't be
# a case of `.none?` without a block
ignore_node(node.send_node)
end
def on_send(node)
if !ignored_node?(node) && node.method_name == :none? && node.arguments.size == 0
add_offense(node)
end
end
def autocorrect(node)
lambda do |corrector|
corrector.replace(node.location.selector, "empty?")
end
end
end
end
end
graphql-ruby-2.2.17/gemfiles/ 0000775 0000000 0000000 00000000000 14764346352 0016031 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/gemfiles/mongoid_6.gemfile 0000664 0000000 0000000 00000000433 14764346352 0021244 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "mongoid", "~> 6.4.1"
if RUBY_VERSION >= "3.0"
gem "libev_scheduler"
gem "evt"
end
gemspec path: "../"
graphql-ruby-2.2.17/gemfiles/mongoid_7.gemfile 0000664 0000000 0000000 00000000431 14764346352 0021243 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "mongoid", "~> 7.0"
if RUBY_VERSION >= "3.0"
gem "libev_scheduler"
gem "evt"
end
gemspec path: "../"
graphql-ruby-2.2.17/gemfiles/rails_6.1.gemfile 0000664 0000000 0000000 00000000636 14764346352 0021066 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", "~> 6.1.0", require: "rails/all"
gem "sqlite3", "~> 1.4", platform: :ruby
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "sequel"
if RUBY_VERSION >= "3.0"
gem "libev_scheduler"
gem "evt"
end
gemspec path: "../"
graphql-ruby-2.2.17/gemfiles/rails_6.1_postgresql.gemfile 0000664 0000000 0000000 00000000425 14764346352 0023345 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", "~> 6.1.0", require: "rails/all"
gem "pg", platform: :ruby
gem "sequel"
gemspec path: "../"
graphql-ruby-2.2.17/gemfiles/rails_7.0.gemfile 0000664 0000000 0000000 00000000563 14764346352 0021065 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", "~> 7.0.0", require: "rails/all"
gem "sqlite3", "~> 1.4", platform: :ruby
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "sequel"
gem "evt"
gem "async"
gemspec path: "../"
graphql-ruby-2.2.17/gemfiles/rails_7.1.gemfile 0000664 0000000 0000000 00000000615 14764346352 0021064 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", "~> 7.1.0", require: "rails/all"
gem "sqlite3", "~> 1.4", platform: :ruby
gem "pg", platform: :ruby
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "sequel"
gem "evt"
gem "async"
gemspec path: "../"
graphql-ruby-2.2.17/gemfiles/rails_master.gemfile 0000664 0000000 0000000 00000001006 14764346352 0022045 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "https://rubygems.org"
gem "bootsnap"
gem "ruby-prof", platform: :ruby
gem "pry"
gem "pry-stack_explorer", platform: :ruby
gem "rails", github: "rails/rails", require: "rails/all", ref: "main"
gem 'sqlite3', "~> 1.4", platform: :ruby
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "sequel"
gem "evt"
if RUBY_ENGINE == "ruby" # This doesn't work on truffle-ruby becuase there's no `IO::READABLE`
gem "libev_scheduler"
end
gem "async"
gemspec path: "../"
graphql-ruby-2.2.17/graphql-c_parser/ 0000775 0000000 0000000 00000000000 14764346352 0017470 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/graphql-c_parser/CHANGELOG.md 0000664 0000000 0000000 00000001062 14764346352 0021300 0 ustar 00root root 0000000 0000000 # GraphQL::CParser
## 1.0.8
- Support directives on variable definitions, requires `graphql` 2.2.10+ #4847
## 1.0.5
- Properly parse integers with leading zeros as Integers, not Floats #4556
## 1.0.4
- Use UTF-8 encoding for static strings #4526
## 1.0.3
- Raise a `ParseError` on bad Unicode escapes (like the Ruby parser) #4514
- Force UTF-8 encoding (like the Ruby parser) #4467
## 1.0.2
- Remove `.y` and `.rl` files to avoid triggering build tasks during install
## 1.0.1
- Fix gem files (to include `ext`)
## 1.0.0
- Release GraphQL::CParser
graphql-ruby-2.2.17/graphql-c_parser/Rakefile 0000664 0000000 0000000 00000000430 14764346352 0021132 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require "bundler/gem_helper"
# use a custom tag to avoid conflicting with GraphQL-Ruby tags in the same git repo
class CustomGemHelper < Bundler::GemHelper
def version_tag
"graphql-c_parser-v#{version}"
end
end
CustomGemHelper.install_tasks
graphql-ruby-2.2.17/graphql-c_parser/ext/ 0000775 0000000 0000000 00000000000 14764346352 0020270 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/ 0000775 0000000 0000000 00000000000 14764346352 0024464 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/extconf.rb 0000664 0000000 0000000 00000000135 14764346352 0026456 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'mkmf'
create_makefile 'graphql/graphql_c_parser_ext'
graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/graphql_c_parser_ext.c 0000664 0000000 0000000 00000001435 14764346352 0031027 0 ustar 00root root 0000000 0000000 #include "graphql_c_parser_ext.h"
VALUE GraphQL_CParser_Lexer_tokenize_with_c(VALUE self, VALUE query_string) {
return tokenize(query_string);
}
VALUE GraphQL_CParser_Parser_c_parse(VALUE self) {
yyparse(self, rb_ivar_get(self, rb_intern("@filename")));
return Qnil;
}
void Init_graphql_c_parser_ext() {
VALUE GraphQL = rb_define_module("GraphQL");
VALUE CParser = rb_define_module_under(GraphQL, "CParser");
VALUE Lexer = rb_define_module_under(CParser, "Lexer");
rb_define_singleton_method(Lexer, "tokenize_with_c", GraphQL_CParser_Lexer_tokenize_with_c, 1);
setup_static_token_variables();
VALUE Parser = rb_define_class_under(CParser, "Parser", rb_cObject);
rb_define_method(Parser, "c_parse", GraphQL_CParser_Parser_c_parse, 0);
initialize_node_class_variables();
}
graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/graphql_c_parser_ext.h 0000664 0000000 0000000 00000000216 14764346352 0031030 0 ustar 00root root 0000000 0000000 #ifndef Graphql_ext_h
#define Graphql_ext_h
#include
#include "lexer.h"
#include "parser.h"
void Init_graphql_c_parser_ext();
#endif
graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/lexer.c 0000664 0000000 0000000 00000147550 14764346352 0025763 0 ustar 00root root 0000000 0000000 #line 1 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
#line 102 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
#line 8 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
static const char _graphql_c_lexer_trans_keys[] = {
4, 22, 4, 43, 14, 47, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 49, 4, 22,
4, 4, 4, 4, 4, 22, 4, 4,
4, 4, 14, 15, 14, 15, 10, 15,
12, 12, 0, 49, 0, 0, 4, 22,
4, 4, 4, 4, 4, 4, 4, 22,
4, 4, 4, 4, 1, 1, 14, 15,
12, 12, 10, 29, 14, 15, 12, 15,
12, 12, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
14, 46, 14, 46, 14, 46, 14, 46,
0
};
static const signed char _graphql_c_lexer_char_class[] = {
0, 1, 2, 2, 1, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 0,
3, 4, 5, 6, 2, 7, 2, 8,
9, 2, 10, 0, 11, 12, 13, 14,
15, 15, 15, 15, 15, 15, 15, 15,
15, 16, 2, 2, 17, 2, 2, 18,
19, 19, 19, 19, 20, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 21, 22, 23, 2, 24, 2,
25, 26, 27, 28, 29, 30, 31, 32,
33, 19, 19, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 19, 45,
46, 19, 47, 48, 49, 0
};
static const short _graphql_c_lexer_index_offsets[] = {
0, 19, 59, 93, 126, 159, 192, 225,
258, 291, 324, 360, 379, 380, 381, 400,
401, 402, 404, 406, 412, 413, 463, 464,
483, 484, 485, 486, 505, 506, 507, 508,
510, 511, 531, 533, 537, 538, 571, 604,
637, 670, 703, 736, 769, 802, 835, 868,
901, 934, 967, 1000, 1033, 1066, 1099, 1132,
1165, 1198, 1231, 1264, 1297, 1330, 1363, 1396,
1429, 1462, 1495, 1528, 1561, 1594, 1627, 1660,
1693, 1726, 1759, 1792, 1825, 1858, 1891, 1924,
1957, 1990, 2023, 2056, 2089, 2122, 2155, 2188,
2221, 2254, 2287, 2320, 2353, 2386, 2419, 2452,
2485, 2518, 2551, 2584, 2617, 2650, 2683, 2716,
2749, 2782, 2815, 2848, 2881, 2914, 2947, 2980,
3013, 3046, 3079, 3112, 3145, 3178, 3211, 3244,
3277, 3310, 3343, 3376, 3409, 3442, 3475, 3508,
3541, 3574, 3607, 3640, 0
};
static const short _graphql_c_lexer_indices[] = {
2, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 3, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 0, 1, 0, 0,
0, 0, 0, 1, 0, 0, 0, 1,
0, 1, 4, 5, 5, 0, 0, 0,
5, 5, 0, 0, 0, 0, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 6, 7, 7, 0,
0, 0, 7, 7, 0, 0, 0, 0,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 8, 8,
0, 0, 0, 8, 8, 0, 0, 0,
0, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 1,
1, 0, 0, 0, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
9, 9, 0, 0, 0, 9, 9, 0,
0, 0, 0, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9,
9, 10, 10, 0, 0, 0, 10, 10,
0, 0, 0, 0, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 11, 11, 0, 0, 0, 11,
11, 0, 0, 0, 0, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 12, 12, 0, 0, 0,
12, 12, 0, 0, 0, 0, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 0, 0,
0, 12, 12, 0, 0, 0, 0, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 0, 0, 1,
15, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 16, 17, 18, 19, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 16,
20, 21, 23, 23, 25, 25, 26, 26,
24, 24, 25, 25, 27, 30, 31, 29,
32, 33, 34, 35, 36, 37, 38, 29,
39, 40, 29, 41, 42, 43, 44, 45,
46, 46, 47, 29, 48, 46, 46, 46,
46, 49, 50, 51, 46, 46, 52, 46,
53, 54, 55, 46, 56, 57, 58, 59,
60, 46, 46, 46, 61, 62, 63, 30,
66, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 3, 14, 69, 70, 71, 14,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14,
16, 72, 18, 73, 41, 42, 75, 26,
26, 76, 76, 23, 23, 76, 76, 76,
76, 77, 76, 76, 76, 76, 76, 76,
76, 76, 77, 25, 25, 75, 74, 42,
42, 78, 46, 46, 13, 13, 13, 46,
46, 13, 13, 13, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 46, 46, 46, 46, 80, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 81, 46,
46, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 82, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 83, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 84, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 46, 46, 46,
46, 46, 46, 85, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 86,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 46, 46, 46,
46, 87, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 88, 46, 46, 46, 46, 46, 46,
46, 46, 89, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 90, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 91, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 92, 46, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 93, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 94, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 95,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 96, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 97, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 98,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 99,
46, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 100, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 101, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 46, 46,
102, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 103, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 46,
104, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
105, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 106,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 107, 108, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 109, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 110, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 111, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 112, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 46,
113, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
114, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 115,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 116,
46, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 117, 46, 46,
46, 118, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 119, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 120, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 46, 46, 121,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 122, 46, 46, 46, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 46, 46, 46,
46, 46, 123, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 124, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 125, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 126, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 127, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 128, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 129, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 130, 46, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 46, 46, 46,
46, 46, 46, 46, 46, 131, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 132, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 133, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 134, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 135, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 136, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 137, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 138, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 46, 46, 46,
46, 139, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 140, 46, 46,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 141, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 142, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 143, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 144, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 145, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 146, 46, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 147, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 148,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
149, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 150, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 151, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 152, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 153, 46, 46, 46, 46, 46,
46, 154, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 155, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 156, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 157, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 158, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 159, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
160, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 161, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 162, 46, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 163, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 164, 46, 46, 46, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 46, 46, 46,
46, 46, 46, 46, 46, 165, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 166, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
167, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 46, 46, 46, 46,
168, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 169, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 170, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 171, 46, 46, 46, 46, 46,
172, 46, 46, 79, 79, 79, 46, 46,
79, 79, 79, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 173, 46,
46, 46, 46, 46, 79, 79, 79, 46,
46, 79, 79, 79, 46, 46, 46, 46,
46, 174, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 79, 79, 79,
46, 46, 79, 79, 79, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 175, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 79, 79,
79, 46, 46, 79, 79, 79, 46, 46,
46, 46, 46, 176, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 79,
79, 79, 46, 46, 79, 79, 79, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 177, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
79, 79, 79, 46, 46, 79, 79, 79,
46, 46, 46, 46, 46, 46, 46, 46,
46, 178, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 79, 79, 79, 46, 46, 79, 79,
79, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 179, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 79, 79, 79, 46, 46, 79,
79, 79, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 180, 46,
46, 46, 46, 46, 46, 46, 46, 46,
46, 0
};
static const signed char _graphql_c_lexer_index_defaults[] = {
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 14, 14, 14, 14, 14,
14, 22, 24, 24, 0, 29, 64, 1,
67, 68, 68, 14, 14, 14, 34, 65,
74, 76, 76, 74, 65, 13, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 79, 79, 79, 79,
79, 79, 79, 79, 0
};
static const short _graphql_c_lexer_cond_targs[] = {
21, 0, 21, 1, 2, 3, 6, 4,
5, 7, 8, 9, 10, 21, 11, 12,
14, 13, 25, 15, 16, 27, 21, 33,
21, 34, 18, 21, 21, 21, 22, 21,
21, 23, 30, 21, 21, 21, 21, 31,
36, 32, 35, 21, 21, 21, 37, 21,
21, 38, 46, 53, 63, 81, 88, 91,
92, 96, 105, 123, 128, 21, 21, 21,
21, 21, 24, 21, 21, 26, 21, 28,
29, 21, 21, 17, 21, 19, 20, 21,
39, 40, 41, 42, 43, 44, 45, 37,
47, 49, 48, 37, 50, 51, 52, 37,
54, 57, 55, 56, 37, 58, 59, 60,
61, 62, 37, 64, 72, 65, 66, 67,
68, 69, 70, 71, 37, 73, 75, 74,
37, 76, 77, 78, 79, 80, 37, 82,
83, 84, 85, 86, 87, 37, 89, 90,
37, 37, 93, 94, 95, 37, 97, 98,
99, 100, 101, 102, 103, 104, 37, 106,
113, 107, 110, 108, 109, 37, 111, 112,
37, 114, 115, 116, 117, 118, 119, 120,
121, 122, 37, 124, 126, 125, 37, 127,
37, 129, 130, 131, 37, 0
};
static const signed char _graphql_c_lexer_cond_actions[] = {
1, 0, 2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 3, 0, 0,
0, 0, 0, 0, 0, 4, 5, 6,
7, 0, 0, 8, 0, 11, 0, 12,
13, 6, 0, 14, 15, 16, 17, 0,
6, 6, 6, 18, 19, 20, 21, 22,
23, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 24, 25, 26,
27, 28, 29, 30, 31, 0, 32, 4,
4, 33, 34, 0, 35, 0, 0, 36,
0, 0, 0, 0, 0, 0, 0, 37,
0, 0, 0, 38, 0, 0, 0, 39,
0, 0, 0, 0, 40, 0, 0, 0,
0, 0, 41, 0, 0, 0, 0, 0,
0, 0, 0, 0, 42, 0, 0, 0,
43, 0, 0, 0, 0, 0, 44, 0,
0, 0, 0, 0, 0, 45, 0, 0,
46, 47, 0, 0, 0, 48, 0, 0,
0, 0, 0, 0, 0, 0, 49, 0,
0, 0, 0, 0, 0, 50, 0, 0,
51, 0, 0, 0, 0, 0, 0, 0,
0, 0, 52, 0, 0, 0, 53, 0,
54, 0, 0, 0, 55, 0
};
static const signed char _graphql_c_lexer_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 9, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0
};
static const signed char _graphql_c_lexer_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 10, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0
};
static const signed char _graphql_c_lexer_eof_trans[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 14, 14, 14, 14, 14,
14, 23, 25, 25, 1, 29, 65, 66,
68, 69, 69, 69, 69, 69, 74, 66,
75, 77, 77, 75, 66, 14, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 0
};
static const int graphql_c_lexer_start = 21;
static const int graphql_c_lexer_first_final = 21;
static const int graphql_c_lexer_error = -1;
static const int graphql_c_lexer_en_main = 21;
#line 104 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
#include
#define INIT_STATIC_TOKEN_VARIABLE(token_name) \
static VALUE GraphQLTokenString##token_name;
INIT_STATIC_TOKEN_VARIABLE(ON)
INIT_STATIC_TOKEN_VARIABLE(FRAGMENT)
INIT_STATIC_TOKEN_VARIABLE(QUERY)
INIT_STATIC_TOKEN_VARIABLE(MUTATION)
INIT_STATIC_TOKEN_VARIABLE(SUBSCRIPTION)
INIT_STATIC_TOKEN_VARIABLE(REPEATABLE)
INIT_STATIC_TOKEN_VARIABLE(RCURLY)
INIT_STATIC_TOKEN_VARIABLE(LCURLY)
INIT_STATIC_TOKEN_VARIABLE(RBRACKET)
INIT_STATIC_TOKEN_VARIABLE(LBRACKET)
INIT_STATIC_TOKEN_VARIABLE(RPAREN)
INIT_STATIC_TOKEN_VARIABLE(LPAREN)
INIT_STATIC_TOKEN_VARIABLE(COLON)
INIT_STATIC_TOKEN_VARIABLE(VAR_SIGN)
INIT_STATIC_TOKEN_VARIABLE(DIR_SIGN)
INIT_STATIC_TOKEN_VARIABLE(ELLIPSIS)
INIT_STATIC_TOKEN_VARIABLE(EQUALS)
INIT_STATIC_TOKEN_VARIABLE(BANG)
INIT_STATIC_TOKEN_VARIABLE(PIPE)
INIT_STATIC_TOKEN_VARIABLE(AMP)
INIT_STATIC_TOKEN_VARIABLE(SCHEMA)
INIT_STATIC_TOKEN_VARIABLE(SCALAR)
INIT_STATIC_TOKEN_VARIABLE(EXTEND)
INIT_STATIC_TOKEN_VARIABLE(IMPLEMENTS)
INIT_STATIC_TOKEN_VARIABLE(INTERFACE)
INIT_STATIC_TOKEN_VARIABLE(UNION)
INIT_STATIC_TOKEN_VARIABLE(ENUM)
INIT_STATIC_TOKEN_VARIABLE(DIRECTIVE)
INIT_STATIC_TOKEN_VARIABLE(INPUT)
static VALUE GraphQL_type_str;
static VALUE GraphQL_true_str;
static VALUE GraphQL_false_str;
static VALUE GraphQL_null_str;
typedef enum TokenType {
AMP,
BANG,
COLON,
DIRECTIVE,
DIR_SIGN,
ENUM,
ELLIPSIS,
EQUALS,
EXTEND,
FALSE_LITERAL,
FLOAT,
FRAGMENT,
IDENTIFIER,
INPUT,
IMPLEMENTS,
INT,
INTERFACE,
LBRACKET,
LCURLY,
LPAREN,
MUTATION,
NULL_LITERAL,
ON,
PIPE,
QUERY,
RBRACKET,
RCURLY,
REPEATABLE,
RPAREN,
SCALAR,
SCHEMA,
STRING,
SUBSCRIPTION,
TRUE_LITERAL,
TYPE_LITERAL,
UNION,
VAR_SIGN,
BLOCK_STRING,
QUOTED_STRING,
UNKNOWN_CHAR,
COMMENT,
BAD_UNICODE_ESCAPE
} TokenType;
typedef struct Meta {
int line;
int col;
char *query_cstr;
char *pe;
VALUE tokens;
VALUE previous_token;
} Meta;
#define STATIC_VALUE_TOKEN(token_type, content_str) \
case token_type: \
token_sym = ID2SYM(rb_intern(#token_type)); \
token_content = GraphQLTokenString##token_type; \
break;
#define DYNAMIC_VALUE_TOKEN(token_type) \
case token_type: \
token_sym = ID2SYM(rb_intern(#token_type)); \
token_content = rb_utf8_str_new(ts, te - ts); \
break;
void emit(TokenType tt, char *ts, char *te, Meta *meta) {
int quotes_length = 0; // set by string tokens below
int line_incr = 0;
VALUE token_sym = Qnil;
VALUE token_content = Qnil;
switch(tt) {
STATIC_VALUE_TOKEN(ON, "on")
STATIC_VALUE_TOKEN(FRAGMENT, "fragment")
STATIC_VALUE_TOKEN(QUERY, "query")
STATIC_VALUE_TOKEN(MUTATION, "mutation")
STATIC_VALUE_TOKEN(SUBSCRIPTION, "subscription")
STATIC_VALUE_TOKEN(REPEATABLE, "repeatable")
STATIC_VALUE_TOKEN(RCURLY, "}")
STATIC_VALUE_TOKEN(LCURLY, "{")
STATIC_VALUE_TOKEN(RBRACKET, "]")
STATIC_VALUE_TOKEN(LBRACKET, "[")
STATIC_VALUE_TOKEN(RPAREN, ")")
STATIC_VALUE_TOKEN(LPAREN, "(")
STATIC_VALUE_TOKEN(COLON, ":")
STATIC_VALUE_TOKEN(VAR_SIGN, "$")
STATIC_VALUE_TOKEN(DIR_SIGN, "@")
STATIC_VALUE_TOKEN(ELLIPSIS, "...")
STATIC_VALUE_TOKEN(EQUALS, "=")
STATIC_VALUE_TOKEN(BANG, "!")
STATIC_VALUE_TOKEN(PIPE, "|")
STATIC_VALUE_TOKEN(AMP, "&")
STATIC_VALUE_TOKEN(SCHEMA, "schema")
STATIC_VALUE_TOKEN(SCALAR, "scalar")
STATIC_VALUE_TOKEN(EXTEND, "extend")
STATIC_VALUE_TOKEN(IMPLEMENTS, "implements")
STATIC_VALUE_TOKEN(INTERFACE, "interface")
STATIC_VALUE_TOKEN(UNION, "union")
STATIC_VALUE_TOKEN(ENUM, "enum")
STATIC_VALUE_TOKEN(DIRECTIVE, "directive")
STATIC_VALUE_TOKEN(INPUT, "input")
// For these, the enum name doesn't match the symbol name:
case TYPE_LITERAL:
token_sym = ID2SYM(rb_intern("TYPE"));
token_content = GraphQL_type_str;
break;
case TRUE_LITERAL:
token_sym = ID2SYM(rb_intern("TRUE"));
token_content = GraphQL_true_str;
break;
case FALSE_LITERAL:
token_sym = ID2SYM(rb_intern("FALSE"));
token_content = GraphQL_false_str;
break;
case NULL_LITERAL:
token_sym = ID2SYM(rb_intern("NULL"));
token_content = GraphQL_null_str;
break;
DYNAMIC_VALUE_TOKEN(IDENTIFIER)
DYNAMIC_VALUE_TOKEN(INT)
DYNAMIC_VALUE_TOKEN(FLOAT)
DYNAMIC_VALUE_TOKEN(COMMENT)
case UNKNOWN_CHAR:
if (ts[0] == '\0') {
return;
} else {
token_content = rb_utf8_str_new(ts, te - ts);
token_sym = ID2SYM(rb_intern("UNKNOWN_CHAR"));
break;
}
case QUOTED_STRING:
quotes_length = 1;
token_content = rb_utf8_str_new(ts + quotes_length, (te - ts - (2 * quotes_length)));
token_sym = ID2SYM(rb_intern("STRING"));
break;
case BLOCK_STRING:
token_sym = ID2SYM(rb_intern("STRING"));
quotes_length = 3;
token_content = rb_utf8_str_new(ts + quotes_length, (te - ts - (2 * quotes_length)));
line_incr = FIX2INT(rb_funcall(token_content, rb_intern("count"), 1, rb_utf8_str_new_cstr("\n")));
break;
case STRING:
// This is used only by the parser, this is never reached
break;
}
if (token_sym != Qnil) {
if (tt == BLOCK_STRING || tt == QUOTED_STRING) {
VALUE mGraphQL = rb_const_get_at(rb_cObject, rb_intern("GraphQL"));
VALUE mGraphQLLanguage = rb_const_get_at(mGraphQL, rb_intern("Language"));
VALUE mGraphQLLanguageLexer = rb_const_get_at(mGraphQLLanguage, rb_intern("Lexer"));
VALUE valid_string_pattern = rb_const_get_at(mGraphQLLanguageLexer, rb_intern("VALID_STRING"));
if (tt == BLOCK_STRING) {
VALUE mGraphQLLanguageBlockString = rb_const_get_at(mGraphQLLanguage, rb_intern("BlockString"));
token_content = rb_funcall(mGraphQLLanguageBlockString, rb_intern("trim_whitespace"), 1, token_content);
}
// The parser doesn't distinguish between these,
// Maybe updated below if it's invalid UTF-8
tt = STRING;
if (
RB_TEST(rb_funcall(token_content, rb_intern("valid_encoding?"), 0)) &&
RB_TEST(rb_funcall(token_content, rb_intern("match?"), 1, valid_string_pattern))
) {
rb_funcall(mGraphQLLanguageLexer, rb_intern("replace_escaped_characters_in_place"), 1, token_content);
if (!RB_TEST(rb_funcall(token_content, rb_intern("valid_encoding?"), 0))) {
token_sym = ID2SYM(rb_intern("BAD_UNICODE_ESCAPE"));
tt = BAD_UNICODE_ESCAPE;
}
} else {
token_sym = ID2SYM(rb_intern("BAD_UNICODE_ESCAPE"));
tt = BAD_UNICODE_ESCAPE;
}
}
VALUE token = rb_ary_new_from_args(6,
token_sym,
rb_int2inum(meta->line),
rb_int2inum(meta->col),
token_content,
meta->previous_token,
INT2FIX(200 + (int)tt)
);
// COMMENTs are retained as `previous_token` but aren't pushed to the normal token list
if (tt != COMMENT) {
rb_ary_push(meta->tokens, token);
}
meta->previous_token = token;
}
// Bump the column counter for the next token
meta->col += te - ts;
meta->line += line_incr;
}
VALUE tokenize(VALUE query_rbstr) {
int cs = 0;
int act = 0;
char *p = StringValueCStr(query_rbstr);
char *pe = p + strlen(p);
char *eof = pe;
char *ts = 0;
char *te = 0;
VALUE tokens = rb_ary_new();
struct Meta meta_s = {1, 1, p, pe, tokens, Qnil};
Meta *meta = &meta_s;
#line 938 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
cs = (int)graphql_c_lexer_start;
ts = 0;
te = 0;
act = 0;
}
#line 354 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
#line 949 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
unsigned int _trans = 0;
const char * _keys;
const short * _inds;
int _ic;
_resume: {}
if ( p == pe && p != eof )
goto _out;
switch ( _graphql_c_lexer_from_state_actions[cs] ) {
case 10: {
{
#line 1 "NONE"
{ts = p;}}
#line 964 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
}
if ( p == eof ) {
if ( _graphql_c_lexer_eof_trans[cs] > 0 ) {
_trans = (unsigned int)_graphql_c_lexer_eof_trans[cs] - 1;
}
}
else {
_keys = ( _graphql_c_lexer_trans_keys + ((cs<<1)));
_inds = ( _graphql_c_lexer_indices + (_graphql_c_lexer_index_offsets[cs]));
if ( ( (*( p))) <= 125 && ( (*( p))) >= 9 ) {
_ic = (int)_graphql_c_lexer_char_class[(int)( (*( p))) - 9];
if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) )
_trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) ));
else
_trans = (unsigned int)_graphql_c_lexer_index_defaults[cs];
}
else {
_trans = (unsigned int)_graphql_c_lexer_index_defaults[cs];
}
}
cs = (int)_graphql_c_lexer_cond_targs[_trans];
if ( _graphql_c_lexer_cond_actions[_trans] != 0 ) {
switch ( _graphql_c_lexer_cond_actions[_trans] ) {
case 6: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1002 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 26: {
{
#line 75 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 75 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(RCURLY, ts, te, meta); }
}}
#line 1015 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 24: {
{
#line 76 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 76 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(LCURLY, ts, te, meta); }
}}
#line 1028 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 17: {
{
#line 77 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 77 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(RPAREN, ts, te, meta); }
}}
#line 1041 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 16: {
{
#line 78 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 78 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(LPAREN, ts, te, meta); }
}}
#line 1054 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 23: {
{
#line 79 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 79 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(RBRACKET, ts, te, meta); }
}}
#line 1067 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 22: {
{
#line 80 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 80 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(LBRACKET, ts, te, meta); }
}}
#line 1080 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 18: {
{
#line 81 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 81 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(COLON, ts, te, meta); }
}}
#line 1093 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 32: {
{
#line 82 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 82 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(BLOCK_STRING, ts, te, meta); }
}}
#line 1106 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 2: {
{
#line 83 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 83 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(QUOTED_STRING, ts, te, meta); }
}}
#line 1119 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 14: {
{
#line 84 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 84 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(VAR_SIGN, ts, te, meta); }
}}
#line 1132 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 20: {
{
#line 85 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 85 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(DIR_SIGN, ts, te, meta); }
}}
#line 1145 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 8: {
{
#line 86 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 86 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(ELLIPSIS, ts, te, meta); }
}}
#line 1158 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 19: {
{
#line 87 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 87 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(EQUALS, ts, te, meta); }
}}
#line 1171 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 13: {
{
#line 88 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 88 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(BANG, ts, te, meta); }
}}
#line 1184 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 25: {
{
#line 89 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 89 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(PIPE, ts, te, meta); }
}}
#line 1197 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 15: {
{
#line 90 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 90 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(AMP, ts, te, meta); }
}}
#line 1210 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 12: {
{
#line 93 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 93 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
meta->line += 1;
meta->col = 1;
}
}}
#line 1226 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 11: {
{
#line 100 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p+1;{
#line 100 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(UNKNOWN_CHAR, ts, te, meta); }
}}
#line 1239 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 34: {
{
#line 54 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p;p = p - 1;{
#line 54 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(INT, ts, te, meta); }
}}
#line 1252 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 35: {
{
#line 55 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p;p = p - 1;{
#line 55 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(FLOAT, ts, te, meta); }
}}
#line 1265 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 31: {
{
#line 82 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p;p = p - 1;{
#line 82 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(BLOCK_STRING, ts, te, meta); }
}}
#line 1278 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 30: {
{
#line 83 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p;p = p - 1;{
#line 83 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(QUOTED_STRING, ts, te, meta); }
}}
#line 1291 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 36: {
{
#line 91 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p;p = p - 1;{
#line 91 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(IDENTIFIER, ts, te, meta); }
}}
#line 1304 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 33: {
{
#line 92 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p;p = p - 1;{
#line 92 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(COMMENT, ts, te, meta); }
}}
#line 1317 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 27: {
{
#line 98 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p;p = p - 1;{
#line 98 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
meta->col += te - ts; }
}}
#line 1330 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 28: {
{
#line 100 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{te = p;p = p - 1;{
#line 100 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(UNKNOWN_CHAR, ts, te, meta); }
}}
#line 1343 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 5: {
{
#line 54 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{p = ((te))-1;
{
#line 54 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(INT, ts, te, meta); }
}}
#line 1357 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 7: {
{
#line 55 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{p = ((te))-1;
{
#line 55 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(FLOAT, ts, te, meta); }
}}
#line 1371 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 1: {
{
#line 100 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{p = ((te))-1;
{
#line 100 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(UNKNOWN_CHAR, ts, te, meta); }
}}
#line 1385 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 3: {
{
#line 1 "NONE"
{switch( act ) {
case 3: {
p = ((te))-1;
{
#line 56 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(ON, ts, te, meta); }
break;
}
case 4: {
p = ((te))-1;
{
#line 57 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(FRAGMENT, ts, te, meta); }
break;
}
case 5: {
p = ((te))-1;
{
#line 58 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(TRUE_LITERAL, ts, te, meta); }
break;
}
case 6: {
p = ((te))-1;
{
#line 59 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(FALSE_LITERAL, ts, te, meta); }
break;
}
case 7: {
p = ((te))-1;
{
#line 60 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(NULL_LITERAL, ts, te, meta); }
break;
}
case 8: {
p = ((te))-1;
{
#line 61 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(QUERY, ts, te, meta); }
break;
}
case 9: {
p = ((te))-1;
{
#line 62 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(MUTATION, ts, te, meta); }
break;
}
case 10: {
p = ((te))-1;
{
#line 63 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(SUBSCRIPTION, ts, te, meta); }
break;
}
case 11: {
p = ((te))-1;
{
#line 64 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(SCHEMA, ts, te, meta); }
break;
}
case 12: {
p = ((te))-1;
{
#line 65 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(SCALAR, ts, te, meta); }
break;
}
case 13: {
p = ((te))-1;
{
#line 66 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(TYPE_LITERAL, ts, te, meta); }
break;
}
case 14: {
p = ((te))-1;
{
#line 67 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(EXTEND, ts, te, meta); }
break;
}
case 15: {
p = ((te))-1;
{
#line 68 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(IMPLEMENTS, ts, te, meta); }
break;
}
case 16: {
p = ((te))-1;
{
#line 69 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(INTERFACE, ts, te, meta); }
break;
}
case 17: {
p = ((te))-1;
{
#line 70 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(UNION, ts, te, meta); }
break;
}
case 18: {
p = ((te))-1;
{
#line 71 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(ENUM, ts, te, meta); }
break;
}
case 19: {
p = ((te))-1;
{
#line 72 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(INPUT, ts, te, meta); }
break;
}
case 20: {
p = ((te))-1;
{
#line 73 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(DIRECTIVE, ts, te, meta); }
break;
}
case 21: {
p = ((te))-1;
{
#line 74 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(REPEATABLE, ts, te, meta); }
break;
}
case 29: {
p = ((te))-1;
{
#line 82 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(BLOCK_STRING, ts, te, meta); }
break;
}
case 30: {
p = ((te))-1;
{
#line 83 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(QUOTED_STRING, ts, te, meta); }
break;
}
case 38: {
p = ((te))-1;
{
#line 91 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
emit(IDENTIFIER, ts, te, meta); }
break;
}
}}
}
#line 1551 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 47: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1561 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 56 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 3;}}
#line 1567 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 41: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1577 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 57 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 4;}}
#line 1583 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 53: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1593 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 58 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 5;}}
#line 1599 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 40: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1609 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 59 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 6;}}
#line 1615 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 46: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1625 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 60 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 7;}}
#line 1631 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 48: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1641 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 61 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 8;}}
#line 1647 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 45: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1657 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 62 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 9;}}
#line 1663 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 52: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1673 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 63 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 10;}}
#line 1679 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 51: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1689 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 64 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 11;}}
#line 1695 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 50: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1705 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 65 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 12;}}
#line 1711 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 54: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1721 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 66 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 13;}}
#line 1727 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 39: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1737 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 67 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 14;}}
#line 1743 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 42: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1753 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 68 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 15;}}
#line 1759 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 44: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1769 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 69 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 16;}}
#line 1775 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 55: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1785 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 70 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 17;}}
#line 1791 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 38: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1801 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 71 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 18;}}
#line 1807 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 43: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1817 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 72 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 19;}}
#line 1823 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 37: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1833 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 73 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 20;}}
#line 1839 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 49: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1849 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 74 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 21;}}
#line 1855 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 4: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1865 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 82 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 29;}}
#line 1871 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 29: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1881 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 83 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 30;}}
#line 1887 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
case 21: {
{
#line 1 "NONE"
{te = p+1;}}
#line 1897 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
{
#line 91 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
{act = 38;}}
#line 1903 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
}
}
if ( p == eof ) {
if ( cs >= 21 )
goto _out;
}
else {
switch ( _graphql_c_lexer_to_state_actions[cs] ) {
case 9: {
{
#line 1 "NONE"
{ts = 0;}}
#line 1923 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.c"
break;
}
}
p += 1;
goto _resume;
}
_out: {}
}
#line 355 "graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl"
return tokens;
}
#define SETUP_STATIC_TOKEN_VARIABLE(token_name, token_content) \
GraphQLTokenString##token_name = rb_utf8_str_new_cstr(token_content); \
rb_funcall(GraphQLTokenString##token_name, rb_intern("-@"), 0); \
rb_global_variable(&GraphQLTokenString##token_name); \
#define SETUP_STATIC_STRING(var_name, str_content) \
var_name = rb_utf8_str_new_cstr(str_content); \
rb_global_variable(&var_name); \
rb_str_freeze(var_name); \
void setup_static_token_variables() {
SETUP_STATIC_TOKEN_VARIABLE(ON, "on")
SETUP_STATIC_TOKEN_VARIABLE(FRAGMENT, "fragment")
SETUP_STATIC_TOKEN_VARIABLE(QUERY, "query")
SETUP_STATIC_TOKEN_VARIABLE(MUTATION, "mutation")
SETUP_STATIC_TOKEN_VARIABLE(SUBSCRIPTION, "subscription")
SETUP_STATIC_TOKEN_VARIABLE(REPEATABLE, "repeatable")
SETUP_STATIC_TOKEN_VARIABLE(RCURLY, "}")
SETUP_STATIC_TOKEN_VARIABLE(LCURLY, "{")
SETUP_STATIC_TOKEN_VARIABLE(RBRACKET, "]")
SETUP_STATIC_TOKEN_VARIABLE(LBRACKET, "[")
SETUP_STATIC_TOKEN_VARIABLE(RPAREN, ")")
SETUP_STATIC_TOKEN_VARIABLE(LPAREN, "(")
SETUP_STATIC_TOKEN_VARIABLE(COLON, ":")
SETUP_STATIC_TOKEN_VARIABLE(VAR_SIGN, "$")
SETUP_STATIC_TOKEN_VARIABLE(DIR_SIGN, "@")
SETUP_STATIC_TOKEN_VARIABLE(ELLIPSIS, "...")
SETUP_STATIC_TOKEN_VARIABLE(EQUALS, "=")
SETUP_STATIC_TOKEN_VARIABLE(BANG, "!")
SETUP_STATIC_TOKEN_VARIABLE(PIPE, "|")
SETUP_STATIC_TOKEN_VARIABLE(AMP, "&")
SETUP_STATIC_TOKEN_VARIABLE(SCHEMA, "schema")
SETUP_STATIC_TOKEN_VARIABLE(SCALAR, "scalar")
SETUP_STATIC_TOKEN_VARIABLE(EXTEND, "extend")
SETUP_STATIC_TOKEN_VARIABLE(IMPLEMENTS, "implements")
SETUP_STATIC_TOKEN_VARIABLE(INTERFACE, "interface")
SETUP_STATIC_TOKEN_VARIABLE(UNION, "union")
SETUP_STATIC_TOKEN_VARIABLE(ENUM, "enum")
SETUP_STATIC_TOKEN_VARIABLE(DIRECTIVE, "directive")
SETUP_STATIC_TOKEN_VARIABLE(INPUT, "input")
SETUP_STATIC_STRING(GraphQL_type_str, "type")
SETUP_STATIC_STRING(GraphQL_true_str, "true")
SETUP_STATIC_STRING(GraphQL_false_str, "false")
SETUP_STATIC_STRING(GraphQL_null_str, "null")
}
graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/lexer.h 0000664 0000000 0000000 00000000221 14764346352 0025747 0 ustar 00root root 0000000 0000000 #ifndef Graphql_lexer_h
#define Graphql_lexer_h
#include
VALUE tokenize(VALUE query_rbstr);
void setup_static_token_variables();
#endif
graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/lexer.rl 0000664 0000000 0000000 00000032176 14764346352 0026153 0 ustar 00root root 0000000 0000000 %%{
machine graphql_c_lexer;
IDENTIFIER = [_A-Za-z][_0-9A-Za-z]*;
NEWLINE = [\c\r\n];
BLANK = [, \t]+;
COMMENT = '#' [^\n\r]*;
INT = '-'? ('0'|[1-9][0-9]*);
FLOAT = INT ('.'[0-9]+) (('e' | 'E')?('+' | '-')?[0-9]+)?;
ON = 'on';
FRAGMENT = 'fragment';
TRUE_LITERAL = 'true';
FALSE_LITERAL = 'false';
NULL_LITERAL = 'null';
QUERY = 'query';
MUTATION = 'mutation';
SUBSCRIPTION = 'subscription';
SCHEMA = 'schema';
SCALAR = 'scalar';
TYPE_LITERAL = 'type';
EXTEND = 'extend';
IMPLEMENTS = 'implements';
INTERFACE = 'interface';
UNION = 'union';
ENUM = 'enum';
INPUT = 'input';
DIRECTIVE = 'directive';
REPEATABLE = 'repeatable';
LCURLY = '{';
RCURLY = '}';
LPAREN = '(';
RPAREN = ')';
LBRACKET = '[';
RBRACKET = ']';
COLON = ':';
# Could limit to hex here, but “bad unicode escape” on 0XXF is probably a
# more helpful error than “unknown char”
UNICODE_ESCAPE = "\\u" ([0-9A-Za-z]{4} | LCURLY [0-9A-Za-z]{4,} RCURLY);
VAR_SIGN = '$';
DIR_SIGN = '@';
ELLIPSIS = '...';
EQUALS = '=';
BANG = '!';
PIPE = '|';
AMP = '&';
QUOTED_STRING = ('"' ((('\\"' | ^'"') - "\\") | UNICODE_ESCAPE | '\\' [\\/bfnrt])* '"');
# catch-all for anything else. must be at the bottom for precedence.
UNKNOWN_CHAR = /./;
BLOCK_STRING = ('"""' ('\\"""' | ^'"' | '"'{1,2} ^'"')* '"'{0,2} '"""');
main := |*
INT => { emit(INT, ts, te, meta); };
FLOAT => { emit(FLOAT, ts, te, meta); };
ON => { emit(ON, ts, te, meta); };
FRAGMENT => { emit(FRAGMENT, ts, te, meta); };
TRUE_LITERAL => { emit(TRUE_LITERAL, ts, te, meta); };
FALSE_LITERAL => { emit(FALSE_LITERAL, ts, te, meta); };
NULL_LITERAL => { emit(NULL_LITERAL, ts, te, meta); };
QUERY => { emit(QUERY, ts, te, meta); };
MUTATION => { emit(MUTATION, ts, te, meta); };
SUBSCRIPTION => { emit(SUBSCRIPTION, ts, te, meta); };
SCHEMA => { emit(SCHEMA, ts, te, meta); };
SCALAR => { emit(SCALAR, ts, te, meta); };
TYPE_LITERAL => { emit(TYPE_LITERAL, ts, te, meta); };
EXTEND => { emit(EXTEND, ts, te, meta); };
IMPLEMENTS => { emit(IMPLEMENTS, ts, te, meta); };
INTERFACE => { emit(INTERFACE, ts, te, meta); };
UNION => { emit(UNION, ts, te, meta); };
ENUM => { emit(ENUM, ts, te, meta); };
INPUT => { emit(INPUT, ts, te, meta); };
DIRECTIVE => { emit(DIRECTIVE, ts, te, meta); };
REPEATABLE => { emit(REPEATABLE, ts, te, meta); };
RCURLY => { emit(RCURLY, ts, te, meta); };
LCURLY => { emit(LCURLY, ts, te, meta); };
RPAREN => { emit(RPAREN, ts, te, meta); };
LPAREN => { emit(LPAREN, ts, te, meta); };
RBRACKET => { emit(RBRACKET, ts, te, meta); };
LBRACKET => { emit(LBRACKET, ts, te, meta); };
COLON => { emit(COLON, ts, te, meta); };
BLOCK_STRING => { emit(BLOCK_STRING, ts, te, meta); };
QUOTED_STRING => { emit(QUOTED_STRING, ts, te, meta); };
VAR_SIGN => { emit(VAR_SIGN, ts, te, meta); };
DIR_SIGN => { emit(DIR_SIGN, ts, te, meta); };
ELLIPSIS => { emit(ELLIPSIS, ts, te, meta); };
EQUALS => { emit(EQUALS, ts, te, meta); };
BANG => { emit(BANG, ts, te, meta); };
PIPE => { emit(PIPE, ts, te, meta); };
AMP => { emit(AMP, ts, te, meta); };
IDENTIFIER => { emit(IDENTIFIER, ts, te, meta); };
COMMENT => { emit(COMMENT, ts, te, meta); };
NEWLINE => {
meta->line += 1;
meta->col = 1;
};
BLANK => { meta->col += te - ts; };
UNKNOWN_CHAR => { emit(UNKNOWN_CHAR, ts, te, meta); };
*|;
}%%
%% write data;
#include
#define INIT_STATIC_TOKEN_VARIABLE(token_name) \
static VALUE GraphQLTokenString##token_name;
INIT_STATIC_TOKEN_VARIABLE(ON)
INIT_STATIC_TOKEN_VARIABLE(FRAGMENT)
INIT_STATIC_TOKEN_VARIABLE(QUERY)
INIT_STATIC_TOKEN_VARIABLE(MUTATION)
INIT_STATIC_TOKEN_VARIABLE(SUBSCRIPTION)
INIT_STATIC_TOKEN_VARIABLE(REPEATABLE)
INIT_STATIC_TOKEN_VARIABLE(RCURLY)
INIT_STATIC_TOKEN_VARIABLE(LCURLY)
INIT_STATIC_TOKEN_VARIABLE(RBRACKET)
INIT_STATIC_TOKEN_VARIABLE(LBRACKET)
INIT_STATIC_TOKEN_VARIABLE(RPAREN)
INIT_STATIC_TOKEN_VARIABLE(LPAREN)
INIT_STATIC_TOKEN_VARIABLE(COLON)
INIT_STATIC_TOKEN_VARIABLE(VAR_SIGN)
INIT_STATIC_TOKEN_VARIABLE(DIR_SIGN)
INIT_STATIC_TOKEN_VARIABLE(ELLIPSIS)
INIT_STATIC_TOKEN_VARIABLE(EQUALS)
INIT_STATIC_TOKEN_VARIABLE(BANG)
INIT_STATIC_TOKEN_VARIABLE(PIPE)
INIT_STATIC_TOKEN_VARIABLE(AMP)
INIT_STATIC_TOKEN_VARIABLE(SCHEMA)
INIT_STATIC_TOKEN_VARIABLE(SCALAR)
INIT_STATIC_TOKEN_VARIABLE(EXTEND)
INIT_STATIC_TOKEN_VARIABLE(IMPLEMENTS)
INIT_STATIC_TOKEN_VARIABLE(INTERFACE)
INIT_STATIC_TOKEN_VARIABLE(UNION)
INIT_STATIC_TOKEN_VARIABLE(ENUM)
INIT_STATIC_TOKEN_VARIABLE(DIRECTIVE)
INIT_STATIC_TOKEN_VARIABLE(INPUT)
static VALUE GraphQL_type_str;
static VALUE GraphQL_true_str;
static VALUE GraphQL_false_str;
static VALUE GraphQL_null_str;
typedef enum TokenType {
AMP,
BANG,
COLON,
DIRECTIVE,
DIR_SIGN,
ENUM,
ELLIPSIS,
EQUALS,
EXTEND,
FALSE_LITERAL,
FLOAT,
FRAGMENT,
IDENTIFIER,
INPUT,
IMPLEMENTS,
INT,
INTERFACE,
LBRACKET,
LCURLY,
LPAREN,
MUTATION,
NULL_LITERAL,
ON,
PIPE,
QUERY,
RBRACKET,
RCURLY,
REPEATABLE,
RPAREN,
SCALAR,
SCHEMA,
STRING,
SUBSCRIPTION,
TRUE_LITERAL,
TYPE_LITERAL,
UNION,
VAR_SIGN,
BLOCK_STRING,
QUOTED_STRING,
UNKNOWN_CHAR,
COMMENT,
BAD_UNICODE_ESCAPE
} TokenType;
typedef struct Meta {
int line;
int col;
char *query_cstr;
char *pe;
VALUE tokens;
VALUE previous_token;
} Meta;
#define STATIC_VALUE_TOKEN(token_type, content_str) \
case token_type: \
token_sym = ID2SYM(rb_intern(#token_type)); \
token_content = GraphQLTokenString##token_type; \
break;
#define DYNAMIC_VALUE_TOKEN(token_type) \
case token_type: \
token_sym = ID2SYM(rb_intern(#token_type)); \
token_content = rb_utf8_str_new(ts, te - ts); \
break;
void emit(TokenType tt, char *ts, char *te, Meta *meta) {
int quotes_length = 0; // set by string tokens below
int line_incr = 0;
VALUE token_sym = Qnil;
VALUE token_content = Qnil;
switch(tt) {
STATIC_VALUE_TOKEN(ON, "on")
STATIC_VALUE_TOKEN(FRAGMENT, "fragment")
STATIC_VALUE_TOKEN(QUERY, "query")
STATIC_VALUE_TOKEN(MUTATION, "mutation")
STATIC_VALUE_TOKEN(SUBSCRIPTION, "subscription")
STATIC_VALUE_TOKEN(REPEATABLE, "repeatable")
STATIC_VALUE_TOKEN(RCURLY, "}")
STATIC_VALUE_TOKEN(LCURLY, "{")
STATIC_VALUE_TOKEN(RBRACKET, "]")
STATIC_VALUE_TOKEN(LBRACKET, "[")
STATIC_VALUE_TOKEN(RPAREN, ")")
STATIC_VALUE_TOKEN(LPAREN, "(")
STATIC_VALUE_TOKEN(COLON, ":")
STATIC_VALUE_TOKEN(VAR_SIGN, "$")
STATIC_VALUE_TOKEN(DIR_SIGN, "@")
STATIC_VALUE_TOKEN(ELLIPSIS, "...")
STATIC_VALUE_TOKEN(EQUALS, "=")
STATIC_VALUE_TOKEN(BANG, "!")
STATIC_VALUE_TOKEN(PIPE, "|")
STATIC_VALUE_TOKEN(AMP, "&")
STATIC_VALUE_TOKEN(SCHEMA, "schema")
STATIC_VALUE_TOKEN(SCALAR, "scalar")
STATIC_VALUE_TOKEN(EXTEND, "extend")
STATIC_VALUE_TOKEN(IMPLEMENTS, "implements")
STATIC_VALUE_TOKEN(INTERFACE, "interface")
STATIC_VALUE_TOKEN(UNION, "union")
STATIC_VALUE_TOKEN(ENUM, "enum")
STATIC_VALUE_TOKEN(DIRECTIVE, "directive")
STATIC_VALUE_TOKEN(INPUT, "input")
// For these, the enum name doesn't match the symbol name:
case TYPE_LITERAL:
token_sym = ID2SYM(rb_intern("TYPE"));
token_content = GraphQL_type_str;
break;
case TRUE_LITERAL:
token_sym = ID2SYM(rb_intern("TRUE"));
token_content = GraphQL_true_str;
break;
case FALSE_LITERAL:
token_sym = ID2SYM(rb_intern("FALSE"));
token_content = GraphQL_false_str;
break;
case NULL_LITERAL:
token_sym = ID2SYM(rb_intern("NULL"));
token_content = GraphQL_null_str;
break;
DYNAMIC_VALUE_TOKEN(IDENTIFIER)
DYNAMIC_VALUE_TOKEN(INT)
DYNAMIC_VALUE_TOKEN(FLOAT)
DYNAMIC_VALUE_TOKEN(COMMENT)
case UNKNOWN_CHAR:
if (ts[0] == '\0') {
return;
} else {
token_content = rb_utf8_str_new(ts, te - ts);
token_sym = ID2SYM(rb_intern("UNKNOWN_CHAR"));
break;
}
case QUOTED_STRING:
quotes_length = 1;
token_content = rb_utf8_str_new(ts + quotes_length, (te - ts - (2 * quotes_length)));
token_sym = ID2SYM(rb_intern("STRING"));
break;
case BLOCK_STRING:
token_sym = ID2SYM(rb_intern("STRING"));
quotes_length = 3;
token_content = rb_utf8_str_new(ts + quotes_length, (te - ts - (2 * quotes_length)));
line_incr = FIX2INT(rb_funcall(token_content, rb_intern("count"), 1, rb_utf8_str_new_cstr("\n")));
break;
case STRING:
// This is used only by the parser, this is never reached
break;
}
if (token_sym != Qnil) {
if (tt == BLOCK_STRING || tt == QUOTED_STRING) {
VALUE mGraphQL = rb_const_get_at(rb_cObject, rb_intern("GraphQL"));
VALUE mGraphQLLanguage = rb_const_get_at(mGraphQL, rb_intern("Language"));
VALUE mGraphQLLanguageLexer = rb_const_get_at(mGraphQLLanguage, rb_intern("Lexer"));
VALUE valid_string_pattern = rb_const_get_at(mGraphQLLanguageLexer, rb_intern("VALID_STRING"));
if (tt == BLOCK_STRING) {
VALUE mGraphQLLanguageBlockString = rb_const_get_at(mGraphQLLanguage, rb_intern("BlockString"));
token_content = rb_funcall(mGraphQLLanguageBlockString, rb_intern("trim_whitespace"), 1, token_content);
}
// The parser doesn't distinguish between these,
// Maybe updated below if it's invalid UTF-8
tt = STRING;
if (
RB_TEST(rb_funcall(token_content, rb_intern("valid_encoding?"), 0)) &&
RB_TEST(rb_funcall(token_content, rb_intern("match?"), 1, valid_string_pattern))
) {
rb_funcall(mGraphQLLanguageLexer, rb_intern("replace_escaped_characters_in_place"), 1, token_content);
if (!RB_TEST(rb_funcall(token_content, rb_intern("valid_encoding?"), 0))) {
token_sym = ID2SYM(rb_intern("BAD_UNICODE_ESCAPE"));
tt = BAD_UNICODE_ESCAPE;
}
} else {
token_sym = ID2SYM(rb_intern("BAD_UNICODE_ESCAPE"));
tt = BAD_UNICODE_ESCAPE;
}
}
VALUE token = rb_ary_new_from_args(6,
token_sym,
rb_int2inum(meta->line),
rb_int2inum(meta->col),
token_content,
meta->previous_token,
INT2FIX(200 + (int)tt)
);
// COMMENTs are retained as `previous_token` but aren't pushed to the normal token list
if (tt != COMMENT) {
rb_ary_push(meta->tokens, token);
}
meta->previous_token = token;
}
// Bump the column counter for the next token
meta->col += te - ts;
meta->line += line_incr;
}
VALUE tokenize(VALUE query_rbstr) {
int cs = 0;
int act = 0;
char *p = StringValueCStr(query_rbstr);
char *pe = p + strlen(p);
char *eof = pe;
char *ts = 0;
char *te = 0;
VALUE tokens = rb_ary_new();
struct Meta meta_s = {1, 1, p, pe, tokens, Qnil};
Meta *meta = &meta_s;
%% write init;
%% write exec;
return tokens;
}
#define SETUP_STATIC_TOKEN_VARIABLE(token_name, token_content) \
GraphQLTokenString##token_name = rb_utf8_str_new_cstr(token_content); \
rb_funcall(GraphQLTokenString##token_name, rb_intern("-@"), 0); \
rb_global_variable(&GraphQLTokenString##token_name); \
#define SETUP_STATIC_STRING(var_name, str_content) \
var_name = rb_utf8_str_new_cstr(str_content); \
rb_global_variable(&var_name); \
rb_str_freeze(var_name); \
void setup_static_token_variables() {
SETUP_STATIC_TOKEN_VARIABLE(ON, "on")
SETUP_STATIC_TOKEN_VARIABLE(FRAGMENT, "fragment")
SETUP_STATIC_TOKEN_VARIABLE(QUERY, "query")
SETUP_STATIC_TOKEN_VARIABLE(MUTATION, "mutation")
SETUP_STATIC_TOKEN_VARIABLE(SUBSCRIPTION, "subscription")
SETUP_STATIC_TOKEN_VARIABLE(REPEATABLE, "repeatable")
SETUP_STATIC_TOKEN_VARIABLE(RCURLY, "}")
SETUP_STATIC_TOKEN_VARIABLE(LCURLY, "{")
SETUP_STATIC_TOKEN_VARIABLE(RBRACKET, "]")
SETUP_STATIC_TOKEN_VARIABLE(LBRACKET, "[")
SETUP_STATIC_TOKEN_VARIABLE(RPAREN, ")")
SETUP_STATIC_TOKEN_VARIABLE(LPAREN, "(")
SETUP_STATIC_TOKEN_VARIABLE(COLON, ":")
SETUP_STATIC_TOKEN_VARIABLE(VAR_SIGN, "$")
SETUP_STATIC_TOKEN_VARIABLE(DIR_SIGN, "@")
SETUP_STATIC_TOKEN_VARIABLE(ELLIPSIS, "...")
SETUP_STATIC_TOKEN_VARIABLE(EQUALS, "=")
SETUP_STATIC_TOKEN_VARIABLE(BANG, "!")
SETUP_STATIC_TOKEN_VARIABLE(PIPE, "|")
SETUP_STATIC_TOKEN_VARIABLE(AMP, "&")
SETUP_STATIC_TOKEN_VARIABLE(SCHEMA, "schema")
SETUP_STATIC_TOKEN_VARIABLE(SCALAR, "scalar")
SETUP_STATIC_TOKEN_VARIABLE(EXTEND, "extend")
SETUP_STATIC_TOKEN_VARIABLE(IMPLEMENTS, "implements")
SETUP_STATIC_TOKEN_VARIABLE(INTERFACE, "interface")
SETUP_STATIC_TOKEN_VARIABLE(UNION, "union")
SETUP_STATIC_TOKEN_VARIABLE(ENUM, "enum")
SETUP_STATIC_TOKEN_VARIABLE(DIRECTIVE, "directive")
SETUP_STATIC_TOKEN_VARIABLE(INPUT, "input")
SETUP_STATIC_STRING(GraphQL_type_str, "type")
SETUP_STATIC_STRING(GraphQL_true_str, "true")
SETUP_STATIC_STRING(GraphQL_false_str, "false")
SETUP_STATIC_STRING(GraphQL_null_str, "null")
}
graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/parser.c 0000664 0000000 0000000 00000410564 14764346352 0026136 0 ustar 00root root 0000000 0000000 /* A Bison parser, made by GNU Bison 3.8.2. */
/* Bison implementation for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* C LALR(1) parser skeleton written by Richard Stallman, by
simplifying the original so-called "semantic" parser. */
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
especially those whose name start with YY_ or yy_. They are
private implementation details that can be changed or removed. */
/* All symbols defined below should begin with yy or YY, to avoid
infringing on user name space. This should be done even for local
variables, as they might otherwise be expanded by user macros.
There are some unavoidable exceptions within include files to
define necessary library symbols; they are noted "INFRINGES ON
USER NAME SPACE" below. */
/* Identify Bison output, and Bison version. */
#define YYBISON 30802
/* Bison version string. */
#define YYBISON_VERSION "3.8.2"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
/* Pure parsers. */
#define YYPURE 2
/* Push parsers. */
#define YYPUSH 0
/* Pull parsers. */
#define YYPULL 1
/* First part of user prologue. */
#line 5 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
// C Declarations
#include
#define YYSTYPE VALUE
int yylex(YYSTYPE *, VALUE, VALUE);
void yyerror(VALUE, VALUE, const char*);
static VALUE GraphQL_Language_Nodes_NONE;
static VALUE r_string_query;
#define MAKE_AST_NODE(node_class_name, nargs, ...) rb_funcall(GraphQL_Language_Nodes_##node_class_name, rb_intern("from_a"), nargs + 1, filename,__VA_ARGS__)
#define SETUP_NODE_CLASS_VARIABLE(node_class_name) static VALUE GraphQL_Language_Nodes_##node_class_name;
SETUP_NODE_CLASS_VARIABLE(Argument)
SETUP_NODE_CLASS_VARIABLE(Directive)
SETUP_NODE_CLASS_VARIABLE(Document)
SETUP_NODE_CLASS_VARIABLE(Enum)
SETUP_NODE_CLASS_VARIABLE(Field)
SETUP_NODE_CLASS_VARIABLE(FragmentDefinition)
SETUP_NODE_CLASS_VARIABLE(FragmentSpread)
SETUP_NODE_CLASS_VARIABLE(InlineFragment)
SETUP_NODE_CLASS_VARIABLE(InputObject)
SETUP_NODE_CLASS_VARIABLE(ListType)
SETUP_NODE_CLASS_VARIABLE(NonNullType)
SETUP_NODE_CLASS_VARIABLE(NullValue)
SETUP_NODE_CLASS_VARIABLE(OperationDefinition)
SETUP_NODE_CLASS_VARIABLE(TypeName)
SETUP_NODE_CLASS_VARIABLE(VariableDefinition)
SETUP_NODE_CLASS_VARIABLE(VariableIdentifier)
SETUP_NODE_CLASS_VARIABLE(ScalarTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(ObjectTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(InterfaceTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(UnionTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(EnumTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(InputObjectTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(EnumValueDefinition)
SETUP_NODE_CLASS_VARIABLE(DirectiveDefinition)
SETUP_NODE_CLASS_VARIABLE(DirectiveLocation)
SETUP_NODE_CLASS_VARIABLE(FieldDefinition)
SETUP_NODE_CLASS_VARIABLE(InputValueDefinition)
SETUP_NODE_CLASS_VARIABLE(SchemaDefinition)
SETUP_NODE_CLASS_VARIABLE(ScalarTypeExtension)
SETUP_NODE_CLASS_VARIABLE(ObjectTypeExtension)
SETUP_NODE_CLASS_VARIABLE(InterfaceTypeExtension)
SETUP_NODE_CLASS_VARIABLE(UnionTypeExtension)
SETUP_NODE_CLASS_VARIABLE(EnumTypeExtension)
SETUP_NODE_CLASS_VARIABLE(InputObjectTypeExtension)
SETUP_NODE_CLASS_VARIABLE(SchemaExtension)
#line 124 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
# ifndef YY_CAST
# ifdef __cplusplus
# define YY_CAST(Type, Val) static_cast (Val)
# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val)
# else
# define YY_CAST(Type, Val) ((Type) (Val))
# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
# endif
# endif
# ifndef YY_NULLPTR
# if defined __cplusplus
# if 201103L <= __cplusplus
# define YY_NULLPTR nullptr
# else
# define YY_NULLPTR 0
# endif
# else
# define YY_NULLPTR ((void*)0)
# endif
# endif
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int yydebug;
#endif
/* Token kinds. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
enum yytokentype
{
YYEMPTY = -2,
YYEOF = 0, /* "end of file" */
YYerror = 256, /* error */
YYUNDEF = 257, /* "invalid token" */
AMP = 200, /* AMP */
BANG = 201, /* BANG */
COLON = 202, /* COLON */
DIRECTIVE = 203, /* DIRECTIVE */
DIR_SIGN = 204, /* DIR_SIGN */
ENUM = 205, /* ENUM */
ELLIPSIS = 206, /* ELLIPSIS */
EQUALS = 207, /* EQUALS */
EXTEND = 208, /* EXTEND */
FALSE_LITERAL = 209, /* FALSE_LITERAL */
FLOAT = 210, /* FLOAT */
FRAGMENT = 211, /* FRAGMENT */
IDENTIFIER = 212, /* IDENTIFIER */
INPUT = 213, /* INPUT */
IMPLEMENTS = 214, /* IMPLEMENTS */
INT = 215, /* INT */
INTERFACE = 216, /* INTERFACE */
LBRACKET = 217, /* LBRACKET */
LCURLY = 218, /* LCURLY */
LPAREN = 219, /* LPAREN */
MUTATION = 220, /* MUTATION */
NULL_LITERAL = 221, /* NULL_LITERAL */
ON = 222, /* ON */
PIPE = 223, /* PIPE */
QUERY = 224, /* QUERY */
RBRACKET = 225, /* RBRACKET */
RCURLY = 226, /* RCURLY */
REPEATABLE = 227, /* REPEATABLE */
RPAREN = 228, /* RPAREN */
SCALAR = 229, /* SCALAR */
SCHEMA = 230, /* SCHEMA */
STRING = 231, /* STRING */
SUBSCRIPTION = 232, /* SUBSCRIPTION */
TRUE_LITERAL = 233, /* TRUE_LITERAL */
TYPE_LITERAL = 234, /* TYPE_LITERAL */
UNION = 235, /* UNION */
VAR_SIGN = 236 /* VAR_SIGN */
};
typedef enum yytokentype yytoken_kind_t;
#endif
/* Token kinds. */
#define YYEMPTY -2
#define YYEOF 0
#define YYerror 256
#define YYUNDEF 257
#define AMP 200
#define BANG 201
#define COLON 202
#define DIRECTIVE 203
#define DIR_SIGN 204
#define ENUM 205
#define ELLIPSIS 206
#define EQUALS 207
#define EXTEND 208
#define FALSE_LITERAL 209
#define FLOAT 210
#define FRAGMENT 211
#define IDENTIFIER 212
#define INPUT 213
#define IMPLEMENTS 214
#define INT 215
#define INTERFACE 216
#define LBRACKET 217
#define LCURLY 218
#define LPAREN 219
#define MUTATION 220
#define NULL_LITERAL 221
#define ON 222
#define PIPE 223
#define QUERY 224
#define RBRACKET 225
#define RCURLY 226
#define REPEATABLE 227
#define RPAREN 228
#define SCALAR 229
#define SCHEMA 230
#define STRING 231
#define SUBSCRIPTION 232
#define TRUE_LITERAL 233
#define TYPE_LITERAL 234
#define UNION 235
#define VAR_SIGN 236
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
int yyparse (VALUE parser, VALUE filename);
/* Symbol kind. */
enum yysymbol_kind_t
{
YYSYMBOL_YYEMPTY = -2,
YYSYMBOL_YYEOF = 0, /* "end of file" */
YYSYMBOL_YYerror = 1, /* error */
YYSYMBOL_YYUNDEF = 2, /* "invalid token" */
YYSYMBOL_AMP = 3, /* AMP */
YYSYMBOL_BANG = 4, /* BANG */
YYSYMBOL_COLON = 5, /* COLON */
YYSYMBOL_DIRECTIVE = 6, /* DIRECTIVE */
YYSYMBOL_DIR_SIGN = 7, /* DIR_SIGN */
YYSYMBOL_ENUM = 8, /* ENUM */
YYSYMBOL_ELLIPSIS = 9, /* ELLIPSIS */
YYSYMBOL_EQUALS = 10, /* EQUALS */
YYSYMBOL_EXTEND = 11, /* EXTEND */
YYSYMBOL_FALSE_LITERAL = 12, /* FALSE_LITERAL */
YYSYMBOL_FLOAT = 13, /* FLOAT */
YYSYMBOL_FRAGMENT = 14, /* FRAGMENT */
YYSYMBOL_IDENTIFIER = 15, /* IDENTIFIER */
YYSYMBOL_INPUT = 16, /* INPUT */
YYSYMBOL_IMPLEMENTS = 17, /* IMPLEMENTS */
YYSYMBOL_INT = 18, /* INT */
YYSYMBOL_INTERFACE = 19, /* INTERFACE */
YYSYMBOL_LBRACKET = 20, /* LBRACKET */
YYSYMBOL_LCURLY = 21, /* LCURLY */
YYSYMBOL_LPAREN = 22, /* LPAREN */
YYSYMBOL_MUTATION = 23, /* MUTATION */
YYSYMBOL_NULL_LITERAL = 24, /* NULL_LITERAL */
YYSYMBOL_ON = 25, /* ON */
YYSYMBOL_PIPE = 26, /* PIPE */
YYSYMBOL_QUERY = 27, /* QUERY */
YYSYMBOL_RBRACKET = 28, /* RBRACKET */
YYSYMBOL_RCURLY = 29, /* RCURLY */
YYSYMBOL_REPEATABLE = 30, /* REPEATABLE */
YYSYMBOL_RPAREN = 31, /* RPAREN */
YYSYMBOL_SCALAR = 32, /* SCALAR */
YYSYMBOL_SCHEMA = 33, /* SCHEMA */
YYSYMBOL_STRING = 34, /* STRING */
YYSYMBOL_SUBSCRIPTION = 35, /* SUBSCRIPTION */
YYSYMBOL_TRUE_LITERAL = 36, /* TRUE_LITERAL */
YYSYMBOL_TYPE_LITERAL = 37, /* TYPE_LITERAL */
YYSYMBOL_UNION = 38, /* UNION */
YYSYMBOL_VAR_SIGN = 39, /* VAR_SIGN */
YYSYMBOL_YYACCEPT = 40, /* $accept */
YYSYMBOL_start = 41, /* start */
YYSYMBOL_document = 42, /* document */
YYSYMBOL_definitions_list = 43, /* definitions_list */
YYSYMBOL_definition = 44, /* definition */
YYSYMBOL_executable_definition = 45, /* executable_definition */
YYSYMBOL_operation_definition = 46, /* operation_definition */
YYSYMBOL_operation_type = 47, /* operation_type */
YYSYMBOL_operation_name_opt = 48, /* operation_name_opt */
YYSYMBOL_variable_definitions_opt = 49, /* variable_definitions_opt */
YYSYMBOL_variable_definitions_list = 50, /* variable_definitions_list */
YYSYMBOL_variable_definition = 51, /* variable_definition */
YYSYMBOL_default_value_opt = 52, /* default_value_opt */
YYSYMBOL_selection_list = 53, /* selection_list */
YYSYMBOL_selection = 54, /* selection */
YYSYMBOL_selection_set = 55, /* selection_set */
YYSYMBOL_selection_set_opt = 56, /* selection_set_opt */
YYSYMBOL_field = 57, /* field */
YYSYMBOL_arguments_opt = 58, /* arguments_opt */
YYSYMBOL_arguments_list = 59, /* arguments_list */
YYSYMBOL_argument = 60, /* argument */
YYSYMBOL_literal_value = 61, /* literal_value */
YYSYMBOL_input_value = 62, /* input_value */
YYSYMBOL_null_value = 63, /* null_value */
YYSYMBOL_variable = 64, /* variable */
YYSYMBOL_list_value = 65, /* list_value */
YYSYMBOL_list_value_list = 66, /* list_value_list */
YYSYMBOL_enum_name = 67, /* enum_name */
YYSYMBOL_enum_value = 68, /* enum_value */
YYSYMBOL_object_value = 69, /* object_value */
YYSYMBOL_object_value_list_opt = 70, /* object_value_list_opt */
YYSYMBOL_object_value_list = 71, /* object_value_list */
YYSYMBOL_object_value_field = 72, /* object_value_field */
YYSYMBOL_object_literal_value = 73, /* object_literal_value */
YYSYMBOL_object_literal_value_list_opt = 74, /* object_literal_value_list_opt */
YYSYMBOL_object_literal_value_list = 75, /* object_literal_value_list */
YYSYMBOL_object_literal_value_field = 76, /* object_literal_value_field */
YYSYMBOL_directives_list_opt = 77, /* directives_list_opt */
YYSYMBOL_directives_list = 78, /* directives_list */
YYSYMBOL_directive = 79, /* directive */
YYSYMBOL_name = 80, /* name */
YYSYMBOL_schema_keyword = 81, /* schema_keyword */
YYSYMBOL_name_without_on = 82, /* name_without_on */
YYSYMBOL_fragment_spread = 83, /* fragment_spread */
YYSYMBOL_inline_fragment = 84, /* inline_fragment */
YYSYMBOL_fragment_definition = 85, /* fragment_definition */
YYSYMBOL_fragment_name_opt = 86, /* fragment_name_opt */
YYSYMBOL_type = 87, /* type */
YYSYMBOL_nullable_type = 88, /* nullable_type */
YYSYMBOL_type_system_definition = 89, /* type_system_definition */
YYSYMBOL_schema_definition = 90, /* schema_definition */
YYSYMBOL_operation_type_definition_list_opt = 91, /* operation_type_definition_list_opt */
YYSYMBOL_operation_type_definition_list = 92, /* operation_type_definition_list */
YYSYMBOL_operation_type_definition = 93, /* operation_type_definition */
YYSYMBOL_type_definition = 94, /* type_definition */
YYSYMBOL_description = 95, /* description */
YYSYMBOL_description_opt = 96, /* description_opt */
YYSYMBOL_scalar_type_definition = 97, /* scalar_type_definition */
YYSYMBOL_object_type_definition = 98, /* object_type_definition */
YYSYMBOL_implements_opt = 99, /* implements_opt */
YYSYMBOL_interfaces_list = 100, /* interfaces_list */
YYSYMBOL_legacy_interfaces_list = 101, /* legacy_interfaces_list */
YYSYMBOL_input_value_definition = 102, /* input_value_definition */
YYSYMBOL_input_value_definition_list = 103, /* input_value_definition_list */
YYSYMBOL_arguments_definitions_opt = 104, /* arguments_definitions_opt */
YYSYMBOL_field_definition = 105, /* field_definition */
YYSYMBOL_field_definition_list_opt = 106, /* field_definition_list_opt */
YYSYMBOL_field_definition_list = 107, /* field_definition_list */
YYSYMBOL_interface_type_definition = 108, /* interface_type_definition */
YYSYMBOL_union_members = 109, /* union_members */
YYSYMBOL_union_type_definition = 110, /* union_type_definition */
YYSYMBOL_enum_type_definition = 111, /* enum_type_definition */
YYSYMBOL_enum_value_definition = 112, /* enum_value_definition */
YYSYMBOL_enum_value_definitions = 113, /* enum_value_definitions */
YYSYMBOL_input_object_type_definition = 114, /* input_object_type_definition */
YYSYMBOL_directive_definition = 115, /* directive_definition */
YYSYMBOL_directive_repeatable_opt = 116, /* directive_repeatable_opt */
YYSYMBOL_directive_locations = 117, /* directive_locations */
YYSYMBOL_type_system_extension = 118, /* type_system_extension */
YYSYMBOL_schema_extension = 119, /* schema_extension */
YYSYMBOL_type_extension = 120, /* type_extension */
YYSYMBOL_scalar_type_extension = 121, /* scalar_type_extension */
YYSYMBOL_object_type_extension = 122, /* object_type_extension */
YYSYMBOL_interface_type_extension = 123, /* interface_type_extension */
YYSYMBOL_union_type_extension = 124, /* union_type_extension */
YYSYMBOL_enum_type_extension = 125, /* enum_type_extension */
YYSYMBOL_input_object_type_extension = 126 /* input_object_type_extension */
};
typedef enum yysymbol_kind_t yysymbol_kind_t;
#ifdef short
# undef short
#endif
/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
and (if available) are included
so that the code can choose integer types of a good width. */
#ifndef __PTRDIFF_MAX__
# include /* INFRINGES ON USER NAME SPACE */
# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
# include /* INFRINGES ON USER NAME SPACE */
# define YY_STDINT_H
# endif
#endif
/* Narrow types that promote to a signed type and that can represent a
signed or unsigned integer of at least N bits. In tables they can
save space and decrease cache pressure. Promoting to a signed type
helps avoid bugs in integer arithmetic. */
#ifdef __INT_LEAST8_MAX__
typedef __INT_LEAST8_TYPE__ yytype_int8;
#elif defined YY_STDINT_H
typedef int_least8_t yytype_int8;
#else
typedef signed char yytype_int8;
#endif
#ifdef __INT_LEAST16_MAX__
typedef __INT_LEAST16_TYPE__ yytype_int16;
#elif defined YY_STDINT_H
typedef int_least16_t yytype_int16;
#else
typedef short yytype_int16;
#endif
/* Work around bug in HP-UX 11.23, which defines these macros
incorrectly for preprocessor constants. This workaround can likely
be removed in 2023, as HPE has promised support for HP-UX 11.23
(aka HP-UX 11i v2) only through the end of 2022; see Table 2 of
. */
#ifdef __hpux
# undef UINT_LEAST8_MAX
# undef UINT_LEAST16_MAX
# define UINT_LEAST8_MAX 255
# define UINT_LEAST16_MAX 65535
#endif
#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
typedef __UINT_LEAST8_TYPE__ yytype_uint8;
#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
&& UINT_LEAST8_MAX <= INT_MAX)
typedef uint_least8_t yytype_uint8;
#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
typedef unsigned char yytype_uint8;
#else
typedef short yytype_uint8;
#endif
#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
typedef __UINT_LEAST16_TYPE__ yytype_uint16;
#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
&& UINT_LEAST16_MAX <= INT_MAX)
typedef uint_least16_t yytype_uint16;
#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
typedef unsigned short yytype_uint16;
#else
typedef int yytype_uint16;
#endif
#ifndef YYPTRDIFF_T
# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
# define YYPTRDIFF_T __PTRDIFF_TYPE__
# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
# elif defined PTRDIFF_MAX
# ifndef ptrdiff_t
# include /* INFRINGES ON USER NAME SPACE */
# endif
# define YYPTRDIFF_T ptrdiff_t
# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
# else
# define YYPTRDIFF_T long
# define YYPTRDIFF_MAXIMUM LONG_MAX
# endif
#endif
#ifndef YYSIZE_T
# ifdef __SIZE_TYPE__
# define YYSIZE_T __SIZE_TYPE__
# elif defined size_t
# define YYSIZE_T size_t
# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
# include /* INFRINGES ON USER NAME SPACE */
# define YYSIZE_T size_t
# else
# define YYSIZE_T unsigned
# endif
#endif
#define YYSIZE_MAXIMUM \
YY_CAST (YYPTRDIFF_T, \
(YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \
? YYPTRDIFF_MAXIMUM \
: YY_CAST (YYSIZE_T, -1)))
#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
/* Stored state numbers (used for stacks). */
typedef yytype_int16 yy_state_t;
/* State numbers in computations. */
typedef int yy_state_fast_t;
#ifndef YY_
# if defined YYENABLE_NLS && YYENABLE_NLS
# if ENABLE_NLS
# include /* INFRINGES ON USER NAME SPACE */
# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
# endif
# endif
# ifndef YY_
# define YY_(Msgid) Msgid
# endif
#endif
#ifndef YY_ATTRIBUTE_PURE
# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
# else
# define YY_ATTRIBUTE_PURE
# endif
#endif
#ifndef YY_ATTRIBUTE_UNUSED
# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
# else
# define YY_ATTRIBUTE_UNUSED
# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
# define YY_USE(E) ((void) (E))
#else
# define YY_USE(E) /* empty */
#endif
/* Suppress an incorrect diagnostic about yylval being uninitialized. */
#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
_Pragma ("GCC diagnostic push") \
_Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
# else
# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
_Pragma ("GCC diagnostic push") \
_Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
_Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
# endif
# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
_Pragma ("GCC diagnostic pop")
#else
# define YY_INITIAL_VALUE(Value) Value
#endif
#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
# define YY_IGNORE_MAYBE_UNINITIALIZED_END
#endif
#ifndef YY_INITIAL_VALUE
# define YY_INITIAL_VALUE(Value) /* Nothing. */
#endif
#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
# define YY_IGNORE_USELESS_CAST_BEGIN \
_Pragma ("GCC diagnostic push") \
_Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
# define YY_IGNORE_USELESS_CAST_END \
_Pragma ("GCC diagnostic pop")
#endif
#ifndef YY_IGNORE_USELESS_CAST_BEGIN
# define YY_IGNORE_USELESS_CAST_BEGIN
# define YY_IGNORE_USELESS_CAST_END
#endif
#define YY_ASSERT(E) ((void) (0 && (E)))
#if 1
/* The parser invokes alloca or malloc; define the necessary symbols. */
# ifdef YYSTACK_USE_ALLOCA
# if YYSTACK_USE_ALLOCA
# ifdef __GNUC__
# define YYSTACK_ALLOC __builtin_alloca
# elif defined __BUILTIN_VA_ARG_INCR
# include /* INFRINGES ON USER NAME SPACE */
# elif defined _AIX
# define YYSTACK_ALLOC __alloca
# elif defined _MSC_VER
# include /* INFRINGES ON USER NAME SPACE */
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
# include /* INFRINGES ON USER NAME SPACE */
/* Use EXIT_SUCCESS as a witness for stdlib.h. */
# ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
# endif
# endif
# endif
# endif
# endif
# ifdef YYSTACK_ALLOC
/* Pacify GCC's 'empty if-body' warning. */
# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
# ifndef YYSTACK_ALLOC_MAXIMUM
/* The OS might guarantee only one guard page at the bottom of the stack,
and a page size can be as small as 4096 bytes. So we cannot safely
invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
to allow for a few compiler-allocated temporary stack slots. */
# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
# endif
# else
# define YYSTACK_ALLOC YYMALLOC
# define YYSTACK_FREE YYFREE
# ifndef YYSTACK_ALLOC_MAXIMUM
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
# endif
# if (defined __cplusplus && ! defined EXIT_SUCCESS \
&& ! ((defined YYMALLOC || defined malloc) \
&& (defined YYFREE || defined free)))
# include /* INFRINGES ON USER NAME SPACE */
# ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
# endif
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
# if ! defined malloc && ! defined EXIT_SUCCESS
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
# if ! defined free && ! defined EXIT_SUCCESS
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# endif
#endif /* 1 */
#if (! defined yyoverflow \
&& (! defined __cplusplus \
|| (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
/* A type that is properly aligned for any stack member. */
union yyalloc
{
yy_state_t yyss_alloc;
YYSTYPE yyvs_alloc;
};
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
/* The size of an array large to enough to hold all stacks, each with
N elements. */
# define YYSTACK_BYTES(N) \
((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
# define YYCOPY_NEEDED 1
/* Relocate STACK from its old location to the new one. The
local variables YYSIZE and YYSTACKSIZE give the old and new number of
elements in the stack, and YYPTR gives the new location of the
stack. Advance YYPTR to a properly aligned location for the next
stack. */
# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
do \
{ \
YYPTRDIFF_T yynewbytes; \
YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
Stack = &yyptr->Stack_alloc; \
yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
yyptr += yynewbytes / YYSIZEOF (*yyptr); \
} \
while (0)
#endif
#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
/* Copy COUNT objects from SRC to DST. The source and destination do
not overlap. */
# ifndef YYCOPY
# if defined __GNUC__ && 1 < __GNUC__
# define YYCOPY(Dst, Src, Count) \
__builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
# else
# define YYCOPY(Dst, Src, Count) \
do \
{ \
YYPTRDIFF_T yyi; \
for (yyi = 0; yyi < (Count); yyi++) \
(Dst)[yyi] = (Src)[yyi]; \
} \
while (0)
# endif
# endif
#endif /* !YYCOPY_NEEDED */
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 79
/* YYLAST -- Last index in YYTABLE. */
#define YYLAST 808
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 40
/* YYNNTS -- Number of nonterminals. */
#define YYNNTS 87
/* YYNRULES -- Number of rules. */
#define YYNRULES 182
/* YYNSTATES -- Number of states. */
#define YYNSTATES 311
/* YYMAXUTOK -- Last valid token kind. */
#define YYMAXUTOK 257
/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
as returned by yylex, with out-of-bounds checking. */
#define YYTRANSLATE(YYX) \
(0 <= (YYX) && (YYX) <= YYMAXUTOK \
? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \
: YYSYMBOL_YYUNDEF)
/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
as returned by yylex. */
static const yytype_int8 yytranslate[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 1, 2
};
#if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_int16 yyrline[] =
{
0, 103, 103, 105, 119, 120, 123, 124, 125, 128,
129, 132, 143, 154, 167, 168, 169, 172, 173, 176,
177, 180, 181, 184, 196, 197, 200, 201, 204, 205,
206, 209, 212, 213, 216, 227, 240, 241, 244, 245,
248, 258, 259, 260, 261, 262, 263, 264, 265, 266,
269, 270, 271, 273, 281, 290, 291, 294, 295, 298,
299, 300, 301, 303, 312, 321, 322, 325, 326, 329,
340, 349, 350, 353, 354, 357, 368, 369, 372, 373,
375, 385, 386, 389, 390, 391, 392, 393, 394, 395,
396, 397, 398, 399, 400, 403, 404, 405, 406, 407,
408, 412, 422, 431, 442, 454, 455, 458, 459, 462,
469, 478, 479, 480, 483, 496, 497, 500, 504, 509,
514, 515, 516, 517, 518, 519, 521, 524, 525, 528,
540, 554, 555, 556, 557, 560, 568, 574, 582, 587,
601, 602, 605, 606, 609, 623, 624, 627, 628, 629,
632, 646, 654, 659, 672, 685, 697, 698, 701, 714,
728, 729, 732, 733, 737, 738, 741, 752, 764, 765,
766, 767, 768, 769, 771, 781, 793, 805, 814, 825,
834, 845, 854
};
#endif
/** Accessing symbol of state STATE. */
#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
#if 1
/* The user-facing name of the symbol whose (internal) number is
YYSYMBOL. No bounds checking. */
static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
static const char *
yysymbol_name (yysymbol_kind_t yysymbol)
{
static const char *const yy_sname[] =
{
"end of file", "error", "invalid token", "AMP", "BANG", "COLON",
"DIRECTIVE", "DIR_SIGN", "ENUM", "ELLIPSIS", "EQUALS", "EXTEND",
"FALSE_LITERAL", "FLOAT", "FRAGMENT", "IDENTIFIER", "INPUT",
"IMPLEMENTS", "INT", "INTERFACE", "LBRACKET", "LCURLY", "LPAREN",
"MUTATION", "NULL_LITERAL", "ON", "PIPE", "QUERY", "RBRACKET", "RCURLY",
"REPEATABLE", "RPAREN", "SCALAR", "SCHEMA", "STRING", "SUBSCRIPTION",
"TRUE_LITERAL", "TYPE_LITERAL", "UNION", "VAR_SIGN", "$accept", "start",
"document", "definitions_list", "definition", "executable_definition",
"operation_definition", "operation_type", "operation_name_opt",
"variable_definitions_opt", "variable_definitions_list",
"variable_definition", "default_value_opt", "selection_list",
"selection", "selection_set", "selection_set_opt", "field",
"arguments_opt", "arguments_list", "argument", "literal_value",
"input_value", "null_value", "variable", "list_value", "list_value_list",
"enum_name", "enum_value", "object_value", "object_value_list_opt",
"object_value_list", "object_value_field", "object_literal_value",
"object_literal_value_list_opt", "object_literal_value_list",
"object_literal_value_field", "directives_list_opt", "directives_list",
"directive", "name", "schema_keyword", "name_without_on",
"fragment_spread", "inline_fragment", "fragment_definition",
"fragment_name_opt", "type", "nullable_type", "type_system_definition",
"schema_definition", "operation_type_definition_list_opt",
"operation_type_definition_list", "operation_type_definition",
"type_definition", "description", "description_opt",
"scalar_type_definition", "object_type_definition", "implements_opt",
"interfaces_list", "legacy_interfaces_list", "input_value_definition",
"input_value_definition_list", "arguments_definitions_opt",
"field_definition", "field_definition_list_opt", "field_definition_list",
"interface_type_definition", "union_members", "union_type_definition",
"enum_type_definition", "enum_value_definition",
"enum_value_definitions", "input_object_type_definition",
"directive_definition", "directive_repeatable_opt",
"directive_locations", "type_system_extension", "schema_extension",
"type_extension", "scalar_type_extension", "object_type_extension",
"interface_type_extension", "union_type_extension",
"enum_type_extension", "input_object_type_extension", YY_NULLPTR
};
return yy_sname[yysymbol];
}
#endif
#define YYPACT_NINF (-259)
#define yypact_value_is_default(Yyn) \
((Yyn) == YYPACT_NINF)
#define YYTABLE_NINF (-148)
#define yytable_value_is_error(Yyn) \
0
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
static const yytype_int16 yypact[] =
{
232, 14, 737, 473, -259, -259, 7, -259, -259, 23,
-259, 202, -259, -259, -259, 704, -259, -259, -259, -259,
-259, 144, -259, -259, -259, -259, -259, -259, -259, -259,
-259, -259, -259, -259, -259, -259, -259, -259, 704, 704,
704, 704, 7, 704, 704, -259, -259, -259, -259, -259,
-259, -259, -259, -259, -259, -259, -259, -259, -259, -259,
-259, -259, -259, -259, 19, 572, -259, -259, 506, -259,
-259, 12, -259, -259, -259, 704, 41, 7, -259, -259,
-259, 38, -259, 59, 704, 704, 704, 704, 704, 704,
7, 7, 62, 7, 73, 6, 62, 7, 605, 605,
75, 7, -259, -259, 704, 704, 7, 58, 70, -259,
-259, 65, 7, 704, 7, 7, 62, 7, 62, 7,
77, 6, 91, 6, 304, 7, 7, 70, 7, 104,
122, 605, -259, 7, 114, 7, 638, -259, -259, 58,
671, -259, 117, 75, -259, 118, 80, -259, 704, -10,
-259, 75, 106, 109, 113, 7, -259, 7, 133, 110,
110, 704, 260, 151, 704, 126, 183, 126, 704, 128,
75, -259, 75, 539, 7, -259, -259, 406, -259, -259,
704, -259, -259, 159, -259, -259, -259, 110, 136, 110,
110, 126, 126, 704, 770, -259, -18, 704, -259, 24,
-259, 151, 704, -259, 39, -259, -259, -259, -259, 142,
-259, -259, -259, -259, 75, -259, -259, -259, -259, 338,
704, -259, -259, -259, -259, 704, -259, -259, -259, -259,
-259, -259, -259, -259, -259, -259, -259, -259, 605, 107,
-259, 146, 66, 79, -259, -259, 142, 7, -259, -259,
167, -259, -259, -259, 704, -259, 82, 704, -259, -259,
-259, 372, 149, 704, -259, 150, 704, -259, 168, -259,
170, -259, 704, -259, -259, -259, 605, 106, -259, -259,
-259, -259, -259, -259, -259, 178, -259, -259, 179, 406,
440, 7, -259, 161, 170, 180, 406, 440, -259, -259,
704, -259, -259, 704, 7, 605, -259, -259, -259, 7,
-259
};
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
Performed when YYTABLE does not specify something else to do. Zero
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
127, 0, 105, 0, 15, 14, 76, 126, 16, 0,
2, 127, 4, 6, 9, 17, 10, 7, 111, 112,
128, 0, 120, 121, 122, 123, 124, 125, 113, 8,
164, 165, 168, 169, 170, 171, 172, 173, 0, 0,
0, 0, 76, 0, 0, 91, 89, 92, 97, 93,
95, 90, 86, 87, 98, 94, 84, 83, 96, 85,
88, 99, 100, 106, 0, 76, 82, 13, 0, 26,
28, 36, 81, 29, 30, 0, 115, 77, 78, 1,
5, 19, 18, 0, 0, 0, 0, 0, 0, 0,
76, 76, 131, 0, 0, 167, 131, 76, 0, 0,
0, 76, 12, 27, 0, 0, 76, 36, 0, 114,
79, 0, 76, 0, 76, 76, 131, 76, 131, 76,
0, 180, 0, 182, 0, 76, 174, 0, 76, 0,
178, 0, 109, 76, 107, 76, 0, 103, 101, 36,
0, 38, 0, 32, 80, 0, 0, 117, 0, 0,
21, 0, 142, 0, 0, 76, 129, 76, 0, 127,
127, 0, 135, 133, 134, 145, 0, 145, 0, 0,
0, 108, 0, 0, 76, 37, 39, 0, 33, 35,
0, 116, 118, 0, 20, 22, 11, 127, 160, 127,
127, 145, 145, 0, 0, 156, 127, 0, 140, 127,
135, 132, 0, 138, 127, 176, 166, 175, 151, 177,
110, 104, 102, 31, 32, 45, 41, 59, 42, 0,
65, 53, 60, 43, 44, 0, 61, 50, 40, 46,
51, 48, 63, 47, 52, 49, 62, 119, 0, 127,
161, 0, 127, 127, 150, 130, 153, 76, 179, 157,
0, 181, 141, 136, 0, 148, 127, 0, 34, 55,
57, 0, 0, 66, 67, 0, 72, 73, 0, 54,
24, 143, 0, 154, 158, 155, 0, 142, 146, 149,
152, 56, 58, 64, 68, 0, 70, 74, 0, 0,
0, 76, 162, 159, 24, 0, 0, 0, 50, 69,
71, 25, 23, 0, 76, 0, 75, 163, 139, 76,
144
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
-259, -259, -259, -259, 177, -259, -259, 9, -259, -259,
-259, 43, -101, 60, -67, -95, -17, -259, -97, -259,
61, -258, -174, -259, -259, -259, -259, 4, -259, -259,
-259, -259, -63, -259, -259, -259, -61, 34, -36, -52,
-3, -170, 2, -259, -259, -259, -259, -81, -259, -259,
-259, -259, 87, -138, -259, -259, 15, -259, -259, -26,
46, -259, -180, -48, -68, -41, -103, -259, -259, 27,
-259, -259, -194, 32, -259, -259, -259, -259, -259, -259,
-259, -259, -259, -259, -259, -259, -259
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
0, 9, 10, 11, 12, 13, 14, 61, 81, 112,
149, 150, 291, 68, 69, 178, 179, 70, 106, 140,
141, 227, 299, 229, 230, 231, 261, 232, 233, 234,
262, 263, 264, 235, 265, 266, 267, 76, 77, 78,
132, 62, 72, 73, 74, 16, 64, 133, 134, 17,
18, 109, 146, 147, 19, 20, 197, 22, 23, 125,
163, 164, 198, 199, 188, 255, 205, 256, 24, 209,
25, 26, 195, 196, 27, 28, 241, 293, 29, 30,
31, 32, 33, 34, 35, 36, 37
};
/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule whose
number is the opposite. If YYTABLE_NINF, syntax error. */
static const yytype_int16 yytable[] =
{
71, 103, 249, 228, 63, 137, 95, 236, 182, 15,
144, 248, 82, 75, 75, 21, 7, 104, 135, 252,
15, 184, 38, 79, 236, 110, 21, -77, 182, 148,
39, 298, 301, 40, 105, 90, 91, 92, 93, 306,
96, 97, 174, 110, 98, 260, 41, 42, 249, 236,
169, 43, 44, 251, 121, 123, 186, 126, 7, 252,
111, 130, 108, 252, 207, 71, 113, 101, -147, 110,
128, 110, 107, 7, 110, 211, 94, 212, 110, 124,
105, 114, 115, 116, 117, 118, 119, 282, 244, 245,
155, 236, 157, 4, 127, 273, 136, 5, 159, 100,
7, 139, 142, 4, 148, 8, 103, 5, 274, 181,
152, 278, 160, 7, 168, 8, 7, 145, 171, 236,
236, 162, 177, 180, 120, 122, 236, 236, 187, 75,
189, 129, -77, 71, 190, 138, 145, 142, 271, 239,
143, 7, 243, 193, 7, 183, 151, 204, 153, 154,
83, 156, 84, 158, 202, 145, 210, 270, 200, 165,
85, 203, 167, 86, 238, 208, 240, 170, 257, 172,
71, 272, 276, 289, 194, 145, 87, 237, 283, 286,
290, 88, 89, 296, 297, 305, 226, 303, 80, 191,
208, 192, 185, 304, 250, 294, 173, 258, 247, 253,
284, 176, -3, 226, 194, 287, 4, 201, 214, 295,
5, 194, 206, 1, 166, 279, 2, 268, 8, 254,
246, 242, 269, 3, 309, 4, 0, 0, 226, 5,
0, 0, 0, 0, 0, 6, 7, 8, 0, 0,
0, 0, 0, 1, 0, 0, 2, 0, 0, 0,
0, 277, 0, 3, 280, 4, 0, 194, 0, 5,
285, 0, 0, 288, 0, 6, 7, 8, 0, 292,
226, 254, -137, 0, 0, -137, 0, -137, 0, 0,
0, 275, 0, 0, -137, -137, 0, 0, 0, 0,
-137, 0, 0, 0, 0, 0, -137, 288, 226, 226,
307, 0, 0, 0, 0, 226, 226, 161, 0, 0,
45, 0, 46, 0, 0, 47, 48, 0, 49, 50,
51, 52, 0, 53, 0, 302, 0, 4, 54, 66,
0, 5, 0, 0, 55, 0, 56, 57, 308, 8,
58, 59, 60, 310, 45, 0, 46, 0, 0, 47,
215, 216, 49, 217, 51, 52, 218, 53, 219, 220,
0, 4, 221, 222, 0, 5, 259, 0, 55, 0,
56, 57, 223, 8, 224, 59, 60, 225, 45, 0,
46, 0, 0, 47, 215, 216, 49, 217, 51, 52,
218, 53, 219, 220, 0, 4, 221, 222, 0, 5,
281, 0, 55, 0, 56, 57, 223, 8, 224, 59,
60, 225, 45, 0, 46, 0, 0, 47, 215, 216,
49, 217, 51, 52, 218, 53, 219, 220, 0, 4,
221, 222, 0, 5, 0, 0, 55, 0, 56, 57,
223, 8, 224, 59, 60, 225, 45, 0, 46, 0,
0, 47, 215, 216, 49, 217, 51, 52, 218, 53,
219, 300, 0, 4, 221, 222, 0, 5, 0, 0,
55, 0, 56, 57, 223, 8, 224, 59, 60, 45,
0, 46, 65, 0, 47, 48, 0, 49, 50, 51,
52, 0, 53, 0, 0, 0, 4, 54, 66, 0,
5, 0, 67, 55, 0, 56, 57, 0, 8, 58,
59, 60, 45, 0, 46, 65, 0, 47, 48, 0,
49, 50, 51, 52, 0, 53, 0, 0, 0, 4,
54, 66, 0, 5, 0, 102, 55, 0, 56, 57,
0, 8, 58, 59, 60, 45, 0, 46, 65, 0,
47, 48, 0, 49, 50, 51, 52, 0, 53, 0,
0, 0, 4, 54, 66, 0, 5, 0, 213, 55,
0, 56, 57, 0, 8, 58, 59, 60, 45, 75,
46, 0, 0, 47, 48, 0, 49, 50, 51, 52,
0, 53, 0, 0, 0, 4, 54, 99, 0, 5,
0, 0, 55, 0, 56, 57, 0, 8, 58, 59,
60, 45, 0, 46, 0, 0, 47, 48, 0, 49,
50, 51, 52, 0, 53, 131, 0, 0, 4, 54,
66, 0, 5, 0, 0, 55, 0, 56, 57, 0,
8, 58, 59, 60, 45, 0, 46, 65, 0, 47,
48, 0, 49, 50, 51, 52, 0, 53, 0, 0,
0, 4, 54, 66, 0, 5, 0, 0, 55, 0,
56, 57, 0, 8, 58, 59, 60, 45, 0, 46,
0, 0, 47, 48, 0, 49, 50, 51, 52, 0,
53, 0, 0, 0, 4, 54, 66, 0, 5, 0,
0, 55, 175, 56, 57, 0, 8, 58, 59, 60,
45, 0, 46, 0, 0, 47, 48, 0, 49, 50,
51, 52, 0, 53, 0, 0, 0, 4, 54, 66,
0, 5, 0, 0, 55, 0, 56, 57, 0, 8,
58, 59, 60, 45, 0, 46, 0, 0, 47, 48,
0, 49, 50, 51, 52, 0, 53, 0, 0, 0,
4, 54, 0, 0, 5, 0, 0, 55, 0, 56,
57, 0, 8, 58, 59, 60, 45, 0, 46, 0,
0, 47, 0, 0, 49, 217, 51, 52, 0, 53,
0, 0, 0, 4, 0, 222, 0, 5, 0, 0,
55, 0, 56, 57, 0, 8, 0, 59, 60
};
static const yytype_int16 yycheck[] =
{
3, 68, 196, 177, 2, 100, 42, 177, 146, 0,
107, 29, 15, 7, 7, 0, 34, 5, 99, 199,
11, 31, 8, 0, 194, 77, 11, 21, 166, 39,
16, 289, 290, 19, 22, 38, 39, 40, 41, 297,
43, 44, 139, 95, 25, 219, 32, 33, 242, 219,
131, 37, 38, 29, 90, 91, 151, 93, 34, 239,
22, 97, 21, 243, 167, 68, 7, 65, 29, 121,
96, 123, 75, 34, 126, 170, 42, 172, 130, 17,
22, 84, 85, 86, 87, 88, 89, 261, 191, 192,
116, 261, 118, 23, 21, 29, 21, 27, 21, 65,
34, 104, 105, 23, 39, 35, 173, 27, 29, 29,
113, 29, 21, 34, 10, 35, 34, 108, 4, 289,
290, 124, 5, 5, 90, 91, 296, 297, 22, 7,
21, 97, 10, 136, 21, 101, 127, 140, 31, 187,
106, 34, 190, 10, 34, 148, 112, 21, 114, 115,
6, 117, 8, 119, 3, 146, 28, 238, 161, 125,
16, 164, 128, 19, 5, 168, 30, 133, 26, 135,
173, 25, 5, 5, 159, 166, 32, 180, 29, 29,
10, 37, 38, 5, 5, 5, 177, 26, 11, 155,
193, 157, 149, 294, 197, 276, 136, 214, 194, 202,
263, 140, 0, 194, 189, 266, 23, 161, 174, 277,
27, 196, 29, 11, 127, 256, 14, 220, 35, 204,
193, 189, 225, 21, 305, 23, -1, -1, 219, 27,
-1, -1, -1, -1, -1, 33, 34, 35, -1, -1,
-1, -1, -1, 11, -1, -1, 14, -1, -1, -1,
-1, 254, -1, 21, 257, 23, -1, 242, -1, 27,
263, -1, -1, 266, -1, 33, 34, 35, -1, 272,
261, 256, 12, -1, -1, 15, -1, 17, -1, -1,
-1, 247, -1, -1, 24, 25, -1, -1, -1, -1,
30, -1, -1, -1, -1, -1, 36, 300, 289, 290,
303, -1, -1, -1, -1, 296, 297, 3, -1, -1,
6, -1, 8, -1, -1, 11, 12, -1, 14, 15,
16, 17, -1, 19, -1, 291, -1, 23, 24, 25,
-1, 27, -1, -1, 30, -1, 32, 33, 304, 35,
36, 37, 38, 309, 6, -1, 8, -1, -1, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
-1, 23, 24, 25, -1, 27, 28, -1, 30, -1,
32, 33, 34, 35, 36, 37, 38, 39, 6, -1,
8, -1, -1, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, -1, 23, 24, 25, -1, 27,
28, -1, 30, -1, 32, 33, 34, 35, 36, 37,
38, 39, 6, -1, 8, -1, -1, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, -1, 23,
24, 25, -1, 27, -1, -1, 30, -1, 32, 33,
34, 35, 36, 37, 38, 39, 6, -1, 8, -1,
-1, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, -1, 23, 24, 25, -1, 27, -1, -1,
30, -1, 32, 33, 34, 35, 36, 37, 38, 6,
-1, 8, 9, -1, 11, 12, -1, 14, 15, 16,
17, -1, 19, -1, -1, -1, 23, 24, 25, -1,
27, -1, 29, 30, -1, 32, 33, -1, 35, 36,
37, 38, 6, -1, 8, 9, -1, 11, 12, -1,
14, 15, 16, 17, -1, 19, -1, -1, -1, 23,
24, 25, -1, 27, -1, 29, 30, -1, 32, 33,
-1, 35, 36, 37, 38, 6, -1, 8, 9, -1,
11, 12, -1, 14, 15, 16, 17, -1, 19, -1,
-1, -1, 23, 24, 25, -1, 27, -1, 29, 30,
-1, 32, 33, -1, 35, 36, 37, 38, 6, 7,
8, -1, -1, 11, 12, -1, 14, 15, 16, 17,
-1, 19, -1, -1, -1, 23, 24, 25, -1, 27,
-1, -1, 30, -1, 32, 33, -1, 35, 36, 37,
38, 6, -1, 8, -1, -1, 11, 12, -1, 14,
15, 16, 17, -1, 19, 20, -1, -1, 23, 24,
25, -1, 27, -1, -1, 30, -1, 32, 33, -1,
35, 36, 37, 38, 6, -1, 8, 9, -1, 11,
12, -1, 14, 15, 16, 17, -1, 19, -1, -1,
-1, 23, 24, 25, -1, 27, -1, -1, 30, -1,
32, 33, -1, 35, 36, 37, 38, 6, -1, 8,
-1, -1, 11, 12, -1, 14, 15, 16, 17, -1,
19, -1, -1, -1, 23, 24, 25, -1, 27, -1,
-1, 30, 31, 32, 33, -1, 35, 36, 37, 38,
6, -1, 8, -1, -1, 11, 12, -1, 14, 15,
16, 17, -1, 19, -1, -1, -1, 23, 24, 25,
-1, 27, -1, -1, 30, -1, 32, 33, -1, 35,
36, 37, 38, 6, -1, 8, -1, -1, 11, 12,
-1, 14, 15, 16, 17, -1, 19, -1, -1, -1,
23, 24, -1, -1, 27, -1, -1, 30, -1, 32,
33, -1, 35, 36, 37, 38, 6, -1, 8, -1,
-1, 11, -1, -1, 14, 15, 16, 17, -1, 19,
-1, -1, -1, 23, -1, 25, -1, 27, -1, -1,
30, -1, 32, 33, -1, 35, -1, 37, 38
};
/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
state STATE-NUM. */
static const yytype_int8 yystos[] =
{
0, 11, 14, 21, 23, 27, 33, 34, 35, 41,
42, 43, 44, 45, 46, 47, 85, 89, 90, 94,
95, 96, 97, 98, 108, 110, 111, 114, 115, 118,
119, 120, 121, 122, 123, 124, 125, 126, 8, 16,
19, 32, 33, 37, 38, 6, 8, 11, 12, 14,
15, 16, 17, 19, 24, 30, 32, 33, 36, 37,
38, 47, 81, 82, 86, 9, 25, 29, 53, 54,
57, 80, 82, 83, 84, 7, 77, 78, 79, 0,
44, 48, 80, 6, 8, 16, 19, 32, 37, 38,
80, 80, 80, 80, 77, 78, 80, 80, 25, 25,
77, 82, 29, 54, 5, 22, 58, 80, 21, 91,
79, 22, 49, 7, 80, 80, 80, 80, 80, 80,
77, 78, 77, 78, 17, 99, 78, 21, 99, 77,
78, 20, 80, 87, 88, 87, 21, 55, 77, 80,
59, 60, 80, 77, 58, 47, 92, 93, 39, 50,
51, 77, 80, 77, 77, 99, 77, 99, 77, 21,
21, 3, 80, 100, 101, 77, 92, 77, 10, 87,
77, 4, 77, 53, 58, 31, 60, 5, 55, 56,
5, 29, 93, 80, 31, 51, 55, 22, 104, 21,
21, 77, 77, 10, 96, 112, 113, 96, 102, 103,
80, 100, 3, 80, 21, 106, 29, 106, 80, 109,
28, 55, 55, 29, 77, 12, 13, 15, 18, 20,
21, 24, 25, 34, 36, 39, 47, 61, 62, 63,
64, 65, 67, 68, 69, 73, 81, 80, 5, 103,
30, 116, 113, 103, 106, 106, 109, 67, 29, 112,
80, 29, 102, 80, 96, 105, 107, 26, 56, 28,
62, 66, 70, 71, 72, 74, 75, 76, 80, 80,
87, 31, 25, 29, 29, 77, 5, 80, 29, 105,
80, 28, 62, 29, 72, 80, 29, 76, 80, 5,
10, 52, 80, 117, 87, 104, 5, 5, 61, 62,
21, 61, 77, 26, 52, 5, 61, 80, 77, 87,
77
};
/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */
static const yytype_int8 yyr1[] =
{
0, 40, 41, 42, 43, 43, 44, 44, 44, 45,
45, 46, 46, 46, 47, 47, 47, 48, 48, 49,
49, 50, 50, 51, 52, 52, 53, 53, 54, 54,
54, 55, 56, 56, 57, 57, 58, 58, 59, 59,
60, 61, 61, 61, 61, 61, 61, 61, 61, 61,
62, 62, 62, 63, 64, 65, 65, 66, 66, 67,
67, 67, 67, 68, 69, 70, 70, 71, 71, 72,
73, 74, 74, 75, 75, 76, 77, 77, 78, 78,
79, 80, 80, 81, 81, 81, 81, 81, 81, 81,
81, 81, 81, 81, 81, 82, 82, 82, 82, 82,
82, 83, 84, 84, 85, 86, 86, 87, 87, 88,
88, 89, 89, 89, 90, 91, 91, 92, 92, 93,
94, 94, 94, 94, 94, 94, 95, 96, 96, 97,
98, 99, 99, 99, 99, 100, 100, 101, 101, 102,
103, 103, 104, 104, 105, 106, 106, 107, 107, 107,
108, 109, 109, 110, 111, 112, 113, 113, 114, 115,
116, 116, 117, 117, 118, 118, 119, 119, 120, 120,
120, 120, 120, 120, 121, 122, 123, 124, 124, 125,
125, 126, 126
};
/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */
static const yytype_int8 yyr2[] =
{
0, 2, 1, 1, 1, 2, 1, 1, 1, 1,
1, 5, 3, 2, 1, 1, 1, 0, 1, 0,
3, 1, 2, 6, 0, 2, 1, 2, 1, 1,
1, 3, 0, 1, 6, 4, 0, 3, 1, 2,
3, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 2, 3, 1, 2, 1,
1, 1, 1, 1, 3, 0, 1, 1, 2, 3,
3, 0, 1, 1, 2, 3, 0, 1, 1, 2,
3, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 3, 5, 3, 6, 0, 1, 1, 2, 1,
3, 1, 1, 1, 3, 0, 3, 1, 2, 3,
1, 1, 1, 1, 1, 1, 1, 0, 1, 4,
6, 0, 3, 2, 2, 1, 3, 1, 2, 6,
1, 2, 0, 3, 6, 0, 3, 0, 1, 2,
6, 1, 3, 6, 7, 3, 1, 2, 7, 8,
0, 1, 1, 3, 1, 1, 6, 3, 1, 1,
1, 1, 1, 1, 4, 6, 6, 6, 4, 7,
4, 7, 4
};
enum { YYENOMEM = -2 };
#define yyerrok (yyerrstatus = 0)
#define yyclearin (yychar = YYEMPTY)
#define YYACCEPT goto yyacceptlab
#define YYABORT goto yyabortlab
#define YYERROR goto yyerrorlab
#define YYNOMEM goto yyexhaustedlab
#define YYRECOVERING() (!!yyerrstatus)
#define YYBACKUP(Token, Value) \
do \
if (yychar == YYEMPTY) \
{ \
yychar = (Token); \
yylval = (Value); \
YYPOPSTACK (yylen); \
yystate = *yyssp; \
goto yybackup; \
} \
else \
{ \
yyerror (parser, filename, YY_("syntax error: cannot back up")); \
YYERROR; \
} \
while (0)
/* Backward compatibility with an undocumented macro.
Use YYerror or YYUNDEF. */
#define YYERRCODE YYUNDEF
/* Enable debugging if requested. */
#if YYDEBUG
# ifndef YYFPRINTF
# include /* INFRINGES ON USER NAME SPACE */
# define YYFPRINTF fprintf
# endif
# define YYDPRINTF(Args) \
do { \
if (yydebug) \
YYFPRINTF Args; \
} while (0)
# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \
do { \
if (yydebug) \
{ \
YYFPRINTF (stderr, "%s ", Title); \
yy_symbol_print (stderr, \
Kind, Value, parser, filename); \
YYFPRINTF (stderr, "\n"); \
} \
} while (0)
/*-----------------------------------.
| Print this symbol's value on YYO. |
`-----------------------------------*/
static void
yy_symbol_value_print (FILE *yyo,
yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, VALUE parser, VALUE filename)
{
FILE *yyoutput = yyo;
YY_USE (yyoutput);
YY_USE (parser);
YY_USE (filename);
if (!yyvaluep)
return;
YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
YY_USE (yykind);
YY_IGNORE_MAYBE_UNINITIALIZED_END
}
/*---------------------------.
| Print this symbol on YYO. |
`---------------------------*/
static void
yy_symbol_print (FILE *yyo,
yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, VALUE parser, VALUE filename)
{
YYFPRINTF (yyo, "%s %s (",
yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
yy_symbol_value_print (yyo, yykind, yyvaluep, parser, filename);
YYFPRINTF (yyo, ")");
}
/*------------------------------------------------------------------.
| yy_stack_print -- Print the state stack from its BOTTOM up to its |
| TOP (included). |
`------------------------------------------------------------------*/
static void
yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
{
YYFPRINTF (stderr, "Stack now");
for (; yybottom <= yytop; yybottom++)
{
int yybot = *yybottom;
YYFPRINTF (stderr, " %d", yybot);
}
YYFPRINTF (stderr, "\n");
}
# define YY_STACK_PRINT(Bottom, Top) \
do { \
if (yydebug) \
yy_stack_print ((Bottom), (Top)); \
} while (0)
/*------------------------------------------------.
| Report that the YYRULE is going to be reduced. |
`------------------------------------------------*/
static void
yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
int yyrule, VALUE parser, VALUE filename)
{
int yylno = yyrline[yyrule];
int yynrhs = yyr2[yyrule];
int yyi;
YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
yyrule - 1, yylno);
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
YYFPRINTF (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr,
YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
&yyvsp[(yyi + 1) - (yynrhs)], parser, filename);
YYFPRINTF (stderr, "\n");
}
}
# define YY_REDUCE_PRINT(Rule) \
do { \
if (yydebug) \
yy_reduce_print (yyssp, yyvsp, Rule, parser, filename); \
} while (0)
/* Nonzero means print parse trace. It is left uninitialized so that
multiple parsers can coexist. */
int yydebug;
#else /* !YYDEBUG */
# define YYDPRINTF(Args) ((void) 0)
# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
# define YY_STACK_PRINT(Bottom, Top)
# define YY_REDUCE_PRINT(Rule)
#endif /* !YYDEBUG */
/* YYINITDEPTH -- initial size of the parser's stacks. */
#ifndef YYINITDEPTH
# define YYINITDEPTH 200
#endif
/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
if the built-in stack extension method is used).
Do not make this value too large; the results are undefined if
YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
evaluated with infinite-precision integer arithmetic. */
#ifndef YYMAXDEPTH
# define YYMAXDEPTH 10000
#endif
/* Context of a parse error. */
typedef struct
{
yy_state_t *yyssp;
yysymbol_kind_t yytoken;
} yypcontext_t;
/* Put in YYARG at most YYARGN of the expected tokens given the
current YYCTX, and return the number of tokens stored in YYARG. If
YYARG is null, return the number of expected tokens (guaranteed to
be less than YYNTOKENS). Return YYENOMEM on memory exhaustion.
Return 0 if there are more than YYARGN expected tokens, yet fill
YYARG up to YYARGN. */
static int
yypcontext_expected_tokens (const yypcontext_t *yyctx,
yysymbol_kind_t yyarg[], int yyargn)
{
/* Actual size of YYARG. */
int yycount = 0;
int yyn = yypact[+*yyctx->yyssp];
if (!yypact_value_is_default (yyn))
{
/* Start YYX at -YYN if negative to avoid negative indexes in
YYCHECK. In other words, skip the first -YYN actions for
this state because they are default actions. */
int yyxbegin = yyn < 0 ? -yyn : 0;
/* Stay within bounds of both yycheck and yytname. */
int yychecklim = YYLAST - yyn + 1;
int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
int yyx;
for (yyx = yyxbegin; yyx < yyxend; ++yyx)
if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
&& !yytable_value_is_error (yytable[yyx + yyn]))
{
if (!yyarg)
++yycount;
else if (yycount == yyargn)
return 0;
else
yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
}
}
if (yyarg && yycount == 0 && 0 < yyargn)
yyarg[0] = YYSYMBOL_YYEMPTY;
return yycount;
}
#ifndef yystrlen
# if defined __GLIBC__ && defined _STRING_H
# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
# else
/* Return the length of YYSTR. */
static YYPTRDIFF_T
yystrlen (const char *yystr)
{
YYPTRDIFF_T yylen;
for (yylen = 0; yystr[yylen]; yylen++)
continue;
return yylen;
}
# endif
#endif
#ifndef yystpcpy
# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
# define yystpcpy stpcpy
# else
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
YYDEST. */
static char *
yystpcpy (char *yydest, const char *yysrc)
{
char *yyd = yydest;
const char *yys = yysrc;
while ((*yyd++ = *yys++) != '\0')
continue;
return yyd - 1;
}
# endif
#endif
static int
yy_syntax_error_arguments (const yypcontext_t *yyctx,
yysymbol_kind_t yyarg[], int yyargn)
{
/* Actual size of YYARG. */
int yycount = 0;
/* There are many possibilities here to consider:
- If this state is a consistent state with a default action, then
the only way this function was invoked is if the default action
is an error action. In that case, don't check for expected
tokens because there are none.
- The only way there can be no lookahead present (in yychar) is if
this state is a consistent state with a default action. Thus,
detecting the absence of a lookahead is sufficient to determine
that there is no unexpected or expected token to report. In that
case, just report a simple "syntax error".
- Don't assume there isn't a lookahead just because this state is a
consistent state with a default action. There might have been a
previous inconsistent state, consistent state with a non-default
action, or user semantic action that manipulated yychar.
- Of course, the expected token list depends on states to have
correct lookahead information, and it depends on the parser not
to perform extra reductions after fetching a lookahead from the
scanner and before detecting a syntax error. Thus, state merging
(from LALR or IELR) and default reductions corrupt the expected
token list. However, the list is correct for canonical LR with
one exception: it will still contain any token that will not be
accepted due to an error action in a later state.
*/
if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
{
int yyn;
if (yyarg)
yyarg[yycount] = yyctx->yytoken;
++yycount;
yyn = yypcontext_expected_tokens (yyctx,
yyarg ? yyarg + 1 : yyarg, yyargn - 1);
if (yyn == YYENOMEM)
return YYENOMEM;
else
yycount += yyn;
}
return yycount;
}
/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
about the unexpected token YYTOKEN for the state stack whose top is
YYSSP.
Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is
not large enough to hold the message. In that case, also set
*YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the
required number of bytes is too large to store. */
static int
yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
const yypcontext_t *yyctx)
{
enum { YYARGS_MAX = 5 };
/* Internationalized format string. */
const char *yyformat = YY_NULLPTR;
/* Arguments of yyformat: reported tokens (one for the "unexpected",
one per "expected"). */
yysymbol_kind_t yyarg[YYARGS_MAX];
/* Cumulated lengths of YYARG. */
YYPTRDIFF_T yysize = 0;
/* Actual size of YYARG. */
int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
if (yycount == YYENOMEM)
return YYENOMEM;
switch (yycount)
{
#define YYCASE_(N, S) \
case N: \
yyformat = S; \
break
default: /* Avoid compiler warnings. */
YYCASE_(0, YY_("syntax error"));
YYCASE_(1, YY_("syntax error, unexpected %s"));
YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
#undef YYCASE_
}
/* Compute error message size. Don't count the "%s"s, but reserve
room for the terminator. */
yysize = yystrlen (yyformat) - 2 * yycount + 1;
{
int yyi;
for (yyi = 0; yyi < yycount; ++yyi)
{
YYPTRDIFF_T yysize1
= yysize + yystrlen (yysymbol_name (yyarg[yyi]));
if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
yysize = yysize1;
else
return YYENOMEM;
}
}
if (*yymsg_alloc < yysize)
{
*yymsg_alloc = 2 * yysize;
if (! (yysize <= *yymsg_alloc
&& *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
*yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
return -1;
}
/* Avoid sprintf, as that infringes on the user's name space.
Don't have undefined behavior even if the translation
produced a string with the wrong number of "%s"s. */
{
char *yyp = *yymsg;
int yyi = 0;
while ((*yyp = *yyformat) != '\0')
if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
{
yyp = yystpcpy (yyp, yysymbol_name (yyarg[yyi++]));
yyformat += 2;
}
else
{
++yyp;
++yyformat;
}
}
return 0;
}
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
static void
yydestruct (const char *yymsg,
yysymbol_kind_t yykind, YYSTYPE *yyvaluep, VALUE parser, VALUE filename)
{
YY_USE (yyvaluep);
YY_USE (parser);
YY_USE (filename);
if (!yymsg)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
YY_USE (yykind);
YY_IGNORE_MAYBE_UNINITIALIZED_END
}
/*----------.
| yyparse. |
`----------*/
int
yyparse (VALUE parser, VALUE filename)
{
/* Lookahead token kind. */
int yychar;
/* The semantic value of the lookahead symbol. */
/* Default value used for initialization, for pacifying older GCCs
or non-GCC compilers. */
YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
/* Number of syntax errors so far. */
int yynerrs = 0;
yy_state_fast_t yystate = 0;
/* Number of tokens to shift before error messages enabled. */
int yyerrstatus = 0;
/* Refer to the stacks through separate pointers, to allow yyoverflow
to reallocate them elsewhere. */
/* Their size. */
YYPTRDIFF_T yystacksize = YYINITDEPTH;
/* The state stack: array, bottom, top. */
yy_state_t yyssa[YYINITDEPTH];
yy_state_t *yyss = yyssa;
yy_state_t *yyssp = yyss;
/* The semantic value stack: array, bottom, top. */
YYSTYPE yyvsa[YYINITDEPTH];
YYSTYPE *yyvs = yyvsa;
YYSTYPE *yyvsp = yyvs;
int yyn;
/* The return value of yyparse. */
int yyresult;
/* Lookahead symbol kind. */
yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
/* Buffer for error messages, and its allocated size. */
char yymsgbuf[128];
char *yymsg = yymsgbuf;
YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
/* The number of symbols on the RHS of the reduced rule.
Keep to zero when no symbol should be popped. */
int yylen = 0;
YYDPRINTF ((stderr, "Starting parse\n"));
yychar = YYEMPTY; /* Cause a token to be read. */
goto yysetstate;
/*------------------------------------------------------------.
| yynewstate -- push a new state, which is found in yystate. |
`------------------------------------------------------------*/
yynewstate:
/* In all cases, when you get here, the value and location stacks
have just been pushed. So pushing a state here evens the stacks. */
yyssp++;
/*--------------------------------------------------------------------.
| yysetstate -- set current state (the top of the stack) to yystate. |
`--------------------------------------------------------------------*/
yysetstate:
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
YY_IGNORE_USELESS_CAST_BEGIN
*yyssp = YY_CAST (yy_state_t, yystate);
YY_IGNORE_USELESS_CAST_END
YY_STACK_PRINT (yyss, yyssp);
if (yyss + yystacksize - 1 <= yyssp)
#if !defined yyoverflow && !defined YYSTACK_RELOCATE
YYNOMEM;
#else
{
/* Get the current used size of the three stacks, in elements. */
YYPTRDIFF_T yysize = yyssp - yyss + 1;
# if defined yyoverflow
{
/* Give user a chance to reallocate the stack. Use copies of
these so that the &'s don't force the real ones into
memory. */
yy_state_t *yyss1 = yyss;
YYSTYPE *yyvs1 = yyvs;
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
be undefined if yyoverflow is a macro. */
yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * YYSIZEOF (*yyssp),
&yyvs1, yysize * YYSIZEOF (*yyvsp),
&yystacksize);
yyss = yyss1;
yyvs = yyvs1;
}
# else /* defined YYSTACK_RELOCATE */
/* Extend the stack our own way. */
if (YYMAXDEPTH <= yystacksize)
YYNOMEM;
yystacksize *= 2;
if (YYMAXDEPTH < yystacksize)
yystacksize = YYMAXDEPTH;
{
yy_state_t *yyss1 = yyss;
union yyalloc *yyptr =
YY_CAST (union yyalloc *,
YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
if (! yyptr)
YYNOMEM;
YYSTACK_RELOCATE (yyss_alloc, yyss);
YYSTACK_RELOCATE (yyvs_alloc, yyvs);
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
}
# endif
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
YY_IGNORE_USELESS_CAST_BEGIN
YYDPRINTF ((stderr, "Stack size increased to %ld\n",
YY_CAST (long, yystacksize)));
YY_IGNORE_USELESS_CAST_END
if (yyss + yystacksize - 1 <= yyssp)
YYABORT;
}
#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
if (yystate == YYFINAL)
YYACCEPT;
goto yybackup;
/*-----------.
| yybackup. |
`-----------*/
yybackup:
/* Do appropriate processing given the current state. Read a
lookahead token if we need one and don't already have one. */
/* First try to decide what to do without reference to lookahead token. */
yyn = yypact[yystate];
if (yypact_value_is_default (yyn))
goto yydefault;
/* Not known => get a lookahead token if don't already have one. */
/* YYCHAR is either empty, or end-of-input, or a valid lookahead. */
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token\n"));
yychar = yylex (&yylval, parser, filename);
}
if (yychar <= YYEOF)
{
yychar = YYEOF;
yytoken = YYSYMBOL_YYEOF;
YYDPRINTF ((stderr, "Now at end of input.\n"));
}
else if (yychar == YYerror)
{
/* The scanner already issued an error message, process directly
to error recovery. But do not keep the error token as
lookahead, it is too special and may lead us to an endless
loop in error recovery. */
yychar = YYUNDEF;
yytoken = YYSYMBOL_YYerror;
goto yyerrlab1;
}
else
{
yytoken = YYTRANSLATE (yychar);
YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
}
/* If the proper action on seeing token YYTOKEN is to reduce or to
detect an error, take that action. */
yyn += yytoken;
if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
goto yydefault;
yyn = yytable[yyn];
if (yyn <= 0)
{
if (yytable_value_is_error (yyn))
goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
/* Shift the lookahead token. */
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
yystate = yyn;
YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Discard the shifted token. */
yychar = YYEMPTY;
goto yynewstate;
/*-----------------------------------------------------------.
| yydefault -- do the default action for the current state. |
`-----------------------------------------------------------*/
yydefault:
yyn = yydefact[yystate];
if (yyn == 0)
goto yyerrlab;
goto yyreduce;
/*-----------------------------.
| yyreduce -- do a reduction. |
`-----------------------------*/
yyreduce:
/* yyn is the number of a rule to reduce with. */
yylen = yyr2[yyn];
/* If YYLEN is nonzero, implement the default value of the action:
'$$ = $1'.
Otherwise, the following line sets YYVAL to garbage.
This behavior is undocumented and Bison
users should not rely upon it. Assigning to YYVAL
unconditionally makes the parser a bit smaller, and it avoids a
GCC warning that YYVAL may be used uninitialized. */
yyval = yyvsp[1-yylen];
YY_REDUCE_PRINT (yyn);
switch (yyn)
{
case 2: /* start: document */
#line 103 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ivar_set(parser, rb_intern("@result"), yyvsp[0]); }
#line 1922 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 3: /* document: definitions_list */
#line 105 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
VALUE position_source = rb_ary_entry(yyvsp[0], 0);
VALUE line, col;
if (RB_TEST(position_source)) {
line = rb_funcall(position_source, rb_intern("line"), 0);
col = rb_funcall(position_source, rb_intern("col"), 0);
} else {
line = INT2FIX(1);
col = INT2FIX(1);
}
yyval = MAKE_AST_NODE(Document, 3, line, col, yyvsp[0]);
}
#line 1939 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 4: /* definitions_list: definition */
#line 119 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 1945 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 5: /* definitions_list: definitions_list definition */
#line 120 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 1951 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 11: /* operation_definition: operation_type operation_name_opt variable_definitions_opt directives_list_opt selection_set */
#line 132 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(OperationDefinition, 7,
rb_ary_entry(yyvsp[-4], 1),
rb_ary_entry(yyvsp[-4], 2),
rb_ary_entry(yyvsp[-4], 3),
(RB_TEST(yyvsp[-3]) ? rb_ary_entry(yyvsp[-3], 3) : Qnil),
yyvsp[-2],
yyvsp[-1],
yyvsp[0]
);
}
#line 1967 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 12: /* operation_definition: LCURLY selection_list RCURLY */
#line 143 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(OperationDefinition, 7,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
r_string_query,
Qnil,
GraphQL_Language_Nodes_NONE,
GraphQL_Language_Nodes_NONE,
yyvsp[-1]
);
}
#line 1983 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 13: /* operation_definition: LCURLY RCURLY */
#line 154 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(OperationDefinition, 7,
rb_ary_entry(yyvsp[-1], 1),
rb_ary_entry(yyvsp[-1], 2),
r_string_query,
Qnil,
GraphQL_Language_Nodes_NONE,
GraphQL_Language_Nodes_NONE,
GraphQL_Language_Nodes_NONE
);
}
#line 1999 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 17: /* operation_name_opt: %empty */
#line 172 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = Qnil; }
#line 2005 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 19: /* variable_definitions_opt: %empty */
#line 176 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2011 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 20: /* variable_definitions_opt: LPAREN variable_definitions_list RPAREN */
#line 177 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[-1]; }
#line 2017 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 21: /* variable_definitions_list: variable_definition */
#line 180 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2023 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 22: /* variable_definitions_list: variable_definitions_list variable_definition */
#line 181 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2029 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 23: /* variable_definition: VAR_SIGN name COLON type default_value_opt directives_list_opt */
#line 184 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(VariableDefinition, 6,
rb_ary_entry(yyvsp[-5], 1),
rb_ary_entry(yyvsp[-5], 2),
rb_ary_entry(yyvsp[-4], 3),
yyvsp[-2],
yyvsp[-1],
yyvsp[0]
);
}
#line 2044 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 24: /* default_value_opt: %empty */
#line 196 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = Qnil; }
#line 2050 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 25: /* default_value_opt: EQUALS literal_value */
#line 197 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[0]; }
#line 2056 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 26: /* selection_list: selection */
#line 200 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2062 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 27: /* selection_list: selection_list selection */
#line 201 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2068 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 31: /* selection_set: LCURLY selection_list RCURLY */
#line 209 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[-1]; }
#line 2074 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 32: /* selection_set_opt: %empty */
#line 212 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new(); }
#line 2080 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 34: /* field: name COLON name arguments_opt directives_list_opt selection_set_opt */
#line 216 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(Field, 7,
rb_ary_entry(yyvsp[-5], 1),
rb_ary_entry(yyvsp[-5], 2),
rb_ary_entry(yyvsp[-5], 3), // alias
rb_ary_entry(yyvsp[-3], 3), // name
yyvsp[-2], // args
yyvsp[-1], // directives
yyvsp[0] // subselections
);
}
#line 2096 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 35: /* field: name arguments_opt directives_list_opt selection_set_opt */
#line 227 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(Field, 7,
rb_ary_entry(yyvsp[-3], 1),
rb_ary_entry(yyvsp[-3], 2),
Qnil, // alias
rb_ary_entry(yyvsp[-3], 3), // name
yyvsp[-2], // args
yyvsp[-1], // directives
yyvsp[0] // subselections
);
}
#line 2112 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 36: /* arguments_opt: %empty */
#line 240 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2118 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 37: /* arguments_opt: LPAREN arguments_list RPAREN */
#line 241 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[-1]; }
#line 2124 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 38: /* arguments_list: argument */
#line 244 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2130 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 39: /* arguments_list: arguments_list argument */
#line 245 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2136 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 40: /* argument: name COLON input_value */
#line 248 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(Argument, 4,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
rb_ary_entry(yyvsp[-2], 3),
yyvsp[0]
);
}
#line 2149 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 41: /* literal_value: FLOAT */
#line 258 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_funcall(rb_ary_entry(yyvsp[0], 3), rb_intern("to_f"), 0); }
#line 2155 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 42: /* literal_value: INT */
#line 259 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_funcall(rb_ary_entry(yyvsp[0], 3), rb_intern("to_i"), 0); }
#line 2161 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 43: /* literal_value: STRING */
#line 260 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_entry(yyvsp[0], 3); }
#line 2167 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 44: /* literal_value: TRUE_LITERAL */
#line 261 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = Qtrue; }
#line 2173 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 45: /* literal_value: FALSE_LITERAL */
#line 262 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = Qfalse; }
#line 2179 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 53: /* null_value: NULL_LITERAL */
#line 273 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(NullValue, 3,
rb_ary_entry(yyvsp[0], 1),
rb_ary_entry(yyvsp[0], 2),
rb_ary_entry(yyvsp[0], 3)
);
}
#line 2191 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 54: /* variable: VAR_SIGN name */
#line 281 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(VariableIdentifier, 3,
rb_ary_entry(yyvsp[-1], 1),
rb_ary_entry(yyvsp[-1], 2),
rb_ary_entry(yyvsp[0], 3)
);
}
#line 2203 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 55: /* list_value: LBRACKET RBRACKET */
#line 290 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2209 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 56: /* list_value: LBRACKET list_value_list RBRACKET */
#line 291 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[-1]; }
#line 2215 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 57: /* list_value_list: input_value */
#line 294 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2221 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 58: /* list_value_list: list_value_list input_value */
#line 295 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2227 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 63: /* enum_value: enum_name */
#line 303 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(Enum, 3,
rb_ary_entry(yyvsp[0], 1),
rb_ary_entry(yyvsp[0], 2),
rb_ary_entry(yyvsp[0], 3)
);
}
#line 2239 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 64: /* object_value: LCURLY object_value_list_opt RCURLY */
#line 312 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InputObject, 3,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
yyvsp[-1]
);
}
#line 2251 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 65: /* object_value_list_opt: %empty */
#line 321 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2257 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 67: /* object_value_list: object_value_field */
#line 325 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2263 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 68: /* object_value_list: object_value_list object_value_field */
#line 326 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2269 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 69: /* object_value_field: name COLON input_value */
#line 329 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(Argument, 4,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
rb_ary_entry(yyvsp[-2], 3),
yyvsp[0]
);
}
#line 2282 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 70: /* object_literal_value: LCURLY object_literal_value_list_opt RCURLY */
#line 340 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InputObject, 3,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
yyvsp[-1]
);
}
#line 2294 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 71: /* object_literal_value_list_opt: %empty */
#line 349 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2300 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 73: /* object_literal_value_list: object_literal_value_field */
#line 353 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2306 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 74: /* object_literal_value_list: object_literal_value_list object_literal_value_field */
#line 354 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2312 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 75: /* object_literal_value_field: name COLON literal_value */
#line 357 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(Argument, 4,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
rb_ary_entry(yyvsp[-2], 3),
yyvsp[0]
);
}
#line 2325 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 76: /* directives_list_opt: %empty */
#line 368 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2331 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 78: /* directives_list: directive */
#line 372 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2337 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 79: /* directives_list: directives_list directive */
#line 373 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2343 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 80: /* directive: DIR_SIGN name arguments_opt */
#line 375 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(Directive, 4,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
rb_ary_entry(yyvsp[-1], 3),
yyvsp[0]
);
}
#line 2356 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 101: /* fragment_spread: ELLIPSIS name_without_on directives_list_opt */
#line 412 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(FragmentSpread, 4,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
rb_ary_entry(yyvsp[-1], 3),
yyvsp[0]
);
}
#line 2369 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 102: /* inline_fragment: ELLIPSIS ON type directives_list_opt selection_set */
#line 422 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InlineFragment, 5,
rb_ary_entry(yyvsp[-4], 1),
rb_ary_entry(yyvsp[-4], 2),
yyvsp[-2],
yyvsp[-1],
yyvsp[0]
);
}
#line 2383 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 103: /* inline_fragment: ELLIPSIS directives_list_opt selection_set */
#line 431 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InlineFragment, 5,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
Qnil,
yyvsp[-1],
yyvsp[0]
);
}
#line 2397 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 104: /* fragment_definition: FRAGMENT fragment_name_opt ON type directives_list_opt selection_set */
#line 442 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(FragmentDefinition, 6,
rb_ary_entry(yyvsp[-5], 1),
rb_ary_entry(yyvsp[-5], 2),
yyvsp[-4],
yyvsp[-2],
yyvsp[-1],
yyvsp[0]
);
}
#line 2412 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 105: /* fragment_name_opt: %empty */
#line 454 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = Qnil; }
#line 2418 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 106: /* fragment_name_opt: name_without_on */
#line 455 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_entry(yyvsp[0], 3); }
#line 2424 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 108: /* type: nullable_type BANG */
#line 459 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = MAKE_AST_NODE(NonNullType, 3, rb_funcall(yyvsp[-1], rb_intern("line"), 0), rb_funcall(yyvsp[-1], rb_intern("col"), 0), yyvsp[-1]); }
#line 2430 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 109: /* nullable_type: name */
#line 462 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(TypeName, 3,
rb_ary_entry(yyvsp[0], 1),
rb_ary_entry(yyvsp[0], 2),
rb_ary_entry(yyvsp[0], 3)
);
}
#line 2442 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 110: /* nullable_type: LBRACKET type RBRACKET */
#line 469 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(ListType, 3,
rb_funcall(yyvsp[-1], rb_intern("line"), 0),
rb_funcall(yyvsp[-1], rb_intern("col"), 0),
yyvsp[-1]
);
}
#line 2454 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 114: /* schema_definition: SCHEMA directives_list_opt operation_type_definition_list_opt */
#line 483 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(SchemaDefinition, 6,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
// TODO use static strings:
rb_hash_aref(yyvsp[0], rb_str_new_cstr("query")),
rb_hash_aref(yyvsp[0], rb_str_new_cstr("mutation")),
rb_hash_aref(yyvsp[0], rb_str_new_cstr("subscription")),
yyvsp[-1]
);
}
#line 2470 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 115: /* operation_type_definition_list_opt: %empty */
#line 496 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_hash_new(); }
#line 2476 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 116: /* operation_type_definition_list_opt: LCURLY operation_type_definition_list RCURLY */
#line 497 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[-1]; }
#line 2482 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 117: /* operation_type_definition_list: operation_type_definition */
#line 500 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = rb_hash_new();
rb_hash_aset(yyval, rb_ary_entry(yyvsp[0], 0), rb_ary_entry(yyvsp[0], 1));
}
#line 2491 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 118: /* operation_type_definition_list: operation_type_definition_list operation_type_definition */
#line 504 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
rb_hash_aset(yyval, rb_ary_entry(yyvsp[0], 0), rb_ary_entry(yyvsp[0], 1));
}
#line 2499 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 119: /* operation_type_definition: operation_type COLON name */
#line 509 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = rb_ary_new_from_args(2, rb_ary_entry(yyvsp[-2], 3), rb_ary_entry(yyvsp[0], 3));
}
#line 2507 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 127: /* description_opt: %empty */
#line 524 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = Qnil; }
#line 2513 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 129: /* scalar_type_definition: description_opt SCALAR name directives_list_opt */
#line 528 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(ScalarTypeDefinition, 5,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
rb_ary_entry(yyvsp[-1], 3),
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-3]) ? rb_ary_entry(yyvsp[-3], 3) : Qnil),
yyvsp[0]
);
}
#line 2528 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 130: /* object_type_definition: description_opt TYPE_LITERAL name implements_opt directives_list_opt field_definition_list_opt */
#line 540 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(ObjectTypeDefinition, 7,
rb_ary_entry(yyvsp[-4], 1),
rb_ary_entry(yyvsp[-4], 2),
rb_ary_entry(yyvsp[-3], 3),
yyvsp[-2], // implements
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-5]) ? rb_ary_entry(yyvsp[-5], 3) : Qnil),
yyvsp[-1],
yyvsp[0]
);
}
#line 2545 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 131: /* implements_opt: %empty */
#line 554 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2551 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 132: /* implements_opt: IMPLEMENTS AMP interfaces_list */
#line 555 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[0]; }
#line 2557 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 133: /* implements_opt: IMPLEMENTS interfaces_list */
#line 556 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[0]; }
#line 2563 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 134: /* implements_opt: IMPLEMENTS legacy_interfaces_list */
#line 557 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[0]; }
#line 2569 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 135: /* interfaces_list: name */
#line 560 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
VALUE new_name = MAKE_AST_NODE(TypeName, 3,
rb_ary_entry(yyvsp[0], 1),
rb_ary_entry(yyvsp[0], 2),
rb_ary_entry(yyvsp[0], 3)
);
yyval = rb_ary_new_from_args(1, new_name);
}
#line 2582 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 136: /* interfaces_list: interfaces_list AMP name */
#line 568 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
VALUE new_name = MAKE_AST_NODE(TypeName, 3, rb_ary_entry(yyvsp[0], 1), rb_ary_entry(yyvsp[0], 2), rb_ary_entry(yyvsp[0], 3));
rb_ary_push(yyval, new_name);
}
#line 2591 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 137: /* legacy_interfaces_list: name */
#line 574 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
VALUE new_name = MAKE_AST_NODE(TypeName, 3,
rb_ary_entry(yyvsp[0], 1),
rb_ary_entry(yyvsp[0], 2),
rb_ary_entry(yyvsp[0], 3)
);
yyval = rb_ary_new_from_args(1, new_name);
}
#line 2604 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 138: /* legacy_interfaces_list: legacy_interfaces_list name */
#line 582 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
rb_ary_push(yyval, MAKE_AST_NODE(TypeName, 3, rb_ary_entry(yyvsp[0], 1), rb_ary_entry(yyvsp[0], 2), rb_ary_entry(yyvsp[0], 3)));
}
#line 2612 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 139: /* input_value_definition: description_opt name COLON type default_value_opt directives_list_opt */
#line 587 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InputValueDefinition, 7,
rb_ary_entry(yyvsp[-4], 1),
rb_ary_entry(yyvsp[-4], 2),
rb_ary_entry(yyvsp[-4], 3),
yyvsp[-2],
yyvsp[-1],
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-5]) ? rb_ary_entry(yyvsp[-5], 3) : Qnil),
yyvsp[0]
);
}
#line 2629 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 140: /* input_value_definition_list: input_value_definition */
#line 601 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2635 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 141: /* input_value_definition_list: input_value_definition_list input_value_definition */
#line 602 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2641 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 142: /* arguments_definitions_opt: %empty */
#line 605 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2647 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 143: /* arguments_definitions_opt: LPAREN input_value_definition_list RPAREN */
#line 606 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[-1]; }
#line 2653 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 144: /* field_definition: description_opt name arguments_definitions_opt COLON type directives_list_opt */
#line 609 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(FieldDefinition, 7,
rb_ary_entry(yyvsp[-4], 1),
rb_ary_entry(yyvsp[-4], 2),
rb_ary_entry(yyvsp[-4], 3),
yyvsp[-1],
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-5]) ? rb_ary_entry(yyvsp[-5], 3) : Qnil),
yyvsp[-3],
yyvsp[0]
);
}
#line 2670 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 145: /* field_definition_list_opt: %empty */
#line 623 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2676 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 146: /* field_definition_list_opt: LCURLY field_definition_list RCURLY */
#line 624 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = yyvsp[-1]; }
#line 2682 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 147: /* field_definition_list: %empty */
#line 627 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = GraphQL_Language_Nodes_NONE; }
#line 2688 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 148: /* field_definition_list: field_definition */
#line 628 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2694 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 149: /* field_definition_list: field_definition_list field_definition */
#line 629 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2700 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 150: /* interface_type_definition: description_opt INTERFACE name implements_opt directives_list_opt field_definition_list_opt */
#line 632 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InterfaceTypeDefinition, 7,
rb_ary_entry(yyvsp[-4], 1),
rb_ary_entry(yyvsp[-4], 2),
rb_ary_entry(yyvsp[-3], 3),
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-5]) ? rb_ary_entry(yyvsp[-5], 3) : Qnil),
yyvsp[-2],
yyvsp[-1],
yyvsp[0]
);
}
#line 2717 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 151: /* union_members: name */
#line 646 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
VALUE new_member = MAKE_AST_NODE(TypeName, 3,
rb_ary_entry(yyvsp[0], 1),
rb_ary_entry(yyvsp[0], 2),
rb_ary_entry(yyvsp[0], 3)
);
yyval = rb_ary_new_from_args(1, new_member);
}
#line 2730 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 152: /* union_members: union_members PIPE name */
#line 654 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
rb_ary_push(yyval, MAKE_AST_NODE(TypeName, 3, rb_ary_entry(yyvsp[0], 1), rb_ary_entry(yyvsp[0], 2), rb_ary_entry(yyvsp[0], 3)));
}
#line 2738 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 153: /* union_type_definition: description_opt UNION name directives_list_opt EQUALS union_members */
#line 659 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(UnionTypeDefinition, 6,
rb_ary_entry(yyvsp[-4], 1),
rb_ary_entry(yyvsp[-4], 2),
rb_ary_entry(yyvsp[-3], 3),
yyvsp[0], // types
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-5]) ? rb_ary_entry(yyvsp[-5], 3) : Qnil),
yyvsp[-2]
);
}
#line 2754 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 154: /* enum_type_definition: description_opt ENUM name directives_list_opt LCURLY enum_value_definitions RCURLY */
#line 672 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(EnumTypeDefinition, 6,
rb_ary_entry(yyvsp[-5], 1),
rb_ary_entry(yyvsp[-5], 2),
rb_ary_entry(yyvsp[-4], 3),
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-6]) ? rb_ary_entry(yyvsp[-6], 3) : Qnil),
yyvsp[-3],
yyvsp[-1]
);
}
#line 2770 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 155: /* enum_value_definition: description_opt enum_name directives_list_opt */
#line 685 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(EnumValueDefinition, 5,
rb_ary_entry(yyvsp[-1], 1),
rb_ary_entry(yyvsp[-1], 2),
rb_ary_entry(yyvsp[-1], 3),
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-2]) ? rb_ary_entry(yyvsp[-2], 3) : Qnil),
yyvsp[0]
);
}
#line 2785 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 156: /* enum_value_definitions: enum_value_definition */
#line 697 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, yyvsp[0]); }
#line 2791 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 157: /* enum_value_definitions: enum_value_definitions enum_value_definition */
#line 698 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, yyvsp[0]); }
#line 2797 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 158: /* input_object_type_definition: description_opt INPUT name directives_list_opt LCURLY input_value_definition_list RCURLY */
#line 701 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InputObjectTypeDefinition, 6,
rb_ary_entry(yyvsp[-5], 1),
rb_ary_entry(yyvsp[-5], 2),
rb_ary_entry(yyvsp[-4], 3),
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-6]) ? rb_ary_entry(yyvsp[-6], 3) : Qnil),
yyvsp[-3],
yyvsp[-1]
);
}
#line 2813 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 159: /* directive_definition: description_opt DIRECTIVE DIR_SIGN name arguments_definitions_opt directive_repeatable_opt ON directive_locations */
#line 714 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(DirectiveDefinition, 7,
rb_ary_entry(yyvsp[-6], 1),
rb_ary_entry(yyvsp[-6], 2),
rb_ary_entry(yyvsp[-4], 3),
(RB_TEST(yyvsp[-2]) ? Qtrue : Qfalse), // repeatable
// TODO see get_description for reading a description from comments
(RB_TEST(yyvsp[-7]) ? rb_ary_entry(yyvsp[-7], 3) : Qnil),
yyvsp[-3],
yyvsp[0]
);
}
#line 2830 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 160: /* directive_repeatable_opt: %empty */
#line 728 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = Qnil; }
#line 2836 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 161: /* directive_repeatable_opt: REPEATABLE */
#line 729 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = Qtrue; }
#line 2842 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 162: /* directive_locations: name */
#line 732 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ yyval = rb_ary_new_from_args(1, MAKE_AST_NODE(DirectiveLocation, 3, rb_ary_entry(yyvsp[0], 1), rb_ary_entry(yyvsp[0], 2), rb_ary_entry(yyvsp[0], 3))); }
#line 2848 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 163: /* directive_locations: directive_locations PIPE name */
#line 733 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{ rb_ary_push(yyval, MAKE_AST_NODE(DirectiveLocation, 3, rb_ary_entry(yyvsp[0], 1), rb_ary_entry(yyvsp[0], 2), rb_ary_entry(yyvsp[0], 3))); }
#line 2854 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 166: /* schema_extension: EXTEND SCHEMA directives_list_opt LCURLY operation_type_definition_list RCURLY */
#line 741 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(SchemaExtension, 6,
rb_ary_entry(yyvsp[-5], 1),
rb_ary_entry(yyvsp[-5], 2),
// TODO use static strings:
rb_hash_aref(yyvsp[-1], rb_str_new_cstr("query")),
rb_hash_aref(yyvsp[-1], rb_str_new_cstr("mutation")),
rb_hash_aref(yyvsp[-1], rb_str_new_cstr("subscription")),
yyvsp[-3]
);
}
#line 2870 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 167: /* schema_extension: EXTEND SCHEMA directives_list */
#line 752 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(SchemaExtension, 6,
rb_ary_entry(yyvsp[-2], 1),
rb_ary_entry(yyvsp[-2], 2),
Qnil,
Qnil,
Qnil,
yyvsp[0]
);
}
#line 2885 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 174: /* scalar_type_extension: EXTEND SCALAR name directives_list */
#line 771 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(ScalarTypeExtension, 4,
rb_ary_entry(yyvsp[-3], 1),
rb_ary_entry(yyvsp[-3], 2),
rb_ary_entry(yyvsp[-1], 3),
yyvsp[0]
);
}
#line 2898 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 175: /* object_type_extension: EXTEND TYPE_LITERAL name implements_opt directives_list_opt field_definition_list_opt */
#line 781 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(ObjectTypeExtension, 6,
rb_ary_entry(yyvsp[-5], 1),
rb_ary_entry(yyvsp[-5], 2),
rb_ary_entry(yyvsp[-3], 3),
yyvsp[-2], // implements
yyvsp[-1],
yyvsp[0]
);
}
#line 2913 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 176: /* interface_type_extension: EXTEND INTERFACE name implements_opt directives_list_opt field_definition_list_opt */
#line 793 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InterfaceTypeExtension, 6,
rb_ary_entry(yyvsp[-5], 1),
rb_ary_entry(yyvsp[-5], 2),
rb_ary_entry(yyvsp[-3], 3),
yyvsp[-2],
yyvsp[-1],
yyvsp[0]
);
}
#line 2928 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 177: /* union_type_extension: EXTEND UNION name directives_list_opt EQUALS union_members */
#line 805 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(UnionTypeExtension, 5,
rb_ary_entry(yyvsp[-5], 1),
rb_ary_entry(yyvsp[-5], 2),
rb_ary_entry(yyvsp[-3], 3),
yyvsp[0], // types
yyvsp[-2]
);
}
#line 2942 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 178: /* union_type_extension: EXTEND UNION name directives_list */
#line 814 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(UnionTypeExtension, 5,
rb_ary_entry(yyvsp[-3], 1),
rb_ary_entry(yyvsp[-3], 2),
rb_ary_entry(yyvsp[-1], 3),
GraphQL_Language_Nodes_NONE, // types
yyvsp[0]
);
}
#line 2956 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 179: /* enum_type_extension: EXTEND ENUM name directives_list_opt LCURLY enum_value_definitions RCURLY */
#line 825 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(EnumTypeExtension, 5,
rb_ary_entry(yyvsp[-6], 1),
rb_ary_entry(yyvsp[-6], 2),
rb_ary_entry(yyvsp[-4], 3),
yyvsp[-3],
yyvsp[-1]
);
}
#line 2970 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 180: /* enum_type_extension: EXTEND ENUM name directives_list */
#line 834 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(EnumTypeExtension, 5,
rb_ary_entry(yyvsp[-3], 1),
rb_ary_entry(yyvsp[-3], 2),
rb_ary_entry(yyvsp[-1], 3),
yyvsp[0],
GraphQL_Language_Nodes_NONE
);
}
#line 2984 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 181: /* input_object_type_extension: EXTEND INPUT name directives_list_opt LCURLY input_value_definition_list RCURLY */
#line 845 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InputObjectTypeExtension, 5,
rb_ary_entry(yyvsp[-6], 1),
rb_ary_entry(yyvsp[-6], 2),
rb_ary_entry(yyvsp[-4], 3),
yyvsp[-3],
yyvsp[-1]
);
}
#line 2998 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
case 182: /* input_object_type_extension: EXTEND INPUT name directives_list */
#line 854 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
{
yyval = MAKE_AST_NODE(InputObjectTypeExtension, 5,
rb_ary_entry(yyvsp[-3], 1),
rb_ary_entry(yyvsp[-3], 2),
rb_ary_entry(yyvsp[-1], 3),
yyvsp[0],
GraphQL_Language_Nodes_NONE
);
}
#line 3012 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
break;
#line 3016 "graphql-c_parser/ext/graphql_c_parser_ext/parser.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
that yytoken be updated with the new translation. We take the
approach of translating immediately before every use of yytoken.
One alternative is translating here after every semantic action,
but that translation would be missed if the semantic action invokes
YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
incorrect destructor might then be invoked immediately. In the
case of YYERROR or YYBACKUP, subsequent parser actions might lead
to an incorrect destructor call or verbose syntax error message
before the lookahead is translated. */
YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
YYPOPSTACK (yylen);
yylen = 0;
*++yyvsp = yyval;
/* Now 'shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
{
const int yylhs = yyr1[yyn] - YYNTOKENS;
const int yyi = yypgoto[yylhs] + *yyssp;
yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
? yytable[yyi]
: yydefgoto[yylhs]);
}
goto yynewstate;
/*--------------------------------------.
| yyerrlab -- here on detecting error. |
`--------------------------------------*/
yyerrlab:
/* Make sure we have latest lookahead translation. See comments at
user semantic actions for why this is necessary. */
yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
/* If not already recovering from an error, report this error. */
if (!yyerrstatus)
{
++yynerrs;
{
yypcontext_t yyctx
= {yyssp, yytoken};
char const *yymsgp = YY_("syntax error");
int yysyntax_error_status;
yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
if (yysyntax_error_status == 0)
yymsgp = yymsg;
else if (yysyntax_error_status == -1)
{
if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
yymsg = YY_CAST (char *,
YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
if (yymsg)
{
yysyntax_error_status
= yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
yymsgp = yymsg;
}
else
{
yymsg = yymsgbuf;
yymsg_alloc = sizeof yymsgbuf;
yysyntax_error_status = YYENOMEM;
}
}
yyerror (parser, filename, yymsgp);
if (yysyntax_error_status == YYENOMEM)
YYNOMEM;
}
}
if (yyerrstatus == 3)
{
/* If just tried and failed to reuse lookahead token after an
error, discard it. */
if (yychar <= YYEOF)
{
/* Return failure if at end of input. */
if (yychar == YYEOF)
YYABORT;
}
else
{
yydestruct ("Error: discarding",
yytoken, &yylval, parser, filename);
yychar = YYEMPTY;
}
}
/* Else will try to reuse lookahead token after shifting the error
token. */
goto yyerrlab1;
/*---------------------------------------------------.
| yyerrorlab -- error raised explicitly by YYERROR. |
`---------------------------------------------------*/
yyerrorlab:
/* Pacify compilers when the user code never invokes YYERROR and the
label yyerrorlab therefore never appears in user code. */
if (0)
YYERROR;
++yynerrs;
/* Do not reclaim the symbols of the rule whose action triggered
this YYERROR. */
YYPOPSTACK (yylen);
yylen = 0;
YY_STACK_PRINT (yyss, yyssp);
yystate = *yyssp;
goto yyerrlab1;
/*-------------------------------------------------------------.
| yyerrlab1 -- common code for both syntax error and YYERROR. |
`-------------------------------------------------------------*/
yyerrlab1:
yyerrstatus = 3; /* Each real token shifted decrements this. */
/* Pop stack until we find a state that shifts the error token. */
for (;;)
{
yyn = yypact[yystate];
if (!yypact_value_is_default (yyn))
{
yyn += YYSYMBOL_YYerror;
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
{
yyn = yytable[yyn];
if (0 < yyn)
break;
}
}
/* Pop the current state because it cannot handle the error token. */
if (yyssp == yyss)
YYABORT;
yydestruct ("Error: popping",
YY_ACCESSING_SYMBOL (yystate), yyvsp, parser, filename);
YYPOPSTACK (1);
yystate = *yyssp;
YY_STACK_PRINT (yyss, yyssp);
}
YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Shift the error token. */
YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
yystate = yyn;
goto yynewstate;
/*-------------------------------------.
| yyacceptlab -- YYACCEPT comes here. |
`-------------------------------------*/
yyacceptlab:
yyresult = 0;
goto yyreturnlab;
/*-----------------------------------.
| yyabortlab -- YYABORT comes here. |
`-----------------------------------*/
yyabortlab:
yyresult = 1;
goto yyreturnlab;
/*-----------------------------------------------------------.
| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. |
`-----------------------------------------------------------*/
yyexhaustedlab:
yyerror (parser, filename, YY_("memory exhausted"));
yyresult = 2;
goto yyreturnlab;
/*----------------------------------------------------------.
| yyreturnlab -- parsing is finished, clean up and return. |
`----------------------------------------------------------*/
yyreturnlab:
if (yychar != YYEMPTY)
{
/* Make sure we have latest lookahead translation. See comments at
user semantic actions for why this is necessary. */
yytoken = YYTRANSLATE (yychar);
yydestruct ("Cleanup: discarding lookahead",
yytoken, &yylval, parser, filename);
}
/* Do not reclaim the symbols of the rule whose action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
YY_STACK_PRINT (yyss, yyssp);
while (yyssp != yyss)
{
yydestruct ("Cleanup: popping",
YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, parser, filename);
YYPOPSTACK (1);
}
#ifndef yyoverflow
if (yyss != yyssa)
YYSTACK_FREE (yyss);
#endif
if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
return yyresult;
}
#line 864 "graphql-c_parser/ext/graphql_c_parser_ext/parser.y"
// Custom functions
int yylex (YYSTYPE *lvalp, VALUE parser, VALUE filename) {
VALUE next_token_idx_rb_int = rb_ivar_get(parser, rb_intern("@next_token_index"));
int next_token_idx = FIX2INT(next_token_idx_rb_int);
VALUE tokens = rb_ivar_get(parser, rb_intern("@tokens"));
VALUE next_token = rb_ary_entry(tokens, next_token_idx);
if (!RB_TEST(next_token)) {
return YYEOF;
}
rb_ivar_set(parser, rb_intern("@next_token_index"), INT2FIX(next_token_idx + 1));
VALUE token_type_rb_int = rb_ary_entry(next_token, 5);
int next_token_type = FIX2INT(token_type_rb_int);
if (next_token_type == 241) { // BAD_UNICODE_ESCAPE
VALUE mGraphQL = rb_const_get_at(rb_cObject, rb_intern("GraphQL"));
VALUE mCParser = rb_const_get_at(mGraphQL, rb_intern("CParser"));
VALUE bad_unicode_error = rb_funcall(
mCParser, rb_intern("prepare_bad_unicode_error"), 1,
parser
);
rb_exc_raise(bad_unicode_error);
}
*lvalp = next_token;
return next_token_type;
}
void yyerror(VALUE parser, VALUE filename, const char *msg) {
VALUE mGraphQL = rb_const_get_at(rb_cObject, rb_intern("GraphQL"));
VALUE mCParser = rb_const_get_at(mGraphQL, rb_intern("CParser"));
VALUE rb_message = rb_str_new_cstr(msg);
VALUE exception = rb_funcall(
mCParser, rb_intern("prepare_parse_error"), 2,
rb_message,
parser
);
rb_exc_raise(exception);
}
#define INITIALIZE_NODE_CLASS_VARIABLE(node_class_name) \
rb_global_variable(&GraphQL_Language_Nodes_##node_class_name); \
GraphQL_Language_Nodes_##node_class_name = rb_const_get_at(mGraphQLLanguageNodes, rb_intern(#node_class_name));
void initialize_node_class_variables() {
VALUE mGraphQL = rb_const_get_at(rb_cObject, rb_intern("GraphQL"));
VALUE mGraphQLLanguage = rb_const_get_at(mGraphQL, rb_intern("Language"));
VALUE mGraphQLLanguageNodes = rb_const_get_at(mGraphQLLanguage, rb_intern("Nodes"));
rb_global_variable(&GraphQL_Language_Nodes_NONE);
GraphQL_Language_Nodes_NONE = rb_ary_new();
rb_ary_freeze(GraphQL_Language_Nodes_NONE);
rb_global_variable(&r_string_query);
r_string_query = rb_str_new_cstr("query");
rb_str_freeze(r_string_query);
INITIALIZE_NODE_CLASS_VARIABLE(Argument)
INITIALIZE_NODE_CLASS_VARIABLE(Directive)
INITIALIZE_NODE_CLASS_VARIABLE(Document)
INITIALIZE_NODE_CLASS_VARIABLE(Enum)
INITIALIZE_NODE_CLASS_VARIABLE(Field)
INITIALIZE_NODE_CLASS_VARIABLE(FragmentDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(FragmentSpread)
INITIALIZE_NODE_CLASS_VARIABLE(InlineFragment)
INITIALIZE_NODE_CLASS_VARIABLE(InputObject)
INITIALIZE_NODE_CLASS_VARIABLE(ListType)
INITIALIZE_NODE_CLASS_VARIABLE(NonNullType)
INITIALIZE_NODE_CLASS_VARIABLE(NullValue)
INITIALIZE_NODE_CLASS_VARIABLE(OperationDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(TypeName)
INITIALIZE_NODE_CLASS_VARIABLE(VariableDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(VariableIdentifier)
INITIALIZE_NODE_CLASS_VARIABLE(ScalarTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(ObjectTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(InterfaceTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(UnionTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(EnumTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(InputObjectTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(EnumValueDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(DirectiveDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(DirectiveLocation)
INITIALIZE_NODE_CLASS_VARIABLE(FieldDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(InputValueDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(SchemaDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(ScalarTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(ObjectTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(InterfaceTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(UnionTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(EnumTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(InputObjectTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(SchemaExtension)
}
graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/parser.h 0000664 0000000 0000000 00000000214 14764346352 0026126 0 ustar 00root root 0000000 0000000 #ifndef Graphql_parser_h
#define Graphql_parser_h
int yyparse(VALUE parser, VALUE filename);
void initialize_node_class_variables();
#endif
graphql-ruby-2.2.17/graphql-c_parser/ext/graphql_c_parser_ext/parser.y 0000664 0000000 0000000 00000070056 14764346352 0026162 0 ustar 00root root 0000000 0000000 %require "3.8"
%define api.pure full
%define parse.error detailed
%{
// C Declarations
#include
#define YYSTYPE VALUE
int yylex(YYSTYPE *, VALUE, VALUE);
void yyerror(VALUE, VALUE, const char*);
static VALUE GraphQL_Language_Nodes_NONE;
static VALUE r_string_query;
#define MAKE_AST_NODE(node_class_name, nargs, ...) rb_funcall(GraphQL_Language_Nodes_##node_class_name, rb_intern("from_a"), nargs + 1, filename,__VA_ARGS__)
#define SETUP_NODE_CLASS_VARIABLE(node_class_name) static VALUE GraphQL_Language_Nodes_##node_class_name;
SETUP_NODE_CLASS_VARIABLE(Argument)
SETUP_NODE_CLASS_VARIABLE(Directive)
SETUP_NODE_CLASS_VARIABLE(Document)
SETUP_NODE_CLASS_VARIABLE(Enum)
SETUP_NODE_CLASS_VARIABLE(Field)
SETUP_NODE_CLASS_VARIABLE(FragmentDefinition)
SETUP_NODE_CLASS_VARIABLE(FragmentSpread)
SETUP_NODE_CLASS_VARIABLE(InlineFragment)
SETUP_NODE_CLASS_VARIABLE(InputObject)
SETUP_NODE_CLASS_VARIABLE(ListType)
SETUP_NODE_CLASS_VARIABLE(NonNullType)
SETUP_NODE_CLASS_VARIABLE(NullValue)
SETUP_NODE_CLASS_VARIABLE(OperationDefinition)
SETUP_NODE_CLASS_VARIABLE(TypeName)
SETUP_NODE_CLASS_VARIABLE(VariableDefinition)
SETUP_NODE_CLASS_VARIABLE(VariableIdentifier)
SETUP_NODE_CLASS_VARIABLE(ScalarTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(ObjectTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(InterfaceTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(UnionTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(EnumTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(InputObjectTypeDefinition)
SETUP_NODE_CLASS_VARIABLE(EnumValueDefinition)
SETUP_NODE_CLASS_VARIABLE(DirectiveDefinition)
SETUP_NODE_CLASS_VARIABLE(DirectiveLocation)
SETUP_NODE_CLASS_VARIABLE(FieldDefinition)
SETUP_NODE_CLASS_VARIABLE(InputValueDefinition)
SETUP_NODE_CLASS_VARIABLE(SchemaDefinition)
SETUP_NODE_CLASS_VARIABLE(ScalarTypeExtension)
SETUP_NODE_CLASS_VARIABLE(ObjectTypeExtension)
SETUP_NODE_CLASS_VARIABLE(InterfaceTypeExtension)
SETUP_NODE_CLASS_VARIABLE(UnionTypeExtension)
SETUP_NODE_CLASS_VARIABLE(EnumTypeExtension)
SETUP_NODE_CLASS_VARIABLE(InputObjectTypeExtension)
SETUP_NODE_CLASS_VARIABLE(SchemaExtension)
%}
%param {VALUE parser}
%param {VALUE filename}
// YACC Declarations
%token AMP 200
%token BANG 201
%token COLON 202
%token DIRECTIVE 203
%token DIR_SIGN 204
%token ENUM 205
%token ELLIPSIS 206
%token EQUALS 207
%token EXTEND 208
%token FALSE_LITERAL 209
%token FLOAT 210
%token FRAGMENT 211
%token IDENTIFIER 212
%token INPUT 213
%token IMPLEMENTS 214
%token INT 215
%token INTERFACE 216
%token LBRACKET 217
%token LCURLY 218
%token LPAREN 219
%token MUTATION 220
%token NULL_LITERAL 221
%token ON 222
%token PIPE 223
%token QUERY 224
%token RBRACKET 225
%token RCURLY 226
%token REPEATABLE 227
%token RPAREN 228
%token SCALAR 229
%token SCHEMA 230
%token STRING 231
%token SUBSCRIPTION 232
%token TRUE_LITERAL 233
%token TYPE_LITERAL 234
%token UNION 235
%token VAR_SIGN 236
%%
// YACC Rules
start: document { rb_ivar_set(parser, rb_intern("@result"), $1); }
document: definitions_list {
VALUE position_source = rb_ary_entry($1, 0);
VALUE line, col;
if (RB_TEST(position_source)) {
line = rb_funcall(position_source, rb_intern("line"), 0);
col = rb_funcall(position_source, rb_intern("col"), 0);
} else {
line = INT2FIX(1);
col = INT2FIX(1);
}
$$ = MAKE_AST_NODE(Document, 3, line, col, $1);
}
definitions_list:
definition { $$ = rb_ary_new_from_args(1, $1); }
| definitions_list definition { rb_ary_push($$, $2); }
definition:
executable_definition
| type_system_definition
| type_system_extension
executable_definition:
operation_definition
| fragment_definition
operation_definition:
operation_type operation_name_opt variable_definitions_opt directives_list_opt selection_set {
$$ = MAKE_AST_NODE(OperationDefinition, 7,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3),
(RB_TEST($2) ? rb_ary_entry($2, 3) : Qnil),
$3,
$4,
$5
);
}
| LCURLY selection_list RCURLY {
$$ = MAKE_AST_NODE(OperationDefinition, 7,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
r_string_query,
Qnil,
GraphQL_Language_Nodes_NONE,
GraphQL_Language_Nodes_NONE,
$2
);
}
| LCURLY RCURLY {
$$ = MAKE_AST_NODE(OperationDefinition, 7,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
r_string_query,
Qnil,
GraphQL_Language_Nodes_NONE,
GraphQL_Language_Nodes_NONE,
GraphQL_Language_Nodes_NONE
);
}
operation_type:
QUERY
| MUTATION
| SUBSCRIPTION
operation_name_opt:
/* none */ { $$ = Qnil; }
| name
variable_definitions_opt:
/* none */ { $$ = GraphQL_Language_Nodes_NONE; }
| LPAREN variable_definitions_list RPAREN { $$ = $2; }
variable_definitions_list:
variable_definition { $$ = rb_ary_new_from_args(1, $1); }
| variable_definitions_list variable_definition { rb_ary_push($$, $2); }
variable_definition:
VAR_SIGN name COLON type default_value_opt directives_list_opt {
$$ = MAKE_AST_NODE(VariableDefinition, 6,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($2, 3),
$4,
$5,
$6
);
}
default_value_opt:
/* none */ { $$ = Qnil; }
| EQUALS literal_value { $$ = $2; }
selection_list:
selection { $$ = rb_ary_new_from_args(1, $1); }
| selection_list selection { rb_ary_push($$, $2); }
selection:
field
| fragment_spread
| inline_fragment
selection_set:
LCURLY selection_list RCURLY { $$ = $2; }
selection_set_opt:
/* none */ { $$ = rb_ary_new(); }
| selection_set
field:
name COLON name arguments_opt directives_list_opt selection_set_opt {
$$ = MAKE_AST_NODE(Field, 7,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3), // alias
rb_ary_entry($3, 3), // name
$4, // args
$5, // directives
$6 // subselections
);
}
| name arguments_opt directives_list_opt selection_set_opt {
$$ = MAKE_AST_NODE(Field, 7,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
Qnil, // alias
rb_ary_entry($1, 3), // name
$2, // args
$3, // directives
$4 // subselections
);
}
arguments_opt:
/* none */ { $$ = GraphQL_Language_Nodes_NONE; }
| LPAREN arguments_list RPAREN { $$ = $2; }
arguments_list:
argument { $$ = rb_ary_new_from_args(1, $1); }
| arguments_list argument { rb_ary_push($$, $2); }
argument:
name COLON input_value {
$$ = MAKE_AST_NODE(Argument, 4,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3),
$3
);
}
literal_value:
FLOAT { $$ = rb_funcall(rb_ary_entry($1, 3), rb_intern("to_f"), 0); }
| INT { $$ = rb_funcall(rb_ary_entry($1, 3), rb_intern("to_i"), 0); }
| STRING { $$ = rb_ary_entry($1, 3); }
| TRUE_LITERAL { $$ = Qtrue; }
| FALSE_LITERAL { $$ = Qfalse; }
| null_value
| enum_value
| list_value
| object_literal_value
input_value:
literal_value
| variable
| object_value
null_value: NULL_LITERAL {
$$ = MAKE_AST_NODE(NullValue, 3,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3)
);
}
variable: VAR_SIGN name {
$$ = MAKE_AST_NODE(VariableIdentifier, 3,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($2, 3)
);
}
list_value:
LBRACKET RBRACKET { $$ = GraphQL_Language_Nodes_NONE; }
| LBRACKET list_value_list RBRACKET { $$ = $2; }
list_value_list:
input_value { $$ = rb_ary_new_from_args(1, $1); }
| list_value_list input_value { rb_ary_push($$, $2); }
enum_name: /* any identifier, but not "true", "false" or "null" */
IDENTIFIER
| ON
| operation_type
| schema_keyword
enum_value: enum_name {
$$ = MAKE_AST_NODE(Enum, 3,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3)
);
}
object_value:
LCURLY object_value_list_opt RCURLY {
$$ = MAKE_AST_NODE(InputObject, 3,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
$2
);
}
object_value_list_opt:
/* nothing */ { $$ = GraphQL_Language_Nodes_NONE; }
| object_value_list
object_value_list:
object_value_field { $$ = rb_ary_new_from_args(1, $1); }
| object_value_list object_value_field { rb_ary_push($$, $2); }
object_value_field:
name COLON input_value {
$$ = MAKE_AST_NODE(Argument, 4,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3),
$3
);
}
/* like the previous, but with literals only: */
object_literal_value:
LCURLY object_literal_value_list_opt RCURLY {
$$ = MAKE_AST_NODE(InputObject, 3,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
$2
);
}
object_literal_value_list_opt:
/* nothing */ { $$ = GraphQL_Language_Nodes_NONE; }
| object_literal_value_list
object_literal_value_list:
object_literal_value_field { $$ = rb_ary_new_from_args(1, $1); }
| object_literal_value_list object_literal_value_field { rb_ary_push($$, $2); }
object_literal_value_field:
name COLON literal_value {
$$ = MAKE_AST_NODE(Argument, 4,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3),
$3
);
}
directives_list_opt:
/* none */ { $$ = GraphQL_Language_Nodes_NONE; }
| directives_list
directives_list:
directive { $$ = rb_ary_new_from_args(1, $1); }
| directives_list directive { rb_ary_push($$, $2); }
directive: DIR_SIGN name arguments_opt {
$$ = MAKE_AST_NODE(Directive, 4,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($2, 3),
$3
);
}
name:
name_without_on
| ON
schema_keyword:
SCHEMA
| SCALAR
| TYPE_LITERAL
| IMPLEMENTS
| INTERFACE
| UNION
| ENUM
| INPUT
| DIRECTIVE
| EXTEND
| FRAGMENT
| REPEATABLE
name_without_on:
IDENTIFIER
| TRUE_LITERAL
| FALSE_LITERAL
| NULL_LITERAL
| operation_type
| schema_keyword
fragment_spread:
ELLIPSIS name_without_on directives_list_opt {
$$ = MAKE_AST_NODE(FragmentSpread, 4,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($2, 3),
$3
);
}
inline_fragment:
ELLIPSIS ON type directives_list_opt selection_set {
$$ = MAKE_AST_NODE(InlineFragment, 5,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
$3,
$4,
$5
);
}
| ELLIPSIS directives_list_opt selection_set {
$$ = MAKE_AST_NODE(InlineFragment, 5,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
Qnil,
$2,
$3
);
}
fragment_definition:
FRAGMENT fragment_name_opt ON type directives_list_opt selection_set {
$$ = MAKE_AST_NODE(FragmentDefinition, 6,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
$2,
$4,
$5,
$6
);
}
fragment_name_opt:
/* none */ { $$ = Qnil; }
| name_without_on { $$ = rb_ary_entry($1, 3); }
type:
nullable_type
| nullable_type BANG { $$ = MAKE_AST_NODE(NonNullType, 3, rb_funcall($1, rb_intern("line"), 0), rb_funcall($1, rb_intern("col"), 0), $1); }
nullable_type:
name {
$$ = MAKE_AST_NODE(TypeName, 3,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3)
);
}
| LBRACKET type RBRACKET {
$$ = MAKE_AST_NODE(ListType, 3,
rb_funcall($2, rb_intern("line"), 0),
rb_funcall($2, rb_intern("col"), 0),
$2
);
}
type_system_definition:
schema_definition
| type_definition
| directive_definition
schema_definition:
SCHEMA directives_list_opt operation_type_definition_list_opt {
$$ = MAKE_AST_NODE(SchemaDefinition, 6,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
// TODO use static strings:
rb_hash_aref($3, rb_str_new_cstr("query")),
rb_hash_aref($3, rb_str_new_cstr("mutation")),
rb_hash_aref($3, rb_str_new_cstr("subscription")),
$2
);
}
operation_type_definition_list_opt:
/* none */ { $$ = rb_hash_new(); }
| LCURLY operation_type_definition_list RCURLY { $$ = $2; }
operation_type_definition_list:
operation_type_definition {
$$ = rb_hash_new();
rb_hash_aset($$, rb_ary_entry($1, 0), rb_ary_entry($1, 1));
}
| operation_type_definition_list operation_type_definition {
rb_hash_aset($$, rb_ary_entry($2, 0), rb_ary_entry($2, 1));
}
operation_type_definition:
operation_type COLON name {
$$ = rb_ary_new_from_args(2, rb_ary_entry($1, 3), rb_ary_entry($3, 3));
}
type_definition:
scalar_type_definition
| object_type_definition
| interface_type_definition
| union_type_definition
| enum_type_definition
| input_object_type_definition
description: STRING
description_opt:
/* none */ { $$ = Qnil; }
| description
scalar_type_definition:
description_opt SCALAR name directives_list_opt {
$$ = MAKE_AST_NODE(ScalarTypeDefinition, 5,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($3, 3),
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$4
);
}
object_type_definition:
description_opt TYPE_LITERAL name implements_opt directives_list_opt field_definition_list_opt {
$$ = MAKE_AST_NODE(ObjectTypeDefinition, 7,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($3, 3),
$4, // implements
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$5,
$6
);
}
implements_opt:
/* none */ { $$ = GraphQL_Language_Nodes_NONE; }
| IMPLEMENTS AMP interfaces_list { $$ = $3; }
| IMPLEMENTS interfaces_list { $$ = $2; }
| IMPLEMENTS legacy_interfaces_list { $$ = $2; }
interfaces_list:
name {
VALUE new_name = MAKE_AST_NODE(TypeName, 3,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3)
);
$$ = rb_ary_new_from_args(1, new_name);
}
| interfaces_list AMP name {
VALUE new_name = MAKE_AST_NODE(TypeName, 3, rb_ary_entry($3, 1), rb_ary_entry($3, 2), rb_ary_entry($3, 3));
rb_ary_push($$, new_name);
}
legacy_interfaces_list:
name {
VALUE new_name = MAKE_AST_NODE(TypeName, 3,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3)
);
$$ = rb_ary_new_from_args(1, new_name);
}
| legacy_interfaces_list name {
rb_ary_push($$, MAKE_AST_NODE(TypeName, 3, rb_ary_entry($2, 1), rb_ary_entry($2, 2), rb_ary_entry($2, 3)));
}
input_value_definition:
description_opt name COLON type default_value_opt directives_list_opt {
$$ = MAKE_AST_NODE(InputValueDefinition, 7,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($2, 3),
$4,
$5,
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$6
);
}
input_value_definition_list:
input_value_definition { $$ = rb_ary_new_from_args(1, $1); }
| input_value_definition_list input_value_definition { rb_ary_push($$, $2); }
arguments_definitions_opt:
/* none */ { $$ = GraphQL_Language_Nodes_NONE; }
| LPAREN input_value_definition_list RPAREN { $$ = $2; }
field_definition:
description_opt name arguments_definitions_opt COLON type directives_list_opt {
$$ = MAKE_AST_NODE(FieldDefinition, 7,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($2, 3),
$5,
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$3,
$6
);
}
field_definition_list_opt:
/* none */ { $$ = GraphQL_Language_Nodes_NONE; }
| LCURLY field_definition_list RCURLY { $$ = $2; }
field_definition_list:
/* none - this is not actually valid but graphql-ruby used to print this */ { $$ = GraphQL_Language_Nodes_NONE; }
| field_definition { $$ = rb_ary_new_from_args(1, $1); }
| field_definition_list field_definition { rb_ary_push($$, $2); }
interface_type_definition:
description_opt INTERFACE name implements_opt directives_list_opt field_definition_list_opt {
$$ = MAKE_AST_NODE(InterfaceTypeDefinition, 7,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($3, 3),
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$4,
$5,
$6
);
}
union_members:
name {
VALUE new_member = MAKE_AST_NODE(TypeName, 3,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($1, 3)
);
$$ = rb_ary_new_from_args(1, new_member);
}
| union_members PIPE name {
rb_ary_push($$, MAKE_AST_NODE(TypeName, 3, rb_ary_entry($3, 1), rb_ary_entry($3, 2), rb_ary_entry($3, 3)));
}
union_type_definition:
description_opt UNION name directives_list_opt EQUALS union_members {
$$ = MAKE_AST_NODE(UnionTypeDefinition, 6,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($3, 3),
$6, // types
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$4
);
}
enum_type_definition:
description_opt ENUM name directives_list_opt LCURLY enum_value_definitions RCURLY {
$$ = MAKE_AST_NODE(EnumTypeDefinition, 6,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($3, 3),
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$4,
$6
);
}
enum_value_definition:
description_opt enum_name directives_list_opt {
$$ = MAKE_AST_NODE(EnumValueDefinition, 5,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($2, 3),
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$3
);
}
enum_value_definitions:
enum_value_definition { $$ = rb_ary_new_from_args(1, $1); }
| enum_value_definitions enum_value_definition { rb_ary_push($$, $2); }
input_object_type_definition:
description_opt INPUT name directives_list_opt LCURLY input_value_definition_list RCURLY {
$$ = MAKE_AST_NODE(InputObjectTypeDefinition, 6,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($3, 3),
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$4,
$6
);
}
directive_definition:
description_opt DIRECTIVE DIR_SIGN name arguments_definitions_opt directive_repeatable_opt ON directive_locations {
$$ = MAKE_AST_NODE(DirectiveDefinition, 7,
rb_ary_entry($2, 1),
rb_ary_entry($2, 2),
rb_ary_entry($4, 3),
(RB_TEST($6) ? Qtrue : Qfalse), // repeatable
// TODO see get_description for reading a description from comments
(RB_TEST($1) ? rb_ary_entry($1, 3) : Qnil),
$5,
$8
);
}
directive_repeatable_opt:
/* nothing */ { $$ = Qnil; }
| REPEATABLE { $$ = Qtrue; }
directive_locations:
name { $$ = rb_ary_new_from_args(1, MAKE_AST_NODE(DirectiveLocation, 3, rb_ary_entry($1, 1), rb_ary_entry($1, 2), rb_ary_entry($1, 3))); }
| directive_locations PIPE name { rb_ary_push($$, MAKE_AST_NODE(DirectiveLocation, 3, rb_ary_entry($3, 1), rb_ary_entry($3, 2), rb_ary_entry($3, 3))); }
type_system_extension:
schema_extension
| type_extension
schema_extension:
EXTEND SCHEMA directives_list_opt LCURLY operation_type_definition_list RCURLY {
$$ = MAKE_AST_NODE(SchemaExtension, 6,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
// TODO use static strings:
rb_hash_aref($5, rb_str_new_cstr("query")),
rb_hash_aref($5, rb_str_new_cstr("mutation")),
rb_hash_aref($5, rb_str_new_cstr("subscription")),
$3
);
}
| EXTEND SCHEMA directives_list {
$$ = MAKE_AST_NODE(SchemaExtension, 6,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
Qnil,
Qnil,
Qnil,
$3
);
}
type_extension:
scalar_type_extension
| object_type_extension
| interface_type_extension
| union_type_extension
| enum_type_extension
| input_object_type_extension
scalar_type_extension: EXTEND SCALAR name directives_list {
$$ = MAKE_AST_NODE(ScalarTypeExtension, 4,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($3, 3),
$4
);
}
object_type_extension:
EXTEND TYPE_LITERAL name implements_opt directives_list_opt field_definition_list_opt {
$$ = MAKE_AST_NODE(ObjectTypeExtension, 6,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($3, 3),
$4, // implements
$5,
$6
);
}
interface_type_extension:
EXTEND INTERFACE name implements_opt directives_list_opt field_definition_list_opt {
$$ = MAKE_AST_NODE(InterfaceTypeExtension, 6,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($3, 3),
$4,
$5,
$6
);
}
union_type_extension:
EXTEND UNION name directives_list_opt EQUALS union_members {
$$ = MAKE_AST_NODE(UnionTypeExtension, 5,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($3, 3),
$6, // types
$4
);
}
| EXTEND UNION name directives_list {
$$ = MAKE_AST_NODE(UnionTypeExtension, 5,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($3, 3),
GraphQL_Language_Nodes_NONE, // types
$4
);
}
enum_type_extension:
EXTEND ENUM name directives_list_opt LCURLY enum_value_definitions RCURLY {
$$ = MAKE_AST_NODE(EnumTypeExtension, 5,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($3, 3),
$4,
$6
);
}
| EXTEND ENUM name directives_list {
$$ = MAKE_AST_NODE(EnumTypeExtension, 5,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($3, 3),
$4,
GraphQL_Language_Nodes_NONE
);
}
input_object_type_extension:
EXTEND INPUT name directives_list_opt LCURLY input_value_definition_list RCURLY {
$$ = MAKE_AST_NODE(InputObjectTypeExtension, 5,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($3, 3),
$4,
$6
);
}
| EXTEND INPUT name directives_list {
$$ = MAKE_AST_NODE(InputObjectTypeExtension, 5,
rb_ary_entry($1, 1),
rb_ary_entry($1, 2),
rb_ary_entry($3, 3),
$4,
GraphQL_Language_Nodes_NONE
);
}
%%
// Custom functions
int yylex (YYSTYPE *lvalp, VALUE parser, VALUE filename) {
VALUE next_token_idx_rb_int = rb_ivar_get(parser, rb_intern("@next_token_index"));
int next_token_idx = FIX2INT(next_token_idx_rb_int);
VALUE tokens = rb_ivar_get(parser, rb_intern("@tokens"));
VALUE next_token = rb_ary_entry(tokens, next_token_idx);
if (!RB_TEST(next_token)) {
return YYEOF;
}
rb_ivar_set(parser, rb_intern("@next_token_index"), INT2FIX(next_token_idx + 1));
VALUE token_type_rb_int = rb_ary_entry(next_token, 5);
int next_token_type = FIX2INT(token_type_rb_int);
if (next_token_type == 241) { // BAD_UNICODE_ESCAPE
VALUE mGraphQL = rb_const_get_at(rb_cObject, rb_intern("GraphQL"));
VALUE mCParser = rb_const_get_at(mGraphQL, rb_intern("CParser"));
VALUE bad_unicode_error = rb_funcall(
mCParser, rb_intern("prepare_bad_unicode_error"), 1,
parser
);
rb_exc_raise(bad_unicode_error);
}
*lvalp = next_token;
return next_token_type;
}
void yyerror(VALUE parser, VALUE filename, const char *msg) {
VALUE mGraphQL = rb_const_get_at(rb_cObject, rb_intern("GraphQL"));
VALUE mCParser = rb_const_get_at(mGraphQL, rb_intern("CParser"));
VALUE rb_message = rb_str_new_cstr(msg);
VALUE exception = rb_funcall(
mCParser, rb_intern("prepare_parse_error"), 2,
rb_message,
parser
);
rb_exc_raise(exception);
}
#define INITIALIZE_NODE_CLASS_VARIABLE(node_class_name) \
rb_global_variable(&GraphQL_Language_Nodes_##node_class_name); \
GraphQL_Language_Nodes_##node_class_name = rb_const_get_at(mGraphQLLanguageNodes, rb_intern(#node_class_name));
void initialize_node_class_variables() {
VALUE mGraphQL = rb_const_get_at(rb_cObject, rb_intern("GraphQL"));
VALUE mGraphQLLanguage = rb_const_get_at(mGraphQL, rb_intern("Language"));
VALUE mGraphQLLanguageNodes = rb_const_get_at(mGraphQLLanguage, rb_intern("Nodes"));
rb_global_variable(&GraphQL_Language_Nodes_NONE);
GraphQL_Language_Nodes_NONE = rb_ary_new();
rb_ary_freeze(GraphQL_Language_Nodes_NONE);
rb_global_variable(&r_string_query);
r_string_query = rb_str_new_cstr("query");
rb_str_freeze(r_string_query);
INITIALIZE_NODE_CLASS_VARIABLE(Argument)
INITIALIZE_NODE_CLASS_VARIABLE(Directive)
INITIALIZE_NODE_CLASS_VARIABLE(Document)
INITIALIZE_NODE_CLASS_VARIABLE(Enum)
INITIALIZE_NODE_CLASS_VARIABLE(Field)
INITIALIZE_NODE_CLASS_VARIABLE(FragmentDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(FragmentSpread)
INITIALIZE_NODE_CLASS_VARIABLE(InlineFragment)
INITIALIZE_NODE_CLASS_VARIABLE(InputObject)
INITIALIZE_NODE_CLASS_VARIABLE(ListType)
INITIALIZE_NODE_CLASS_VARIABLE(NonNullType)
INITIALIZE_NODE_CLASS_VARIABLE(NullValue)
INITIALIZE_NODE_CLASS_VARIABLE(OperationDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(TypeName)
INITIALIZE_NODE_CLASS_VARIABLE(VariableDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(VariableIdentifier)
INITIALIZE_NODE_CLASS_VARIABLE(ScalarTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(ObjectTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(InterfaceTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(UnionTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(EnumTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(InputObjectTypeDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(EnumValueDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(DirectiveDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(DirectiveLocation)
INITIALIZE_NODE_CLASS_VARIABLE(FieldDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(InputValueDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(SchemaDefinition)
INITIALIZE_NODE_CLASS_VARIABLE(ScalarTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(ObjectTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(InterfaceTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(UnionTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(EnumTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(InputObjectTypeExtension)
INITIALIZE_NODE_CLASS_VARIABLE(SchemaExtension)
}
graphql-ruby-2.2.17/graphql-c_parser/graphql-c_parser.gemspec 0000664 0000000 0000000 00000002107 14764346352 0024267 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
$LOAD_PATH.push File.expand_path("../lib", __FILE__)
require "graphql/c_parser/version"
require "date"
Gem::Specification.new do |s|
s.name = "graphql-c_parser"
s.version = GraphQL::CParser::VERSION
s.date = Date.today.to_s
s.summary = "A parser for GraphQL, implemented as a C extension"
s.homepage = "https://github.com/rmosolgo/graphql-ruby"
s.authors = ["Robert Mosolgo"]
s.email = ["rdmosolgo@gmail.com"]
s.license = "MIT"
s.required_ruby_version = ">= 2.4.0"
s.metadata = {
"homepage_uri" => "https://graphql-ruby.org",
"changelog_uri" => "https://github.com/rmosolgo/graphql-ruby/blob/master/graphql-c_parser/CHANGELOG.md",
"source_code_uri" => "https://github.com/rmosolgo/graphql-ruby",
"bug_tracker_uri" => "https://github.com/rmosolgo/graphql-ruby/issues",
"mailing_list_uri" => "https://buttondown.email/graphql-ruby",
}
s.files = Dir["{lib,ext}/**/*.{rb,h,c}"]
s.extensions << "ext/graphql_c_parser_ext/extconf.rb"
s.add_dependency "graphql", ">= 2.2.10"
end
graphql-ruby-2.2.17/graphql-c_parser/lib/ 0000775 0000000 0000000 00000000000 14764346352 0020236 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/graphql-c_parser/lib/graphql-c_parser.rb 0000664 0000000 0000000 00000000071 14764346352 0024013 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require "graphql/c_parser"
graphql-ruby-2.2.17/graphql-c_parser/lib/graphql/ 0000775 0000000 0000000 00000000000 14764346352 0021674 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/graphql-c_parser/lib/graphql/c_parser.rb 0000664 0000000 0000000 00000007122 14764346352 0024021 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require "graphql"
require "graphql/c_parser/version"
require "graphql/graphql_c_parser_ext"
module GraphQL
module CParser
def self.parse(query_str, filename: nil, trace: GraphQL::Tracing::NullTrace)
parser = Parser.new(query_str, filename, trace)
parser.result
end
def self.parse_file(filename)
contents = File.read(filename)
parse(contents, filename: filename)
end
def self.prepare_parse_error(message, parser)
if message.start_with?("memory exhausted")
return GraphQL::ParseError.new("This query is too large to execute.", nil, nil, parser.query_string, filename: parser.filename)
end
token = parser.tokens[parser.next_token_index - 1]
if token
# There might not be a token if it's a comments-only string
line = token[1]
col = token[2]
if line && col
location_str = " at [#{line}, #{col}]"
if !message.include?(location_str)
message += location_str
end
end
if !message.include?("end of file")
message.sub!(/, unexpected ([a-zA-Z ]+)(,| at)/, ", unexpected \\1 (#{token[3].inspect})\\2")
end
end
GraphQL::ParseError.new(message, line, col, parser.query_string, filename: parser.filename)
end
def self.prepare_bad_unicode_error(parser)
token = parser.tokens[parser.next_token_index - 1]
line = token[1]
col = token[2]
GraphQL::ParseError.new(
"Parse error on bad Unicode escape sequence: #{token[3].inspect} (error) at [#{line}, #{col}]",
line,
col,
parser.query_string,
filename: parser.filename
)
end
module Lexer
def self.tokenize(graphql_string)
if !(graphql_string.encoding == Encoding::UTF_8 || graphql_string.ascii_only?)
graphql_string = graphql_string.dup.force_encoding(Encoding::UTF_8)
end
if !graphql_string.valid_encoding?
return [
[
:BAD_UNICODE_ESCAPE,
1,
1,
graphql_string,
nil, # prev token
241 # BAD_UNICODE_ESCAPE in lexer.rl
]
]
end
tokenize_with_c(graphql_string)
end
end
class Parser
def initialize(query_string, filename, trace)
if query_string.nil?
raise GraphQL::ParseError.new("No query string was present", nil, nil, query_string)
end
@query_string = query_string
@filename = filename
@tokens = nil
@next_token_index = 0
@result = nil
@trace = trace
end
def result
if @result.nil?
@tokens = @trace.lex(query_string: @query_string) do
GraphQL::CParser::Lexer.tokenize(@query_string)
end
@trace.parse(query_string: @query_string) do
c_parse
@result
end
end
@result
end
attr_reader :tokens, :next_token_index, :query_string, :filename
end
end
def self.scan_with_c(graphql_string)
GraphQL::CParser::Lexer.tokenize(graphql_string)
end
def self.parse_with_c(string, filename: nil, trace: GraphQL::Tracing::NullTrace)
if string.nil?
raise GraphQL::ParseError.new("No query string was present", nil, nil, string)
end
document = GraphQL::CParser.parse(string, filename: filename, trace: trace)
if document.definitions.size == 0
raise GraphQL::ParseError.new("Unexpected end of document", 1, 1, string)
end
document
end
self.default_parser = GraphQL::CParser
end
graphql-ruby-2.2.17/graphql-c_parser/lib/graphql/c_parser/ 0000775 0000000 0000000 00000000000 14764346352 0023472 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/graphql-c_parser/lib/graphql/c_parser/version.rb 0000664 0000000 0000000 00000000137 14764346352 0025505 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module GraphQL
module CParser
VERSION = "1.0.8"
end
end
graphql-ruby-2.2.17/graphql-ruby.png 0000664 0000000 0000000 00000010340 14764346352 0017357 0 ustar 00root root 0000000 0000000 PNG
IHDR g O ۢ sBIT|d pHYs a a?i tEXtSoftware www.inkscape.org< ]IDATxkTՕ֣i@^VuKv!Hd ia,A2fEdYc|A,i߈(N&jpdfT59Uz=hn=.tϚszw9)f6I2"&{R6ZkL~")J=MC*O͋Y) v)VކT(>ރXPX_4\yMwD˳qYh脯PZtW/Z{ˡrl ܑG$zi Ҿm#cCt3/؛MkRlɟP۸3RlQi k<&^@juJ;
p&FK@
0㿺dyC!fP+kf|]Ʒh#J16XYzQ6X kl!ӬO2ŋ4F]qII[5-z(vQ!$dx+ .Tm
YsiAhiR7?wZ0@$'ކI YPiv$*,)Ib C_L_?brGKĊ;%g]iil~
1 Cb.
/V]]ўWH%TN$"i 2֏HfƦ`SJ{ ]Pg5Я\ič7M9OEO5D|KM̋)^
RASQpIJL{9^fsw&Q.Pd(PZg>IfyxυLi>-^!'6^E@J z|op:× W?<iٲ3R_ a5l%fؿu_˞VM,bPe] ibbi.Iq.Пfur?._pPDeoR#(69S9\wS_ݶ#[&m_)2~]>5u?4\|
߀oQ(6p$fy0^ZCCoRNg+ǹ@/õpf_hN:=^?.iĽ
Wv
Hy`SngߟKvn$h?ygx;^Εz7+߽?zfR^$CR:"G@zSܦac{ꊄ <_I(T,Ćj,e*Z_pi&hi/vw۪igtF$ dҠs">;&Nw겅~xXŠ
jCX;/leXnLLvU /WN^bX&,诳v"ƌy1KA_LoX^pŽPLT~n4^EJuB8cZ^i:,yhGN; Mвbx}/}.GlBJ?DڜHΰ^0EDpUE,ٽ5/z6ۉ\FUK[ԓr+.FeJ/;> zfljA
X݂Ph wh}rZj~"*w7 Hm?O/ZO5i9/z}+{Z4:CTBXS
0*\^ԚZpM9h I`s Vc)*R(CzGEfyF!&`Qb@a[/K.L5MIq >D^Yf2Bϴ#̤v #Vl8+0%l̄BDpu?I++W] ݅|,R1PJգ|=-ٟWg}I13! G.3btEQ'1D%j&@ki,eYhK菠O*48J ^֘EԒHm;Q~kùH}ٴai-ӺŬxUc6HobPP[[x ӣWzS찕aVDa c$Dy@BUcŪQgۧdF۟VN@X]ԦBUeL(_Cʑ@t)@&/9mj}JѵDž M5b:n'_ 4FB9pM>eMWu$>5i=8̳T
C4@tý׀^+ٝ<W^Lb,1z~Z(K
6 BeMO%
ٛzVh R0jd^#6Eo:~uÜf|C61*\
,ştEC4D/X%(QӰ.R|$fvttHV(p[*ZY7yӌoPdjK3R)V
qUB
1:߸g5wK*A%SuBuwm ކ{ ${k8%ow @>1dġ79Jx!?'nቮ"FDo()l^>語hCmU'bn&493鬫z|!}ij*U\1_>[Y7yqCgOe*\WT #xHr3vnGΝdr 2i|UE\_*1e7x1.7EB/V҇JU{-`%W4^Ttyż+[ԛ+MpA56Se-߭e0(*F GÖ9E͘3m%$}`%NC=w [~䨥Ce*rz/^e(H^8mG9hah-;N[1#bb,qu^_
[HRF&2xN3+|%僤®4=Wz"MTa#u }%-T߰nP|)rVq`g)A9kV`j~pĺ;>A2 zʛhG#tLȁ&^IYYlv"3ʺCǺ#|S7
:\8f!(u_sqͱFB1WĸtCOqIHs#}ǚ8@AGƯT$;3fIB:?7hᘓ=[1#8 ]mu|<
1pלX__'*IuU.TʳP@%WՁK+APnb@gbЗbú.)*ܻãW4_,ĚvutWAL\U'c EȊЀ[cb@?9iz^;:6D>ʜq@gx@,AAGnj/LP̋z]Ҩݕ)& } !rH#Ϣ(gMd@~!v/L $}}(ʳMeVN %["|C1(1(qs2~
BK&Jr
K@ѿ6P0(Фc.}@"̎-9͟K59ݜ3YؒgB6pk}0eQ>F:q}+r4 IENDB` graphql-ruby-2.2.17/graphql-ruby.svg 0000664 0000000 0000000 00000002404 14764346352 0017374 0 ustar 00root root 0000000 0000000
graphql-ruby-2.2.17/graphql.gemspec 0000664 0000000 0000000 00000003552 14764346352 0017246 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
$LOAD_PATH.push File.expand_path("../lib", __FILE__)
require "graphql/version"
require "date"
Gem::Specification.new do |s|
s.name = "graphql"
s.version = GraphQL::VERSION
s.date = Date.today.to_s
s.summary = "A GraphQL language and runtime for Ruby"
s.description = "A plain-Ruby implementation of GraphQL."
s.homepage = "https://github.com/rmosolgo/graphql-ruby"
s.authors = ["Robert Mosolgo"]
s.email = ["rdmosolgo@gmail.com"]
s.license = "MIT"
s.required_ruby_version = ">= 2.7.0"
s.metadata = {
"homepage_uri" => "https://graphql-ruby.org",
"changelog_uri" => "https://github.com/rmosolgo/graphql-ruby/blob/master/CHANGELOG.md",
"source_code_uri" => "https://github.com/rmosolgo/graphql-ruby",
"bug_tracker_uri" => "https://github.com/rmosolgo/graphql-ruby/issues",
"mailing_list_uri" => "https://buttondown.email/graphql-ruby",
"rubygems_mfa_required" => "true",
}
s.files = Dir["{lib}/**/*", "MIT-LICENSE", "readme.md", ".yardopts"]
s.add_runtime_dependency "base64"
s.add_development_dependency "benchmark-ips"
s.add_development_dependency "concurrent-ruby", "~>1.0"
s.add_development_dependency "graphql-batch"
s.add_development_dependency "memory_profiler"
s.add_development_dependency "minitest"
s.add_development_dependency "minitest-focus"
s.add_development_dependency "minitest-reporters"
s.add_development_dependency "rake"
s.add_development_dependency 'rake-compiler'
s.add_development_dependency "rubocop", "1.12" # for Ruby 2.4 enforcement
# website stuff
s.add_development_dependency "jekyll"
s.add_development_dependency "yard"
s.add_development_dependency "jekyll-algolia"
s.add_development_dependency "jekyll-redirect-from"
s.add_development_dependency "m", "~> 1.5.0"
s.add_development_dependency "webrick"
end
graphql-ruby-2.2.17/guides/ 0000775 0000000 0000000 00000000000 14764346352 0015516 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/CNAME 0000664 0000000 0000000 00000000021 14764346352 0016255 0 ustar 00root root 0000000 0000000 graphql-ruby.org
graphql-ruby-2.2.17/guides/_config.yml 0000664 0000000 0000000 00000001233 14764346352 0017644 0 ustar 00root root 0000000 0000000 title: GraphQL Ruby
baseurl: ""
url: "https://graphql-ruby.org"
exclude:
- .gitignore
keep_files: ["api-doc", ".git"]
# Build settings
markdown: kramdown
highlighter: rouge
kramdown:
auto_ids: true
hard_wrap: false
input: GFM
defaults:
-
scope:
path: ""
values:
layout: "default"
fullwidth: true
algolia:
application_id: '8VO8708WUV'
index_name: 'prod_graphql_ruby'
settings:
searchableAttributes:
- section
- title
- headings
- content
customRanking:
- desc(title)
- desc(headings)
- desc(content)
plugins:
- jekyll-algolia
- jekyll-redirect-from
graphql-ruby-2.2.17/guides/_layouts/ 0000775 0000000 0000000 00000000000 14764346352 0017355 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/_layouts/default.html 0000664 0000000 0000000 00000006354 14764346352 0021677 0 ustar 00root root 0000000 0000000
{% if page.section contains "GraphQL" %}
{{ page.section }} - {{ page.title }}
{% else %}
GraphQL - {{ page.title }}
{% endif %}
graphql-ruby-2.2.17/guides/_plugins/ 0000775 0000000 0000000 00000000000 14764346352 0017336 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/_plugins/api_doc.rb 0000664 0000000 0000000 00000015704 14764346352 0021270 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require_relative "../../lib/graphql/version"
require "kramdown"
module GraphQLSite
API_DOC_ROOT = "/api-doc/#{GraphQL::VERSION}/"
module APIDoc
def api_doc(input)
if !input.start_with?("GraphQL")
ruby_ident = "GraphQL::#{input}"
else
ruby_ident = input
end
doc_path = ruby_ident
.gsub("::", "/") # namespaces
.sub(/#(.+)$/, "#\\1-instance_method") # instance methods
.sub(/\.(.+)$/, "#\\1-class_method") # class methods
%|#{input}|
end
def link_to_img(img_path, img_title)
full_img_path = "#{@context.registers[:site].baseurl}#{img_path}"
<<-HTML
HTML
end
end
class APIDocRoot < Liquid::Tag
def render(context)
API_DOC_ROOT
end
end
class CalloutBlock < Liquid::Block
def initialize(tag_name, callout_class, tokens)
super
@callout_class = callout_class.strip
end
def render(context)
raw_text = super
site = context.registers[:site]
converter = site.find_converter_instance(::Jekyll::Converters::Markdown)
rendered_text = converter.convert(raw_text)
heading = case @callout_class
when "warning"
"⚠ Heads up!"
else
raise ArgumentError, "Unhandled callout class: #{@callout_class.inspect}"
end
%|
#{heading}
#{rendered_text}
|
end
end
class OpenAnIssue < Liquid::Tag
def initialize(tag_name, issue_info, tokens)
title, body = issue_info.split(",")
# remove whitespace and quotes if value is present
@title = strip_arg(title)
@body = strip_arg(body)
end
def render(context)
%|open an issue|
end
private
def strip_arg(text)
text && text.strip[1..-2]
end
end
# Build a URL relative to `site.baseurl`,
# asserting that the page exists.
class InternalLink < Liquid::Tag
GUIDES_ROOT = "guides/"
def initialize(tag_name, guide_info, tokens)
text, path = guide_info.split(",")
# remove whitespace and quotes if value is present
@text = strip_arg(text)
@path = strip_arg(path)
if @path && @path.start_with?("/")
@path = @path[1..-1]
end
if !exist?(@path)
raise "Internal link failed, couldn't find file for: #{path}"
end
end
def render(context)
<<-HTML.chomp
#{@text}
HTML
end
private
def strip_arg(text)
text && text.strip[1..-2]
end
POSSIBLE_EXTENSIONS = [".html", ".md"]
def exist?(path)
filepath = GUIDES_ROOT + path.split("#").first
filepath = filepath.sub(".html", "")
POSSIBLE_EXTENSIONS.any? { |ext| File.exist?(filepath + ext) }
end
end
class TableOfContents < Liquid::Tag
def render(context)
headers = context["page"]["content"].scan(/^##+[^\n]+$/m)
section_count = 0
current_table = header_table = [nil]
prev_depth = nil
headers.each do |h|
header_hashes = h.match(/^#+/)[0]
depth = header_hashes.size
if depth == 2
section_count += 1
end
text = h.gsub(/^#+ /, "")
target = text.downcase
.gsub(/[^a-z0-9_]+/, "-")
.sub(/-$/, "")
.sub(/^-/, "")
rendered_text = Kramdown::Document.new(text, auto_ids: false)
.to_html
.sub("
", "")
.sub("
", "") # remove wrapping added by kramdown
if prev_depth
if prev_depth > depth
# outdent
current_table = current_table[0]
elsif prev_depth < depth
# indent
new_table = [current_table]
current_table[-1][-1] = new_table
current_table = new_table
else
# same depth
end
end
current_table << [rendered_text, target, []]
prev_depth = depth
end
table_html = "".dup
render_table_into_html(table_html, header_table)
html = <<~HTML
Contents
#{table_html}
HTML
if section_count == 0
if headers.any?
full_path = "guides/#{context["page"]["path"]}"
warn("No sections identified for #{full_path} -- make sure it's using `## ...` for section headings.")
end
""
else
html
end
end
private
def render_table_into_html(html_str, table)
html_str << ""
table.each_with_index do |entry, idx|
if idx == 0
next # parent reference
end
rendered_text, target, child_table = *entry
html_str << "
"
html_str << "#{rendered_text}"
if child_table.any?
render_table_into_html(html_str, child_table)
end
html_str << "
"
end
html_str << ""
end
end
end
Liquid::Template.register_filter(GraphQLSite::APIDoc)
Liquid::Template.register_tag("api_doc_root", GraphQLSite::APIDocRoot)
Liquid::Template.register_tag("open_an_issue", GraphQLSite::OpenAnIssue)
Liquid::Template.register_tag("internal_link", GraphQLSite::InternalLink)
Liquid::Template.register_tag("table_of_contents", GraphQLSite::TableOfContents)
Liquid::Template.register_tag('callout', GraphQLSite::CalloutBlock)
Jekyll::Hooks.register :site, :pre_render do |site|
section_pages = Hash.new { |h, k| h[k] = [] }
section_names = []
site.pages.each do |page|
this_section = page.data["section"]
if this_section
this_section_pages = section_pages[this_section]
this_section_pages << page
this_section_pages.sort_by! { |page| page.data["index"] || 100 }
page.data["section_pages"] = this_section_pages
section_names << this_section
end
end
section_names.compact!
section_names.uniq!
all_sections = []
section_names.each do |section_name|
all_sections << {
"name" => section_name,
"overview_page" => section_pages[section_name].first,
}
end
sorted_section_names = site.pages.find { |p| p.data["title"] == "Guides Index" }.data["sections"].map { |s| s["name"] }
all_sections.sort_by! { |s| sorted_section_names.index(s["name"]) }
site.data["all_sections"] = all_sections
end
module Jekyll
module Algolia
module Hooks
def self.before_indexing_each(record, node, context)
record = record.dup
record.delete(:section_pages)
record
end
end
end
end
graphql-ruby-2.2.17/guides/_sass/ 0000775 0000000 0000000 00000000000 14764346352 0016626 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/_sass/reset.scss 0000664 0000000 0000000 00000002102 14764346352 0020640 0 ustar 00root root 0000000 0000000 /* https://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
graphql-ruby-2.2.17/guides/_tasks/ 0000775 0000000 0000000 00000000000 14764346352 0017002 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/_tasks/site.rb 0000664 0000000 0000000 00000013737 14764346352 0020306 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require "yard"
require "webrick"
namespace :apidocs do
desc "Fetch a gem version from RubyGems, build the docs"
task :gen_version, [:version] do |t, args|
# GITHUB_REF comes from GitHub Actions
version = args[:version] || ENV["GITHUB_REF"] || raise("A version is required")
puts "Building docs for #{version}"
# GitHub Actions gives the full tag name
if version.start_with?("refs/tags/")
version = version[10..-1]
end
if version.start_with?("v")
version = version[1..-1]
end
Dir.mktmpdir do
puts "Fetching graphql-#{version}"
system("gem fetch graphql --version=#{version}")
system("gem unpack graphql-#{version}.gem")
system("rm graphql-#{version}.gem")
Dir.chdir("graphql-#{version}") do
# Copy it into gh-pages for publishing
# and locally for previewing
push_dest = File.expand_path("../gh-pages/api-doc/#{version}")
local_dest = File.expand_path("../guides/_site/api-doc/#{version}")
puts "Creating directories: #{push_dest.inspect}, #{local_dest.inspect}"
FileUtils.mkdir_p(push_dest)
FileUtils.mkdir_p(local_dest)
system("yardoc")
puts "Copying from #{Dir.pwd}/doc to #{push_dest}"
copy_entry "doc", push_dest
puts "Copying from #{Dir.pwd}/doc to #{local_dest}"
copy_entry "doc", local_dest
end
end
puts "Successfully generated docs for #{version}"
end
end
namespace :site do
desc "View the documentation site locally"
task serve: [] do # if you need api docs, add `:build_doc` to the list of dependencies
require "jekyll"
options = {
"source" => File.expand_path("guides"),
"destination" => File.expand_path("guides/_site"),
"watch" => true,
"serving" => true
}
# Generate the site in server mode.
puts "Running Jekyll..."
Jekyll::Commands::Build.process(options)
Jekyll::Commands::Serve.process(options)
end
desc "Get the gh-pages branch locally, make sure it's up-to-date"
task :fetch_latest do
# Ensure the gh-pages dir exists so we can generate into it.
puts "Checking for gh-pages dir..."
unless File.exist?("./gh-pages")
puts "Creating gh-pages dir..."
sh "git clone git@github.com:rmosolgo/graphql-ruby gh-pages"
end
# Ensure latest gh-pages branch history.
Dir.chdir("gh-pages") do
sh "git checkout gh-pages"
sh "git pull origin gh-pages"
end
end
desc "Remove all generated HTML (making space to re-generate)"
task :clean_html do
# Proceed to purge all files in case we removed a file in this release.
puts "Cleaning gh-pages directory..."
purge_exclude = [
'gh-pages/.',
'gh-pages/..',
'gh-pages/.git',
'gh-pages/.gitignore',
'gh-pages/api-doc',
]
FileList["gh-pages/{*,.*}"].exclude(*purge_exclude).each do |path|
sh "rm -rf #{path}"
end
end
desc "Build guides/ into gh-pages/ with Jekyll"
task :build_html do
# Copy site to gh-pages dir.
puts "Building site into gh-pages branch..."
ENV['JEKYLL_ENV'] = 'production'
require "jekyll"
Jekyll::Commands::Build.process({
"source" => File.expand_path("guides"),
"destination" => File.expand_path("gh-pages"),
"sass" => { "style" => "compressed" }
})
File.write('gh-pages/.nojekyll', "Prevent GitHub from running Jekyll")
end
desc "Commit new docs"
task :commit_changes do
puts "Committing and pushing to GitHub Pages..."
sha = `git rev-parse HEAD`.strip
Dir.chdir('gh-pages') do
system "git status"
system "git add ."
system "git status"
system "git commit --allow-empty -m 'Updating to #{sha}.'"
end
end
desc "Push docs to gh-pages branch"
task :push_commit do
Dir.chdir('gh-pages') do
sh "git push origin gh-pages"
end
end
desc "Commit the local site to the gh-pages branch and publish to GitHub Pages"
task publish: [:build_doc, :update_search_index, :fetch_latest, :clean_html, :build_html, :commit_changes, :push_commit]
YARD::Rake::YardocTask.new(:prepare_yardoc)
task build_doc: :prepare_yardoc do
require_relative "../../lib/graphql/version"
def to_rubydoc_url(path)
"/api-doc/#{GraphQL::VERSION}/" + path
.gsub("::", "/") # namespaces
.sub(/#(.+)$/, "#\\1-instance_method") # instance methods
.sub(/\.(.+)$/, "#\\1-class_method") # class methods
end
DOC_TEMPLATE = <<-PAGE
---
layout: doc_stub
search: true
title: %{title}
url: %{url}
rubydoc_url: %{url}
doc_stub: true
---
%{documentation}
PAGE
puts "Preparing YARD docs @ v#{GraphQL::VERSION} for search index..."
registry = YARD::Registry.load!(".yardoc")
files_target = "guides/yardoc"
FileUtils.rm_rf(files_target)
FileUtils.mkdir_p(files_target)
# Get docs for all classes and modules
docs = registry.all(:class, :module)
docs.each do |code_object|
begin
# Skip private classes and modules
if code_object.visibility == :private
next
end
rubydoc_url = to_rubydoc_url(code_object.path)
page_content = DOC_TEMPLATE % {
title: code_object.path,
url: rubydoc_url,
documentation: code_object.format.gsub(/-{2,}/, " ").gsub(/^\s+/, ""),
}
filename = code_object.path.gsub(/\W+/, "_")
filepath = "guides/yardoc/#{filename}.md"
File.write(filepath, page_content)
rescue StandardError => err
puts "Error on: #{code_object.path}"
puts err
puts err.backtrace
end
end
puts "Wrote #{docs.size} YARD docs to #{files_target}."
end
desc "Update the Algolia search index used for graphql-ruby.org"
task :update_search_index do
if !ENV["ALGOLIA_API_KEY"]
warn("Can't update search index without ALGOLIA_API_KEY; Search will be out-of-date.")
else
system("bundle exec jekyll algolia push --source=./guides")
end
end
end
graphql-ruby-2.2.17/guides/authorization/ 0000775 0000000 0000000 00000000000 14764346352 0020416 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/authorization/authorization.md 0000664 0000000 0000000 00000011303 14764346352 0023636 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Authorization
desc: During execution, check if the current user has permission to access retrieved objects.
index: 3
---
While a query is running, you can check each object to see whether the current user is authorized to interact with that object. If the user is _not_ authorized, you can handle the case with an error.
## Adding Authorization Checks
Schema members have `authorized?` methods which will be called during execution:
- Type classes have `.authorized?(object, context)` class methods
- Fields have `#authorized?(object, args, context)` instance methods
- Arguments have `#authorized?(object, arg_value, context)` instance methods
- Mutations and Resolvers have `.authorized?(object, context)` class methods and `#authorized?(args)` instance methods
These methods are called with:
- `object`: the object from your application which was returned from a field
- `args`/`arg_value`: The arguments for a field, or the value of an argument
- `context`: the query context, based on the hash passed as `context:`
#### Object Authorization
When you implement this method to return `false`, the query will be halted, for example:
```ruby
class Types::Friendship < Types::BaseObject
# You can only see the details on a `Friendship`
# if you're one of the people involved in it.
def self.authorized?(object, context)
super && (object.to_friend == context[:viewer] || object.from_friend == context[:viewer])
end
end
```
(Always call `super` to get the default checks, too.)
Now, whenever an object of type `Friendship` is going to be returned to the client, it will first go through the `.authorized?` method. If that method returns false, the field will get `nil` instead of the original object, and you may handle that case with an error (see below).
#### Field Authorization
Field `#authorized?` methods are called before resolving a field, for example:
```ruby
class Types::BaseField < GraphQL::Schema::Field
# Pass `field ..., require_admin: true` to reject non-admin users from a given field
def initialize(*args, require_admin: false, **kwargs, &block)
@require_admin = require_admin
super(*args, **kwargs, &block)
end
def authorized?(obj, args, ctx)
# if `require_admin:` was given, then require the current user to be an admin
super && (@require_admin ? ctx[:viewer]&.admin? : true)
end
end
```
For this to work, the base field class must be {% internal_link "configured with other GraphQL types", "/type_definitions/extensions.html#customizing-fields" %}.
#### Argument Authorization
Argument `#authorized?` hooks are called before resolving the field that the argument belongs to. For example:
```ruby
class Types::BaseArgument < GraphQL::Schema::Argument
def initialize(*args, require_logged_in: false, **kwargs, &block)
@require_logged_in = require_logged_in
super(*args, **kwargs, &block)
end
def authorized?(obj, arg_value, ctx)
super && if @require_logged_in
ctx[:viewer].present?
else
true
end
end
end
```
For this to work, the base argument class must be {% internal_link "configured with other GraphQL types", "/type_definitions/extensions.html#customizing-arguments" %}.
## Mutation Authorization
See mutations/mutation_authorization.html#can-this-user-perform-this-action {% internal_link "Mutation Authorization", "/mutations/mutation_authorization.html#can-this-user-perform-this-action" %}) in the Mutation Guides.
## Handling Unauthorized Objects
By default, GraphQL-Ruby silently replaces unauthorized objects with `nil`, as if they didn't exist. You can customize this behavior by implementing {{ "Schema.unauthorized_object" | api_doc }} in your schema class, for example:
```ruby
class MySchema < GraphQL::Schema
# Override this hook to handle cases when `authorized?` returns false for an object:
def self.unauthorized_object(error)
# Add a top-level error to the response instead of returning nil:
raise GraphQL::ExecutionError, "An object of type #{error.type.graphql_name} was hidden due to permissions"
end
end
```
Now, the custom hook will be called instead of the default one.
If `.unauthorized_object` returns a non-`nil` object (and doesn't `raise` an error), then that object will be used in place of the unauthorized object.
A similar hook is available for unauthorized fields:
```ruby
class MySchema < GraphQL::Schema
# Override this hook to handle cases when `authorized?` returns false for a field:
def self.unauthorized_field(error)
# Add a top-level error to the response instead of returning nil:
raise GraphQL::ExecutionError, "The field #{error.field.graphql_name} on an object of type #{error.type.graphql_name} was hidden due to permissions"
end
end
```
graphql-ruby-2.2.17/guides/authorization/can_can_integration.md 0000664 0000000 0000000 00000030126 14764346352 0024727 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: CanCan Integration
desc: Hook up GraphQL to CanCan abilities
index: 4
pro: true
---
[GraphQL::Pro](https://graphql.pro) includes an integration for powering GraphQL authorization with [CanCan](https://github.com/CanCanCommunity/cancancan).
__Why bother?__ You _could_ put your authorization code in your GraphQL types themselves, but writing a separate authorization layer gives you a few advantages:
- Since the authorization code isn't embedded in GraphQL, you can use the same logic in non-GraphQL (or legacy) parts of the app.
- The authorization logic can be tested in isolation, so your end-to-end GraphQL tests don't have to cover as many possibilities.
## Getting Started
__NOTE__: Requires the latest gems, so make sure your `Gemfile` has:
```ruby
# For CanCanIntegration:
gem "graphql-pro", ">=1.7.11"
# For list scoping:
gem "graphql", ">=1.8.7"
```
Then, `bundle install`.
Whenever you run queries, include `:current_user` in the context:
```ruby
context = {
current_user: current_user,
# ...
}
MySchema.execute(..., context: context)
```
## Authorizing Objects
For each object type, you can assign a required action for Ruby objects of that type. To get started, include the `ObjectIntegration` in your base object class:
```ruby
# app/graphql/types/base_object.rb
class Types::BaseObject < GraphQL::Schema::Object
# Add the CanCan integration:
include GraphQL::Pro::CanCanIntegration::ObjectIntegration
# By default, require `can :read, ...`
can_can_action(:read)
# Or, to require no permissions by default:
# can_can_action(nil)
end
```
Now, anyone fetching an object will need `can :read, ...` for that object.
CanCan configurations are inherited, and can be overridden in subclasses. For example, to allow _all_ viewers to see the `Query` root type:
```ruby
class Types::Query < Types::BaseObject
# Allow anyone to see the query root
can_can_action nil
end
```
### Bypassing CanCan
`can_can_action(nil)` will override any inherited configuration and skip CanCan checks for an object, field, argument or mutation.
### Handling Unauthorized Objects
When any CanCan check returns `false`, the unauthorized object is passed to {{ "Schema.unauthorized_object" | api_doc }}, as described in {% internal_link "Handling unauthorized objects", "/authorization/authorization#handling-unauthorized-objects" %}.
## Scopes
#### ActiveRecord::Relation
The CanCan integration adds [CanCan's `.accessible_by`](https://github.com/cancancommunity/cancancan/wiki/Fetching-Records) to GraphQL-Ruby's {% internal_link "list scoping", "/authorization/scoping" %}
To scope lists of interface or union type, include the integration in your base union class and base interface module _and_ set a base `can_can_action`, if desired:
```ruby
class BaseUnion < GraphQL::Schema::Union
include GraphQL::Pro::CanCanIntegration::UnionIntegration
# To provide a default action for scoping lists:
can_can_action :read
end
module BaseInterface
include GraphQL::Schema::Interface
include GraphQL::Pro::CanCanIntegration::InterfaceIntegration
# To provide a default action for scoping lists:
can_can_action :read
end
```
#### Array
For Arrays, the CanCan integration will use `.select { ... }` to filter items using the `can_can_action` from the lists's type.
#### Bypassing scopes
To allow an unscoped relation to be returned from a field, disable scoping with `scope: false`, for example:
```ruby
# Allow anyone to browse the job postings
field :job_postings, [Types::JobPosting], null: false,
scope: false
```
## Authorizing Fields
You can also require certain checks on a field-by-field basis. First, include the integration in your base field class:
```ruby
# app/graphql/types/base_field.rb
class Types::BaseField < GraphQL::Schema::Field
# Add the CanCan integration:
include GraphQL::Pro::CanCanIntegration::FieldIntegration
# By default, don't require a role at field-level:
can_can_action nil
end
```
If you haven't already done so, you should also hook up your base field class to your base object and base interface:
```ruby
# app/graphql/types/base_object.rb
class Types::BaseObject < GraphQL::Schema::Object
field_class Types::BaseField
end
# app/graphql/types/base_interface.rb
module Types::BaseInterface
# ...
field_class Types::BaseField
end
# app/graphql/mutations/base_mutation.rb
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
field_class Types::BaseField
end
```
Then, you can add `can_can_action:` options to your fields:
```ruby
class Types::JobPosting < Types::BaseObject
# Only allow `can :review_applications, JobPosting` users
# to see who has applied
field :applicants, [Types::User],
can_can_action: :review_applicants
end
```
It will require the named action (`:review_applicants`) for the object being viewed (a `JobPosting`).
### Authorizing by attribute
CanCan 3.0 added attribute-level authorization ([pull request](https://github.com/CanCanCommunity/cancancan/pull/474)). You can leverage this in your field definitions with the `can_can_attribute:` configuration:
```ruby
# This will call `.can?(:read, user, :email_address)`
field :email_address, String,
can_can_action: :read,
can_can_attribute: :email_address
```
You could also provide a _default value_ for `can_can_attribute` in your base field class:
```ruby
class Types::BaseField
def initialize(*args, **kwargs, &block)
# pass all configs to the super class:
super
# Then set a new `can_can_attribute` value, if applicable
if can_can_attribute.nil? && can_can_action.present?
# `method_sym` is the thing GraphQL-Ruby will use to resolve this field
can_can_attribute(method_sym)
end
end
end
```
(See {{ "GraphQL::Schema::Field" | api_doc }} for the different values available for defaults.)
### Providing a Custom CanCan Subject
Authorization checks are _skipped_ whenever the underlying `object` is `nil`. This can happen in root query fields, for example, when no `root_value: ...` is given. To provide a `can_can_subject` in this case, you can add it as a field configuration:
```ruby
field :users, Types::User.connection_type, null: false,
can_can_action: :manage,
# `:all` will be used instead of `object` (which is `nil`)
can_can_subject: :all
```
The configuration above will call `can?(:manage, :all)` whenever that field is requested.
## Authorizing Arguments
Similar to field-level checks, you can require certain permissions to _use_ certain arguments. To do this, add the integration to your base argument class:
```ruby
class Types::BaseArgument < GraphQL::Schema::Argument
# Include the integration and default to no permissions required
include GraphQL::Pro::CanCanIntegration::ArgumentIntegration
can_can_action nil
end
```
Then, make sure your base argument is hooked up to your base field and base input object:
```ruby
class Types::BaseField < GraphQL::Schema::Field
argument_class Types::BaseArgument
# PS: see "Authorizing Fields" to make sure your base field is hooked up to objects, interfaces and mutations
end
class Types::BaseInputObject < GraphQL::Schema::InputObject
argument_class Types::BaseArgument
end
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
argument_class Types::BaseArgument
end
```
Now, arguments accept a `can_can_action:` option, for example:
```ruby
class Types::Company < Types::BaseObject
field :employees, Types::Employee.connection_type do
# Only admins can filter employees by email:
argument :email, String, required: false, can_can_action: :admin
end
end
```
This will check for `can :admin, Company` (or a similar rule for the `company` being queried) for the current user.
## Authorizing Mutations
There are a few ways to authorize GraphQL mutations with the CanCan integration:
- Add a [mutation-level roles](#mutation-level-roles)
- Run checks on [objects loaded by ID](#authorizing-loaded-objects)
Also, you can configure [unauthorized object handling](#unauthorized-mutations)
#### Setup
Add `MutationIntegration` to your base mutation, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
include GraphQL::Pro::CanCanIntegration::MutationIntegration
# Also, to use argument-level authorization:
argument_class Types::BaseArgument
end
```
Also, you'll probably want a `BaseMutationPayload` where you can set a default role:
```ruby
class Types::BaseMutationPayload < Types::BaseObject
# If `BaseObject` requires some permissions, override that for mutation results.
# Assume that anyone who can run a mutation can read their generated result types.
can_can_action nil
end
```
And hook it up to your base mutation:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
object_class Types::BaseMutationPayload
field_class Types::BaseField
end
```
#### Mutation-level roles
Each mutation can have a class-level `can_can_action` which will be checked before loading objects or resolving, for example:
```ruby
class Mutations::PromoteEmployee < Mutations::BaseMutation
can_can_action :run_mutation
end
```
In the example above, `can :run_mutation, Mutations::PromoteEmployee` will be checked before running the mutation. (The currently-running instance of `Mutations::PromoteEmployee` is passed to the ability checker.)
#### Authorizing Loaded Objects
Mutations can automatically load and authorize objects by ID using the `loads:` option.
Beyond the normal [object reading permissions](#authorizing-objects), you can add an additional role for the specific mutation input using a `can_can_action:` option:
```ruby
class Mutations::FireEmployee < Mutations::BaseMutation
argument :employee_id, ID,
loads: Types::Employee,
can_can_action: :supervise,
end
```
In the case above, the mutation will halt unless the `can :supervise, ...` check returns true. (The fetched instance of `Employee` is passed to the ability checker.)
#### Unauthorized Mutations
By default, an authorization failure in a mutation will raise a Ruby exception. You can customize this by implementing `#unauthorized_by_can_can(owner, value)` in your base mutation, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
def unauthorized_by_can_can(owner, value)
# No error, just return nil:
nil
end
end
```
The method is called with:
- `owner`: the `GraphQL::Schema::Argument` instance or mutation class whose role was not satisfied
- `value`: the object which didn't pass for `context[:current_user]`
Since it's a mutation method, you can also access `context` in that method.
Whatever that method returns will be treated as an early return value for the mutation, so for example, you could return {% internal_link "errors as data", "/mutations/mutation_errors" %}:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
field :errors, [String]
def unauthorized_by_can_can(owner, value)
# Return errors as data:
{ errors: ["Missing required permission: #{owner.can_can_action}, can't access #{value.inspect}"] }
end
end
```
## Authorizing Resolvers
Resolvers are authorized just like [mutations](#authorizing-mutations), and require similar setup:
```ruby
# app/graphql/resolvers/base_resolver.rb
class Resolvers::BaseResolver < GraphQL::Schema::Resolver
include GraphQL::Pro::CanCanIntegration::ResolverIntegration
argument_class BaseArgument
# can_can_action(nil) # to disable authorization by default
end
```
Beyond that, see [Authorizing Mutations](#authorizing-mutations) above for further details.
## Custom Abilities Class
By default, the integration will look for a top-level `::Ability` class.
If you're using a different class, provide an instance ahead-of-time as `context[:can_can_ability]`
For example, you could _always_ add one in your schema's `#execute` method:
```ruby
class MySchema < GraphQL::Schema
# Override `execute` to provide a custom Abilities instance for the CanCan integration
def self.execute(*args, context: {}, **kwargs)
# Assign `context[:can_can_ability]` to an instance of our custom class
context[:can_can_ability] = MyAuthorization::CustomAbilitiesClass.new(context[:current_user])
super
end
end
```
graphql-ruby-2.2.17/guides/authorization/overview.md 0000664 0000000 0000000 00000013645 14764346352 0022617 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Overview
desc: Overview of GraphQL authorization in general and an intro to the built-in framework.
index: 0
---
Here's a conceptual approach to GraphQL authorization, followed by an introduction to the built-in authorization framework. Each part of the framework is described in detail in its own guide.
## Authorization: GraphQL vs REST
In a REST API, the common authorization pattern is fairly simple. Before performing the requested action, the server asserts that the current client has the required permissions for that action. For example:
```ruby
class PostsController < ApiController
def create
# First, check the client's permission level:
if current_user.can?(:create_posts)
# If the user is permitted, then perform the action:
post = Post.create(params)
render json: post
else
# Otherwise, return an error:
render nothing: true, status: 403
end
end
end
```
However, this request-by-request mindset doesn't map well to GraphQL because there's only one controller and the requests that come to it may be _very_ different. To illustrate the problem:
```ruby
class GraphqlController < ApplicationController
def execute
# What permission is required for `query_str`?
# It depends on the string! So, you can't generalize at this level.
if current_user.can?(:"???")
MySchema.execute(query_str, context: ctx, variables: variables)
end
end
end
```
So, what new mindset will work with a GraphQL API?
For __mutations__, remember that each mutation is like an API request in itself. For example, `Posts#create` above would map to the `createPost(...)` mutation in GraphQL. So, each mutation should be authorized in its own right.
For __queries__, you can think of each individual _object_ like a `GET` request to a REST API. So, each object should be authorized for reading in its own right.
By applying this mindset, each part of the GraphQL query will be properly authorized before it is executed. Also, since the different units of code are each authorized on their own, you can be sure that each incoming query will be properly authorized, even if it's a brand new query that the server has never seen before.
## What About Authentication?
As a reminder:
- _Authentication_ is the process of determining what user is making the current request, for example, accepting a username and password, or finding a `User` in the database from `session[:current_user_id]`.
- _Authorization_ is the process of verifying that the current user has permission to do something (or see something), for example, checking `admin?` status or looking up permission groups from the database.
In general, authentication is _not_ addressed in GraphQL at all. Instead, your controller should get the current user based on the HTTP request (eg, an HTTP header or a cookie) and provide that information to the GraphQL query. For example:
```ruby
class GraphqlController < ApplicationController
def execute
# Somehow get the current `User` from this HTTP request.
current_user = get_logged_in_user(request)
# Provide the current user in `context` for use during the query
context = { current_user: current_user }
MySchema.execute(query_str, context: context, ...)
end
end
```
After your HTTP handler has loaded the current user, you can access it via `context[:current_user]` in your GraphQL code.
## Authorization in Your Business Logic
Before introducing GraphQL-specific authorization, consider the advantages of application-level authorization. (See the [GraphQL.org post](https://graphql.org/learn/authorization/) on the same topic.) For example, here's authorization mixed into the GraphQL API layer:
```ruby
field :posts, [Types::Post], null: false
def posts
# Perform an auth check in the GraphQL field code:
if context[:current_user].admin?
Post.all
else
Post.published
end
end
```
The downside of this is that, when `Types::Post` is queried in other contexts, the same authorization check may not be applied. Additionally, since the authorization code is coupled with the GraphQL API, the only way to test it is via GraphQL queries, which adds some complexity to tests.
Alternatively, you could move the authorization to your business logic, the `Post` class:
```ruby
class Post < ActiveRecord::Base
# Return the list of posts which `user` may see
def self.posts_for(user)
if user.admin?
self.all
else
self.published
end
end
end
```
Then, use this application method in your GraphQL code:
```ruby
field :posts, [Types::Post], null: false
def posts
# Fetch the posts this user can see:
Post.posts_for(context[:current_user])
end
```
In this case, `Post.posts_for(user)` could be tested _independently_ from GraphQL. Then, you have less to worry about in your GraphQL tests. As a bonus, you can use `Post.posts_for(user)` in _other_ parts of the app, too, such as the web UI or REST API.
## GraphQL-Ruby's Authorization Framework
Despite the advantages of authorization at the application layer, as described above, there might be some reasons to authorize in the API layer:
- Have an extra assurance that your API layer is secure
- Authorize the API request _before_ running it (see "visibility" below)
- Integrate with code that doesn't have authorization built-in
To accomplish these, you can use GraphQL-Ruby's authorization framework. The framework has three levels, each of which is described in its own guide:
- {% internal_link "Visibility", "/authorization/visibility" %} hides parts of the GraphQL schema from users who don't have full permission.
- {% internal_link "Authorization", "/authorization/authorization" %} checks application objects during execution to be sure the user has permission to access them.
Also, [GraphQL::Pro](https://graphql.pro) has integrations for {% internal_link "CanCan", "/authorization/can_can_integration" %} and {% internal_link "Pundit", "/authorization/pundit_integration" %}.
graphql-ruby-2.2.17/guides/authorization/pundit_integration.md 0000664 0000000 0000000 00000037054 14764346352 0024657 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Pundit Integration
desc: Hook up GraphQL to Pundit policies
index: 4
pro: true
---
[GraphQL::Pro](https://graphql.pro) includes an integration for powering GraphQL authorization with [Pundit](https://github.com/varvet/pundit) policies.
__Why bother?__ You _could_ put your authorization code in your GraphQL types themselves, but writing a separate authorization layer gives you a few advantages:
- Since the authorization code isn't embedded in GraphQL, you can use the same logic in non-GraphQL (or legacy) parts of the app.
- The authorization logic can be tested in isolation, so your end-to-end GraphQL tests don't have to cover as many possibilities.
## Getting Started
__NOTE__: Requires the latest gems, so make sure your `Gemfile` has:
```ruby
# For PunditIntegration:
gem "graphql-pro", ">=1.7.9"
# For list scoping:
gem "graphql", ">=1.8.7"
```
Then, `bundle install`.
Whenever you run queries, include `:current_user` in the context:
```ruby
context = {
current_user: current_user,
# ...
}
MySchema.execute(..., context: context)
```
## Authorizing Objects
You can specify Pundit roles that must be satisfied in order for viewers to see objects of a certain type. To get started, include the `ObjectIntegration` in your base object class:
```ruby
# app/graphql/types/base_object.rb
class Types::BaseObject < GraphQL::Schema::Object
# Add the Pundit integration:
include GraphQL::Pro::PunditIntegration::ObjectIntegration
# By default, require staff:
pundit_role :staff
# Or, to require no permissions by default:
# pundit_role nil
end
```
Now, anyone trying to read a GraphQL object will have to pass the `#staff?` check on that object's policy.
Then, each child class can override that parent configuration. For example, allow _all_ viewers to read the `Query` root:
```ruby
class Types::Query < Types::BaseObject
# Allow anyone to see the query root
pundit_role nil
end
```
#### Policies and Methods
For each object returned by GraphQL, the integration matches it to a policy and method.
The policy is found using [`Pundit.policy!`](https://www.rubydoc.info/gems/pundit/Pundit%2Epolicy!), which looks up a policy using the object's class name. (This can be customized, see below.)
Then, GraphQL will call a method on the policy to see whether the object is permitted or not. This method is assigned in the object class, for example:
```ruby
class Types::Employee < Types::BaseObject
# Only show employee objects to their bosses,
# or when that employee is the current viewer
pundit_role :employer_or_self
# ...
end
```
That configuration will call `#employer_or_self?` on the corresponding Pundit policy.
#### Custom Policy Class
By default, the integration uses `Pundit.policy!(current_user, object)` to find a policy. You can specify a policy class using `pundit_policy_class(...)`:
```ruby
class Types::Employee < Types::BaseObject
pundit_policy_class(Policies::CustomEmployeePolicy)
# Or, you could use a string:
# pundit_policy_class("Policies::CustomEmployeePolicy")
end
```
For really custom policy lookup, see [Custom Policy Lookup](#custom-policy-lookup) below.
#### Bypassing Policies
The integration requires that every object with a `pundit_role` has a corresponding policy class. To allow objects to _skip_ authorization, you can pass `nil` as the role:
```ruby
class Types::PublicProfile < Types::BaseObject
# Anyone can see this
pundit_role nil
end
```
#### Handling Unauthorized Objects
When any Policy method returns `false`, the unauthorized object is passed to {{ "Schema.unauthorized_object" | api_doc }}, as described in {% internal_link "Handling unauthorized objects", "/authorization/authorization#handling-unauthorized-objects" %}.
## Scopes
The Pundit integration adds [Pundit scopes](https://github.com/varvet/pundit#scopes) to GraphQL-Ruby's {% internal_link "list scoping", "/authorization/scoping" %} feature. Any list or connection will be scoped. If a scope is missing, the query will crash rather than risk leaking unfiltered data.
To scope lists of interface or union type, include the integration in your base union class and base interface module:
```ruby
class BaseUnion < GraphQL::Schema::Union
include GraphQL::Pro::PunditIntegration::UnionIntegration
end
module BaseInterface
include GraphQL::Schema::Interface
include GraphQL::Pro::PunditIntegration::InterfaceIntegration
end
```
#### Bypassing scopes
To allow an unscoped relation to be returned from a field, disable scoping with `scope: false`, for example:
```ruby
# Allow anyone to browse the job postings
field :job_postings, [Types::JobPosting], null: false,
scope: false
```
## Authorizing Fields
You can also require certain checks on a field-by-field basis. First, include the integration in your base field class:
```ruby
# app/graphql/types/base_field.rb
class Types::BaseField < GraphQL::Schema::Field
# Add the Pundit integration:
include GraphQL::Pro::PunditIntegration::FieldIntegration
# By default, don't require a role at field-level:
pundit_role nil
end
```
If you haven't already done so, you should also hook up your base field class to your base object and base interface:
```ruby
# app/graphql/types/base_object.rb
class Types::BaseObject < GraphQL::Schema::Object
field_class Types::BaseField
end
# app/graphql/types/base_interface.rb
module Types::BaseInterface
# ...
field_class Types::BaseField
end
# app/graphql/mutations/base_mutation.rb
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
field_class Types::BaseField
end
```
Then, you can add `pundit_role:` options to your fields:
```ruby
class Types::JobPosting < Types::BaseObject
# Allow signed-in users to browse listings
pundit_role :signed_in
# But, only allow `JobPostingPolicy#staff?` users to see
# who has applied
field :applicants, [Types::User],
pundit_role: :staff
end
```
It will call the named role (eg, `#staff?`) on the parent object's policy (eg `JobPostingPolicy`).
#### Custom Policy Class
You can override the policy class for a field using `pundit_policy_class:`, for example:
```ruby
class Types::JobPosting < Types::BaseObject
# Only allow `ApplicantsPolicy#staff?` users to see
# who has applied
field :applicants, [Types::User],
pundit_role: :staff,
pundit_policy_class: ApplicantsPolicy
# Or with a string:
# pundit_policy_class: "ApplicantsPolicy"
end
```
This will initialize an `ApplicantsPolicy` with the parent object (a `Job`) and call `#staff?` on it.
For really custom policy lookup, see [Custom Policy Lookup](#custom-policy-lookup) below.
## Authorizing Arguments
Similar to field-level checks, you can require certain permissions to _use_ certain arguments. To do this, add the integration to your base argument class:
```ruby
class Types::BaseArgument < GraphQL::Schema::Argument
# Include the integration and default to no permissions required
include GraphQL::Pro::PunditIntegration::ArgumentIntegration
pundit_role nil
end
```
Then, make sure your base argument is hooked up to your base field and base input object:
```ruby
class Types::BaseField < GraphQL::Schema::Field
argument_class Types::BaseArgument
# PS: see "Authorizing Fields" to make sure your base field is hooked up to objects, interfaces and mutations
end
class Types::BaseInputObject < GraphQL::Schema::InputObject
argument_class Types::BaseArgument
end
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
argument_class Types::BaseArgument
end
```
Now, arguments accept a `pundit_role:` option, for example:
```ruby
class Types::Company < Types::BaseObject
field :employees, Types::Employee.connection_type do
# Only admins can filter employees by email:
argument :email, String, required: false, pundit_role: :admin
end
end
```
The role will be called on the parent object's policy, for example `CompanyPolicy#admin?` in the case above.
## Authorizing Mutations
There are a few ways to authorize GraphQL mutations with the Pundit integration:
- Add a [mutation-level roles](#mutation-level-roles)
- Run checks on [objects loaded by ID](#authorizing-loaded-objects)
Also, you can configure [unauthorized object handling](#unauthorized-mutations)
#### Setup
Add `MutationIntegration` to your base mutation, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
include GraphQL::Pro::PunditIntegration::MutationIntegration
# Also, to use argument-level authorization:
argument_class Types::BaseArgument
end
```
Also, you'll probably want a `BaseMutationPayload` where you can set a default role:
```ruby
class Types::BaseMutationPayload < Types::BaseObject
# If `BaseObject` requires some permissions, override that for mutation results.
# Assume that anyone who can run a mutation can read their generated result types.
pundit_role nil
end
```
And hook it up to your base mutation:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
object_class Types::BaseMutationPayload
field_class Types::BaseField
end
```
#### Mutation-level roles
Each mutation can have a class-level `pundit_role` which will be checked before loading objects or resolving, for example:
```ruby
class Mutations::PromoteEmployee < Mutations::BaseMutation
pundit_role :admin
end
```
In the example above, `PromoteEmployeePolicy#admin?` will be checked before running the mutation.
#### Custom Policy Class
By default, Pundit uses the mutation's class name to look up a policy. You can override this by defining `pundit_policy_class` on your mutation:
```ruby
class Mutations::PromoteEmployee < Mutations::BaseMutation
pundit_policy_class ::UserPolicy
pundit_role :admin
end
```
Now, the mutation will check `UserPolicy#admin?` before running.
For really custom policy lookup, see [Custom Policy Lookup](#custom-policy-lookup) below.
#### Authorizing Loaded Objects
Mutations can automatically load and authorize objects by ID using the `loads:` option.
Beyond the normal [object reading permissions](#authorizing-objects), you can add an additional role for the specific mutation input using a `pundit_role:` option:
```ruby
class Mutations::FireEmployee < Mutations::BaseMutation
argument :employee_id, ID,
loads: Types::Employee,
pundit_role: :supervisor,
end
```
In the case above, the mutation will halt unless the `EmployeePolicy#supervisor?` method returns true.
#### Unauthorized Mutations
By default, an authorization failure in a mutation will raise a Ruby exception. You can customize this by implementing `#unauthorized_by_pundit(owner, value)` in your base mutation, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
def unauthorized_by_pundit(owner, value)
# No error, just return nil:
nil
end
end
```
The method is called with:
- `owner`: the `GraphQL::Schema::Argument` or mutation class whose role was not satisfied
- `value`: the object which didn't pass for `context[:current_user]`
Since it's a mutation method, you can also access `context` in that method.
Whatever that method returns will be treated as an early return value for the mutation, so for example, you could return {% internal_link "errors as data", "/mutations/mutation_errors" %}:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
field :errors, [String]
def unauthorized_by_pundit(owner, value)
# Return errors as data:
{ errors: ["Missing required permission: #{owner.pundit_role}, can't access #{value.inspect}"] }
end
end
```
## Authorizing Resolvers
Resolvers are authorized just like [mutations](#authorizing-mutations), and require similar setup:
```ruby
# app/graphql/resolvers/base_resolver.rb
class Resolvers::BaseResolver < GraphQL::Schema::Resolver
include GraphQL::Pro::PunditIntegration::ResolverIntegration
argument_class BaseArgument
# pundit_role nil # to disable authorization by default
end
```
Beyond that, see [Authorizing Mutations](#authorizing-mutations) above for further details.
## Custom Policy Lookup
By default, the integration uses `Pundit`'s top-level methods to interact with policies:
- `Pundit.policy!(context[:current_user], object)` is called to find a policy instance
- `Pundit.policy_scope!(context[:current_user], items)` is called to filter `items`
### Custom Policy Methods
You can implement a custom lookup by defining the following methods in your schema:
- `pundit_policy_class_for(object, context)` to return a policy class (or raise an error if one isn't found)
- `pundit_role_for(object, context)` to return a role method (Symbol), or `nil` to bypass authorization
- `scope_by_pundit_policy(context, items)` to apply a scope to `items` (or raise an error if one isn't found)
Since different objects have different lifecycles, the hooks are installed slightly different ways:
- Your base argument, field, and mutation classes should have _instance methods_ with those names
- Your base type classes should have _class methods_ with that name
Here's an example of how the custom hooks can be installed:
```ruby
module CustomPolicyLookup
# Lookup policies in the `SystemAdmin::` namespace for system_admin users
# @return [Class]
def pundit_policy_class_for(object, context)
current_user = context[:current_user]
if current_user.system_admin?
SystemAdmin.const_get("#{object.class.name}Policy")
else
super
end
end
# Require admin permissions if the object is pending_approval
def pundit_role_for(object, context)
if object.pending_approval?
:admin
else
super # fall back to the normally-configured role
end
end
end
# Add policy hooks as class methods
class Types::BaseObject < GraphQL::Schema::Object
extend CustomPolicyLookup
end
class Types::BaseUnion < GraphQL::Schema::Union
extend CustomPolicyLookup
end
module Types::BaseInterface
include GraphQL::Schema::Interface
# Add this as a class method that will be "inherited" by other interfaces:
definition_methods do
include CustomPolicyLookup
end
end
# Add policy hooks as instance methods
class Types::BaseField < GraphQL::Schema::Field
include CustomPolicyLookup
end
class Types::BaseArgument < GraphQL::Schema::Argument
include CustomPolicyLookup
end
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
include CustomPolicyLookup
end
```
### One Policy Per Class
Another good approach is to have one policy per class. You can implement `policy_class_for(object, context)` to look up a policy _within_ the class, for example:
```ruby
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
def policy_class_for(_object, _context)
# Look up a nested `Policy` constant:
self.class.const_get(:Policy)
end
end
```
Then, each mutation can define its policy inline, for example:
```ruby
class Mutations::PromoteEmployee < Mutations::BaseMutation
# This will be found by `BaseMutation.policy_class`, defined above:
class Policy
# ...
end
pundit_role :admin
end
```
Now, `Mutations::PromoteEmployee::Policy#admin?` will be checked before running the mutation.
## Custom User Lookup
By default, the Pundit integration looks for the current user in `context[:current_user]`. You can override this by implementing `#pundit_user` on your custom query context class. For example:
```ruby
# app/graphql/query_context.rb
class QueryContext < GraphQL::Query::Context
def pundit_user
# Lookup `context[:viewer]` instead:
self[:viewer]
end
end
```
Then be sure to hook up your custom class in the schema:
```ruby
class MySchema < GraphQL::Schema
context_class(QueryContext)
end
```
Then, the Pundit integration will use your `def pundit_user` to get the current user at runtime.
graphql-ruby-2.2.17/guides/authorization/scoping.md 0000664 0000000 0000000 00000004265 14764346352 0022411 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Scoping
desc: Filter lists to match the current viewer and context
index: 4
---
_Scoping_ is a complementary consideration to authorization. Rather than checking "can this user see this thing?", scoping takes a list of items filters it to the subset which is appropriate for the current viewer and context.
For similar features, see [Pundit scopes](https://github.com/varvet/pundit#scopes) and [Cancan's `.accessible_by`](https://github.com/cancancommunity/cancancan/wiki/Fetching-Records).
## `scope:` option
Fields accept a `scope:` option to enable (or disable) scoping, for example:
```ruby
field :products, [Types::Product], scope: true
# Or
field :all_products, [Types::Product], scope: false
```
For __list__ and __connection__ fields, `scope: true` is the default. For all other fields, `scope: false` is the default. You can override this by using the `scope:` option.
## `.scope_items(items, ctx)` method
Type classes may implement `.scope_items(items, ctx)`. This method is called when a field has `scope: true`. For example,
```ruby
field :products, [Types::Product] # has `scope: true` by default
```
Will call:
```ruby
class Types::Product < Types::BaseObject
def self.scope_items(items, context)
# filter items here
end
end
```
The method should return a new list with only the appropriate items for the current `context`.
## Bypassing object-level authorization
If you know that any items returned from `.scope_items` should be visible to the current client, you can skip the normal `.authorized?(obj, ctx)` checks by configuring `reauthorize_scoped_objects(false)` in your type definition. For example:
```ruby
class Types::Product < Types::BaseObject
# Check that singly-loaded objects are visible to the current viewer
def self.authorized?(object, context)
object.visible_to?(context[:viewer])
end
# Filter any list to only include objects that are visible to the current viewer
def self.scope_items(items, context)
items.visible_for(context[:viewer])
end
# If an object of this type was returned from `.scope_items`,
# don't call `.authorized?` with it.
reauthorize_scoped_objects(false)
end
```
graphql-ruby-2.2.17/guides/authorization/visibility.md 0000664 0000000 0000000 00000007555 14764346352 0023143 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Authorization
title: Visibility
desc: Programatically hide parts of the GraphQL schema from some users.
index: 1
redirect_from:
- /schema/limiting_visibility
---
With GraphQL-Ruby, it's possible to _hide_ parts of your schema from some users. This isn't exactly part of the GraphQL spec, but it's roughly within the bounds of the spec.
Here are some reasons you might want to hide parts of your schema:
- You don't want non-admin users to know about administration functions of the schema.
- You're developing a new feature and want to make a gradual release to only a few users first.
## Hiding Parts of the Schema
You can customize the visibility of parts of your schema by reimplementing various `visible?` methods:
- Type classes have a `.visible?(context)` class method
- Fields and arguments have a `#visible?(context)` instance method
- Enum values have `#visible?(context)` instance method
- Mutation classes have a `.visible?(context)` class method
These methods are called with the query context, based on the hash you pass as `context:`. If the method returns false, then that member of the schema will be treated as though it doesn't exist for the entirety of the query. That is:
- In introspection, the member will _not_ be included in the result
- In normal queries, if a query references that member, it will return a validation error, since that member doesn't exist
## Object Visibility
Let's say you're working on a new feature which should remain secret for a while. You can implement `.visible?` in a type:
```ruby
class Types::SecretFeature < Types::BaseObject
def self.visible?(context)
# only show it to users with the secret_feature enabled
super && context[:viewer].feature_enabled?(:secret_feature)
end
end
```
(Always call `super` to inherit the default behavior.)
Now, the following bits of GraphQL will return validation errors:
- Fields that return `SecretFeature`, eg `query { findSecretFeature { ... } }`
- Fragments on `SecretFeature`, eg `Fragment SF on SecretFeature`
And in introspection:
- `__schema { types { ... } }` will not include `SecretFeature`
- `__type(name: "SecretFeature")` will return `nil`
- Any interfaces or unions which normally include `SecretFeature` will _not_ include it
- Any fields that return `SecretFeature` will be excluded from introspection
## Field Visibility
```ruby
class Types::BaseField < GraphQL::Schema::Field
# Pass `field ..., require_admin: true` to hide this field from non-admin users
def initialize(*args, require_admin: false, **kwargs, &block)
@require_admin = require_admin
super(*args, **kwargs, &block)
end
def visible?(ctx)
# if `require_admin:` was given, then require the current user to be an admin
super && (@require_admin ? ctx[:viewer]&.admin? : true)
end
end
```
For this to work, the base field class must be {% internal_link "configured with other GraphQL types", "/type_definitions/extensions.html#customizing-fields" %}.
## Argument Visibility
```ruby
class Types::BaseArgument < GraphQL::Schema::Argument
# If `require_logged_in: true` is given, then this argument will be hidden from logged-out viewers
def initialize(*args, require_logged_in: false, **kwargs, &block)
@require_logged_in = require_logged_in
super(*args, **kwargs, &block)
end
def visible?(ctx)
super && (@require_logged_in ? ctx[:viewer].present? : true)
end
end
```
For this to work, the base argument class must be {% internal_link "configured with other GraphQL types", "/type_definitions/extensions.html#customizing-arguments" %}.
## Opting Out
By default, GraphQL-Ruby always runs visibility checks. You can opt out of this by adding to your schema class:
```ruby
class MySchema < GraphQL::Schema
# ...
# Opt out of GraphQL-Ruby's visibility feature:
use GraphQL::Schema::AlwaysVisible
end
```
For big schemas, this can be a worthwhile speed-up.
graphql-ruby-2.2.17/guides/changesets/ 0000775 0000000 0000000 00000000000 14764346352 0017642 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/changesets/definition.md 0000664 0000000 0000000 00000030052 14764346352 0022314 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
enterprise: true
section: GraphQL Enterprise - Changesets
title: Defining Changesets
desc: Creating a set of modifications to release in an API version
index: 2
---
After {% internal_link "installing Changeset integrations", "/changesets/installation" %} in your schema, you can create Changesets which modify parts of the schema. Changesets extend `GraphQL::Enterprise::Changeset` and include a `release` string. Once a Changeset class is defined, it can be referenced with `added_in: ...` or `removed_in: ...` configurations in the schema.
__Note:__ Before GraphQL-Enterprise 1.3.0, Changesets were configured with `modifies ...` blocks. These blocks are still supported and you can find the documentation for that API [on GitHub](https://github.com/rmosolgo/graphql-ruby/blob/v2.0.22/guides/changesets/definition.md).
## Changeset Classes
This Changeset will be available to any client whose `context[:changeset_version]` is on or after `2020-12-01`:
```ruby
# app/graphql/changesets/deprecate_recipe_flag.rb
class Changesets::DeprecateRecipeTags < GraphQL::Enterprise::Changeset
release "2020-12-01"
end
```
Additionally, Changesets must be {% internal_link "released", "/changesets/releases" %} for their changes to be published.
## Publishing with `added_in:`
New things can be published in a changeset by adding `added_in: SomeChangeset` to their configuration. For example, to add a new argument to a field:
```ruby
field :search_recipes, [Types::Recipe] do
argument :query, String
argument :tags, [Types::RecipeTag], required: false, added_in: Changesets::AddRecipeTags
end
```
You can also provide a _replacement_ implementation by using `added_in:`. When a new definition has the same name as an existing definition, it implicitly replaces the previous definition in new versions of the API. For example:
```ruby
field :rating, Integer, "A 1-5 score for this recipe" # This definition will be superseded by the following one
field :rating, Float, "A 1.0-5.0 score for this recipe", added_in: Changesets::FloatingPointRatings
```
Here, a new implementation for `rating` will be used when clients requests an API version that includes `Changesets::FloatingPointRatings`. (If the client requests a version _before_ that changeset, then the preceding implementation would be used instead.)
## Removing with `removed_in:`
A `removed_in:` configuration removes something in the named changeset. For example, these enum values are replaced with more clearly-named ones:
```ruby
class Types::RecipeTag < Types::BaseEnum
# These are replaced by *_HEAT below:
value :SPICY, removed_in: Changesets::ClarifyHeatTags
value :MEDIUM, removed_in: Changesets::ClarifyHeatTags
value :MILD, removed_in: Changesets::ClarifyHeatTags
# These new tags are more clear:
value :SPICY_HEAT, added_in: Changesets::ClarifyHeatTags
value :MEDIUM_HEAT, added_in: Changesets::ClarifyHeatTags
value :MILD_HEAT, added_in: Changesets::ClarifyHeatTags
end
```
If something has been defined several times, a `removed_in:` configuration removes _all_ definitions:
```ruby
class Mutations::SubmitRecipeRating < Mutations::BaseMutation
# This is replaced in future API versions by the following argument
argument :rating, Integer
# This replaces the previous, but in another future version,
# it is removed completely (and so is the previous one)
argument :rating, Float, added_in: Changesets::FloatingPointRatings, removed_in: Changesets::RemoveRatingsCompletely
end
```
## Examples
See below for the different kind of modifications you can make in a changeset:
- [Fields](#fields): adding, modifying, and removing fields
- [Arguments](#arguments): adding, modifying, and removing arguments
- [Enum values](#enum-values): adding, modifying, and removing arguments
- [Unions](#unions): adding or removing object types from a union
- [Interfaces](#interfaces): adding or removing interface implementations from object types
- [Types](#types): changing one type definition for another
- [Runtime](#runtime): choosing a behavior at runtime based on the current request and changeset
### Fields
To add or redefine a field, use `field(..., added_in: ...)`, including all configuration values for the new implementation (see {{ "GraphQL::Schema::Field#initialize" | api_doc }}). The definition given here will override the previous definition (if there was one) whenever this Changeset applies.
```ruby
class Types::Recipe < Types::BaseObject
# This new field is available when `context[:changeset_version]`
# is on or after the release date of `AddRecipeTags`
field :tags, [Types::RecipeTag], added_in: Changeset::AddRecipeTags
end
```
To remove a field, add a `removed_in: ...` configuration to the last definition of the field:
```ruby
class Types::Recipe < Types::BaseObject
# Even after migrating to floating point values,
# the "rating" feature never took off,
# so we removed it entirely eventually.
field :rating, Integer
field :rating, Float, added_in: Changeset::FloatingPointRatings,
removed_in: Changeset::RemoveRatings
end
```
When a field is removed, queries that request that field will be invalid, unless the client has requested a previous API version where the field is still available.
### Arguments
You can add, redefine, or remove arguments that belong to fields, input objects, or resolvers. Use `added_in: ...` to provide a new (or updated) definition for an argument, for example:
```ruby
class Types::RecipesFilter < Types::BaseInputObject
argument :rating, Integer
# This new definition is available when
# the client's `context[:changeset_version]` includes `FloatingPointRatings`
argument :rating, Float, added_in: Changesets::FloatingPointRatings
end
```
To remove an argument entirely, add a `removed_in: ...` configuration to the last definition. It will remove _all_ implementations for that argument. For example:
```ruby
class Mutations::SubmitRating < Mutations::BaseMutation
# Remove this because it's irrelevant:
argument :phone_number, String, removed_in: Changesets::StopCollectingPersonalInformation
end
```
When arguments are removed, the schema will reject any queries which use them unless the client has requested a previous API version where the argument is still allowed.
### Enum Values
With Changesets, you can add, redefine, or remove enum values. To add a new value (or provide a new implementation for a value), include `added_in:` in the `value(...)` configuration:
```ruby
class Types::RecipeTag < Types::BaseEnum
# This enum will accept and return `KETO` only when the client's API version
# includes `AddKetoDietSupport`'s release date.
value :KETO, added_in: Changesets::AddKetoDietSupport
end
```
Values can be removed with `removed_in:`, for example:
```ruby
class Types::RecipeTag < Types::BaseEnum
# Old API versions will serve this value;
# new versions won't accept it or return it.
value :GRAPEFRUIT_DIET, removed_in: Changesets::RemoveLegacyDiets
end
```
When enum values are removed, they won't be accepted as input and they won't be allowed as return values from fields unless the client has requested a previous API version where those values are still allowed.
### Unions
You can add to or remove from a union's possible types. To release a new union member, include `added_in:` in the `possible_types` configuration:
```ruby
class Types::Cookable < Types::BaseUnion
possible_types Types::Recipe, Types::Ingredient
# Add this to the union when clients opt in to our new feature:
possible_types Types::Cuisine, added_in: Changeset::ReleaseCuisines
```
To remove a member from a union, move it to a `possible_types` call with `removed_in: ...`:
```ruby
# Stop including this in the union in new API versions:
possible_types Types::Chef, removed_in: Changeset::LessChefHype
```
When a possible type is removed, it will not be associated with the union type in introspection queries or schema dumps.
### Interfaces
You can add to or remove from an object type's interface definitions. To add one or more interface implementations, use `implements(..., added_in:)`. This will add the interface and its fields to the object whenever this Changeset is active, for example:
```ruby
class Types::Recipe < Types::BaseObject
# Add this new implementation in new API versions only:
implements Types::RssSubject, added_in: Changesets::AddRssSupport
end
```
To remove one or more more interface implementations, add `removed_in:` to the `implements ...` configuration, for example:
```ruby
implements Types::RssSubject,
added_in: Changesets::AddRssSupport,
# Sadly, nobody seems to want to use this,
# so we removed it all:
removed_in: Changesets::RemoveRssSupport
```
When an interface implementation is removed, then the interface will not be associated with the object in introspection queries or schema dumps. Also, any fields inherited from the interface will be hidden from clients. (If the object defines the field itself, it will still be visible.)
### Types
Using Changesets, it's possible to define a new type using the same name as an old type. (Only one type per name is allowed for each query, but different queries can use different types for the same name.)
First, to define two types with the same name, make two different type definitions. One of them will have to use `graphql_name(...)` to specify the conflicting type name. For example, to migrate an enum type to an object type, define two types:
```ruby
# app/graphql/types/legacy_recipe_flag.rb
# In the old version of the schema, "recipe tags" were limited to defined set of values.
# This enum was renamed from `Types::RecipeTag`, then `graphql_name("RecipeTag")`
# was added for GraphQL.
class Types::LegacyRecipeTag < Types::BaseEnum
graphql_name "RecipeTag"
# ...
end
```
```ruby
# app/graphql/types/recipe_flag.rb
# But in the new schema, each tag is a full-fledged object with fields of its own
class Types::RecipeTag < Types::BaseObject
field :name, String, null: false
field :is_vegetarian, Boolean, null: false
# ...
end
```
Then, add or update fields or arguments to use the _new_ type instead of the old one. For example:
```diff
class Types::Recipe < Types::BaseObject
# Change this definition to point at the newly-renamed _legacy_ type
# (It's the same type definition, but the Ruby class has a new name)
- field :tags, [Types::RecipeTag]
+ field :tags, [Types::LegacyRecipeTag]
# And add a new field for the new type:
+ field :tags, [Types::RecipeTag], added_in: Changesets::MigrateRecipeTagToObject
end
```
With that Changeset, `Recipe.tags` will return an object type instead of an enum type. Clients requesting older versions will still receive enum values from that field.
The resolver will probably need an update, too, for example:
```ruby
class Types::Recipe < Types::BaseObject
# Here's the original definition which returns enum values:
field :tags, [Types::LegacyRecipeTag], null: false
# Here's the new definition which replaces the previous one on new API versions:
field :tags, [Types::RecipeTag], null: false, added_in: Changesets::MigrateRecipeTagToObject
def flags
all_flag_objects = object.flag_objects
if Changesets::MigrateRecipeTagToObject.active?(context)
# Here's the new behavior, returning full objects:
all_flag_objects
else
# Convert this to enum values, for legacy behavior:
all_flag_objects.map { |f| f.name.upcase }
end
end
end
```
That way, legacy clients will continue to receive enum values while new clients will receive objects.
## Runtime
While a query is running, you can check if a changeset applies by using its `.active?(context)` method. For example:
```ruby
class Types::Recipe
field :flag, Types::RecipeFlag, null: true
def flag
# Check if this changeset applies to the current request:
if Changesets::DeprecateRecipeFlag.active?(context)
Stats.count(:deprecated_recipe_flag, context[:viewer])
end
# ...
end
end
```
Besides observability, you can use a runtime check when a resolver needs to pick a different behavior depending on the API version.
After defining a changeset, add it to the schema to {% internal_link "release it", "/changesets/releases" %}.
graphql-ruby-2.2.17/guides/changesets/installation.md 0000664 0000000 0000000 00000006744 14764346352 0022700 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
enterprise: true
section: GraphQL Enterprise - Changesets
title: Installing Changesets
desc: Adding Changesets to your schema
index: 1
---
Changesets require some updates to the schema (to define changesets) and some updates to your controller (to receive version headers from clients).
## Schema Setup
To get started with [GraphQL-Enterprise](https://graphql.pro/enterprise) Changesets, you have to add them to your schema. They're added in several places:
- To support versioning arguments, add the `ArgumentIntegration` to your base argument:
```ruby
# app/graphql/types/base_argument.rb
class Types::BaseArgument < GraphQL::Schema::Argument
include GraphQL::Enterprise::Changeset::ArgumentIntegration
end
```
Also, make sure that your `BaseField`, `BaseInputObject`, `BaseResolver`, and `BaseMutation` have `argument_class(Types::BaseArgument)` configured in them.
- To support versioning fields, add the `FieldIntegration` to your base field:
```ruby
# app/graphql/types/base_field.rb
class Types::BaseField < GraphQL::Schema::Field
include GraphQL::Enterprise::Changeset::FieldIntegration
argument_class(Types::BaseArgument)
end
```
Also, make sure that your `BaseObject`, `BaseInterface`, and `BaseMutation` have `field_class(Types::BaseField)` configured in them.
- To support versioning enum values, add the `EnumValueIntegration` to your base enum value:
```ruby
# app/graphql/types/base_enum_value.rb
class Types::BaseEnumValue < GraphQL::Schema::EnumValue
include GraphQL::Enterprise::Changeset::EnumValueIntegration
end
```
Also, make sure that your `BaseEnum` has `enum_value_class(Types::BaseEnumValue)` configured in it.
- To support versioning union memberships and interface implementations, add the `TypeMembershipIntegration` to your base type membership:
```ruby
# app/graphql/types/base_type_membership.rb
class Types::BaseTypeMembership < GraphQL::Schema::TypeMembership
include GraphQL::Enterprise::Changeset::TypeMembershipIntegration
end
```
Also, make sure that your `BaseUnion` and `BaseInterface` have `type_membership_class(Types::BaseTypeMembership)` configured in it. (`TypeMembership`s are used by GraphQL-Ruby to link object types to the union types they belong to and the interfaces they implement. By using a custom type membership class, you can make objects belong (or _not_ belong) to unions or interfaces, depending on the API version.)
Once those integrations are set up, you're ready to {% internal_link "write a changeset", "/changesets/definition" %} and start {% internal_link "releasing API versions", "/changesets/releases" %}!
## Controller Setup
Additionally, your controller must pass `context[:changeset_version]` when running queries. To provide this, update your controller:
```ruby
class GraphqlController < ApplicationController
def execute
context = {
# ...
changeset_version: headers["API-Version"], # <- Your header here. Choose something for API clients to pass.
}
result = MyAppSchema.execute(..., context: context)
# ...
end
end
```
In the example above, `API-Version: ...` will be parsed from the incoming request and used as `context[:changeset_version]`.
If `context[:changeset_version]` is `nil`, then _no_ changesets will apply to that request.
Now that Changesets are installed, read on to {% internal_link "define some changesets", "/changesets/definition" %}.
graphql-ruby-2.2.17/guides/changesets/overview.md 0000664 0000000 0000000 00000004676 14764346352 0022047 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
enterprise: true
section: GraphQL Enterprise - Changesets
title: API Versioning for GraphQL-Ruby
desc: Evolve your schema over time, feature-by-feature
index: 0
---
Out-of-the-box, GraphQL is [versionless by design](https://graphql.org/learn/best-practices/#versioning). GraphQL's openness to extension paves the way for continuously expanding and improving an API. You can _always_ add new fields, new arguments, and new types to implement new features and customize existing behavior.
However, sometimes a business case may call for a different versioning scheme. [GraphQL-Enterprise](https://graphql.pro/enterprise)'s "Changesets" enable schemas to release _any_ change -- even breaking changes -- to clients, depending on what version of the schema they're using. With Changesets, you can redefine existing fields, define new types using old names, add or remove enum values -- anything, really -- while maintaining compatibility for existing clients.
## Why Changesets?
Changesets are a _complementary_ evolution technique to continuous additions. In general, additive changes (new fields, new arguments, new types) are best added right to the existing schema. But if you need to _remove_ something from the schema or redefine existing parts of the schema in non-backwards-compatible ways, Changesets provide a handy way of doing so.
For example, if you add a values to an Enum, you can just add it to the existing schema:
```diff
class Types::RecipeTag < Types::BaseEnum
value "LOW_FAT"
value "LOW_CARB"
+ value "VEGAN"
+ value "KETO"
+ value "GRAPEFRUIT_DIET"
end
```
However, if you want to change the schema in ways that would _break_ previous queries, you can do that with a Changeset:
```ruby
class Types::RecipeTag < Types::BaseEnum
# Turns out this makes you sick:
value "GRAPEFRUIT_DIET", removed_in: Changesets::RemoveLegacyDiets
end
```
Then, only clients requesting API versions _before_ this changeset would be able to use `GRAPEFRUIT_DIET`; clients requesting newer versions could not send it as input and would not receive it in responses.
(Changesets _also_ support additive changes, if you prefer to make them that way.)
## Getting Started
To start using Changesets, read on:
- {% internal_link "Installing Changesets", "/changesets/installation" %}
- {% internal_link "Writing Changesets", "/changesets/definition" %}
- {% internal_link "Releasing Changesets", "/changesets/releases" %}
graphql-ruby-2.2.17/guides/changesets/releases.md 0000664 0000000 0000000 00000005713 14764346352 0021775 0 ustar 00root root 0000000 0000000 ---
layout: guide
doc_stub: false
search: true
enterprise: true
section: GraphQL Enterprise - Changesets
title: Releasing Changesets
desc: Associating changes to version numbers
index: 3
---
To be available to clients, Changesets added to the schema with `use GraphQL::Enterprise::Changeset::Release changeset_dir: "..."`:
```ruby
class MyAppSchema < GraphQL::Schema
# Add this before root types so that newly-added types are also added to the schema
use GraphQL::Enterprise::Changeset::Release, changeset_dir: "app/graphql/changesets"
query(...)
mutation(...)
subscription(...)
end
```
This attaches each Changeset defined in `app/graphql/changesets/*.rb` to the schema. (It assumes Rails conventions, where an underscored file like `app/graphql/changesets/add_some_feature.rb` contains a class like `Changesets::AddSomeFeature`.)
{% callout warning %}
Add `GraphQL::Enterprise::Changeset::Release` _before_ hooking up your root `query(...)`, `mutation(...)`, and `subscription(...)` types. Otherwise, the schema may not find links to types in new schema versions.
{% endcallout %}
Alternatively, Changesets can be explicitly attached using `changesets: [...]`, for example:
```ruby
class MyAppSchema < GraphQL::Schema
use GraphQL::Enterprise::Changeset::Release, changesets: [
Changesets::DeprecateRecipeFlag,
Changesets::RemoveRecipeFlag,
]
# ...
end
```
Only changesets in the directory (or in the array) will be shown to clients. The `release ...` configuration in the changeset will be compared to `context[:changeset_version]` to determine if the changeset applies to the current request.
## Inspecting Releases
To preview releases, you can create schema dumps by passing `context: { changeset_version: ... }` to {{ "Schema.to_definition" | api_doc }}.
For example, to see how the schema looks with `API-Version: 2021-06-01`:
```ruby
schema_sdl = MyAppSchema.to_definition(context: { changeset_version: "2021-06-01"})
# The GraphQL schema definition for the schema at version "2021-06-01":
puts schema_sdl
```
To make sure schema versions don't change unexpectedly, use the techniques described in the {% internal_link "Schema structure guide", "/testing/schema_structure" %}.
### Introspection Methods
You can also inspect a schema's changesets programmatically. `GraphQL::Enterprise` adds a `Schema.changesets` method which returns a `Set` of changeset classes:
```ruby
MySchema.changesets
# #
```
Additionally, each changeset has a `.changes` method describing its modifications:
```ruby
AddNewFeature.changes
# [
# #,
# #,
# #,
# ...
# ]
```
Each `Change` object responds to:
- `.member`, the part of the schema that was modified
- `.type`, the kind of modification (`:addition` when something new is added, `:removal` when a member is removed or replaced with a new definition)
graphql-ruby-2.2.17/guides/css/ 0000775 0000000 0000000 00000000000 14764346352 0016306 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/css/main.scss 0000664 0000000 0000000 00000046217 14764346352 0020141 0 ustar 00root root 0000000 0000000 ---
---
@import "reset";
$brand-color: #a5152a;
$dark-theme-brand-color: #e5534b;
$brand-color-light: #ed8090;
$brand-color-extralight: #f9e8ee;
$dark-theme-brand-color-extralight: #262324;
$experimental-background: #fff7cf;
$experimental-color: hsla(50, 100%, 32%, 0.15);
$pro-color: #406db5;
$pro-background: hsla(217, 100%, 29%, 0.15);
$enterprise-color: #238c44;
$enterprise-background: hsla(135, 97%, 25%, 0.15);
$dark-theme-code-border: #aaaaaa;
$code-border: #d6d6d6;
$dark-theme-code-background: #1e1b1b;
$code-background: #fafafa;
$dark-theme-code-color: #b5b5b5;
$code-color: #777777;
$code-border-radius: 2px;
$muted-color: #777777;
$subtle-color: #aaaaaa;
$font: 'Rubik', sans-serif;
$code-font: 'Monaco', monospace;
$faint-color: #f0f0f0;
$dark-theme-faint-color: #6a6969;
$font-color: black;
$dark-theme-font-color: #dbdbdb;
$background-color: #fafafa;
$dark-theme-background-color: #422e2e;
$container-color: white;
$dark-theme-container-color: #424242;
body {
font-family: $font;
background: $background-color;
.dark-theme-button::after {
content: "☀"
}
}
body.dark-theme {
background: $dark-theme-code-background;
color: $dark-theme-font-color;
.dark-theme-button::after {
content: "☽"
}
}
strong, b {
font-weight: bold;
}
// Algolia highlights:
.ais-Highlight {
font-style: normal;
font-weight: bold;
}
.dark-theme {
.header {
background: $dark-theme-container-color;
box-shadow: 0px 0px 10px 0px black;
.nav a:hover {
color: $font-color;
background-color: $dark-theme-brand-color;
}
}
}
.header {
box-shadow: 0px 0px 10px 0px #d6d6d6;
z-index: 1;
position: relative;
background: $container-color;
.nav {
$height: 30px;
$margin: 10px;
display: flex;
flex-wrap: wrap;
align-items: center;
$fade-time: 0.2s;
.nav-links {
margin-left: auto;
display: flex;
}
.img-link {
transition: background $fade-time;
img {
transition: filter $fade-time;
transition: -webkit-filter $fade-time;
filter: brightness(1) invert(0);
-webkit-filter: brightness(1) invert(0);
}
&:hover {
img {
-webkit-filter: brightness(0) invert(1);
filter: brightness(0) invert(1);
}
}
}
img {
height: $height;
width: auto;
margin: $margin;
}
a, span {
transition: background-color $fade-time;
transition: color $fade-time;
&:hover {
background-color: $brand-color;
color: white;
}
padding: $margin;
height: $height;
display: flex;
align-items: center;
text-decoration: none;
}
}
}
.header-container {
margin: 0px 20px 0px 20px;
}
.container {
max-width: 1200px;
&.fullwidth {
max-width: 100%;
margin: 0px 20px 0px 20px;
}
margin: 0px auto;
padding: 10px 20px;
background: $container-color;
}
.dark-theme {
.container {
background: $dark-theme-container-color;
}
}
.callout {
.heading {
font-size: 20px;
font-weight: bold;
margin-bottom: 20px;
}
padding: 20px 20px 10px 20px;
margin: 20px;
border: 2px;
border-radius: 10px;
&.callout-warning {
background-color: rgba(255, 217, 0, 0.2);
border-color: rgba(255, 217, 0, 0.5);
}
}
pre {
font-family: $code-font;
padding: 0.5rem;
border: 1px solid $code-border;
border-radius: $code-border-radius;
background-color: $code-background;
margin: 10px 0px;
overflow-x: auto;
line-height: 1.4rem;
}
.dark-theme {
pre {
background-color: $dark-theme-code-background;
border: 1px solid $dark-theme-code-border;
}
}
p, li {
line-height: 1.3rem;
}
li {
margin-left: 15px;
margin-top: 5px
}
p, ul {
margin-bottom: 20px;
}
ul {
list-style-type: disc;
list-style-position: outside;
}
ol {
list-style: decimal;
margin-left: 5px;
}
code {
font-family: $code-font;
color: $code-color;
font-weight: 400;
}
.dark-theme code {
color: $dark-theme-code-color;
}
.code .line-numbers {
display: none;
}
.dark-theme a {
color: $dark-theme-brand-color;
border-color: $dark-theme-brand-color;
}
a {
color: $brand-color;
border-color: $brand-color;
text-decoration: none;
}
a:hover, a:hover code {
text-decoration: underline;
}
#readme img {
display: none;
}
.guide-container {
a.img-link {
background: none;
&:hover {
background: none;
}
img {
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
max-height: 300px;
max-width: 100%;
&:hover {
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
}
}
}
.cell {
overflow-x: scroll;
}
.monitoring-img-group {
display: flex;
flex-direction: row;
margin-bottom: 20px;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.guides-toc {
ul {
list-style: none;
display: flex;
flex-wrap: wrap;
}
li {
padding-bottom: 10px;
padding-right: 10px;
}
}
.guides {
.guide-desc {
color: $muted-color;
margin-left: 5px;
}
ul {
margin-left: 10px;
list-style: none;
}
}
@mixin doc-header($color, $background-color) {
background-color: $background-color;
color: $color;
border-radius: $code-border-radius;
padding: 10px 10px 10px 10px;
margin-bottom: 10px;
border: 1px solid $color;
p {
margin: 0px;
padding: 0px;
}
a {
color: $color;
&:hover {
background-color: $color;
color: $background-color;
}
}
}
.experimental-header {
@include doc-header($experimental-color, $experimental-background);
}
.pro-header {
@include doc-header($pro-color, $pro-background);
}
.enterprise-header {
@include doc-header($enterprise-color, $enterprise-background);
}
.dark-theme .guide-footer {
background-color: $dark-theme-brand-color-extralight;
}
.guide-footer {
background: $brand-color-extralight;
margin: 25px 0px 0px 0px;
padding: 10px;
border-radius: $code-border-radius;
}
.dark-theme {
.hero {
.hero-part {
&.shaded {
background: $dark-theme-faint-color;
}
h2 {
color: $dark-theme-brand-color;
text-shadow: $dark-theme-background-color 1px 1px 1px;
}
}
}
}
.hero {
display: flex;
flex-direction: column;
justify-content: space-around;
.hero-title {
display: flex;
justify-content: center;
align-items: center;
img, h1 {
margin: 20px 10px 30px 10px;
}
}
.hero-subtitle {
p {
margin: 5px auto;
text-align: center;
}
padding: 10px 0px;
}
.hero-part {
&.shaded {
background: $faint-color;
}
h2 {
color: $brand-color;
text-shadow: #cccccc 1px 1px 1px;
font-size: 1.4em;
}
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.hero-feature {
padding: 15px;
flex-basis: calc(50% - 60px);
flex-grow: 1;
}
}
}
h1, h2, h3, h4, h5 {
margin: 25px 0px 15px 0px;
a {
text-decoration: none;
}
}
.guide-header {
margin-bottom: 15px;
}
h1 { font-size: 1.5rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.2rem; }
h4 { font-size: 1.1rem; }
h5 { font-size: 1.05rem; }
em { font-style: italic; }
table {
width: 100%;
margin: 0px 0px 15px 0px;
thead {
text-align: left;
border-bottom: 1px solid $subtle-color;
}
td, th {
padding: 5px 10px 5px 0px;
}
}
.dark-theme {
.search-input {
background: $dark-theme-code-background;
color: $dark-theme-font-color;
}
.search-results-container {
background-color: $dark-theme-background-color;
#search-results {
.search-result {
&:focus, &:hover {
background-color: $dark-theme-container-color;
border-bottom-color: $dark-theme-brand-color;
.search-title {
color: $dark-theme-brand-color;
}
}
.search-category {
border: 1px solid $dark-theme-brand-color;
color: $dark-theme-brand-color;
}
}
}
}
}
.search-input {
font-size: 1em;
padding: 5px;
margin: 10px;
border: 1px solid $subtle-color;
border-radius: 3px;
}
.search-results-container {
$bg: #eaeaea;
$bg-highlight: #f9f9f9;
background-color: $bg;
#search-results {
$fade-time: 0.1s;
display: flex;
flex-direction: column;
max-width: 1040px;
margin: 0 auto;
.search-result {
text-decoration: none;
color: $font-color;
padding: 6px 10px 0px 6px;
line-height: 18px;
border-bottom: 2px solid transparent;
transition: border-bottom-color $fade-time;
.search-title {
font-weight: bold;
margin-right: 8px;
transition: color $fade-time;
}
.search-preview {
color: $subtle-color;
}
.search-category {
border: 1px solid $brand-color;
border-radius: 3px;
margin: 0 8px 0 0;
padding: 3px;
font-size: 0.7em;
color: $brand-color;
position: relative;
top: -3px;
}
&:focus, &:hover {
outline: none;
.search-title {
color: $brand-color;
}
background-color: $bg-highlight;
border-bottom-color: $brand-color;
}
}
}
}
.dark-theme ul.breadcrumb .jump-to-select {
color: $dark-theme-brand-color;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='292.4' height='292.4'%3E%3Cpath fill='%23e5534b' d='M287 69.4a17.6 17.6 0 0 0-13-5.4H18.4c-5 0-9.3 1.8-12.9 5.4A17.6 17.6 0 0 0 0 82.2c0 5 1.8 9.3 5.4 12.9l128 127.9c3.6 3.6 7.8 5.4 12.8 5.4s9.2-1.8 12.8-5.4L287 95c3.5-3.5 5.4-7.8 5.4-12.8 0-5-1.9-9.2-5.5-12.8z'/%3E%3C/svg%3E");
}
ul.breadcrumb {
color: $muted-color;
li {
display: inline;
list-style: none;
margin: 0;
}
li:before {
content: "»";
margin: 0px 4px 0px 2px;
}
li:first-child:before {
content: "";
margin: 0;
}
.jump-to-select {
box-sizing: border-box;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
padding: 5px 20px 5px 5px;
border: 1px solid $code-border;
border-radius: 5px;
background-color: transparent;
color: $brand-color;
font-size: 16px;
font-weight: 500;
line-height: 1.3;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='292.4' height='292.4'%3E%3Cpath fill='%23a5152a' d='M287 69.4a17.6 17.6 0 0 0-13-5.4H18.4c-5 0-9.3 1.8-12.9 5.4A17.6 17.6 0 0 0 0 82.2c0 5 1.8 9.3 5.4 12.9l128 127.9c3.6 3.6 7.8 5.4 12.8 5.4s9.2-1.8 12.8-5.4L287 95c3.5-3.5 5.4-7.8 5.4-12.8 0-5-1.9-9.2-5.5-12.8z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 8px center;
background-size: 9px;
cursor: default;
&:hover {
border-color: #777;
}
&:focus {
border-color: #999;
box-shadow: 0 0 1px 2px #6db4ff;
outline: none;
}
option {
color: black;
}
}
}
.dark-theme {
.table-of-contents {
background: $dark-theme-code-background;
}
}
.table-of-contents {
float: right;
border: 1px solid $subtle-color;
border-radius: 3px;
padding: 15px;
margin: 0 10px 10px 10px;
width: 300px;
background: $code-background;
.contents-header {
margin: 0 0 5px 20px;
}
.contents-list {
margin: 0;
list-style: decimal;
padding-left: 5px;
.contents-entry {
&::marker {
color: $muted-color;
}
.contents-entry {
list-style: none;
}
}
}
}
/* pygments CSS, github theme */
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #000000; font-weight: bold } /* Keyword */
.highlight .o { color: #000000; font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #000000; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #000000; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #d01040 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #0086B3 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nl { color: #990000; font-weight: bold } /* Name.Label */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #000080 } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #d01040 } /* Literal.String.Backtick */
.highlight .sc { color: #d01040 } /* Literal.String.Char */
.highlight .sd { color: #d01040 } /* Literal.String.Doc */
.highlight .s2 { color: #d01040 } /* Literal.String.Double */
.highlight .se { color: #d01040 } /* Literal.String.Escape */
.highlight .sh { color: #d01040 } /* Literal.String.Heredoc */
.highlight .si { color: #d01040 } /* Literal.String.Interpol */
.highlight .sx { color: #d01040 } /* Literal.String.Other */
.highlight .sr { color: #009926 } /* Literal.String.Regex */
.highlight .s1 { color: #d01040 } /* Literal.String.Single */
.highlight .ss { color: #990073 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
.dark-theme {
.highlight .hll { background-color: #49483e }
pre.highlight { background: #272822; color: #f8f8f2 }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
graphql-ruby-2.2.17/guides/dataloader/ 0000775 0000000 0000000 00000000000 14764346352 0017616 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/dataloader/adopting.md 0000664 0000000 0000000 00000010374 14764346352 0021752 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Dataloader
title: Dataloader vs. GraphQL-Batch
desc: Comparing and Contrasting Batch Loading Options
index: 3
---
{{ "GraphQL::Dataloader" | api_doc }} solves the same problem as [`GraphQL::Batch`](https://github.com/shopify/graphql-batch). There are a few major differences between the modules:
- __Concurrency Primitive:__ GraphQL-Batch uses `Promise`s from [`promise.rb`](https://github.com/lgierth/promise.rb); GraphQL::Dataloader uses Ruby's [`Fiber` API](https://ruby-doc.org/core-3.0.0/Fiber.html). These primitives dictate how batch loading code is written (see below for comparisons).
- __Maturity:__ Frankly, GraphQL-Batch is about as old as GraphQL-Ruby, and it's been in production at Shopify, GitHub, and others for many years. GraphQL::Dataloader is new, and although Ruby has supported `Fiber`s since 1.9, they still aren't widely used.
- __Scope:__ It's not currently possible to use `GraphQL::Dataloader` _outside_ GraphQL.
The incentive in writing `GraphQL::Dataloader` was to leverage `Fiber`'s ability to _transparently_ pause and resume work, which removes the need for `Promise`s (and removes the resulting complexity in the code). Additionally, `GraphQL::Dataloader` should _eventually_ support Ruby 3.0's `Fiber.scheduler` API, which runs I/O in the background by default.
## Comparison: Fetching a single object
In this example, a single object is batch-loaded to satisfy a GraphQL field.
- With __GraphQL-Batch__, you call a loader, which returns a `Promise`:
```ruby
record_promise = Loaders::Record.load(1)
```
Then, under the hood, GraphQL-Ruby manages the promise (using its `lazy_resolve` feature, upstreamed from GraphQL-Batch many years ago). GraphQL-Ruby will call `.sync` on it when no futher execution is possible; `promise.rb` implements `Promise#sync` to execute the pending work.
- With __GraphQL::Dataloader__, you get a source, then call `.load` on it, which may pause the current Fiber, but it returns the requested object.
```ruby
dataloader.with(Sources::Record).load(1)
```
Since the requested object is (eventually) returned from `.load`, Nothing else is required.
## Comparison: Fetching objects in sequence (dependent)
In this example, one object is loaded, then another object is loaded _based on_ the first one.
- With __GraphQL-Batch__, `.then { ... }` is used to join dependent code blocks:
```ruby
Loaders::Record.load(1).then do |record|
Loaders::OtherRecord.load(record.other_record_id)
end
```
That call returns a `Promise`, which is stored by GraphQL-Ruby, and finally `.sync`ed.
- With __GraphQL-Dataloader__, `.load(...)` returns the requested object (after a potential `Fiber` pause), so no other method calls are necessary:
```ruby
record = dataloader.with(Sources::Record).load(1)
dataloader.with(Sources::OtherRecord).load(record.other_record_id)
```
## Comparison: Fetching objects concurrently (independent)
Sometimes, you need multiple _independent_ records to perform a calcuation. Each record is loaded, then they're combined in some bit of work.
- With __GraphQL-Batch__, `Promise.all(...)` is used to to wait for several pending loads:
```ruby
promise_1 = Loaders::Record.load(1)
promise_2 = Loaders::OtherRecord.load(2)
Promise.all([promise_1, promise_2]).then do |record, other_record|
do_something(record, other_record)
end
```
If the objects are loaded from the same loader, then `.load_many` also works:
```ruby
Loaders::Record.load_many([1, 2]).then do |record, other_record|
do_something(record, other_record)
end
```
- With __GraphQL::Dataloader__, each request is registered with `.request(...)` (which never pauses the Fiber), then data is loaded with `.load` (which will pause the Fiber as needed):
```ruby
# first, make some requests
request_1 = dataloader.with(Sources::Record).request(1)
request_2 = dataloader.with(Sources::OtherRecord).request(2)
# then, load the objects and do something
record = request_1.load
other_record = request_2.load
do_something(record, other_record)
```
If the objects come from the same `Source`, then `.load_all` will return the objects directly:
```ruby
record, other_record = dataloader.with(Sources::Record).load_all([1, 2])
do_something(record, other_record)
```
graphql-ruby-2.2.17/guides/dataloader/async_dataloader.md 0000664 0000000 0000000 00000003022 14764346352 0023432 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Dataloader
title: Async Source Execution
desc: Using AsyncDataloader to fetch external data in parallel
index: 5
---
`AsyncDataloader` will run {{ "GraphQL::Dataloader::Source#fetch" | api_doc }} calls in parallel, so that external service calls (like database queries or network calls) don't have to wait in a queue.
To use `AsyncDataloader`, hook it up in your schema _instead of_ `GraphQL::Dataloader`:
```diff
- use GraphQL::Dataloader
+ use GraphQL::Dataloader::AsyncDataloader
```
__Also__, add [the `async` gem](https://github.com/socketry/async) to your project, for example:
```
bundle add async
```
Now, {{ "GraphQL::Dataloader::AsyncDataloader" | api_doc }} will create `Async::Task` instances instead of plain `Fiber`s and the `async` gem will manage parallelism.
For a demonstration of this behavior, see: [https://github.com/rmosolgo/rails-graphql-async-demo](https://github.com/rmosolgo/rails-graphql-async-demo)
_You can also implement {% internal_link "manual parallelism", "/dataloader/parallelism" %} using `dataloader.yield`._
## Rails
For Rails, you'll need **Rails 7.1**, which properly supports fiber-based concurrency, and you'll also want to configure Rails to use Fibers for isolation:
```ruby
class Application < Rails::Application
# ...
config.active_support.isolation_level = :fiber
end
```
## Other Options
You can also manually implement parallelism with Dataloader. See the {% internal_link "Dataloader Parallelism", "/dataloader/parallelism" %} guide for details.
graphql-ruby-2.2.17/guides/dataloader/dataloader.md 0000664 0000000 0000000 00000001515 14764346352 0022242 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Dataloader
title: Dataloader
desc: The Dataloader orchestrates Fibers and Sources
index: 2
---
{{ "GraphQL::Dataloader" | api_doc }} instances are created for each query (or multiplex) and they:
- Cache {% internal_link "Source", "/dataloader/sources" %} instances for the duration of GraphQL execution
- Run pending Fibers to resolve data requirements and continue GraphQL execution
During a query, you can access the dataloader instance with:
- {{ "GraphQL::Query::Context#dataloader" | api_doc }} (`context.dataloader`, anywhere that query context is available)
- {{ "GraphQL::Schema::Object#dataloader" | api_doc }} (`dataloader` inside a resolver method)
- {{ "GraphQL::Schema::Resolver#dataloader" | api_doc }} (`dataloader` inside `def resolve` of a Resolver, Mutation, or Subscription class.)
graphql-ruby-2.2.17/guides/dataloader/overview.md 0000664 0000000 0000000 00000013026 14764346352 0022010 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Dataloader
title: Overview
desc: Getting started with the Fiber-based Dataloader
index: 0
---
{{ "GraphQL::Dataloader" | api_doc }} provides efficient, batched access to external services, backed by Ruby's `Fiber` concurrency primitive. It has a per-query result cache and {% internal_link "AsyncDataloader", "/dataloader/async_dataloader" %} supports truly parallel execution out-of-the-box.
`GraphQL::Dataloader` is inspired by [`@bessey`'s proof-of-concept](https://github.com/bessey/graphql-fiber-test/tree/no-gem-changes) and [shopify/graphql-batch](https://github.com/shopify/graphql-batch).
## Batch Loading
`GraphQL::Dataloader` facilitates a two-stage approach to fetching data from external sources (like databases or APIs):
- First, GraphQL fields register their data requirements (eg, object IDs or query parameters)
- Then, after as many requirements have been gathered as possible, `GraphQL::Dataloader` initiates _actual_ fetches to external services
That cycle is repeated during execution: data requirements are gathered until no further GraphQL fields can be executed, then `GraphQL::Dataloader` triggers external calls based on those requirements and GraphQL execution resumes.
## Fibers
`GraphQL::Dataloader` uses Ruby's `Fiber`, a lightweight concurrency primitive which supports application-level scheduling _within_ a `Thread`. By using `Fiber`, `GraphQL::Dataloader` can pause GraphQL execution when data is requested, then resume execution after the data is fetched.
At a high level, `GraphQL::Dataloader`'s usage of `Fiber` looks like this:
- GraphQL execution is run inside a Fiber.
- When that Fiber returns, if the Fiber was paused to wait for data, then GraphQL execution resumes with the _next_ (sibling) GraphQL field inside a new Fiber.
- That cycle continues until no further sibling fields are available and all known Fibers are paused.
- `GraphQL::Dataloader` takes the first paused Fiber and resumes it, causing the `GraphQL::Dataloader::Source` to execute its `#fetch(...)` call. That Fiber continues execution as far as it can.
- Likewise, paused Fibers are resumed, causing GraphQL execution to continue, until all paused Fibers are evaluated completely.
Whenever `GraphQL::Dataloader` creates a new `Fiber`, it copies each pair from `Thread.current[...]` and reassigns them inside the new `Fiber`.
`AsyncDataloader`, built on top of the [`async` gem](https://github.com/socketry/async), supports parallel I/O operations (like network and database communication) via Ruby's non-blocking `Fiber.schedule` API. {% internal_link "Learn more →", "/dataloader/async_dataloader" %}.
## Getting Started
To install {{ "GraphQL::Dataloader" | api_doc }}, add it to your schema with `use ...`, for example:
```ruby
class MySchema < GraphQL::Schema
# ...
use GraphQL::Dataloader
end
```
Then, inside your schema, you can request batch-loaded objects by their lookup key with `dataloader.with(...).load(...)`:
```ruby
field :user, Types::User do
argument :handle, String
end
def user(handle:)
dataloader.with(Sources::UserByHandle).load(handle)
end
```
Or, load several objects by passing an array of lookup keys to `.load_all(...)`:
```ruby
field :is_following, Boolean, null: false do
argument :follower_handle, String
argument :followed_handle, String
end
def is_following(follower_handle:, followed_handle:)
follower, followed = dataloader
.with(Sources::UserByHandle)
.load_all([follower_handle, followed_handle])
followed && follower && follower.follows?(followed)
end
```
To prepare requests from several sources, use `.request(...)`, then call `.load` after all requests are registered:
```ruby
class AddToList < GraphQL::Schema::Mutation
argument :handle, String
argument :list, String, as: :list_name
field :list, Types::UserList
def resolve(handle:, list_name:)
# first, register the requests:
user_request = dataloader.with(Sources::UserByHandle).request(handle)
list_request = dataloader.with(Sources::ListByName, context[:viewer]).request(list_name)
# then, use `.load` to wait for the external call and return the object:
user = user_request.load
list = list_request.load
# Now, all objects are ready.
list.add_user!(user)
{ list: list }
end
end
```
### `loads:` and `object_from_id`
`dataloader` is also available as `context.dataloader`, so you can use it to implement `MySchema.object_from_id`. For example:
```ruby
class MySchema < GraphQL::Schema
def self.object_from_id(id, ctx)
model_class, database_id = IdDecoder.decode(id)
ctx.dataloader.with(Sources::RecordById, model_class).load(database_id)
end
end
```
Then, any arguments with `loads:` will use that method to fetch objects. For example:
```ruby
class FollowUser < GraphQL::Schema::Mutation
argument :follow_id, ID, loads: Types::User
field :followed, Types::User
def resolve(follow:)
# `follow` was fetched using the Schema's `object_from_id` hook
context[:viewer].follow!(follow)
{ followed: follow }
end
end
```
## Data Sources
To implement batch-loading data sources, see the {% internal_link "Sources guide", "/dataloader/sources" %}.
## Parallelism
You can run I/O operations in parallel with GraphQL::Dataloader. There are two approaches:
- `AsyncDataloader` uses the `async` gem to automatically background I/O from `Dataloader::Source#fetch` calls. {% internal_link "Read More", "/dataloader/async_dataloader" %}
- You can manually call `dataloader.yield` after starting work in the background. {% internal_link "Read More", "/dataloader/parallelism" %}
graphql-ruby-2.2.17/guides/dataloader/parallelism.md 0000664 0000000 0000000 00000005507 14764346352 0022454 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Dataloader
title: Manual Parallelism
desc: Yield to Dataloader after starting work
index: 7
---
You can coordinate with {{ "GraphQL::Dataloader" | api_doc }} to run tasks in the background. To do this, call `dataloader.yield` inside `Source#fetch` after kicking off your task. For example:
```ruby
def fetch(ids)
# somehow queue up a background query,
# see examples below
future_result = async_query_for(ids)
# return control to the dataloader
dataloader.yield
# dataloader will come back here
# after calling other sources,
# now wait for the value
future_result.value
end
```
_Alternatively, you can use {% internal_link "AsyncDataloader", "/dataloader/async_dataloader" %} to automatically background I/O inside `Source#fetch` calls._
## Example: Rails load_async
You can use Rails's `load_async` method to load `ActiveRecord::Relation`s in the background. For example:
```ruby
class Sources::AsyncRelationSource < GraphQL::Dataloader::Source
def fetch(relations)
relations.each(&:load_async) # start loading them in the background
dataloader.yield # hand back to GraphQL::Dataloader
relations.each(&:load) # now, wait for the result, returning the now-loaded relation
end
end
```
You could call that source from a GraphQL field method:
```ruby
field :direct_reports, [Person]
def direct_reports
# prepare an ActiveRecord::Relation:
direct_reports = Person.where(manager: object)
# pass it off to the source:
dataloader
.with(Sources::AsyncRelationSource)
.load(direct_reports)
end
```
## Example: Rails async calculations
In a Dataloader source, you can run Rails async calculations in the background while other work continues. For example:
```ruby
class Sources::DirectReportsCount < GraphQL::Dataloader::Source
def fetch(users)
# Start the queries in the background:
promises = users.map { |u| u.direct_reports.async_count }
# Return to GraphQL::Dataloader:
dataloader.yield
# Now return the results, waiting if necessary:
promises.map(&:value)
end
end
```
Which could be used in a GraphQL field:
```ruby
field :direct_reports_count, Int
def direct_reports_count
dataloader.with(Sources::DirectReportsCount).load(object)
end
```
## Example: Concurrent::Future
You could use `concurrent-ruby` to put work in a background thread. For example, using `Concurrent::Future`:
```ruby
class Sources::ExternalDataSource < GraphQL::Dataloader::Source
def fetch(urls)
# Start some I/O-intensive work:
futures = urls.map do |url|
Concurrent::Future.execute {
# Somehow fetch and parse data:
get_remote_json(url)
}
end
# Yield back to GraphQL::Dataloader:
dataloader.yield
# Dataloader has done what it can,
# so now return the value, waiting if necessary:
futures.map(&:value)
end
end
```
graphql-ruby-2.2.17/guides/dataloader/sources.md 0000664 0000000 0000000 00000016015 14764346352 0021626 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Dataloader
title: Sources
desc: Batch-loading objects for GraphQL::Dataloader
index: 1
---
_Sources_ are what {{ "GraphQL::Dataloader" | api_doc }} uses to fetch data from external services.
## Source Concepts
Sources are classes that inherit from `GraphQL::Dataloader::Source`. A Source _must_ implement `def fetch(keys)` to return a list of objects, one for each of the given keys. A source _may_ implement `def initialize(...)` to accept other batching parameters.
Sources will receive two kinds of inputs from `GraphQL::Dataloader`:
- _keys_, which correspond to objects requested by the application.
Keys are passed to `def fetch(keys)`, which must return an object (or `nil`) for each of `keys`, in the same order as `keys`.
Under the hood, each Source instance maintains a `key => object` cache.
- _batch parameters_, which are the basis of batched groups. For example, if you're loading records from different database tables, the table name would be a batch parameter.
Batch parameters are given to `dataloader.with(source_class, *batch_parameters)`, and the default is _no batch parameters_. When you define a source, you should add the batch parameters to `def initialize(...)` and store them in instance variables.
(`dataloader.with(source_class, *batch_parameters)` returns an instance of `source_class` with the given batch parameters -- but it might be an instance which was cached by `dataloader`.)
Additionally, batch parameters are used to de-duplicate Source initializations during a query run. `.with(...)` calls that have the same batch parameters will use the same Source instance under the hood. To customize how Sources are de-duplicated, see {{ "GraphQL::Dataloader::Source.batch_key_for" | api_doc }}.
## Example: Loading Strings from Redis by Key
The simplest source might fetch values based on their keys. For example:
```ruby
# app/graphql/sources/redis_string.rb
class Sources::RedisString < GraphQL::Dataloader::Source
REDIS = Redis.new
def fetch(keys)
# Redis's `mget` will return a value for each key with a `nil` for any not-found key.
REDIS.mget(*keys)
end
end
```
This loader could be used in GraphQL like this:
```ruby
some_string = dataloader.with(Sources::RedisString).load("some_key")
```
Calls to `.load(key)` will be batched, and when `GraphQL::Dataloader` can't go any further, it will dispatch a call to `def fetch(keys)` above.
## Example: Loading ActiveRecord Objects by ID
To fetch ActiveRecord objects by ID, the source should also accept the _model class_ as a batching parameter. For example:
```ruby
# app/graphql/sources/active_record_object.rb
class Sources::ActiveRecordObject < GraphQL::Dataloader::Source
def initialize(model_class)
@model_class = model_class
end
def fetch(ids)
records = @model_class.where(id: ids)
# return a list with `nil` for any ID that wasn't found
ids.map { |id| records.find { |r| r.id == id.to_i } }
end
end
```
This source could be used for any `model_class`, for example:
```ruby
author = dataloader.with(Sources::ActiveRecordObject, ::User).load(1)
post = dataloader.with(Sources::ActiveRecordObject, ::Post).load(1)
```
## Example: Batched Calculations
Besides fetching objects, Sources can return values from batched calculations. For example, a system could batch up checks for who a user follows:
```ruby
# for a given user, batch checks to see whether this user follows another user.
# (The default `user.followings.where(followed_user_id: followed).exists?` would cause N+1 queries.)
class Sources::UserFollowingExists < GraphQL::Dataloader::Source
def initialize(user)
@user = user
end
def fetch(handles)
# Prepare a `SELECT id FROM users WHERE handle IN(...)` statement
user_ids = ::User.where(handle: handles).select(:id)
# And use it to filter this user's followings:
followings = @user.followings.where(followed_user_id: user_ids)
# Now, for followings that _actually_ hit a user, get the handles for those users:
followed_users = ::User.where(id: followings.select(:followed_user_id))
# Finally, return a result set, with one entry (true or false) for each of the given `handles`
handles.map { |h| !!followed_users.find { |u| u.handle == h }}
end
end
```
It could be used like this:
```ruby
is_following = dataloader.with(Sources::UserFollowingExists, context[:viewer]).load(handle)
```
After all requests were batched, `#fetch` will return a Boolean result to `is_following`.
## Example: Loading in a background thread
Inside `Source#fetch(keys)`, you can call `dataloader.yield` to return control to the Dataloader. This way, it will proceed loading other Sources (if there are any), then return the source that yielded.
A simple example, spinning up a new Thread:
```ruby
def fetch(keys)
# spin up some work in a background thread
thread = Thread.new {
fetch_external_data(keys)
}
# return control to the dataloader
dataloader.yield
# at this point,
# the dataloader has tried everything else and come back to this source,
# so block if necessary:
thread.value
end
```
See the {% internal_link "parallelism guide", "/dataloader/parallelism" %} for details about this approach.
## Filling the Dataloader Cache
If you load records from the database, you can use them to populate a source's cache by using {{ "Dataloader::Source#merge" | api_doc }}. For example:
```ruby
# Build a `{ key => value }` map to populate the cache
comments_by_id = post.comments.each_with_object({}) { |comment, hash| hash[comment.id] = comment }
# Merge the map into the source's cache
dataloader.with(Sources::ActiveRecordObject, Comment).merge(comments_by_id)
```
After that, any calls to `.load(id)` will use those already-loaded records if they're available.
## De-duplicating equivalent objects
Sometimes, _different_ objects in the application should load the same object from `fetch`. You can customize this behavior by implementing `def result_key_for(key)` in your application. For example, to map records from your ORM to their database ID:
```ruby
# Load the `created_by` person for a record from our database
class CreatedBySource < GraphQL::Dataloader::Source
def result_key_for(key)
key.id # Use the record's ID to deduplicate different `.load` calls
end
# Fetch a `person` for each of `records`, based on their created_by_id
def fetch(records)
PersonService.find_each(records.map(&:created_by_id))
end
end
```
In this case, `records` will include the _first_ object for each unique `record.id` -- subsequent records with the same `.id` will be assumed to be duplicates. Under the hood, the `Source` will cache the result based on the record's `id`.
Alternatively, you could use this to make the `Source` retain each incoming object, even when they would _otherwise_ be treated as duplicates. (This would come in handy when you need `def fetch` to mutate each object). For example, to treat _every_ incoming object as distinct:
```ruby
def result_key_for(record)
record.object_id # even if the records are equivalent, handle each distinct Ruby object separately
end
```
graphql-ruby-2.2.17/guides/dataloader/testing.md 0000664 0000000 0000000 00000005435 14764346352 0021624 0 ustar 00root root 0000000 0000000 ---
layout: guide
search: true
section: Dataloader
title: Testing
desc: Tips for testing Dataloader implementation
index: 4
---
There are a few techniques for testing your {{ "GraphQL::Dataloader" | api_doc }} setup.
## Integration Tests
One important feature of `Dataloader` is how it manages database access while GraphQL runs queries. You can test that by listening for database queries while running queries, for example, with ActiveRecord:
```ruby
def test_active_record_queries_are_batched_and_cached
# set up a listener function
database_queries = 0
callback = lambda {|_name, _started, _finished, _unique_id, _payload| database_queries += 1 }
query_str = <<-GRAPHQL
{
a1: author(id: 1) { name }
a2: author(id: 2) { name }
b1: book(id: 1) { author { name } }
b2: book(id: 2) { author { name } }
}
GRAPHQL
# Run the query with the listener
ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
MySchema.execute(query_str)
end
# One query for authors, one query for books
assert_equal 2, database_queries
end
```
You could also make specific assertions on the queries that are run (see the [`sql.active_record` docs](https://edgeguides.rubyonrails.org/active_support_instrumentation.html#active-record)). For other frameworks and databases, check your ORM or library for instrumentation options.
## Testing Dataloader Sources
You can also test `Dataloader` behavior outside of GraphQL using {{ "GraphQL::Dataloader.with_dataloading" | api_doc }}. For example, let's if you have a `Sources::ActiveRecord` source defined like so:
```ruby
module Sources
class User < GraphQL::Dataloader::Source
def fetch(ids)
records = User.where(id: ids)
# return a list with `nil` for any ID that wasn't found, so the shape matches
ids.map { |id| records.find { |r| r.id == id.to_i } }
end
end
end
```
You can test it like so:
```ruby
def test_it_fetches_objects_by_id
user_1, user_2, user_3 = 3.times.map { User.create! }
database_queries = 0
callback = lambda {|_name, _started, _finished, _unique_id, _payload| database_queries += 1 }
ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
GraphQL::Dataloader.with_dataloading do |dataloader|
req1 = dataloader.with(Sources::ActiveRecord).request(user_1.id)
req2 = dataloader.with(Sources::ActiveRecord).request(user_2.id)
req3 = dataloader.with(Sources::ActiveRecord).request(user_3.id)
req4 = dataloader.with(Sources::ActiveRecord).request(-1)
# Validate source's matching up of records
expect(req1.load).to eq(user_1)
expect(req2.load).to eq(user_2)
expect(req3.load).to eq(user_3)
expect(req4.load).to be_nil
end
end
assert_equal 1, database_queries, "All users were looked up at once"
end
```
graphql-ruby-2.2.17/guides/defer/ 0000775 0000000 0000000 00000000000 14764346352 0016603 5 ustar 00root root 0000000 0000000 graphql-ruby-2.2.17/guides/defer/defer-graphiql-gif.gif 0000664 0000000 0000000 00000240317 14764346352 0022736 0 ustar 00root root 0000000 0000000 GIF89aw !NETSCAPE2.0 ! , &5!*;7771D7I:L=P$-A%0B&4H+5E+3J(8L.6R+=T1:L4FX>HY/D`1Gb2Id3Kh`JMNPRTVX\\@a@dBhDkGpIsJuKyN}^`dnfphrkunxq{t~aaeegghgkjmkpnrpvtxu}y|
ORSUvx{}VWY[^``bdeghikmnp8_8`:c>j?kEpCrK{FwFxGyH|J}}KPMOPS^Vb|l뇂̕ܙ蜷 H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0FI3͛8sɳϟ@
JѣHҬӧPJJիXj-t֯`ÊKٳhӪUu۷pʝKݻ*ӫ_Ͼ˟Oo (h&iğOF(VhfeB82ˈ$8K+1x,0(4*wч0##XEG5iH&L6IE84,GNf\v`rWQM#@Vp)tHM)|AFڠW硈&jݝmA4CoVjPfM'A6E^j:qꪬ&ѧШ&(Ry+6J
(a
bAN+dD
+8ۮJZQnkFo
uk,JP '$0D9D0w DS)(,' oC#4C3-+0"<'-ZFB:6:]6pKETA7;`ت -hsGnZ
76,$0wPȐ,a,و+*B۴͵6nV006-D033A]7Dᬣ2Cs}
s
i /0l^0 l/`@ ˱`6+mL=h:Cn~0 ڱԖ1,}XAm㌓͢iCH=D$D}Ӛey}
r6+`s7W4ͥmsl
p6=@ .k;)\BH*RQxEDEp92m~F@[ݢF1Np
@
~
HD!:H\$$/Q.ZRA4$
X
M 9a69Ңj ̏