- OperationStore: Add forward compatibility for removing old validation code #5164
- OperationStore: Improve
sync
performance withGraphQL::Schema::Visibility
- Subscriptions: show broadcast subscriber count in dashboard (Pusher requires "subscription count" to be turned on and
use ... show_broadcast_subscribers_count: true
)
- OperationStore: Accept a
context:
in#add
- Subscriptions: use a single Pusher or Ably channel to deliver broadcast payloads to subscribers
- Dashboard: fix crash when a topic had no active subscriptions
- Subscriptions: Track
last_triggered_at
; add more metadata to the dashboard.
- OperationStore: require the
ActiveRecord
backend inside anActiveSupport.on_load(:active_record) { ... }
block to improve Rails compatibility
- Subscriptions: Fix another Lua error in big cleanup operations
- Subscriptions: Fix Lua error when cleaning up huge numbers of inactive subscriptions
- OperationStore: remove needless call to
.metadata
#4947
- Pundit, CanCan, OperationStore: add Rails generators for getting started
- OperationStore: Fix
.reindex
for many stored operations #4940
- Dashboard: handle missing index references gracefully #4940
- OperationStore: Don't call
query.query_string
if there's already a parsed document #4922
- RelationConnection: support Arel's
NullsFirst
andNullsLast
nodes #4910
- OperationStore::AddOperationBatch: remove rescue for StatementInvalid inside transaction
- RelationConnection: Don't quote table names that weren't quoted in original SQL, fixes #4508 (comment)
- OperationStore: fix
sync
endpoint for Rack 3+ #4829 - Improve error message handling on Rails 7.1
@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.)
- Pundit integration: improve error message when a
Scope
class is missing
-
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 by manually configuring a
pundit_policy_class
in the field's return type, then adding aclass 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: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: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
- add
- Subscriptions: send
more: false
when the server callsunsubscribe
- Ably subscriptions: update webhook handler for
presence.message
events
- OperationStore:
.dup
the givencontext
to avoid leaking state between queries when indexing - Subscriptions: use the schema or query logger to output debug messages
- OperationStore: don't sort directives when normalizing, properly retain directives on Operation and Fragment definitions #4703
- OperationStore: also pass
context:
for ActiveRecord backend batches
- OperationStore: accept
context:
forAddOperationBatch.call
#4697
- OperationStore: accept
context:
toValidate.validate
#4697
- OperationStore: don't rescue application-raised
KeyError
s #4699
- OperationStore: fix compatibility with 1.12.x #4696
- Improve compatibility with GraphQL-Ruby 1.12.x
- OperationStore: Preserve variable default values of
false
when normalizing queries
- OperationStore: search for operation during
Query#initialize
to avoid races with other instrumentation. Adduse ... trace: true
to get the old behavior.
- Stable relation connections: quote table names and column names in
WHERE
clauses #4508
- Defer: Add
incremental: true
for new proposed wire format, add example for working with GraphQL-Batch #4477
- Stable relation connection: Quote table names and column names in selects and orders #4485
@defer
: updatecontext[:current_path]
usage to fixpath:
on deferred errors
OperationStore
: fix when used with Changesets (or other ways of defining arguments with the same name) #4440
- Remove debug output, oops
- Fix
OperationStore
with new module-based execution traces (#4389)
- Support the
redis-client
gem asredis:
- Dashboard: Support Ruby 3.2.0
- OperationStore: Support
Changeset-Version
header for syncing with changesets #4304
- Stable Relation Connections: Fix handling of Postgres JSON accesses
- Subscriptions: accept
connection_pool:
instead ofredis:
for use with theconnection_pool
gem
- Stable connections: rescue
ActiveRecord::StatementInvalid
when loading nodes and return a client-facing error instead
- Ably subscriptions: Also listen for
presence.leave
webhooks to clean up subscriptions more quickly
- Dashboard: nicely render subscriptions that are not found or cleaned up by
read_subscription_failed_error
- Add
GraphQL::Pro::Subscriptions#read_subscription_failed_error
for handling errors that are raised when reloading queries from storage
- Add dashboard component for Enterprise mutation limiter
- Redis: update redis usage to be forward-compatible with redis 5.x #4167
- Stable connections: support SQL queries that sort by
IS NOT NULL
#4153
- Stable connections: handle
edges {...}
when an invalid cursor is given #4148
- Use
deprecated_accepts_definitions
to stop warnings when loading this gem on 1.13.x
- Pusher subscriptions: don't try to send empty trigger batches to Pusher
- 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. Passuse ..., update_last_used_at_every: 0
to update that column synchronously, instead, as before.
- OperationStore: Fix no method error in Redis pipeline usage
- Postgres stable connection: support more complex aliased selects #3976
- Encoders: don't extend
DeprecatedDefine
if it's not present (graphql-ruby < 1.12)
- Future-proof for GraphQL-Ruby 2.0
- Dashboard, Routes: support lazy-loading the schema with
Routes::Lazy
#3868 - OperationStore: Update deprecated usage of
@redis.pipelined
to address warning
- Stream, Defer: Include
hasNext: true|false
in patches
- Stream: Add
@stream
directive for evaluating list items one-at-a-time
- Stable connections: Fix using startCursor / endCursor without nodes #3752
- Stable Connections: Properly handle cursors containing invalid JSON #3735
- Operation Store sync: ActiveRecord backend performance improvements: when syncing operations, only validate newly-added operations, reduce allocations when normalizing incoming query strings
- Operation Store sync: fix when operations are re-synced with new aliases
- Operation Store: Use Rails
insert_all
for better performance when adding new operations
- Pundit and CanCan integrations: Add
ResolverIntegration
modules for plain resolvers #3392
- OperationStore Redis backend: pipeline updates to last_used_at values #3672
- OperationStore: fix a stack overflow error on GraphQL 1.9 #3653
- Dashboard: add a component for GraphQL-Enterprise rate limiters
- Stable cursors: raise an error on unrecognized orderings instead of ignoring them #3605
- Stable cursors: Handle
Arel::Attributes::Attribute
andArel::SqlLiteral
#3605
- Stable connections: nicely handle incoming cursors with too many sort values #3581
- Stable connections: improve handling of
SELECT
withCASE
#3558 - Defer: fix to support runtime wrapper objects in graphql-ruby 1.12.13
- Ably subscriptions: send
quickAck: true
for a faster response from Ably
- Defer: support dataloader inside deferred blocks
- Defer: support
label:
argument which is returned in the patch for that deferral #3454
- Dashboard: fix stack error when OperationStore isn't configured on a class-based schema
- 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
- Stable Connections: Re-select aliased fields that are referenced by ORDER BY. #3421
- Pundit integration: properly halt when
unauthorized_by_pundit
returns errors-as-data after a mutation argument fails authorization #3384
- Pundit, CanCan integrations: properly call configured auth hooks for arguments that are lists and input objects
- Fix OperationStore assignment on GraphQL-Ruby 1.9
- Subscriptions: change the default
cleanup_delay_s:
to 5 seconds (usecleanup_delay_s: 0
to get the old behavior)
- Subscriptions: Handle unsubscribe race condition #3357
- CanCan integration: support
can_can_subject:
config for overriding the use ofobject
as the CanCan subject #3350
- Subscriptions: Support
Redis::Namespace
without deprecation warnings forscript load
#3347
- Stable connections: implement
range_add_edge
to leverage GraphQL-Ruby 1.12.5's improved RangeAdd #2184
- Defer: Update to work with Dataloader
- 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 theredis-namespace
gem #3322
- Stable Relation Connection: Don't emit
OR ... IS NULL
for columns that are known to benull: false
(this improves index utilization)
- Pusher subscriptions:
context[:compress_pusher_payload] = true
will cause the payload to be gzipped before being sent to Pusher
- Subscriptions: don't generate keys inside Lua scripts (for redis-namespace compatibility, and probably better support for Redis cluster) #3307
- OperationStore: add
OperationStore::AddOperationBatch.call
for adding data directly - Subscriptions: use Lua scripts for more efficient Redis access
- Updates for 1.12.0 compatibility
- OperationStore: improve performance by batching reads and writes during updates
- Subscriptions: Add
stale_ttl_s:
andcleanup_delay_s:
to customize persistence in Redis #3252
- Fix duplicate calls to
Argument#authorized?
in CanCan and Pundit integrations #3242
- Ably Subscriptions:
cipher_base:
sets up end-to-end encryption
- 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
- Stable Connections: Use method access to get
.cursor_#{idx}
values instead of.attributes[:cursor_#{idx}]
, fixes #3149
- Stable Connections: use
.to_sql
to handle orderings that use complex Arel expressions (#3109)
- Pundit: add
pundit_policy_class_for(object, context)
andpundit_role_for(object, context)
for custom runtime lookups
- Subscriptions: don't send empty updates when subscriptions return
:no_update
- OperationStore: improve handling of archived operations in index views
(Oops, bad release!)
-
OperationStore: Store & display
last_used_at
for operation store clients and operations. To upgrade, add the column to your ActiveRecord table: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:
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
- CanCan: Accept
can_can_attribute:
configuration, which is passed as the third input to.can?(...)
- Add PubnubSubscriptions
- Update subscription implementations to support
broadcast: true
when available
- More Ruby 2.7 warning fixes
- Return the proper
pageInfo
values when it's requested beforeedges
ornodes
(#2972)
- Fix some warnings on Ruby 2.7
- StableRelationConnection: properly return
hasNextPage: true
whenbefore
andmax_page_size
are used.
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.
GraphQL::Pro::Subscriptions
is deprecated; useGraphQL::Pro::PusherSubscriptions
instead which works the same, but better (see below). This new name avoids confusion with the later-addedAblySubscriptions
.
GraphQL::Pro::PusherSubscriptions
replacesGraphQL::Pro::Subscriptions
and adds orphaned record cleanup. (No more dangling records in Redis.)
- Use
nonce: true
when working with cursors in new stable connections
- OperationStore supports a
redis:
backend - OperationStore supports an arbitrary
backend_class:
for persistence operations
- Use a loop when clearing Redis subscription state to avoid large stack traces #2701
- Handle empty subscription keys when publishing updates #2061
- Improve backwards compat with OperationStore (Improve adding
.tracer
, use.graphql_name
when indexing)
- Fix OperationStore on class-based schemas with query instrumenters that use the query string
GraphQL::Pro::Monitoring
is deprecated; see Tracing for a replacement: https://graphql-ruby.org/queries/tracing.htmlGraphQL::Pro::Repository
is deprecated; see OperationStore for a replacement: https://graphql-ruby.org/operation_store/overview.html
- 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
).
- Add the Access query analyzer to class-based schemas
- Forwards-compatibility for graphql 1.10.0
- Support 1.10.0.pre1's input object argument
loads:
authorization
- Continue authorizing input object arguments
- Use millisecond-aware string format for datetimes in cursors
- Support multiple subscriptions in one document
- Support custom
#can_can_ability
methods on query context for CanCanIntegration - Support custom
#pundit_user
method on query context for PunditIntegration
- Fix off-by-one error when paginating backwards from the last item in a stable relation connection
- Include expected HMAC digest in OperationStore debug output
- Include content-length and content-type headers in OperationStore JSON responses
- Support stable connections ordered by Arel SQL literals
- Support stable connections on realized views (which don't have primary keys)
- Pundit integration: support
pundit_policy_class
String names when scoping connections
- Add
GraphQL::Pro::Defer
, implementing@defer
for streaming responses
- Pundit integration: correctly authorize fields when Query root is nil
- Pundit integration: use overridden
pundit_policy_class
for scoping and mutation authorization
- 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
- Support inheritance with
pundit_policy_class(...)
- Support
pundit_policy_class(...)
andpundit_policy_class:
to manually specify a class or class name.
- Inject
context
into policy lookup hooks instead of just the user
- Extract
pundit_policy
andscope_by_pundit_policy
hooks for user override
- Properly render subscription context in dashboard
- Don't pass arrays to Pundit scopes (fixes #2008)
- Prepare for future compat with graphql-ruby 1.9
- 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
- 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
- Fix Pusher reference in AblySubscriptions
- Add
GraphQL::Pro::AblySubscriptions
for GraphQL subscriptions over Ably.io transport
- Support
NULLS LAST
in stable cursors
- Improve operation store models to work when
config.active_record.primary_key_prefix_type
is set
- Support Rails 3.2 with OperationStore
- Use
.select
to filter items in CanCanIntegration
- 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
-
PunditIntegration
: instead of raisingMutationAuthorizationFailed
when an argument fails authorization, it will send aGraphQL::UnauthorizedError
to yourSchema.unauthorized_object
hook. (This is what all other authorization failures do.) To retain the previous behavior, in your base mutation, add: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
.
- 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.
- Add
GraphQL::Pro::CanCanIntegration
which leverages GraphQL-Ruby's built-in auth
PunditIntegration
: Don't try to authorize loaded objects when they'renil
- Update
PunditIntegration
for arguments, unions, interfaces and mutations
- Add a new
PunditIntegration
which leverages the built-in authorization methods
- Authorization: fix scoping lists of abstract type when there's no
#scope
method on the strategy
- Fix ordering of authorization field instrumenter (put it at the end, not the beginning of the list)
- Authorization: Add
view
/access
/authorize
methods toGraphQL::Schema::Mutation
- 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).
- Support Mongoid::Criteria in authorization scoping
- Fix authorization code for when
ActiveRecord
is not defined
- Use a more permissive regexp (
/^\s*((?:[a-z._]+)\(.*\))\s*(asc|desc)?\s*$/im
) to parse SQL functions
- Fix route helpers to support class-based schemas
- Support
1.8-pre
versions of GraphQL-Ruby
- Fix OperationStore when other query instrumenters need
.query_string
- Support
LEAST(...)
in stable cursors
- Support
CASE ... END
in stable cursors
- Support
FIELD(...)
in stable cursors
- Improve detection of
OperationStore
for the dashboard - Serve
Content-Type
andContent-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
- Support
composite_primary_keys
gem
GraphQL::Pro::UI
renamed toGraphQL::Pro::Dashboard
- Routing method
.ui
was renamed to.dashboard
- Added
GraphQL::Pro::Subscriptions
- Added subscriptions component to Dashboard
- Don't crash when scoping lists of abstract types with Pundit
- Use
authorize(:pundit, namespace: )
to lookup policies in a namespace instead of the global namespace.
- Introspection data is allowed through
fallback:
authorize:
andaccess:
filters. (It can be hidden with aview:
filter.)
- Properly return
nil
when a list of authorized objects returnsnil
- Add
authorization(..., operation_store:)
option for authorizing operation store requests
- Support
ConnectionType.bidrectional_pagination?
in stable RelationConnection
- Fix load issue when Rails is not present
-
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 likecursor_#{idx}
, so you'll notice this in your SQL logs.
- Bump
graphql
dependency to1.6
- Routing extensions moved to
using GraphQL::Pro::Routes
- Deprecate
using GraphQL::Pro
, move extensions toGraphQL::Pro::Routes
- Add
GraphQL::Pro::OperationStore
for persisted queries with Rails
- Update
authorization
to use type-levelresolve_type
hooks
- Update authorization instrumentation for
graphql >= 1.6.5
- Fix typo in RelationConnection source
- Correctly fall back to offset-based cursors with
before:
argument
- Add
Schema#unauthorized_object(obj, ctx)
hook for failed runtime checks
- Prevent usage of
parent_role:
withview:
oraccess:
(since parent role requires a runtime check) - Fix versioned, encrypted cursors with 16-byte legacy cursors
OrderedRelationConnection
supports ordering by joined fields
- Update auth plugin for new Relay instrumenters
Pro::Encoder
supportsencoder(...)
as documented
- Fix compatibility of
RelationConnection
andRangeAdd
helper
- Add
:datadog
monitoring
ActiveRecord::Relation
s can be scoped by PunditScope
s, CanCanaccessible_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 withauthorization(..., current_user: ...)
- Serve static, persisted queries with
GraphQL::Pro::Repository
- Fix compatibility of
RelationConnection
andRangeAdd
helper
- Raise
GraphQL::Pro::RelationConnection::InvalidRelationError
when a grouped, unordered relation is returned from a field. (This relation can't be stably paginated.)
- Formally support ActiveRecord
>= 4.1.0
- Support grouped relations in
GraphQL::Pro::RelationConnection
-
Authorize fields based on their parent object, for example:
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
- Fix monitoring when
Query#selected_operation
is nil
- 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
- Fix
OrderedRelationConnection
when neitherfirst
norlast
are provided (usemax_page_size
or don't limit)
OrderedRelationConnection
exposes more metadata methods:parent
,field
,arguments
,max_page_size
,first
,after
,last
,before
- 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 toPundit.policy
, skipping apundit_policy_name
configuration.)
OrderedRelationConnection
exposes the underlying relation as#nodes
(likeRelationConnection
does), supporting custom connection fields.
-
CanCan integration now supports a custom
Ability
class with theability_class:
option:authorize :cancan, ability_class: CustomAbility
GraphQL::Pro
released