From f15fa66f03fadceb0f2c60e5268ff3196c047724 Mon Sep 17 00:00:00 2001 From: Eduardo Morales Date: Wed, 15 Oct 2025 11:16:48 -0300 Subject: [PATCH 01/18] authorize action refactor --- lib/hq/graphql/ext/object_extensions.rb | 2 +- lib/hq/graphql/field.rb | 2 +- lib/hq/graphql/version.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/hq/graphql/ext/object_extensions.rb b/lib/hq/graphql/ext/object_extensions.rb index c53c428..27c6ddc 100644 --- a/lib/hq/graphql/ext/object_extensions.rb +++ b/lib/hq/graphql/ext/object_extensions.rb @@ -57,7 +57,7 @@ def with_model(model_name, attributes: true, associations: true, auto_nil: true, attr_writer :authorized_action def authorized_action - @authorized_action ||= :read + @authorized_action ||= :view end def field_from_association(association, auto_nil:, internal_association: false, &block) diff --git a/lib/hq/graphql/field.rb b/lib/hq/graphql/field.rb index 8e36adf..a0b7dcd 100644 --- a/lib/hq/graphql/field.rb +++ b/lib/hq/graphql/field.rb @@ -5,7 +5,7 @@ module GraphQL class Field < ::GraphQL::Schema::Field attr_reader :authorize_action, :authorize - def initialize(*args, authorize_action: :read, authorize: nil, klass: nil, **options, &block) + def initialize(*args, authorize_action: :view, authorize: nil, klass: nil, **options, &block) super(*args, **options, &block) @authorize_action = authorize_action @authorize = authorize diff --git a/lib/hq/graphql/version.rb b/lib/hq/graphql/version.rb index df82d51..f69e598 100644 --- a/lib/hq/graphql/version.rb +++ b/lib/hq/graphql/version.rb @@ -2,6 +2,6 @@ module HQ module GraphQL - VERSION = "2.3.6" + VERSION = "3.2.0" end end From 199ad3fc3a288bbb3177d457832a1fec9e2f1fd2 Mon Sep 17 00:00:00 2001 From: Eduardo Morales Date: Wed, 15 Oct 2025 17:49:15 -0300 Subject: [PATCH 02/18] change version --- lib/hq/graphql/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hq/graphql/version.rb b/lib/hq/graphql/version.rb index f69e598..df50950 100644 --- a/lib/hq/graphql/version.rb +++ b/lib/hq/graphql/version.rb @@ -2,6 +2,6 @@ module HQ module GraphQL - VERSION = "3.2.0" + VERSION = "2.3.7" end end From e83424a05a468ef411bfd5a226357b6a20ebd6ad Mon Sep 17 00:00:00 2001 From: Eduardo Morales Date: Wed, 15 Oct 2025 18:00:39 -0300 Subject: [PATCH 03/18] 3.2.0 version --- lib/hq/graphql/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hq/graphql/version.rb b/lib/hq/graphql/version.rb index df50950..f69e598 100644 --- a/lib/hq/graphql/version.rb +++ b/lib/hq/graphql/version.rb @@ -2,6 +2,6 @@ module HQ module GraphQL - VERSION = "2.3.7" + VERSION = "3.2.0" end end From 3626e35364d1333a86ce01c11bdf2274d03e6c1f Mon Sep 17 00:00:00 2001 From: Eduardo Morales Date: Wed, 15 Oct 2025 18:13:35 -0300 Subject: [PATCH 04/18] 2.4.0 version --- lib/hq/graphql/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hq/graphql/version.rb b/lib/hq/graphql/version.rb index f69e598..4a4fa97 100644 --- a/lib/hq/graphql/version.rb +++ b/lib/hq/graphql/version.rb @@ -2,6 +2,6 @@ module HQ module GraphQL - VERSION = "3.2.0" + VERSION = "2.4.0" end end From 4025eeb2c9740522250a10a2bb390c8c4d92f896 Mon Sep 17 00:00:00 2001 From: Eduardo Morales Date: Thu, 16 Oct 2025 15:14:16 -0300 Subject: [PATCH 05/18] fix combustion error --- hq-graphql.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/hq-graphql.gemspec b/hq-graphql.gemspec index 358c410..db4536f 100644 --- a/hq-graphql.gemspec +++ b/hq-graphql.gemspec @@ -25,6 +25,7 @@ Gem::Specification.new do |s| s.add_dependency "graphql-schema_comparator", "~> 1.0" s.add_dependency "pg", "~> 1.1" + s.add_development_dependency 'concurrent-ruby', "1.3.4" s.add_development_dependency "byebug", "~> 11.0" s.add_development_dependency "combustion", "~> 1.1" s.add_development_dependency "database_cleaner", "~> 1.7" From b42f443c574628e9b0a58d3671d2a79bd3a4a7df Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 27 Nov 2025 11:16:53 -0300 Subject: [PATCH 06/18] change on rails dependencies --- hq-graphql.gemspec | 2 +- lib/hq/graphql/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hq-graphql.gemspec b/hq-graphql.gemspec index 358c410..260e643 100644 --- a/hq-graphql.gemspec +++ b/hq-graphql.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |s| s.files = Dir["{lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - s.add_dependency "rails", "~> 6.0" + s.add_dependency "rails", ">= 6.0", "<= 8.1.1" s.add_dependency "graphql", "~> 1.12" s.add_dependency "graphql-batch", "~> 0.4" diff --git a/lib/hq/graphql/version.rb b/lib/hq/graphql/version.rb index df82d51..df50950 100644 --- a/lib/hq/graphql/version.rb +++ b/lib/hq/graphql/version.rb @@ -2,6 +2,6 @@ module HQ module GraphQL - VERSION = "2.3.6" + VERSION = "2.3.7" end end From e942d1a6fecdca717f1e395cefa0c15fa669b810 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 27 Nov 2025 13:22:27 -0300 Subject: [PATCH 07/18] changelog to standard --- CHANGELOG.md | 189 ++++++++++++++++++++++++--------------------------- 1 file changed, 89 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36d4035..dd3ca54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,69 +1,76 @@ -# Changelog - -### Breaking changes - -### Deprecations - -### New features - -### Bug fixes - -# 2.3.6 (6 December 2024) - -### Bug fixes +# HQ_GRAPHQL -- All pagination queries created with root_query, def_root and resolvers will have a 250 limit as default. +# Changelog -# 2.3.5 (14 January 2023) +All notable changes to this project are documented in this file -### Breaking changes +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -- New Queries will execute validations instead of after_initialize callback. Will accept initial parameters before run validations +### Guiding Principles -# 2.3.4 (6 March 2023) +- Changelogs are for humans, not machines. +- There should be an entry for every single version. +- The same types of changes should be grouped. +- Versions and sections should be linkable. +- The latest version comes first. +- The release date of each version is displayed. +- Mention whether you follow Semantic Versioning. -### Breaking changes +### Types of changes -- limit_max is removed from root_query. Now is 250 +- **Added** for new features. +- **Changed** for changes in existing functionality. +- **Deprecated** for soon-to-be removed features. +- **Removed** for now removed features. +- **Fixed** for any bug fixes. +- **Security** in case of vulnerabilities. -# 2.3.3 (3 February 2023) +# [2.2.0] 2021-01-27 +### Changed +- Removed ::HQ::GraphQL::Types::Object. Use ::GraphQL::Types::JSON. +- Removed ::HQ::GraphQL::Schema::Enum. Use ::GraphQL::Schema::Enum. +- Removed ::HQ::GraphQL::Schema::InputObject. Use ::GraphQL::Schema::InputObject. +- Removed ::HQ::GraphQL::Schema::Mutation. Use ::GraphQL::Schema::Mutation. +- Removed ::HQ::GraphQL::Schema::Object. Use ::GraphQL::Schema::Object. +- Removed ::HQ::GraphQL::Schema. Use ::GraphQL::Schema. +### Added +- Supports graphql-ruby v1.12 and the ::GraphQL::Execution::Interpreter -### New features +# [2.2.1] 2021-02-04 +### Fixed +- Fixed a problem with `::HQ::GraphQL::Comparator` not working correctly when comparing schema definitions -- By default, New Queries will be generated if Create Mutation is available. These queries will be useful for forms init. Default values will be based on methods applied using after_initialize callback on model. +# [2.2.2] 2021-02-12 +### Fixed +- UUID scalar supports nil input. This is related to a change introduced in graphql-ruby v1.10 in which `.coerce_input` is called on nil values. -``` -{ - newAdvisor { - name - advisor_status_id - demographic { - id - ... - } +# [2.2.3] 2021-07-21 +### Added +- Root queries support field filters +```graphql +query { + users(filters: [{ field: username, operation: LIKE, value: "gmail.com" }]) { + id + username } } ``` -# 2.3.2 (13 January 2023) - -### New features - -- Root queries filters with new filters: - Operation IN: field included in array_values - OR filter: add isOr: true to pass an OR statement (based on filter order passed) - Comparison between columns: using column_value argument - -# 2.3.0 (8 November 2022) - -### Breaking changes - -- All list queries are now pagination based on queries (connection type) +# [2.2.4] 2021-10-08 +### Fixed +- Multiplex queries correctly load dynamic types -# 2.2.6 (23 September 2022) +# [2.2.5] 2021-11-02 +### Fixed +- Date Type issue fixed -### New features +# [2.2.6] 2022-02-14 +### Fixed +- FilterInput type naming change due to naming collision with resources +# [2.2.6] 2022-09-23 +### Added - List queries with optional pagination based on queries (connection type) ``` query { @@ -76,64 +83,46 @@ query { } ``` +# [2.3.0] 2022-11-08 +### Changed +- All list queries are now pagination based on queries (connection type) +# [2.3.2] 2023-01-13 +### Added +- Root queries filters with new filters: + * Operation IN: field included in array_values + * OR filter: add isOr: true to pass an OR statement (based on filter order passed) + * Comparison between columns: using column_value argument -# 2.2.6 (14 February 2022) - -### Bug fixes - -- FilterInput type naming change due to naming collision with resources - -# 2.2.5 (2 November 2021) - -### Bug fixes - -- Date Type issue fixed - -# 2.2.4 (8 October 2021) - -### Bug fixes - -- Multiplex queries correctly load dynamic types - -# 2.2.3 (21 July 2021) - -### New features - -- Root queries support field filters - -```graphql -query { - users(filters: [{ field: username, operation: LIKE, value: "gmail.com" }]) { - id - username +# [2.3.3] 2023-02-03 +### Added +- By default, New Queries will be generated if Create Mutation is available. These queries will be useful for forms init. Default values will be based on methods applied using after_initialize callback on model. +``` +{ + newAdvisor { + name + advisor_status_id + demographic { + id + ... + } } } ``` -# 2.2.2 (12 February 2021) - -### Bug fixes - -- UUID scalar supports nil input. This is related to a change introduced in graphql-ruby v1.10 in which `.coerce_input` is called on nil values. - -# 2.2.1 (04 February 2021) - -### Bug fixes - -- Fixed a problem with `::HQ::GraphQL::Comparator` not working correctly when comparing schema definitions - -# 2.2.0 (27 January 2021) - -### Breaking changes +# [2.3.4] 2023-03-06 +### Changed +- limit_max is removed from root_query. Now is 250 -- Removed ::HQ::GraphQL::Types::Object. Use ::GraphQL::Types::JSON. -- Removed ::HQ::GraphQL::Schema::Enum. Use ::GraphQL::Schema::Enum. -- Removed ::HQ::GraphQL::Schema::InputObject. Use ::GraphQL::Schema::InputObject. -- Removed ::HQ::GraphQL::Schema::Mutation. Use ::GraphQL::Schema::Mutation. -- Removed ::HQ::GraphQL::Schema::Object. Use ::GraphQL::Schema::Object. -- Removed ::HQ::GraphQL::Schema. Use ::GraphQL::Schema. +## [2.3.5] 2024-12-06 +### Fixed +- New Queries will execute validations instead of after_initialize callback. Will accept initial parameters before run validations -### New features +## [2.3.6] 2024-12-06 +### Fixed +- All pagination queries created with root_query, def_root and resolvers will have a 250 limit as default. -- Supports graphql-ruby v1.12 and the ::GraphQL::Execution::Interpreter +## [2.3.7] 2025-11-27 +### Changed +- Changelog file modified for standard +- On the gemspec file, allow to be used for Rails versions between 6.1 and 8.1.1. From 69d3a22d7a12c32a8359262df6b35ff242b09c25 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Tue, 2 Dec 2025 16:33:07 -0300 Subject: [PATCH 08/18] to 5.0.0 --- CHANGELOG.md | 5 +++-- Gemfile | 2 +- lib/hq/graphql/version.rb | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3ca54..0c8caa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,7 +122,8 @@ query { ### Fixed - All pagination queries created with root_query, def_root and resolvers will have a 250 limit as default. -## [2.3.7] 2025-11-27 +## [5.0.0] 2025-12-01 ### Changed - Changelog file modified for standard -- On the gemspec file, allow to be used for Rails versions between 6.1 and 8.1.1. +- Ruby version upgraded to 3.4.4 +- In the gemspec file, allow to be used for Rails versions between 6.1 and 8.1.1. diff --git a/Gemfile b/Gemfile index 97e42f0..4a1c230 100644 --- a/Gemfile +++ b/Gemfile @@ -6,5 +6,5 @@ gemspec # fix rspec conflict caused by rails 6 gem "net-imap", require: false -gem "net-pop", require: false +gem "net-pop", require: false gem "net-smtp", require: false diff --git a/lib/hq/graphql/version.rb b/lib/hq/graphql/version.rb index df50950..ae6db52 100644 --- a/lib/hq/graphql/version.rb +++ b/lib/hq/graphql/version.rb @@ -2,6 +2,6 @@ module HQ module GraphQL - VERSION = "2.3.7" + VERSION = "5.0.0" end end From e16f517a829957610d3dbe5cfb87845fe95175a5 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Tue, 2 Dec 2025 17:24:46 -0300 Subject: [PATCH 09/18] version patch --- lib/hq/graphql/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hq/graphql/version.rb b/lib/hq/graphql/version.rb index ae6db52..0f3c18c 100644 --- a/lib/hq/graphql/version.rb +++ b/lib/hq/graphql/version.rb @@ -2,6 +2,6 @@ module HQ module GraphQL - VERSION = "5.0.0" + VERSION = "5.0.0-beta.1" end end From 081a089c3682705e15f2619e3b294188f21da8ec Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Tue, 2 Dec 2025 17:25:41 -0300 Subject: [PATCH 10/18] rubocop --- hq-graphql.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hq-graphql.gemspec b/hq-graphql.gemspec index 0aeea8d..eaf97bb 100644 --- a/hq-graphql.gemspec +++ b/hq-graphql.gemspec @@ -25,9 +25,9 @@ Gem::Specification.new do |s| s.add_dependency "graphql-schema_comparator", "~> 1.0" s.add_dependency "pg", "~> 1.1" - s.add_development_dependency 'concurrent-ruby', "1.3.4" s.add_development_dependency "byebug", "~> 11.0" s.add_development_dependency "combustion", "~> 1.1" + s.add_development_dependency "concurrent-ruby", "1.3.4" s.add_development_dependency "database_cleaner", "~> 1.7" s.add_development_dependency "factory_bot_rails", "~> 5.0" s.add_development_dependency "faker", "~> 2.1" From 9ad767884caff1842ad1da5812de67987d0ea8a5 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Wed, 10 Dec 2025 11:21:29 -0300 Subject: [PATCH 11/18] rubocop upgrade and fixes --- .rubocop-https---onehq-com-rubocop3-yml | 229 ------------------ .rubocop.yml | 3 +- Gemfile | 1 + hq-graphql.gemspec | 8 +- lib/hq/graphql/filters.rb | 6 +- .../filters/relative_date_expression.rb | 8 +- lib/hq/graphql/resource.rb | 1 - lib/hq/graphql/version.rb | 2 +- .../pagination_connection_type_spec.rb | 2 +- spec/lib/graphql/types_spec.rb | 2 +- 10 files changed, 15 insertions(+), 247 deletions(-) delete mode 100644 .rubocop-https---onehq-com-rubocop3-yml diff --git a/.rubocop-https---onehq-com-rubocop3-yml b/.rubocop-https---onehq-com-rubocop3-yml deleted file mode 100644 index aa6013f..0000000 --- a/.rubocop-https---onehq-com-rubocop3-yml +++ /dev/null @@ -1,229 +0,0 @@ -require: - - rubocop-performance - - rubocop-rails - -AllCops: - TargetRubyVersion: 3.0 - DisabledByDefault: true - NewCops: disable - Exclude: - - "**/node_modules/**/*" - - "**/spec/**/*" - - "**/templates/**/*" - - "**/vendor/**/*" - -Bundler: - Enabled: true - -Gemspec: - Enabled: true - -Lint: - Enabled: true - -Naming: - Enabled: true - -Rails: - Enabled: true - -Performance: - Enabled: true - -Security: - Enabled: true - -Layout/CaseIndentation: - Enabled: true - -# Align comments with method definitions. -Layout/CommentIndentation: - Enabled: true - -Layout/DotPosition: - Enabled: true - EnforcedStyle: trailing - -Layout/ElseAlignment: - Enabled: true - -# Align `end` with the matching keyword or starting expression except for -# assignments, where it should be aligned with the LHS. -Layout/EndAlignment: - Enabled: true - EnforcedStyleAlignWith: variable - AutoCorrect: true - -Layout/EmptyLineAfterMagicComment: - Enabled: true - -Layout/EmptyLinesAroundBlockBody: - Enabled: true - -# In a regular class definition, no empty lines around the body. -Layout/EmptyLinesAroundClassBody: - Enabled: true - -# In a regular method definition, no empty lines around the body. -Layout/EmptyLinesAroundMethodBody: - Enabled: true - -# In a regular module definition, no empty lines around the body. -Layout/EmptyLinesAroundModuleBody: - Enabled: true - -Layout/FirstArgumentIndentation: - Enabled: true - -Layout/IndentationConsistency: - Enabled: true - -# Two spaces, no tabs (for indentation). -Layout/IndentationWidth: - Enabled: true - -Layout/LeadingCommentSpace: - Enabled: true - -Layout/SpaceAfterColon: - Enabled: true - -Layout/SpaceAfterComma: - Enabled: true - -Layout/SpaceAfterSemicolon: - Enabled: true - -Layout/SpaceAroundEqualsInParameterDefault: - Enabled: true - -Layout/SpaceAroundKeyword: - Enabled: true - -Layout/SpaceAroundOperators: - Enabled: true - -Layout/SpaceBeforeComma: - Enabled: true - -Layout/SpaceBeforeComment: - Enabled: true - -Layout/SpaceBeforeFirstArg: - Enabled: true - -# Use `foo {}` not `foo{}`. -Layout/SpaceBeforeBlockBraces: - Enabled: true - -# Use `foo { bar }` not `foo {bar}`. -Layout/SpaceInsideBlockBraces: - Enabled: true - EnforcedStyleForEmptyBraces: space - -# Use `{ a: 1 }` not `{a:1}`. -Layout/SpaceInsideHashLiteralBraces: - Enabled: true - -Layout/SpaceInsideParens: - Enabled: true - -# Detect hard tabs, no hard tabs. -Layout/IndentationStyle: - Enabled: true - -# Blank lines should not have any spaces. -Layout/TrailingEmptyLines: - Enabled: true - -# No trailing whitespace. -Layout/TrailingWhitespace: - Enabled: true - -Naming/PredicateName: - Enabled: false - -Naming/MethodParameterName: - Enabled: false - -Performance/RedundantBlockCall: - Enabled: false - -Rails/ApplicationController: - Enabled: false - -Rails/ApplicationMailer: - Enabled: false - -Rails/ApplicationRecord: - Enabled: false - -Rails/Date: - Enabled: false - -Rails/LexicallyScopedActionFilter: - Enabled: false - -Rails/Output: - Enabled: false - -Rails/RakeEnvironment: - Enabled: false - -Rails/SkipsModelValidations: - Enabled: true - AllowedMethods: [update_all] - -# Prefer &&/|| over and/or. -Style/AndOr: - Enabled: true - -# Prefer Foo.method over Foo::method -Style/ColonMethodCall: - Enabled: true - -Style/DefWithParentheses: - Enabled: true - -Style/BlockDelimiters: - Enabled: true - -Style/FrozenStringLiteralComment: - Enabled: true - EnforcedStyle: always - -# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }. -Style/HashSyntax: - Enabled: true - -# Defining a method with parameters needs parentheses. -Style/MethodDefParentheses: - Enabled: true - -Style/ParenthesesAroundCondition: - Enabled: true - -Style/RedundantBegin: - Enabled: true - -Style/RedundantFreeze: - Enabled: true - -# Use quotes for string literals when they are enough. -Style/RedundantPercentQ: - Enabled: true - -Style/RedundantReturn: - Enabled: true - AllowMultipleReturnValues: true - -Style/Semicolon: - Enabled: true - AllowAsExpressionSeparator: true - -Style/StringLiterals: - Enabled: true - EnforcedStyle: double_quotes - -Style/TrivialAccessors: - Enabled: true diff --git a/.rubocop.yml b/.rubocop.yml index 458c498..9ad0bb3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,6 +1,5 @@ inherit_from: - - https://onehq.com/rubocop3.yml + - https://onehq.com/rubocop3_4.yml AllCops: SuggestExtensions: false - TargetRubyVersion: 2.6 diff --git a/Gemfile b/Gemfile index 4a1c230..15965a7 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,7 @@ # frozen_string_literal: true source "https://rubygems.org" +gem "bundler-audit", "~> 0.9.3" gemspec diff --git a/hq-graphql.gemspec b/hq-graphql.gemspec index eaf97bb..58d28fe 100644 --- a/hq-graphql.gemspec +++ b/hq-graphql.gemspec @@ -14,7 +14,7 @@ Gem::Specification.new do |s| s.summary = "OneHQ GraphQL Library" s.description = "OneHQ GraphQL Library" s.license = "MIT" - s.required_ruby_version = ">= 2.6" + s.required_ruby_version = ">= 3.4" s.files = Dir["{lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] @@ -34,7 +34,7 @@ Gem::Specification.new do |s| s.add_development_dependency "rspec", "~> 3.8" s.add_development_dependency "rspec_junit_formatter", "~> 0.4.1" s.add_development_dependency "rspec-rails", "~> 4.0" - s.add_development_dependency "rubocop", "~> 1.8" - s.add_development_dependency "rubocop-performance", "~> 1.4" - s.add_development_dependency "rubocop-rails", "~> 2.3" + s.add_development_dependency "rubocop", ">= 1.60", "< 2.0" + s.add_development_dependency "rubocop-performance", ">= 1.20", "< 3.0" + s.add_development_dependency "rubocop-rails", ">= 2.24", "< 3.0" end diff --git a/lib/hq/graphql/filters.rb b/lib/hq/graphql/filters.rb index c16f07b..8b06a1b 100644 --- a/lib/hq/graphql/filters.rb +++ b/lib/hq/graphql/filters.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require "hq/graphql/filter_operations" require "hq/graphql/util" require "hq/graphql/filters/relative_date_expression" @@ -145,9 +146,7 @@ def initialize(name:, type:, graphql_name: nil, description: nil, operations: ni @operations = normalize_operations(Array(operations)) end - def graphql_name - @graphql_name - end + attr_reader :graphql_name def resolver? @resolver.present? @@ -448,7 +447,6 @@ def column_value_presence def range_operation? [DATE_RANGE_BETWEEN, DATE_RANGE_NOT_BETWEEN].include?(operation) end - end class NumericFilter < Filter diff --git a/lib/hq/graphql/filters/relative_date_expression.rb b/lib/hq/graphql/filters/relative_date_expression.rb index acd8f9d..aab2309 100644 --- a/lib/hq/graphql/filters/relative_date_expression.rb +++ b/lib/hq/graphql/filters/relative_date_expression.rb @@ -90,9 +90,9 @@ def parse_anchor(payload) anchor = payload[:anchor].to_s.downcase offset = case position - when "last" then -1 - when "next" then 1 - else 0 + when "last" then -1 + when "next" then 1 + else 0 end adjusted = current_time.advance(period_plural(period) => offset) @@ -133,7 +133,7 @@ def period_plural(period) end def current_time - Time.zone ? Time.zone.now : Time.now + Time.zone ? Time.zone.now : Time.current end end end diff --git a/lib/hq/graphql/resource.rb b/lib/hq/graphql/resource.rb index 5692bc1..9826385 100644 --- a/lib/hq/graphql/resource.rb +++ b/lib/hq/graphql/resource.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require "set" require "hq/graphql/ext/enum_extensions" require "hq/graphql/ext/input_object_extensions" require "hq/graphql/ext/object_extensions" diff --git a/lib/hq/graphql/version.rb b/lib/hq/graphql/version.rb index 0f3c18c..1b069bf 100644 --- a/lib/hq/graphql/version.rb +++ b/lib/hq/graphql/version.rb @@ -2,6 +2,6 @@ module HQ module GraphQL - VERSION = "5.0.0-beta.1" + VERSION = "5.0.0-beta.2" end end diff --git a/spec/lib/graphql/pagination_connection_type_spec.rb b/spec/lib/graphql/pagination_connection_type_spec.rb index 3bea558..f3178d3 100644 --- a/spec/lib/graphql/pagination_connection_type_spec.rb +++ b/spec/lib/graphql/pagination_connection_type_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::PaginationConnectionType do let(:resource) do diff --git a/spec/lib/graphql/types_spec.rb b/spec/lib/graphql/types_spec.rb index e8b7585..8952526 100644 --- a/spec/lib/graphql/types_spec.rb +++ b/spec/lib/graphql/types_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::Types do From 8a6b96b054a76684f17a92baa70bdd86bae72d5d Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Wed, 10 Dec 2025 11:25:13 -0300 Subject: [PATCH 12/18] rails 7 changes --- lib/hq/graphql/association_loader.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/hq/graphql/association_loader.rb b/lib/hq/graphql/association_loader.rb index e096ed2..00ddaf5 100644 --- a/lib/hq/graphql/association_loader.rb +++ b/lib/hq/graphql/association_loader.rb @@ -35,7 +35,10 @@ def validate end def preload_association(records) - ::ActiveRecord::Associations::Preloader.new.preload(records, @association_name) + ::ActiveRecord::Associations::Preloader.new( + records: records, + associations: @association_name + ).call end def read_association(record) From 65f324e8dbd56c07549419e4948eeb30a99650bc Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Wed, 10 Dec 2025 11:33:23 -0300 Subject: [PATCH 13/18] ruby 3.4.4 target on tekton --- .tekton/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.tekton/values.yaml b/.tekton/values.yaml index 010a738..a4a3df8 100644 --- a/.tekton/values.yaml +++ b/.tekton/values.yaml @@ -16,6 +16,6 @@ global: vault.security.banzaicloud.io/vault-path: "jwt-hub" vault.security.banzaicloud.io/vault-auth-method: "jwt" vault.security.banzaicloud.io/vault-tls-secret: "custom-trusted-ca" - rubyVersion: 3.0.4 + rubyVersion: 3.4.4 gem: *gem mountGemDockerfile: true From a38c74f1803bac3896e0ef5ca9b44100d6dcc66c Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Wed, 10 Dec 2025 11:34:42 -0300 Subject: [PATCH 14/18] ruby 3.4.4 target on tekton pt2 --- .tekton/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.tekton/values.yaml b/.tekton/values.yaml index a4a3df8..89c11f1 100644 --- a/.tekton/values.yaml +++ b/.tekton/values.yaml @@ -1,4 +1,4 @@ -rubyVersion: 3.0.0 +rubyVersion: 3.4.4 publish: false gem: &gem hq-graphql From 3b44f6e02a245d90fb304a713f7244340e35c46c Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Tue, 23 Dec 2025 13:16:07 -0300 Subject: [PATCH 15/18] beta.2 --- CHANGELOG.md | 22 +++++++------- Gemfile | 5 ++-- hq-graphql.gemspec | 30 +++++++++---------- .../graphql/paginated_association_loader.rb | 24 +++++++-------- spec/internal/app/models/manager.rb | 8 ++--- spec/internal/db/schema.rb | 26 ++++++++-------- .../paginated_association_loader_spec.rb | 8 ++--- 7 files changed, 62 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c8caa0..83587ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -97,18 +97,18 @@ query { # [2.3.3] 2023-02-03 ### Added - By default, New Queries will be generated if Create Mutation is available. These queries will be useful for forms init. Default values will be based on methods applied using after_initialize callback on model. -``` -{ - newAdvisor { - name - advisor_status_id - demographic { - id - ... + ``` + { + newAdvisor { + name + advisor_status_id + demographic { + id + ... + } + } } - } -} -``` + ``` # [2.3.4] 2023-03-06 ### Changed diff --git a/Gemfile b/Gemfile index 15965a7..26c8829 100644 --- a/Gemfile +++ b/Gemfile @@ -2,10 +2,11 @@ source "https://rubygems.org" gem "bundler-audit", "~> 0.9.3" - -gemspec +gem "ostruct", "~> 0.6" # fix rspec conflict caused by rails 6 gem "net-imap", require: false gem "net-pop", require: false gem "net-smtp", require: false + +gemspec diff --git a/hq-graphql.gemspec b/hq-graphql.gemspec index 58d28fe..8288ab3 100644 --- a/hq-graphql.gemspec +++ b/hq-graphql.gemspec @@ -18,23 +18,23 @@ Gem::Specification.new do |s| s.files = Dir["{lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - s.add_dependency "rails", ">= 6.0", "<= 8.1.1" + s.add_dependency "rails", ">= 6.0", "<= 8.1.1" - s.add_dependency "graphql", "~> 1.12" - s.add_dependency "graphql-batch", "~> 0.4" - s.add_dependency "graphql-schema_comparator", "~> 1.0" - s.add_dependency "pg", "~> 1.1" + s.add_dependency "graphql", "~> 1.12" + s.add_dependency "graphql-batch", "~> 0.4" + s.add_dependency "graphql-schema_comparator", "~> 1.0" + s.add_dependency "pg", "~> 1.1" - s.add_development_dependency "byebug", "~> 11.0" - s.add_development_dependency "combustion", "~> 1.1" - s.add_development_dependency "concurrent-ruby", "1.3.4" - s.add_development_dependency "database_cleaner", "~> 1.7" - s.add_development_dependency "factory_bot_rails", "~> 5.0" - s.add_development_dependency "faker", "~> 2.1" + s.add_development_dependency "byebug", "~> 12.0" + s.add_development_dependency "combustion", "~> 1.5" + s.add_development_dependency "concurrent-ruby", "1.3.5" + s.add_development_dependency "database_cleaner", "~> 2.1" + s.add_development_dependency "factory_bot_rails", "~> 6.5" + s.add_development_dependency "faker", "~> 3.5" s.add_development_dependency "rspec", "~> 3.8" s.add_development_dependency "rspec_junit_formatter", "~> 0.4.1" - s.add_development_dependency "rspec-rails", "~> 4.0" - s.add_development_dependency "rubocop", ">= 1.60", "< 2.0" - s.add_development_dependency "rubocop-performance", ">= 1.20", "< 3.0" - s.add_development_dependency "rubocop-rails", ">= 2.24", "< 3.0" + s.add_development_dependency "rspec-rails", "~> 7.0" + s.add_development_dependency "rubocop", "~> 1.81" # code quality check for sonarqube + s.add_development_dependency "rubocop-performance", "~> 1.26" + s.add_development_dependency "rubocop-rails", "~> 2.34" end diff --git a/lib/hq/graphql/paginated_association_loader.rb b/lib/hq/graphql/paginated_association_loader.rb index 0f0b5cf..06295bf 100644 --- a/lib/hq/graphql/paginated_association_loader.rb +++ b/lib/hq/graphql/paginated_association_loader.rb @@ -18,14 +18,14 @@ def self.for(*args, scope: nil, **kwargs) def initialize(model, association_name, internal_association: false, limit: nil, offset: nil, scope: nil, sort_by: nil, sort_order: nil) super() - @model = model - @association_name = association_name + @model = model + @association_name = association_name @internal_association = internal_association - @limit = [0, limit].max if limit - @offset = [0, offset].max if offset - @scope = scope - @sort_by = sort_by || :created_at - @sort_order = normalize_sort_order(sort_order) + @limit = [0, limit].max if limit + @offset = [0, offset].max if offset + @scope = scope + @sort_by = sort_by || :created_at + @sort_order = normalize_sort_order(sort_order) validate! end @@ -41,7 +41,7 @@ def cache_key(record) def perform(records) values = records.map { |r| source_value(r) } - scope = + scope = if @limit || @offset # If a limit or offset is added, then we need to transform the query # into a lateral join so that we can limit on groups of data. @@ -59,9 +59,9 @@ def perform(records) # > ) a_top ON TRUE # > WHERE addresses.user_id IN ($1, $2, ..., $N) # > ORDER BY a_top.created_at DESC - inner_table = association_class.arel_table + inner_table = association_class.arel_table lateral_join_table = through_reflection? ? through_association.klass.arel_table : inner_table - from_table = lateral_join_table.alias("outer") + from_table = lateral_join_table.alias("outer") inside_scope = default_scope. select(inner_table[::Arel.star]). @@ -134,8 +134,8 @@ def default_scope if through_reflection? source = association_class.arel_table target = through_association.klass.arel_table - join = source.join(target).on(target[association.foreign_key].eq(source[source_join_key])) - scope = scope.joins(join.join_sources) + join = source.join(target).on(target[association.foreign_key].eq(source[source_join_key])) + scope = scope.joins(join.join_sources) end scope diff --git a/spec/internal/app/models/manager.rb b/spec/internal/app/models/manager.rb index 2ee8e44..2f31c2c 100644 --- a/spec/internal/app/models/manager.rb +++ b/spec/internal/app/models/manager.rb @@ -1,8 +1,8 @@ class Manager < ::ActiveRecord::Base belongs_to :organization - has_many :active_users, -> { where(inactive: [nil, false]) }, class_name: "User" - has_many :users, inverse_of: :organization - has_many :advisors, through: :users - has_many :not_joe, -> { where.not(name: "Joe" ) }, through: :users, source: :advisor + has_many :active_users, -> { where(inactive: [nil, false]) }, class_name: "User", inverse_of: :manager, foreign_key: :manager_id + has_many :users, inverse_of: :manager, foreign_key: :manager_id + has_many :advisors, through: :users + has_many :not_joe, -> { where.not(name: "Joe") }, through: :users, source: :advisor end diff --git a/spec/internal/db/schema.rb b/spec/internal/db/schema.rb index 4fcab82..a48dc82 100644 --- a/spec/internal/db/schema.rb +++ b/spec/internal/db/schema.rb @@ -5,29 +5,29 @@ enable_extension "pgcrypto" create_table "organizations", force: true, id: :uuid do |t| - t.string :name, limit: 63, null: false - t.timestamps null: false + t.string :name, limit: 63, null: false + t.timestamps null: false end create_table "advisors", force: true, id: :uuid do |t| - t.references :organization, null: false, index: true, foreign_key: true, type: :uuid - t.string :name, null: false - t.string :nickname, null: false - t.timestamps null: false + t.references :organization, null: false, index: true, foreign_key: true, type: :uuid + t.string :name, null: false + t.string :nickname, null: false + t.timestamps null: false end create_table "managers", force: true, id: :uuid do |t| - t.references :organization, null: false, index: true, foreign_key: true, type: :uuid - t.timestamps null: false + t.references :organization, null: false, index: true, foreign_key: true, type: :uuid + t.timestamps null: false end create_table "users", force: true, id: :uuid do |t| - t.belongs_to :organization, null: false, index: true, foreign_key: true, type: :uuid - t.belongs_to :advisor, null: true, index: true, foreign_key: true, type: :uuid - t.belongs_to :manager, null: true, index: true, foreign_key: true, type: :uuid + t.belongs_to :organization, null: false, index: true, foreign_key: true, type: :uuid + t.belongs_to :advisor, null: true, index: true, foreign_key: true, type: :uuid + t.belongs_to :manager, null: true, index: true, foreign_key: true, type: :uuid t.boolean :inactive - t.string :name, null: false - t.timestamps null: false + t.string :name, null: false + t.timestamps null: false end create_table "test_types", force: true, id: :uuid do |t| diff --git a/spec/lib/graphql/paginated_association_loader_spec.rb b/spec/lib/graphql/paginated_association_loader_spec.rb index 88434a1..5cf880f 100644 --- a/spec/lib/graphql/paginated_association_loader_spec.rb +++ b/spec/lib/graphql/paginated_association_loader_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::PaginatedAssociationLoader do let(:now) { Time.zone.now } @@ -22,9 +22,9 @@ def load(association, **options) loader = described_class.for(Manager, association, **options) # Load two associations to test that grouped limits + offsets work Promise.all([ - loader.load(manager1), - loader.load(manager2) - ]) + loader.load(manager1), + loader.load(manager2) + ]) end results From 65cbe0dd649dae7766b808dcbdf637a24af28c89 Mon Sep 17 00:00:00 2001 From: alejandroaguilera Date: Tue, 23 Dec 2025 17:44:22 -0300 Subject: [PATCH 16/18] rubocop indentation --- hq-graphql.gemspec | 34 +++++----- lib/hq/graphql/enum/sort_order.rb | 2 +- .../graphql/ext/active_record_extensions.rb | 4 ++ lib/hq/graphql/ext/enum_extensions.rb | 2 - lib/hq/graphql/ext/input_object_extensions.rb | 2 +- lib/hq/graphql/ext/object_extensions.rb | 5 +- lib/hq/graphql/ext/schema_extensions.rb | 1 + .../field_extension/paginated_loader.rb | 22 +++--- lib/hq/graphql/filter_operations.rb | 6 +- lib/hq/graphql/filters.rb | 15 ++-- lib/hq/graphql/pagination_connection_type.rb | 2 +- lib/hq/graphql/resource.rb | 68 +++++++++---------- spec/lib/graphql/comparator_spec.rb | 10 ++- .../ext/active_record_extensions_spec.rb | 8 ++- spec/lib/graphql/ext/enum_extensions_spec.rb | 12 ++-- .../ext/input_object_extensions_spec.rb | 2 +- .../lib/graphql/ext/object_extensions_spec.rb | 2 +- .../lib/graphql/ext/schema_extensions_spec.rb | 15 +++- spec/lib/graphql/filters_spec.rb | 49 +++++++------ spec/lib/graphql/inputs_spec.rb | 3 +- spec/lib/graphql/object_association_spec.rb | 17 +++-- .../paginated_association_loader_spec.rb | 10 +-- .../pagination_connection_type_spec.rb | 36 +++++++--- spec/lib/graphql/resource_pagination_spec.rb | 16 ++--- spec/lib/graphql/resource_spec.rb | 44 ++++++++---- spec/lib/graphql/types/uuid_spec.rb | 12 ++-- spec/lib/graphql/types_spec.rb | 3 + 27 files changed, 231 insertions(+), 171 deletions(-) diff --git a/hq-graphql.gemspec b/hq-graphql.gemspec index 8288ab3..18ae4ee 100644 --- a/hq-graphql.gemspec +++ b/hq-graphql.gemspec @@ -18,23 +18,23 @@ Gem::Specification.new do |s| s.files = Dir["{lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - s.add_dependency "rails", ">= 6.0", "<= 8.1.1" + s.add_dependency "rails", ">= 6.0", "<= 8.1.1" - s.add_dependency "graphql", "~> 1.12" - s.add_dependency "graphql-batch", "~> 0.4" - s.add_dependency "graphql-schema_comparator", "~> 1.0" - s.add_dependency "pg", "~> 1.1" + s.add_dependency "graphql", "~> 1.12" + s.add_dependency "graphql-batch", "~> 0.4" + s.add_dependency "graphql-schema_comparator", "~> 1.0" + s.add_dependency "pg", "~> 1.1" - s.add_development_dependency "byebug", "~> 12.0" - s.add_development_dependency "combustion", "~> 1.5" - s.add_development_dependency "concurrent-ruby", "1.3.5" - s.add_development_dependency "database_cleaner", "~> 2.1" - s.add_development_dependency "factory_bot_rails", "~> 6.5" - s.add_development_dependency "faker", "~> 3.5" - s.add_development_dependency "rspec", "~> 3.8" - s.add_development_dependency "rspec_junit_formatter", "~> 0.4.1" - s.add_development_dependency "rspec-rails", "~> 7.0" - s.add_development_dependency "rubocop", "~> 1.81" # code quality check for sonarqube - s.add_development_dependency "rubocop-performance", "~> 1.26" - s.add_development_dependency "rubocop-rails", "~> 2.34" + s.add_development_dependency "byebug", "~> 12.0" + s.add_development_dependency "combustion", "~> 1.5" + s.add_development_dependency "concurrent-ruby", "1.3.5" + s.add_development_dependency "database_cleaner", "~> 2.1" + s.add_development_dependency "factory_bot_rails", "~> 6.5" + s.add_development_dependency "faker", "~> 3.5" + s.add_development_dependency "rspec", "~> 3.8" + s.add_development_dependency "rspec_junit_formatter", "~> 0.6" + s.add_development_dependency "rspec-rails", "~> 7.0" + s.add_development_dependency "rubocop", "~> 1.81" # code quality check for sonarqube + s.add_development_dependency "rubocop-performance", "~> 1.26" + s.add_development_dependency "rubocop-rails", "~> 2.34" end diff --git a/lib/hq/graphql/enum/sort_order.rb b/lib/hq/graphql/enum/sort_order.rb index f9de930..c0076f3 100644 --- a/lib/hq/graphql/enum/sort_order.rb +++ b/lib/hq/graphql/enum/sort_order.rb @@ -6,7 +6,7 @@ module HQ module GraphQL module Enum class SortOrder < ::GraphQL::Schema::Enum - value "ASC", value: :asc + value "ASC", value: :asc value "DESC", value: :desc end end diff --git a/lib/hq/graphql/ext/active_record_extensions.rb b/lib/hq/graphql/ext/active_record_extensions.rb index fed6ac9..bbe33d3 100644 --- a/lib/hq/graphql/ext/active_record_extensions.rb +++ b/lib/hq/graphql/ext/active_record_extensions.rb @@ -76,6 +76,7 @@ def add_attributes(*attrs) validate_model! added_attributes.concat attrs.map(&:to_sym) end + alias_method :add_attribute, :add_attributes alias_method :add_attrs, :add_attributes alias_method :add_attr, :add_attributes @@ -84,6 +85,7 @@ def remove_attributes(*attrs) validate_model! removed_attributes.concat attrs.map(&:to_sym) end + alias_method :remove_attribute, :remove_attributes alias_method :remove_attrs, :remove_attributes alias_method :remove_attr, :remove_attributes @@ -92,12 +94,14 @@ def add_associations(*associations) validate_model! added_associations.concat associations.map(&:to_sym) end + alias_method :add_association, :add_associations def remove_associations(*associations) validate_model! removed_associations.concat associations.map(&:to_sym) end + alias_method :remove_association, :remove_associations def model_klass diff --git a/lib/hq/graphql/ext/enum_extensions.rb b/lib/hq/graphql/ext/enum_extensions.rb index 010156b..2d45c62 100644 --- a/lib/hq/graphql/ext/enum_extensions.rb +++ b/lib/hq/graphql/ext/enum_extensions.rb @@ -74,7 +74,6 @@ def default_model_name to_s.sub(/^((::)?\w+)::/, "") end - # This override method allow us to keep the suffix `-Type` # if we don't specify the `graphql_name`. def default_graphql_name @@ -84,5 +83,4 @@ def default_graphql_name end end - ::GraphQL::Schema::Enum.extend ::HQ::GraphQL::Ext::EnumExtensions diff --git a/lib/hq/graphql/ext/input_object_extensions.rb b/lib/hq/graphql/ext/input_object_extensions.rb index d7229fb..87cf9fe 100644 --- a/lib/hq/graphql/ext/input_object_extensions.rb +++ b/lib/hq/graphql/ext/input_object_extensions.rb @@ -19,7 +19,7 @@ def self.included(klass) module InstanceMethods # Recursively format attributes so that they are compatible with `accepts_nested_attributes_for` def format_nested_attributes - self.each.inject({}) do |formatted_attrs, (key, value) | + self.each.inject({}) do |formatted_attrs, (key, value)| if self.class.nested_attributes.include?(key.to_s) formatted_value = if value.is_a?(Array) diff --git a/lib/hq/graphql/ext/object_extensions.rb b/lib/hq/graphql/ext/object_extensions.rb index 27c6ddc..de47188 100644 --- a/lib/hq/graphql/ext/object_extensions.rb +++ b/lib/hq/graphql/ext/object_extensions.rb @@ -54,6 +54,7 @@ def with_model(model_name, attributes: true, associations: true, auto_nil: true, end private + attr_writer :authorized_action def authorized_action @@ -62,11 +63,11 @@ def authorized_action def field_from_association(association, auto_nil:, internal_association: false, &block) association_klass = association.klass - name = association.name.to_s + name = association.name.to_s return if field_exists?(name) klass = model_klass - type = Types[association_klass] + type = Types[association_klass] case association.macro when :has_many diff --git a/lib/hq/graphql/ext/schema_extensions.rb b/lib/hq/graphql/ext/schema_extensions.rb index f0f0cfd..6c299fb 100644 --- a/lib/hq/graphql/ext/schema_extensions.rb +++ b/lib/hq/graphql/ext/schema_extensions.rb @@ -11,6 +11,7 @@ def self.prepended(klass) klass.alias_method :add_type_and_traverse_without_types, :add_type_and_traverse klass.alias_method :add_type_and_traverse, :add_type_and_traverse_with_types end + def multiplex(*args, **options) load_types! super diff --git a/lib/hq/graphql/field_extension/paginated_loader.rb b/lib/hq/graphql/field_extension/paginated_loader.rb index 35f00a0..8a8a6fc 100644 --- a/lib/hq/graphql/field_extension/paginated_loader.rb +++ b/lib/hq/graphql/field_extension/paginated_loader.rb @@ -7,20 +7,20 @@ module GraphQL module FieldExtension class PaginatedLoader < ::GraphQL::Schema::FieldExtension def resolve(object:, arguments:, **_options) - limit = arguments[:limit] - offset = arguments[:offset] - sort_by = arguments[:sort_by] - sort_order = arguments[:sort_order] - scope = field.scope.call(**arguments.except(:limit, :offset, :sort_by, :sort_order)) if field.scope - loader = PaginatedAssociationLoader.for( + limit = arguments[:limit] + offset = arguments[:offset] + sort_by = arguments[:sort_by] + sort_order = arguments[:sort_order] + scope = field.scope.call(**arguments.except(:limit, :offset, :sort_by, :sort_order)) if field.scope + loader = PaginatedAssociationLoader.for( klass, association, internal_association: internal_association, - scope: scope, - limit: limit, - offset: offset, - sort_by: sort_by, - sort_order: sort_order + scope: scope, + limit: limit, + offset: offset, + sort_by: sort_by, + sort_order: sort_order ) loader.load(object.object) diff --git a/lib/hq/graphql/filter_operations.rb b/lib/hq/graphql/filter_operations.rb index 1a6727c..6694e03 100644 --- a/lib/hq/graphql/filter_operations.rb +++ b/lib/hq/graphql/filter_operations.rb @@ -9,10 +9,10 @@ class Operation attr_reader :name, :arel, :check_for_null, :sanitize def initialize(name:, arel:, check_for_null: false, sanitize: nil) - @name = name - @arel = arel + @name = name + @arel = arel @check_for_null = check_for_null - @sanitize = sanitize + @sanitize = sanitize end def sanitize_value(value) diff --git a/lib/hq/graphql/filters.rb b/lib/hq/graphql/filters.rb index 8b06a1b..fa908ad 100644 --- a/lib/hq/graphql/filters.rb +++ b/lib/hq/graphql/filters.rb @@ -117,13 +117,14 @@ def self.normalize_column(scope, column) return column if column.is_a?(Arel::Attributes::Attribute) return column if column.respond_to?(:relation) && column.respond_to?(:name) - arel_table = if scope.respond_to?(:arel_table) - scope.arel_table - elsif scope.respond_to?(:klass) - scope.klass.arel_table - else - raise ArgumentError, "Cannot determine table for provided scope" - end + arel_table = + if scope.respond_to?(:arel_table) + scope.arel_table + elsif scope.respond_to?(:klass) + scope.klass.arel_table + else + raise ArgumentError, "Cannot determine table for provided scope" + end arel_table[column.to_sym] end diff --git a/lib/hq/graphql/pagination_connection_type.rb b/lib/hq/graphql/pagination_connection_type.rb index dfebe63..cf7060d 100644 --- a/lib/hq/graphql/pagination_connection_type.rb +++ b/lib/hq/graphql/pagination_connection_type.rb @@ -12,7 +12,7 @@ def cursors (0...(object.items.size)).step(object.first || object.items.size + 1).map do |item| Base64.urlsafe_encode64(item.to_s).delete("=") end - end + end def total_count object.items.size diff --git a/lib/hq/graphql/resource.rb b/lib/hq/graphql/resource.rb index 9826385..b9e3dd2 100644 --- a/lib/hq/graphql/resource.rb +++ b/lib/hq/graphql/resource.rb @@ -74,17 +74,17 @@ def nil_query_object def query_object @query_object ||= begin - qo = - if @query_object_options - options, block = @query_object_options - @query_object_options = nil - build_graphql_object(**options, &block) - else - build_graphql_object - end - remove_const(:Query) if const_defined?(:Query, false) - const_set(:Query, qo) - end + qo = + if @query_object_options + options, block = @query_object_options + @query_object_options = nil + build_graphql_object(**options, &block) + else + build_graphql_object + end + remove_const(:Query) if const_defined?(:Query, false) + const_set(:Query, qo) + end end def sort_fields_enum @@ -113,23 +113,23 @@ def const_missing(constant_name) def filter_input @filter_input ||= begin - scoped_self = self - - input_class = Class.new(::GraphQL::Schema::InputObject) do - graphql_name "#{scoped_self.graphql_name}QueryFilterInput" - - argument :field, scoped_self.filter_fields_enum, required: true - argument :operation, Enum::FilterOperation, required: true - argument :is_or, ::GraphQL::Schema::Scalar::Boolean, required: false - argument :value, String, required: false - argument :date_value, ::HQ::GraphQL::Types::DateFilterValueInput, required: false - argument :date_range_value, ::HQ::GraphQL::Types::DateFilterRangeInput, required: false - argument :array_values, [String], required: false - argument :column_value, scoped_self.filter_column_value_enum, required: false - end + scoped_self = self - const_set(:FilterInput, input_class) - end + input_class = Class.new(::GraphQL::Schema::InputObject) do + graphql_name "#{scoped_self.graphql_name}QueryFilterInput" + + argument :field, scoped_self.filter_fields_enum, required: true + argument :operation, Enum::FilterOperation, required: true + argument :is_or, ::GraphQL::Schema::Scalar::Boolean, required: false + argument :value, String, required: false + argument :date_value, ::HQ::GraphQL::Types::DateFilterValueInput, required: false + argument :date_range_value, ::HQ::GraphQL::Types::DateFilterRangeInput, required: false + argument :array_values, [String], required: false + argument :column_value, scoped_self.filter_column_value_enum, required: false + end + + const_set(:FilterInput, input_class) + end end def filter_fields_enum @@ -308,11 +308,11 @@ def root_query(find_one: true, find_all: true, limit_max: 250) # set limit_max if first/last N is not provided scope = if limit.present? || !(context.query.provided_variables.symbolize_keys.keys & [:first, :last]).any? - limit = [[limit_max, *limit].min, 0].max - scope.limit(limit).offset(offset) - else - scope.offset(offset) - end + limit = [[limit_max, *limit].min, 0].max + scope.limit(limit).offset(offset) + else + scope.offset(offset) + end sort_by ||= :updated_at sort_order ||= :desc @@ -391,9 +391,7 @@ def build_filter_fields_enum(include_custom_fields: true) scoped_self = self Class.new(::GraphQL::Schema::Enum) do - enum_name = include_custom_fields ? - "#{scoped_self.graphql_name}QueryFilterFields" : - "#{scoped_self.graphql_name}QueryFilterColumnFields" + enum_name = include_custom_fields ? "#{scoped_self.graphql_name}QueryFilterFields" : "#{scoped_self.graphql_name}QueryFilterColumnFields" graphql_name enum_name diff --git a/spec/lib/graphql/comparator_spec.rb b/spec/lib/graphql/comparator_spec.rb index 74259e2..2d7485b 100644 --- a/spec/lib/graphql/comparator_spec.rb +++ b/spec/lib/graphql/comparator_spec.rb @@ -30,17 +30,20 @@ describe "Comparing two schemas" do context "when the criticality is not valid" do it "should raise an error" do - expect { described_class.compare(schema, schema, criticality: :invalid_criticality) }.to raise_error(::ArgumentError, /Invalid criticality. Possible values are #{described_class::CRITICALITY.keys.join(", ")}/i) + expect { described_class.compare(schema, schema, criticality: :invalid_criticality) }. + to raise_error(::ArgumentError, /Invalid criticality. Possible values are #{described_class::CRITICALITY.keys.join(", ")}/i) end end context "when the schemas are identical" do it "should return nil" do result = described_class.compare(schema, schema, criticality: :non_breaking) + expect(result).to be_nil definition = schema.to_definition result = described_class.compare(definition, definition, criticality: :non_breaking) + expect(result).to be_nil end end @@ -101,6 +104,7 @@ context "when the criticality is set to dangerous" do it "should list dangerous and breaking changes" do result = described_class.compare(schema, new_schema, criticality: :dangerous) + expect(result[:breaking]).not_to be_nil expect(result[:dangerous]).not_to be_nil expect(result[:breaking].count).to eq(1) @@ -109,6 +113,7 @@ it "should not list non-breaking changes" do result = described_class.compare(schema, new_schema, criticality: :dangerous) + expect(result[:non_breaking]).to be_nil end end @@ -116,6 +121,7 @@ context "when the criticality is set to breaking" do it "should list the breaking changes" do result = described_class.compare(schema, new_schema) + expect(result[:breaking]).not_to be_nil expect(result[:breaking].count).to eq(1) expect(result[:breaking].first.criticality.reason).to match(/Removing a field is a breaking change/i) @@ -123,6 +129,7 @@ it "should not list dangerous or non-breaking changes" do result = described_class.compare(schema, new_schema) + expect(result[:dangerous]).to be_nil expect(result[:non_breaking]).to be_nil end @@ -159,6 +166,7 @@ it "should return nil" do result = described_class.compare(schema, new_schema, criticality: :dangerous) + expect(result).to be_nil end end diff --git a/spec/lib/graphql/ext/active_record_extensions_spec.rb b/spec/lib/graphql/ext/active_record_extensions_spec.rb index 56f9bc8..306d27e 100644 --- a/spec/lib/graphql/ext/active_record_extensions_spec.rb +++ b/spec/lib/graphql/ext/active_record_extensions_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::Ext::ActiveRecordExtensions do let(:extended_klass) do @@ -20,6 +20,7 @@ def self.counter describe ".add_attributes" do it "aliases add_attributes" do add_attributes = extended_klass.method(:add_attributes) + aggregate_failures do expect(add_attributes).to eql(extended_klass.method(:add_attribute)) expect(add_attributes).to eql(extended_klass.method(:add_attrs)) @@ -31,6 +32,7 @@ def self.counter describe ".remove_attributes" do it "aliases remove_attributes" do remove_attributes = extended_klass.method(:remove_attributes) + aggregate_failures do expect(remove_attributes).to eql(extended_klass.method(:remove_attribute)) expect(remove_attributes).to eql(extended_klass.method(:remove_attrs)) @@ -54,9 +56,9 @@ def self.counter describe ".lazy_load" do it "lazy loads once" do # First time it works - expect { extended_klass.lazy_load! }.to change { extended_klass.counter }.by(1) + expect { extended_klass.lazy_load! }.to change { extended_klass.counter }.by(1) # Second time it does nothing - expect { extended_klass.lazy_load! }.to change { extended_klass.counter }.by(0) + expect { extended_klass.lazy_load! }.to change { extended_klass.counter }.by(0) end end end diff --git a/spec/lib/graphql/ext/enum_extensions_spec.rb b/spec/lib/graphql/ext/enum_extensions_spec.rb index 93f7452..e9f4c9b 100644 --- a/spec/lib/graphql/ext/enum_extensions_spec.rb +++ b/spec/lib/graphql/ext/enum_extensions_spec.rb @@ -21,49 +21,53 @@ def build_enum(**args) expected_keys = [advisor1.name, advisor2.name].map { |name| name.delete(" ") } enum = build_enum + expect(enum.values).to be_empty + enum.lazy_load! + expect(enum.values.keys).to contain_exactly(*expected_keys) expect(enum.values.values.map(&:value)).to contain_exactly(advisor1, advisor2) end it "globally registers an enum" do enum = build_enum + expect(::HQ::GraphQL.enums).to contain_exactly(Advisor) expect(::HQ::GraphQL::Types[Advisor]).to eq enum end it "disables registration" do build_enum(register: false) + expect(::HQ::GraphQL.enums).to be_empty expect { ::HQ::GraphQL::Types[Advisor] }.to raise_error ::HQ::GraphQL::Types::Error end it "supports scoping" do expected_keys = [advisor1.name.delete(" ")] - organization_id = advisor1.organization_id enum = build_enum(scope: -> { where(organization_id: organization_id) }) - enum.lazy_load! + expect(enum.values.keys).to contain_exactly(*expected_keys) expect(enum.values.values.map(&:value)).to contain_exactly(advisor1) end it "supports prefixes" do expected_keys = ["OneHQ#{advisor1.name.delete(" ")}"] - enum = build_enum(prefix: "OneHQ") enum.lazy_load! + expect(enum.values.keys).to contain_exactly(*expected_keys) expect(enum.values.values.map(&:value)).to contain_exactly(advisor1) end it "supports value method override" do advisor1.update(nickname: "Ricky Bobby") - enum = build_enum(value_method: :nickname) enum.lazy_load! + expect(enum.values.keys).to contain_exactly(advisor1.nickname.delete(" ")) expect(enum.values.values.map(&:value)).to contain_exactly(advisor1) end diff --git a/spec/lib/graphql/ext/input_object_extensions_spec.rb b/spec/lib/graphql/ext/input_object_extensions_spec.rb index ab163fb..1bfb42e 100644 --- a/spec/lib/graphql/ext/input_object_extensions_spec.rb +++ b/spec/lib/graphql/ext/input_object_extensions_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::Ext::InputObjectExtensions do diff --git a/spec/lib/graphql/ext/object_extensions_spec.rb b/spec/lib/graphql/ext/object_extensions_spec.rb index d88a7bd..40073f7 100644 --- a/spec/lib/graphql/ext/object_extensions_spec.rb +++ b/spec/lib/graphql/ext/object_extensions_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::Ext::ObjectExtensions do diff --git a/spec/lib/graphql/ext/schema_extensions_spec.rb b/spec/lib/graphql/ext/schema_extensions_spec.rb index e4b11da..0e9e12c 100644 --- a/spec/lib/graphql/ext/schema_extensions_spec.rb +++ b/spec/lib/graphql/ext/schema_extensions_spec.rb @@ -26,7 +26,8 @@ end end - let(:query_str) { <<~GRAPHQL + let(:query_str) { + <<~GRAPHQL query { field } @@ -35,12 +36,14 @@ it "loads types when executing a query" do expect(schema).to receive(:load_types!) + schema.execute(query_str) end it "loads types when executing multiple queries" do expect(schema).to receive(:load_types!) - schema.multiplex([ query: query_str ]) + + schema.multiplex([query: query_str]) end end @@ -57,9 +60,12 @@ it "should write the schema successfully to the filepath" do schema.dump + expect(schema.dump_directory).to eq(Rails.root.join("files")) expect(schema.dump_filename).to eq("temp_schema.graphql") + file_contents = ::File.read(::File.join(schema.dump_directory, schema.dump_filename)) + expect(file_contents).to eq(schema.to_definition) end end @@ -83,9 +89,11 @@ it "should default to app/graphql" do schema.dump expected_filepath = Rails.root.join("app", "graphql") + expect(schema.dump_directory).to eq(expected_filepath) file_contents = ::File.read(::File.join(schema.dump_directory, schema.dump_filename)) + expect(file_contents).to eq(schema.to_definition) end end @@ -102,8 +110,11 @@ it "should use the class name as the filename" do schema.dump + expect(schema.dump_filename).to eq("#{class_name.underscore}.graphql") + file_contents = ::File.read(::File.join(schema.dump_directory, schema.dump_filename)) + expect(file_contents).to eq(schema.to_definition) end end diff --git a/spec/lib/graphql/filters_spec.rb b/spec/lib/graphql/filters_spec.rb index 16b8008..fe4637d 100644 --- a/spec/lib/graphql/filters_spec.rb +++ b/spec/lib/graphql/filters_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::Filters do include ActiveSupport::Testing::TimeHelpers @@ -128,7 +128,7 @@ } } } - GRAPHQL + GRAPHQL } before(:each) do @@ -139,22 +139,22 @@ it "generates enums of filterable fields" do resource::FilterFields.lazy_load! expect(resource::FilterFields.values.keys).to contain_exactly( - "id", - "count", - "amount", - "isBool", - "name", - "createdDate", - "createdAt", - "updatedAt", - "countPlusOne", - "createdRecently", - "relatedCreatedRecently", - "countFiltered", - "nameFiltered", - "idFiltered", - "boolFiltered" - ) + "id", + "count", + "amount", + "isBool", + "name", + "createdDate", + "createdAt", + "updatedAt", + "countPlusOne", + "createdRecently", + "relatedCreatedRecently", + "countFiltered", + "nameFiltered", + "idFiltered", + "boolFiltered" + ) resource::FilterColumnFields.lazy_load! expect(resource::FilterColumnFields.values.keys).to contain_exactly("id", "count", "amount", "isBool", "name", "createdDate", "createdAt", "updatedAt") @@ -329,16 +329,15 @@ target_two = TestType.create(count: 12) results = schema.execute(query, variables: { filters: [ { field: "count", operation: "EQUAL", value: target.count.to_s }, - { field: "count", operation: "EQUAL", value: target_two.count.to_s, isOr: true}, + { field: "count", operation: "EQUAL", value: target_two.count.to_s, isOr: true }, { field: "count", operation: "IN", arrayValues: [target.count.to_s, target_two.count.to_s], isOr: true } - ]}) + ] }) data = results["data"]["testTypes"]["nodes"] expect(data.length).to be 2 expect(data[0]["id"]).to eql(target_two.id) expect(data[1]["id"]).to eql(target.id) end - it "only supports numerical values" do results = schema.execute(query, variables: { filters: [{ field: "count", operation: "GREATER_THAN", value: "Fizz" }] }) errors = results["errors"] @@ -407,9 +406,9 @@ target_two = TestType.create(name: "Unique Name Two") results = schema.execute(query, variables: { filters: [ { field: "name", operation: "EQUAL", value: target.name }, - { field: "name", operation: "EQUAL", value: target_two.name, isOr: true}, + { field: "name", operation: "EQUAL", value: target_two.name, isOr: true }, { field: "name", operation: "IN", arrayValues: [target.name, target_two.name], isOr: true } - ]}) + ] }) data = results["data"]["testTypes"]["nodes"] expect(data.length).to be 2 expect(data[0]["id"]).to eql(target_two.id) @@ -455,9 +454,9 @@ target_two = TestType.create results = schema.execute(query, variables: { filters: [ { field: "id", operation: "EQUAL", value: target.id }, - { field: "id", operation: "EQUAL", value: target_two.id, isOr: true}, + { field: "id", operation: "EQUAL", value: target_two.id, isOr: true }, { field: "id", operation: "IN", arrayValues: [target.id, target_two.id], isOr: true } - ]}) + ] }) data = results["data"]["testTypes"]["nodes"] expect(data.length).to be 2 expect(data[0]["id"]).to eql(target_two.id) diff --git a/spec/lib/graphql/inputs_spec.rb b/spec/lib/graphql/inputs_spec.rb index 847d331..2d5d728 100644 --- a/spec/lib/graphql/inputs_spec.rb +++ b/spec/lib/graphql/inputs_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::Inputs do @@ -36,5 +36,4 @@ expect { described_class[Advisor] }.to raise_error(described_class::Error) end end - end diff --git a/spec/lib/graphql/object_association_spec.rb b/spec/lib/graphql/object_association_spec.rb index b34cb75..7693cf4 100644 --- a/spec/lib/graphql/object_association_spec.rb +++ b/spec/lib/graphql/object_association_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::ObjectAssociation do let!(:organization_resource) do @@ -34,7 +34,6 @@ Class.new(::HQ::GraphQL::RootQuery) end - let(:schema) do Class.new(::GraphQL::Schema) do query(RootQuery) @@ -61,16 +60,16 @@ let!(:user3) { ::FactoryBot.create(:user, organization: organization) } let(:find_organization) { <<~GRAPHQL - query FindOrganization($id: ID!, $userName: String) { - organization(id: $id) { + query FindOrganization($id: ID!, $userName: String) { + organization(id: $id) { + id + customAssociation(name: $userName) { id - customAssociation(name: $userName) { - id - name - } + name } } - GRAPHQL + } + GRAPHQL } it "finds active users" do diff --git a/spec/lib/graphql/paginated_association_loader_spec.rb b/spec/lib/graphql/paginated_association_loader_spec.rb index 5cf880f..08e898c 100644 --- a/spec/lib/graphql/paginated_association_loader_spec.rb +++ b/spec/lib/graphql/paginated_association_loader_spec.rb @@ -5,12 +5,12 @@ let(:organization) { ::FactoryBot.create(:organization) } - let(:manager1) { ::FactoryBot.create(:manager, organization: organization) } - let(:manager2) { ::FactoryBot.create(:manager, organization: organization) } + let(:manager1) { ::FactoryBot.create(:manager, organization: organization) } + let(:manager2) { ::FactoryBot.create(:manager, organization: organization) } - let!(:user1) { ::FactoryBot.create(:user, organization: organization, manager: manager1, created_at: now, updated_at: now + 1.minutes) } - let!(:user2) { ::FactoryBot.create(:user, organization: organization, manager: manager1, created_at: now + 1.minutes, updated_at: now + 2.minutes, inactive: true) } - let!(:user3) { ::FactoryBot.create(:user, organization: organization, manager: manager1, created_at: now + 2.minutes, updated_at: now) } + let!(:user1) { ::FactoryBot.create(:user, organization: organization, manager: manager1, created_at: now, updated_at: now + 1.minutes) } + let!(:user2) { ::FactoryBot.create(:user, organization: organization, manager: manager1, created_at: now + 1.minutes, updated_at: now + 2.minutes, inactive: true) } + let!(:user3) { ::FactoryBot.create(:user, organization: organization, manager: manager1, created_at: now + 2.minutes, updated_at: now) } before(:each) do # Create dummy data to verify data is properly filtered diff --git a/spec/lib/graphql/pagination_connection_type_spec.rb b/spec/lib/graphql/pagination_connection_type_spec.rb index f3178d3..54e2a7e 100644 --- a/spec/lib/graphql/pagination_connection_type_spec.rb +++ b/spec/lib/graphql/pagination_connection_type_spec.rb @@ -23,7 +23,8 @@ let!(:test_types) { 252.times.map { |i| TestType.create(created_at: 1.year.ago, count: i) } } - let(:query) { <<-GRAPHQL + let(:query) { + <<-GRAPHQL query findTestTypes($before: String, $after: String, $first: Int, $last: Int, $sortOrder: SortOrder) { testTypes(before: $before, after: $after, first: $first, last: $last, sortOrder: $sortOrder) { cursors @@ -51,39 +52,45 @@ it "first 1" do results = schema.execute(query, variables: { first: 1, sortOrder: "ASC" }) advisors = results["data"]["testTypes"]["nodes"].pluck("id") + expect(advisors).to eq test_types.first(1).map(&:id) end it "first 2" do results = schema.execute(query, variables: { first: 2, sortOrder: "ASC" }) advisors = results["data"]["testTypes"]["nodes"].pluck("id") + expect(advisors).to eq test_types.first(2).map(&:id) end it "first 2, with totalCount > limit_max" do results = schema.execute(query, variables: { first: 2, sortOrder: "ASC" }) data = results["data"]["testTypes"]["nodes"] - totalCount = results["data"]["testTypes"]["totalCount"] + total_count = results["data"]["testTypes"]["totalCount"] + expect(data.length).to be 2 - expect(totalCount).to be 252 + expect(total_count).to be 252 end it "last 1" do results = schema.execute(query, variables: { last: 1, sortOrder: "ASC" }) advisors = results["data"]["testTypes"]["nodes"].pluck("id") + expect(advisors).to eq test_types.last(1).map(&:id) end it "last 2" do results = schema.execute(query, variables: { last: 2, sortOrder: "ASC" }) advisors = results["data"]["testTypes"]["nodes"].pluck("id") + expect(advisors).to eq test_types.last(2).map(&:id) end it "last 2, with totalCount > limit_max" do results = schema.execute(query, variables: { last: 2, sortOrder: "ASC" }) data = results["data"]["testTypes"]["nodes"] - totalCount = results["data"]["testTypes"]["totalCount"] + total_count = results["data"]["testTypes"]["totalCount"] + expect(data.length).to be 2 - expect(totalCount).to be 252 + expect(total_count).to be 252 end end @@ -94,6 +101,7 @@ cursor = edges.last["cursor"] results = schema.execute(query, variables: { first: 2, after: cursor, sortOrder: "ASC" }) advisors = results["data"]["testTypes"]["nodes"].pluck("id") + expect(advisors).to eq test_types.drop(2).first(2).map(&:id) end it "last 2, after 2 element cursor" do @@ -102,6 +110,7 @@ cursor = edges.last["cursor"] results = schema.execute(query, variables: { last: 2, after: cursor, sortOrder: "ASC" }) advisors = results["data"]["testTypes"]["nodes"].pluck("id") + expect(advisors).to eq test_types.last(2).map(&:id) end end @@ -112,6 +121,7 @@ cursor = edges.last["cursor"] results = schema.execute(query, variables: { first: 2, before: cursor, sortOrder: "ASC" }) advisors = results["data"]["testTypes"]["nodes"].pluck("id") + expect(advisors).to eq test_types.first(1).map(&:id) end it "last 2, before 2 element cursor" do @@ -120,6 +130,7 @@ cursor = edges.last["cursor"] results = schema.execute(query, variables: { first: 2, before: cursor, sortOrder: "ASC" }) advisors = results["data"]["testTypes"]["nodes"].pluck("id") + expect(advisors).to eq test_types.first(1).map(&:id) end end @@ -128,23 +139,26 @@ it "page size == 250 with first > 250" do results = schema.execute(query, variables: { first: 1000, sortOrder: "ASC" }) data = results["data"]["testTypes"]["nodes"] - totalCount = results["data"]["testTypes"]["totalCount"] + total_count = results["data"]["testTypes"]["totalCount"] + expect(data.length).to be 250 - expect(totalCount).to be 252 + expect(total_count).to be 252 end it "page size == 250 with last > 250" do results = schema.execute(query, variables: { last: 1000, sortOrder: "ASC" }) data = results["data"]["testTypes"]["nodes"] - totalCount = results["data"]["testTypes"]["totalCount"] + total_count = results["data"]["testTypes"]["totalCount"] + expect(data.length).to be 250 - expect(totalCount).to be 252 + expect(total_count).to be 252 end it "page size == 250 without first and last" do results = schema.execute(query, variables: { first: 1000, sortOrder: "ASC" }) data = results["data"]["testTypes"]["nodes"] - totalCount = results["data"]["testTypes"]["totalCount"] + total_count = results["data"]["testTypes"]["totalCount"] + expect(data.length).to be 250 - expect(totalCount).to be 252 + expect(total_count).to be 252 end end end diff --git a/spec/lib/graphql/resource_pagination_spec.rb b/spec/lib/graphql/resource_pagination_spec.rb index 0d09d91..0365a49 100644 --- a/spec/lib/graphql/resource_pagination_spec.rb +++ b/spec/lib/graphql/resource_pagination_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::Resource do let!(:manager_resource) do @@ -35,13 +35,13 @@ end let(:association_fields) { ["offset", "limit", "sortBy", "sortOrder"] } - let(:connection_fields) { ["before", "after", "first", "last"] } - let(:query_fields) { association_fields + connection_fields + ["filters"] } - let(:root_fields) { root_query.fields } - let(:managers_field) { root_fields["managers"] } + let(:connection_fields) { ["before", "after", "first", "last"] } + let(:query_fields) { association_fields + connection_fields + ["filters"] } + let(:root_fields) { root_query.fields } + let(:managers_field) { root_fields["managers"] } let(:managers_arguments) { managers_field.arguments } - let(:users_field) { root_fields["users"] } - let(:users_arguments) { users_field.arguments } + let(:users_field) { root_fields["users"] } + let(:users_arguments) { users_field.arguments } before(:each) do allow(::HQ::GraphQL.config).to receive(:use_experimental_associations) { true } @@ -59,7 +59,6 @@ expect(managers_arguments["sortOrder"].type).to eq HQ::GraphQL::Enum::SortOrder expect(managers_arguments["sortBy"].type).to eq HQ::GraphQL::Enum::SortBy expect(HQ::GraphQL::Enum::SortBy.values.keys).to contain_exactly("CreatedAt", "UpdatedAt") - expect(users_arguments["sortOrder"].type).to eq HQ::GraphQL::Enum::SortOrder expect(users_arguments["sortBy"].type).not_to eq HQ::GraphQL::Enum::SortBy expect(users_arguments["sortBy"].type).to eq user_resource.sort_fields_enum @@ -69,6 +68,7 @@ it "adds pagination to association fields" do users_field = manager_resource.query_object.fields["users"] users_arguments = users_field.arguments + expect(users_field.arguments.keys).to contain_exactly(*association_fields) expect(users_arguments["sortOrder"].type).to eq HQ::GraphQL::Enum::SortOrder expect(users_arguments["sortBy"].type).not_to eq HQ::GraphQL::Enum::SortBy diff --git a/spec/lib/graphql/resource_spec.rb b/spec/lib/graphql/resource_spec.rb index af94807..edfd813 100644 --- a/spec/lib/graphql/resource_spec.rb +++ b/spec/lib/graphql/resource_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::Resource do let(:organization_type) do @@ -179,11 +179,13 @@ it "removes name" do ::HQ::GraphQL::Inputs[Advisor].lazy_load! expected = ["id", "nickname", "organizationId", "createdAt", "updatedAt", "X"] + expect(::HQ::GraphQL::Inputs[Advisor].arguments.keys).to contain_exactly(*expected) end it "customizes graphql name" do ::HQ::GraphQL::Inputs[Advisor].lazy_load! + expect(::HQ::GraphQL::Inputs[Advisor].graphql_name).to eql("CustomAdvisorInput") end end @@ -232,7 +234,8 @@ end describe ".def_root" do - let(:find_onehq) { <<-GRAPHQL + let(:find_onehq) { + <<-GRAPHQL query advisorsNamedOneHq { advisorsNamedOneHq { nodes { @@ -306,22 +309,26 @@ def build_resource(stubbed_class) it "strips /^Resources/ and /Resource$/" do c = build_resource("Resources::OrganizationResource") + expect(c.model_klass).to eq Organization end it "strips /^Resources/" do c = build_resource("Resources::Organization") + expect(c.model_klass).to eq Organization end it "strips /Resource$/" do c = build_resource("OrganizationResource") + expect(c.model_klass).to eq Organization end end context "execution" do - let(:find_advisor) { <<-GRAPHQL + let(:find_advisor) { + <<-GRAPHQL query findAdvisor($id: ID!) { advisor(id: $id) { name @@ -334,7 +341,8 @@ def build_resource(stubbed_class) GRAPHQL } - let(:find_advisors) { <<-GRAPHQL + let(:find_advisors) { + <<-GRAPHQL query findAdvisors($first: Int, $limit: Int) { advisors(first: $first, limit: $limit) { nodes { @@ -349,7 +357,8 @@ def build_resource(stubbed_class) GRAPHQL } - let(:create_mutation) { <<-GRAPHQL + let(:create_mutation) { + <<-GRAPHQL mutation createAdvisor($attributes: AdvisorInput!) { createAdvisor(attributes: $attributes) { errors @@ -375,10 +384,11 @@ def build_resource(stubbed_class) } } } - GRAPHQL + GRAPHQL } - let(:destroy_mutation) { <<-GRAPHQL + let(:destroy_mutation) { + <<-GRAPHQL mutation destroyAdvisor($id: ID!) { destroyAdvisor(id: $id) { errors @@ -390,7 +400,8 @@ def build_resource(stubbed_class) GRAPHQL } - let(:new_advisor) { <<-GRAPHQL + let(:new_advisor) { + <<-GRAPHQL query newAdvisor { newAdvisor { name @@ -428,6 +439,7 @@ def build_resource(stubbed_class) 10.times { FactoryBot.create(:advisor) } results = schema.execute(find_advisors, variables: { first: 5 }) data = results["data"]["advisors"]["nodes"] + expect(data.length).to be 5 end @@ -435,6 +447,7 @@ def build_resource(stubbed_class) 251.times { FactoryBot.create(:advisor) } results = schema.execute(find_advisors, variables: {}) data = results["data"]["advisors"]["nodes"] + expect(data.length).to be 250 end @@ -444,6 +457,7 @@ def build_resource(stubbed_class) nickname = "Bobby" results = schema.execute(create_mutation, variables: { attributes: { name: name, nickname: nickname, organizationId: organization.id } }) data = results["data"] + aggregate_failures do expect(data["errors"]).to be_nil expect(data["createAdvisor"]["resource"]["name"]).to eql name @@ -464,8 +478,8 @@ def build_resource(stubbed_class) organization: { id: advisor.organization_id, name: organization_name } } }) - data = results["data"] + aggregate_failures do expect(data["errors"]).to be_nil expect(data["updateAdvisor"]["resource"]["name"]).to eql name @@ -478,8 +492,8 @@ def build_resource(stubbed_class) it "destroys" do advisor = FactoryBot.create(:advisor) results = schema.execute(destroy_mutation, variables: { id: advisor.id }) - data = results["data"] + aggregate_failures do expect(data["errors"]).to be_nil expect(data["destroyAdvisor"]["resource"]["name"]).to eql advisor.name @@ -490,6 +504,7 @@ def build_resource(stubbed_class) it "uses new" do results = schema.execute(new_advisor) data = results["data"]["newAdvisor"] + expect(data.length).to be 2 end @@ -503,6 +518,7 @@ def build_resource(stubbed_class) end results = schema.execute(find_advisor, variables: { id: advisor.id }) data = results["data"] + expect(data["advisor"]).to be_nil end @@ -540,8 +556,8 @@ def build_resource(stubbed_class) organization: { id: advisor.organization_id, name: organization_name } } }) - data = results["data"] + aggregate_failures do expect(data["updateAdvisor"]).to be_nil expect(Advisor.find(advisor.id).name).to eql advisor.name @@ -557,8 +573,8 @@ def build_resource(stubbed_class) end advisor = FactoryBot.create(:advisor) results = schema.execute(destroy_mutation, variables: { id: advisor.id }) - data = results["data"] + aggregate_failures do expect(data["destroyAdvisor"]).to be_nil expect(Advisor.where(id: advisor.id).exists?).to eql true @@ -586,8 +602,8 @@ def build_resource(stubbed_class) name: "Bob" } }) - data = results["data"] + aggregate_failures do expect(data["updateAdvisor"]["errors"]).to be_present expect(data["updateAdvisor"]["resource"]).to be_nil @@ -619,8 +635,8 @@ def build_resource(stubbed_class) name: "Bob" } }) - data = results["data"] + aggregate_failures do expect(data["updateAdvisor"]["errors"]).to be_present expect(data["updateAdvisor"]["resource"]).to be_nil diff --git a/spec/lib/graphql/types/uuid_spec.rb b/spec/lib/graphql/types/uuid_spec.rb index ad08347..d0fdb2b 100644 --- a/spec/lib/graphql/types/uuid_spec.rb +++ b/spec/lib/graphql/types/uuid_spec.rb @@ -1,11 +1,11 @@ -require 'rails_helper' +require "rails_helper" describe ::HQ::GraphQL::Types::UUID do let(:hql_object_klass) do Class.new(::GraphQL::Schema::Object) do graphql_name "TestQuery" - field :id, ::HQ::GraphQL::Types::UUID, null: false + field :id, ::HQ::GraphQL::Types::UUID, null: false field :name, ::HQ::GraphQL::Types::UUID, null: false end end @@ -59,25 +59,27 @@ def advisor(id: nil) it "queries" do result = schema.execute(query_str, variables: { id: advisor.id }) + expect(result.dig("data", "advisor", "id")).to eq advisor.id end describe ".coerce_result" do it "raises an error on incorrect type" do - expect { schema.execute(broken_query_str, variables: { id: advisor.id }) }.to raise_error( - ::GraphQL::CoercionError, "\"#{advisor.name}\" is not a valid UUID" - ) + expect { schema.execute(broken_query_str, variables: { id: advisor.id }) }. + to raise_error(::GraphQL::CoercionError, "\"#{advisor.name}\" is not a valid UUID") end end describe ".coerce_input" do it "supports nil input" do result = schema.execute(query_str, variables: { id: nil }) + expect(result.dig("data", "advisor", "id")).to be_nil end it "displays an error message" do result = schema.execute(query_str, variables: { id: "1" }) + aggregate_failures do expect(result["errors"].length).to eql(1) expect(result["errors"][0]["message"]).to eql("Variable $id of type UUID was provided invalid value") diff --git a/spec/lib/graphql/types_spec.rb b/spec/lib/graphql/types_spec.rb index 8952526..eff7ef6 100644 --- a/spec/lib/graphql/types_spec.rb +++ b/spec/lib/graphql/types_spec.rb @@ -26,7 +26,9 @@ expect(type_object.superclass).to eql(::GraphQL::Schema::Object) expect(type_object).to eql(described_class[Advisor]) expect(type_object.fields.keys).to contain_exactly("customField") + type_object.lazy_load! + expect(type_object.fields.keys).to contain_exactly("customField") end end @@ -44,6 +46,7 @@ include ::HQ::GraphQL::Resource self.model_name = "Agent" end + expect(sti_resource.query_object).to eql(described_class["Agent"]) end From 1890e6e69b343cb7a6dbca086c8d66ff5694efb3 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Mon, 5 Jan 2026 09:27:38 -0300 Subject: [PATCH 17/18] RuboCop indentation pt2 --- lib/hq/graphql/resource.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/hq/graphql/resource.rb b/lib/hq/graphql/resource.rb index b9e3dd2..2b7d33a 100644 --- a/lib/hq/graphql/resource.rb +++ b/lib/hq/graphql/resource.rb @@ -307,12 +307,13 @@ def root_query(find_one: true, find_all: true, limit_max: 250) offset = [0, *offset].max # set limit_max if first/last N is not provided - scope = if limit.present? || !(context.query.provided_variables.symbolize_keys.keys & [:first, :last]).any? - limit = [[limit_max, *limit].min, 0].max - scope.limit(limit).offset(offset) - else - scope.offset(offset) - end + scope = + if limit.present? || !(context.query.provided_variables.symbolize_keys.keys & [:first, :last]).any? + limit = [[limit_max, *limit].min, 0].max + scope.limit(limit).offset(offset) + else + scope.offset(offset) + end sort_by ||= :updated_at sort_order ||= :desc From e3c37071591bd05dcfa0a7e24d90984853a5a560 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Mon, 26 Jan 2026 09:39:38 -0300 Subject: [PATCH 18/18] beta3 --- hq-graphql.gemspec | 6 +++--- lib/hq/graphql/version.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hq-graphql.gemspec b/hq-graphql.gemspec index 18ae4ee..d9bcea9 100644 --- a/hq-graphql.gemspec +++ b/hq-graphql.gemspec @@ -18,9 +18,9 @@ Gem::Specification.new do |s| s.files = Dir["{lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - s.add_dependency "rails", ">= 6.0", "<= 8.1.1" + s.add_dependency "rails", ">= 6.0", "<= 7.2.3" - s.add_dependency "graphql", "~> 1.12" + s.add_dependency "graphql", "~> 1.13" s.add_dependency "graphql-batch", "~> 0.4" s.add_dependency "graphql-schema_comparator", "~> 1.0" s.add_dependency "pg", "~> 1.1" @@ -34,7 +34,7 @@ Gem::Specification.new do |s| s.add_development_dependency "rspec", "~> 3.8" s.add_development_dependency "rspec_junit_formatter", "~> 0.6" s.add_development_dependency "rspec-rails", "~> 7.0" - s.add_development_dependency "rubocop", "~> 1.81" # code quality check for sonarqube + s.add_development_dependency "rubocop", "~> 1.81" s.add_development_dependency "rubocop-performance", "~> 1.26" s.add_development_dependency "rubocop-rails", "~> 2.34" end diff --git a/lib/hq/graphql/version.rb b/lib/hq/graphql/version.rb index 1b069bf..3eba6c2 100644 --- a/lib/hq/graphql/version.rb +++ b/lib/hq/graphql/version.rb @@ -2,6 +2,6 @@ module HQ module GraphQL - VERSION = "5.0.0-beta.2" + VERSION = "5.0.0-beta.3" end end