CHANGELOG-pro.md
Execution::Next runtimeostruct dependency@defer: Correctly handle fields where @defer is present twice #5434@defer: Update implementation to address warnings in GraphQL-Ruby 2.5.12+OperationStore: also support visibility_profile: on lazy routes.OperationStore: add visibility_profile: ... argument to operation_store_sync so that incoming operations are bound to the given profile.@defer, @stream: Include "data" in the payload, if there is any, even if there are "errors" #5365nil values in Postgres #5346FutureStream: Support GraphQL::ExecutionError raised from lazy enumeratorsFutureStream: Add #to_incremental_h@stream: Add FutureStream for lazy enumeratorssync performance with GraphQL::Schema::Visibilityuse ... show_broadcast_subscribers_count: true)context: in #addlast_triggered_at; add more metadata to the dashboard.ActiveRecord backend inside an ActiveSupport.on_load(:active_record) { ... } block to improve Rails compatibility.metadata #4947.reindex for many stored operations #4940query.query_string if there's already a parsed document #4922NullsFirst and NullsLast nodes #4910sync endpoint for Rack 3+ #4829@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.)Scope class is missingPundit 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:
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)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:
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
more: false when the server calls unsubscribepresence.message events.dup the given context to avoid leaking state between queries when indexingcontext: for ActiveRecord backend batchescontext: for AddOperationBatch.call #4697context: to Validate.validate #4697KeyErrors #4699false when normalizing queriesQuery#initialize to avoid races with other instrumentation. Add use ... trace: true to get the old behavior.WHERE clauses #4508incremental: true for new proposed wire format, add example for working with GraphQL-Batch #4477@defer: update context[:current_path] usage to fix path: on deferred errorsOperationStore: fix when used with Changesets (or other ways of defining arguments with the same name) #4440OperationStore with new module-based execution traces (#4389)redis-client gem as redis:Changeset-Version header for syncing with changesets #4304connection_pool: instead of redis: for use with the connection_pool gemActiveRecord::StatementInvalid when loading nodes and return a client-facing error insteadpresence.leave webhooks to clean up subscriptions more quicklyread_subscription_failed_errorGraphQL::Pro::Subscriptions#read_subscription_failed_error for handling errors that are raised when reloading queries from storageIS NOT NULL #4153edges {...} when an invalid cursor is given #4148deprecated_accepts_definitions to stop warnings when loading this gem on 1.13.xuse ..., batch_size: 1 to revert to the previous behavior.last_used_at every 5 seconds. Pass use ..., update_last_used_at_every: 0 to update that column synchronously, instead, as before.DeprecatedDefine if it's not present (graphql-ruby < 1.12)Routes::Lazy #3868@redis.pipelined to address warninghasNext: true|false in patches@stream directive for evaluating list items one-at-a-timeinsert_all for better performance when adding new operationsResolverIntegration modules for plain resolvers #3392Arel::Attributes::Attribute and Arel::SqlLiteral #3605SELECT with CASE #3558quickAck: true for a faster response from Ablylabel: argument which is returned in the patch for that deferral #3454use_owner_role(true) configuration optionunauthorized_by_pundit returns errors-as-data after a mutation argument fails authorization #3384cleanup_delay_s: to 5 seconds (use cleanup_delay_s: 0 to get the old behavior)can_can_subject: config for overriding the use of object as the CanCan subject #3350Redis::Namespace without deprecation warnings for script load #3347range_add_edge to leverage GraphQL-Ruby 1.12.5's improved RangeAdd #2184MULTI instead of Lua for some operationsEVAL_SHA for duplicate scripts to reduce network overhead #3285redis.call, which is unsupported in the redis-namespace gem #3322OR ... IS NULL for columns that are known to be null: false (this improves index utilization)context[:compress_pusher_payload] = true will cause the payload to be gzipped before being sent to PusherOperationStore::AddOperationBatch.call for adding data directlystale_ttl_s: and cleanup_delay_s: to customize persistence in Redis #3252Argument#authorized? in CanCan and Pundit integrations #3242cipher_base: sets up end-to-end encryptionARRAY[...] selections and cursors on Postgres #3166.cursor_#{idx} values instead of .attributes[:cursor_#{idx}], fixes #3149.to_sql to handle orderings that use complex Arel expressions (#3109)pundit_policy_class_for(object, context) and pundit_role_for(object, context) for custom runtime lookups:no_update(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
can_can_attribute: configuration, which is passed as the third input to .can?(...)broadcast: true when availablepageInfo values when it's requested before edges or nodes (#2972)hasNextPage: true when before and max_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; use GraphQL::Pro::PusherSubscriptions instead which works the same, but better (see below). This new name avoids confusion with the later-added AblySubscriptions.GraphQL::Pro::PusherSubscriptions replaces GraphQL::Pro::Subscriptions and adds orphaned record cleanup. (No more dangling records in Redis.)nonce: true when working with cursors in new stable connectionsredis: backendbackend_class: for persistence operations.tracer, use .graphql_name when indexing)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.htmlNULL 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).loads: authorization#can_can_ability methods on query context for CanCanIntegration#pundit_user method on query context for PunditIntegrationpundit_policy_class String names when scoping connectionsGraphQL::Pro::Defer, implementing @defer for streaming responsespundit_policy_class for scoping and mutation authorizationpundit_policy_class if there is one#initialize for schema classes that don't need itpundit_policy_class(...)pundit_policy_class(...) and pundit_policy_class: to manually specify a class or class name.context into policy lookup hooks instead of just the userpundit_policy and scope_by_pundit_policy hooks for user overriderake routes output for operation store endpoint.log files from the gem bundleGraphQL::Pro::AblySubscriptions for GraphQL subscriptions over Ably.io transportNULLS LAST in stable cursorsconfig.active_record.primary_key_prefix_type is set.select to filter items in CanCanIntegrationcan_can_action to .accessible_byContent-Length header in the dashboardPunditIntegration: 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:
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.
GraphQL::Pro::CanCanIntegration which leverages GraphQL-Ruby's built-in authPunditIntegration: Don't try to authorize loaded objects when they're nilPunditIntegration for arguments, unions, interfaces and mutationsPunditIntegration which leverages the built-in authorization methods#scope method on the strategyview/access/authorize methods to GraphQL::Schema::Mutationfallback: 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).ActiveRecord is not defined/^\s*((?:[a-z._]+)\(.*\))\s*(asc|desc)?\s*$/im) to parse SQL functions1.8-pre versions of GraphQL-Ruby.query_stringLEAST(...) in stable cursorsCASE ... END in stable cursorsFIELD(...) in stable cursorsOperationStore for the dashboardContent-Type and Content-Length headers with dashboard pagesDashboard#inspect for Rails routes outputcomposite_primary_keys gemGraphQL::Pro::UI renamed to GraphQL::Pro::Dashboard.ui was renamed to .dashboardGraphQL::Pro::Subscriptionsauthorize(:pundit, namespace: ) to lookup policies in a namespace instead of the global namespace.fallback: authorize: and access: filters. (It can be hidden with a view: filter.)nil when a list of authorized objects returns nilauthorization(..., operation_store:) option for authorizing operation store requestsConnectionType.bidrectional_pagination? in stable RelationConnectionFix 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.
graphql dependency to 1.6using GraphQL::Pro::Routesusing GraphQL::Pro, move extensions to GraphQL::Pro::RoutesGraphQL::Pro::OperationStore for persisted queries with Railsauthorization to use type-level resolve_type hooksgraphql >= 1.6.5before: argumentSchema#unauthorized_object(obj, ctx) hook for failed runtime checksparent_role: with view: or access: (since parent role requires a runtime check)OrderedRelationConnection supports ordering by joined fieldsPro::Encoder supports encoder(...) as documentedRelationConnection and RangeAdd helper:datadog monitoringActiveRecord::Relations can be scoped by Pundit Scopes, CanCan accessible_by, or custom strategy's #scope(gate, relation) methodsauthorization(..., fallback: { ... }):current_user key can be customized with authorization(..., current_user: ...)GraphQL::Pro::RepositoryRelationConnection and RangeAdd helperGraphQL::Pro::RelationConnection::InvalidRelationError when a grouped, unordered relation is returned from a field. (This relation can't be stably paginated.)>= 4.1.0GraphQL::Pro::RelationConnectionAuthorize 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
Query#selected_operation is nilmonitor_scalars: false to skip monitoring on scalarsOrderedRelationConnection when neither first nor last are provided (use max_page_size or don't limit)OrderedRelationConnection exposes more metadata methods: parent, field, arguments, max_page_size, first, after, last, before__graphql_pro_access_not_allowed__.nil. (It previously fell back to Pundit.policy, skipping a pundit_policy_name configuration.)OrderedRelationConnection exposes the underlying relation as #nodes (like RelationConnection does), supporting custom connection fields.CanCan integration now supports a custom Ability class with the ability_class: option:
authorize :cancan, ability_class: CustomAbility
GraphQL::Pro released