graphiti 1.3.9 → 1.7.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30f5b9382256603c1f3f8f4ab8c4e614804c1a2e2152617d7b19892bca6bd465
4
- data.tar.gz: 948837bfa0f8deee2f44849aba9df2bb18f2fdf532a1caaab92b16c7d9ba91fd
3
+ metadata.gz: 526bde7653f2c482b92ee75c5a7afee5823f675024b9c6925e86aa04924e27d3
4
+ data.tar.gz: e7441df1db552bf0b30ee3d85a16fa644f4d770cff40bf199e9338c003ce810b
5
5
  SHA512:
6
- metadata.gz: 4fe6fff9c219fd463378bbdc793f648cbeffe27c61c191f11e2aab4723e952d2d8f7cc26b334255e12adca3e9d819b1bbde17697a6621f11a28151d2649d6d9c
7
- data.tar.gz: becca9eaa17f328a99669e1e855a4024862b45d1902ddf30de597f7b33e3f52e4145b0f1dba1542a0d144ba2bc1bdec280ad9d8fa599a102ead9efb5260e1ab3
6
+ metadata.gz: 1cccf050029f667eb96d0c76e379df5ecaddec574eede0708b3847cdb821b35fd1b527a8ffc5759d72f9d9a0f739d1d756cc4ea114dad1606621f6de13a814e3
7
+ data.tar.gz: 2f80a0ce18045b984ec722a395f79028ae1da6d2fbd7923424d5371bf177990c3692fa7c835d5ad27ecfe56b9d0da0a215c7ae3aff82cf47fc9822fb9e88a6c5
@@ -0,0 +1,2 @@
1
+ enabled:
2
+ - cla
@@ -28,10 +28,11 @@ jobs:
28
28
  fail-fast: false
29
29
  matrix:
30
30
  ruby:
31
- - "2.6"
32
31
  - "2.7"
33
32
  - "3.0"
34
33
  - "3.1"
34
+ - "3.2"
35
+ - "3.3"
35
36
  gemfile:
36
37
  - Gemfile
37
38
  - gemfiles/rails_5_2.gemfile
@@ -40,12 +41,13 @@ jobs:
40
41
  - gemfiles/rails_5_2_graphiti_rails.gemfile
41
42
  - gemfiles/rails_6_graphiti_rails.gemfile
42
43
  - gemfiles/rails_7_graphiti_rails.gemfile
44
+ - gemfiles/rails_7_1_graphiti_rails.gemfile
43
45
  appraisal:
44
46
  - true
45
47
  - false
46
48
  include:
47
49
  - ruby: ruby-head
48
- gemfile: Gemfile
50
+ gemfile: gemfiles/rails_7_1.gemfile
49
51
  appraisal: true
50
52
  - ruby: ruby-head
51
53
  gemfile: Gemfile
@@ -66,7 +68,9 @@ jobs:
66
68
  appraisal: false
67
69
  - gemfile: gemfiles/rails_7_graphiti_rails.gemfile
68
70
  appraisal: false
69
- # Rails 5 can't run on Ruby 3
71
+ - gemfile: gemfiles/rails_7_1_graphiti_rails.gemfile
72
+ appraisal: false
73
+ # Rails 5 can't run on Ruby 3
70
74
  - gemfile: gemfiles/rails_5_2.gemfile
71
75
  ruby: 3.0
72
76
  - gemfile: gemfiles/rails_5_2_graphiti_rails.gemfile
@@ -75,11 +79,14 @@ jobs:
75
79
  ruby: 3.1
76
80
  - gemfile: gemfiles/rails_5_2_graphiti_rails.gemfile
77
81
  ruby: 3.1
78
- # Raise 7 can't run on 2.6
79
- - gemfile: gemfiles/rails_7.gemfile
80
- ruby: 2.6
81
- - gemfile: gemfiles/rails_7_graphiti_rails.gemfile
82
- ruby: 2.6
82
+ - gemfile: gemfiles/rails_5_2.gemfile
83
+ ruby: 3.2
84
+ - gemfile: gemfiles/rails_5_2_graphiti_rails.gemfile
85
+ ruby: 3.2
86
+ - gemfile: gemfiles/rails_5_2.gemfile
87
+ ruby: 3.3
88
+ - gemfile: gemfiles/rails_5_2_graphiti_rails.gemfile
89
+ ruby: 3.3
83
90
  continue-on-error: ${{ matrix.ruby == 'ruby-head' }}
84
91
  env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
85
92
  BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
@@ -94,3 +101,14 @@ jobs:
94
101
  bundler-cache: true
95
102
  - name: Run tests
96
103
  run: bundle exec rspec
104
+ publish:
105
+ name: Release
106
+ runs-on: ubuntu-latest
107
+ if: github.ref == 'refs/heads/master'
108
+ needs: [test]
109
+ steps:
110
+ - name: Dispatch Release
111
+ uses: benc-uk/workflow-dispatch@v1
112
+ with:
113
+ workflow: Generate New Release
114
+ token: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: Generate New Release
3
+
4
+ on:
5
+ workflow_dispatch:
6
+
7
+ jobs:
8
+ release:
9
+ name: Release
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout
13
+ uses: actions/checkout@v3
14
+ with:
15
+ submodules: true
16
+ persist-credentials: false
17
+ - name: Set up Ruby
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: "3.1"
21
+ - name: Build
22
+ run: |
23
+ gem install bundler
24
+ git submodule update --init --recursive
25
+ bundle install --jobs 4 --retry 3
26
+ - name: Setup Node.js
27
+ uses: actions/setup-node@v2
28
+ with:
29
+ node-version: 14
30
+ - name: Install Dependencies
31
+ run: yarn install --frozen-lockfile
32
+ - name: Release
33
+ env:
34
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35
+ GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }}
36
+ run: node_modules/.bin/semantic-release
data/.gitignore CHANGED
@@ -7,6 +7,7 @@
7
7
  /spec/reports/
8
8
  /gemfiles/*.lock
9
9
  /tmp/
10
+ node_modules
10
11
  .byebug_history
11
12
  spec/.rspec-examples
12
13
  spec/dummy/log/*
data/.standard.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  fix: true
2
2
  parallel: true
3
- ruby_version: 2.4
3
+ ruby_version: 2.7
4
4
 
5
5
  ignore:
6
6
  - 'vendor/**/*'
data/Appraisals CHANGED
@@ -42,3 +42,18 @@ appraise "rails-7-graphiti-rails" do
42
42
  gem "database_cleaner"
43
43
  gem "graphiti-rails", "~> 0.4.0"
44
44
  end
45
+
46
+ appraise "rails-7-1" do
47
+ gem "rails", "~> 7.1"
48
+ gem "rspec-rails"
49
+ gem "sqlite3", "~> 1.4.0"
50
+ gem "database_cleaner"
51
+ end
52
+
53
+ appraise "rails-7-1-graphiti-rails" do
54
+ gem "rails", "~> 7.1"
55
+ gem "rspec-rails"
56
+ gem "sqlite3", "~> 1.4.0"
57
+ gem "database_cleaner"
58
+ gem "graphiti-rails", "~> 0.4.0"
59
+ end
data/CHANGELOG.md CHANGED
@@ -1,4 +1,122 @@
1
- ## Unreleased
1
+ graphiti changelog
2
+
3
+ ## [1.7.5](https://github.com/graphiti-api/graphiti/compare/v1.7.4...v1.7.5) (2024-09-16)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * Fixes error in version check for ActiveRecord adapter introduced in [#478](https://github.com/graphiti-api/graphiti/issues/478) ([#479](https://github.com/graphiti-api/graphiti/issues/479)) ([42c82c3](https://github.com/graphiti-api/graphiti/commit/42c82c397f20eb91c02835e518ff4c351c028ea7))
9
+
10
+ ## [1.7.4](https://github.com/graphiti-api/graphiti/compare/v1.7.3...v1.7.4) (2024-09-11)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * update ActiveRecord adapter w/ support for Rails 7.2+ ([#478](https://github.com/graphiti-api/graphiti/issues/478)) ([8313e33](https://github.com/graphiti-api/graphiti/commit/8313e3359f0dde28d9940867c7ded964db4c854d))
16
+
17
+ ## [1.7.3](https://github.com/graphiti-api/graphiti/compare/v1.7.2...v1.7.3) (2024-06-26)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * require OpenStruct explicitly ([#475](https://github.com/graphiti-api/graphiti/issues/475)) ([e0fa18a](https://github.com/graphiti-api/graphiti/commit/e0fa18a8d7f051e385e6e081f79f2ecae92a9260))
23
+
24
+ ## [1.7.2](https://github.com/graphiti-api/graphiti/compare/v1.7.1...v1.7.2) (2024-06-11)
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * require necessary ActiveSupport parts in proper order ([bb2a488](https://github.com/graphiti-api/graphiti/commit/bb2a48874a6533522df6eb027d0df8ec14c80a20))
30
+
31
+ ## [1.7.1](https://github.com/graphiti-api/graphiti/compare/v1.7.0...v1.7.1) (2024-04-18)
32
+
33
+
34
+ ### Bug Fixes
35
+
36
+ * properly display .find vs .all in debugger statements ([d2a7a03](https://github.com/graphiti-api/graphiti/commit/d2a7a038a649818979d52ccd898e68dba78b051f))
37
+ * rescue error from sideloads updated_at calculation, defaulting to the current time ([661e3b5](https://github.com/graphiti-api/graphiti/commit/661e3b5212e2649870a200067d0d5d52fa962637))
38
+
39
+ # [1.7.0](https://github.com/graphiti-api/graphiti/compare/v1.6.4...v1.7.0) (2024-03-27)
40
+
41
+
42
+ ### Features
43
+
44
+ * Add support for caching renders in Graphiti, and better support using etags and stale? in the controller ([#424](https://github.com/graphiti-api/graphiti/issues/424)) ([8bae50a](https://github.com/graphiti-api/graphiti/commit/8bae50ab82559e2644d506e16a4f715effd89317))
45
+
46
+ ## [1.6.4](https://github.com/graphiti-api/graphiti/compare/v1.6.3...v1.6.4) (2024-03-27)
47
+
48
+ ## [1.6.3](https://github.com/graphiti-api/graphiti/compare/v1.6.2...v1.6.3) (2024-03-26)
49
+
50
+
51
+ ### Bug Fixes
52
+
53
+ * Remove thread pool executor logic until we get a better handle on what's causing thread pool hangs. refs [#469](https://github.com/graphiti-api/graphiti/issues/469) ([7941b6f](https://github.com/graphiti-api/graphiti/commit/7941b6f75ce1001b034ed6e83c148b893e9f3d99)), closes [#471](https://github.com/graphiti-api/graphiti/issues/471) [#470](https://github.com/graphiti-api/graphiti/issues/470)
54
+
55
+ ## [1.6.2](https://github.com/graphiti-api/graphiti/compare/v1.6.1...v1.6.2) (2024-03-22)
56
+
57
+
58
+ ### Bug Fixes
59
+
60
+ * thread pool scope and mutex need to be global across all instances of Scope for it to be a global thread pool ([#471](https://github.com/graphiti-api/graphiti/issues/471)) ([51fb51c](https://github.com/graphiti-api/graphiti/commit/51fb51c31f0043d98aa07f689a8cf8c758fa823b))
61
+
62
+ ## [1.6.1](https://github.com/graphiti-api/graphiti/compare/v1.6.0...v1.6.1) (2024-03-22)
63
+
64
+
65
+ ### Bug Fixes
66
+
67
+ * correct thread-pool mutex logic which was causing a deadlock ([0400ab0](https://github.com/graphiti-api/graphiti/commit/0400ab0d97a1382b66b5295fdc7aa7db680e77cc))
68
+
69
+ # [1.6.0](https://github.com/graphiti-api/graphiti/compare/v1.5.3...v1.6.0) (2024-03-20)
70
+
71
+
72
+ ### Features
73
+
74
+ * add thread pool and concurrency_max_threads configuration option ([#470](https://github.com/graphiti-api/graphiti/issues/470)) ([697d761](https://github.com/graphiti-api/graphiti/commit/697d76172adec24cd7e7522300c8335233fdcc36))
75
+
76
+ ## [1.5.3](https://github.com/graphiti-api/graphiti/compare/v1.5.2...v1.5.3) (2024-03-18)
77
+
78
+
79
+ ### Bug Fixes
80
+
81
+ * leverage ruby-2.7 parameter forwarding ([#431](https://github.com/graphiti-api/graphiti/issues/431)) ([ae09a46](https://github.com/graphiti-api/graphiti/commit/ae09a464b2156742bb093537deac0578a1a3e40e))
82
+ * prevent :id stripping when :id not in path ([#447](https://github.com/graphiti-api/graphiti/issues/447)) ([e1dd811](https://github.com/graphiti-api/graphiti/commit/e1dd811283f6e6fe7a36b925934df0ecbb4d3411))
83
+
84
+ ## [1.5.2](https://github.com/graphiti-api/graphiti/compare/v1.5.1...v1.5.2) (2024-03-18)
85
+
86
+
87
+ ### Bug Fixes
88
+
89
+ * Enum should allow the conventionally case-sensitive operators ([#434](https://github.com/graphiti-api/graphiti/issues/434)) ([56d34fd](https://github.com/graphiti-api/graphiti/commit/56d34fd4801bc32c13d64aca880b82b717b2ab81))
90
+
91
+ ## [1.5.1](https://github.com/graphiti-api/graphiti/compare/v1.5.0...v1.5.1) (2024-03-18)
92
+
93
+
94
+ ### Bug Fixes
95
+
96
+ * polymorphic `on` expects a symbol ([#433](https://github.com/graphiti-api/graphiti/issues/433)) ([4e58702](https://github.com/graphiti-api/graphiti/commit/4e587021265323bd0b170b57e9c7aecaa7f826d7))
97
+
98
+ # [1.5.0](https://github.com/graphiti-api/graphiti/compare/v1.4.0...v1.5.0) (2024-03-18)
99
+
100
+
101
+ ### Features
102
+
103
+ * add before_sideload hook ([#371](https://github.com/graphiti-api/graphiti/issues/371)) ([f68b61f](https://github.com/graphiti-api/graphiti/commit/f68b61ff09ec61ecf23acc5bc37d0accba14aeed))
104
+
105
+ ## 1.4.0, Sun March 17th 2024
106
+ Features:
107
+ - [461](https://github.com/graphiti-api/graphiti/pull/461), [463](https://github.com/graphiti-api/graphiti/pull/463) Add support for Rails 7.1 + Ruby 3.2 + Ruby 3.3
108
+
109
+ Fixes:
110
+ - [464](https://github.com/graphiti-api/graphiti/pull/464) Check for url presence before trying to append
111
+ - [407](https://github.com/graphiti-api/graphiti/pull/407) Sort types in generated schema
112
+ - [421](https://github.com/graphiti-api/graphiti/pull/421) Re-use resource class for remote sideloads to avoid memory leak
113
+ - [452](https://github.com/graphiti-api/graphiti/pull/452) Resolve inconsistency for filters containing curly brackets
114
+ - [446](https://github.com/graphiti-api/graphiti/pull/446) Fix private call
115
+
116
+ ## 1.3.9, May 25th 2022
117
+ Use an options hash for log subscriber instead of positional arguments
118
+
119
+ ## 1.x ??
2
120
 
3
121
  Features:
4
122
  - [329](https://github.com/graphiti-api/graphiti/pull/329) Propagate `extra_fields` to related resource links.
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  group :test do
7
+ gem "database_cleaner"
7
8
  gem "pry"
8
9
  gem "pry-byebug", platform: [:mri]
9
10
  gem "appraisal"
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
- ![Build Status](https://travis-ci.org/graphiti-api/graphiti.svg?branch=master)
1
+ [![CI](https://github.com/graphiti-api/graphiti/actions/workflows/ci.yml/badge.svg)](https://github.com/graphiti-api/graphiti/actions/workflows/ci.yml)
2
2
  [![Gem Version](https://badge.fury.io/rb/graphiti.svg)](https://badge.fury.io/rb/graphiti)
3
3
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
4
+ [![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)
4
5
 
5
6
  <p align="center">
6
7
  <a href="https://www.graphiti.dev/guides">
@@ -0,0 +1,18 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 7.1"
6
+ gem "rspec-rails"
7
+ gem "sqlite3", "~> 1.4.0"
8
+ gem "database_cleaner"
9
+
10
+ group :test do
11
+ gem "pry"
12
+ gem "pry-byebug", platform: [:mri]
13
+ gem "appraisal"
14
+ gem "guard"
15
+ gem "guard-rspec"
16
+ end
17
+
18
+ gemspec path: "../"
@@ -0,0 +1,19 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 7.1"
6
+ gem "rspec-rails"
7
+ gem "sqlite3", "~> 1.4.0"
8
+ gem "database_cleaner"
9
+ gem "graphiti-rails", "~> 0.4.0"
10
+
11
+ group :test do
12
+ gem "pry"
13
+ gem "pry-byebug", platform: [:mri]
14
+ gem "appraisal"
15
+ gem "guard"
16
+ gem "guard-rspec"
17
+ end
18
+
19
+ gemspec path: "../"
data/graphiti.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.bindir = "exe"
17
17
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
18
  spec.require_paths = ["lib"]
19
- spec.required_ruby_version = ">= 2.6"
19
+ spec.required_ruby_version = ">= 2.7"
20
20
 
21
21
  spec.add_dependency "jsonapi-serializable", "~> 0.3.0"
22
22
  spec.add_dependency "jsonapi-renderer", "~> 0.2", ">= 0.2.2"
@@ -39,7 +39,7 @@ module Graphiti
39
39
  :not_match
40
40
  ],
41
41
  uuid: [:eq, :not_eq],
42
- enum: [:eq, :not_eq],
42
+ enum: [:eq, :not_eq, :eql, :not_eql],
43
43
  integer_id: numerical_operators,
44
44
  integer: numerical_operators,
45
45
  big_decimal: numerical_operators,
@@ -26,6 +26,7 @@ module Graphiti
26
26
  alias_method :filter_boolean_eq, :filter_eq
27
27
  alias_method :filter_uuid_eq, :filter_eq
28
28
  alias_method :filter_enum_eq, :filter_eq
29
+ alias_method :filter_enum_eql, :filter_eq
29
30
 
30
31
  def filter_not_eq(scope, attribute, value)
31
32
  scope.where.not(attribute => value)
@@ -37,6 +38,7 @@ module Graphiti
37
38
  alias_method :filter_boolean_not_eq, :filter_not_eq
38
39
  alias_method :filter_uuid_not_eq, :filter_not_eq
39
40
  alias_method :filter_enum_not_eq, :filter_not_eq
41
+ alias_method :filter_enum_not_eql, :filter_not_eq
40
42
 
41
43
  def filter_string_eq(scope, attribute, value, is_not: false)
42
44
  column = column_for(scope, attribute)
@@ -302,7 +304,11 @@ module Graphiti
302
304
  end
303
305
 
304
306
  def close
305
- ::ActiveRecord::Base.clear_active_connections!
307
+ if ::ActiveRecord.version > "7.2"
308
+ ::ActiveRecord::Base.connection_handler.clear_active_connections!
309
+ else
310
+ ::ActiveRecord::Base.clear_active_connections!
311
+ end
306
312
  end
307
313
 
308
314
  def can_group?
@@ -15,10 +15,12 @@ module Graphiti
15
15
  attr_accessor :pagination_links
16
16
  attr_accessor :typecast_reads
17
17
  attr_accessor :raise_on_missing_sidepost
18
+ attr_accessor :before_sideload
18
19
 
19
20
  attr_reader :debug, :debug_models
20
21
 
21
22
  attr_writer :schema_path
23
+ attr_writer :cache_rendering
22
24
 
23
25
  # Set defaults
24
26
  # @api private
@@ -31,6 +33,7 @@ module Graphiti
31
33
  @pagination_links = false
32
34
  @typecast_reads = true
33
35
  @raise_on_missing_sidepost = true
36
+ @cache_rendering = false
34
37
  self.debug = ENV.fetch("GRAPHITI_DEBUG", true)
35
38
  self.debug_models = ENV.fetch("GRAPHITI_DEBUG_MODELS", false)
36
39
 
@@ -51,6 +54,16 @@ module Graphiti
51
54
  end
52
55
  end
53
56
 
57
+ def cache_rendering?
58
+ use_caching = @cache_rendering && Graphiti.cache.respond_to?(:fetch)
59
+
60
+ use_caching.tap do |use|
61
+ if @cache_rendering && !Graphiti.cache&.respond_to?(:fetch)
62
+ raise "You must configure a cache store in order to use cache_rendering. Set Graphiti.cache = Rails.cache, for example."
63
+ end
64
+ end
65
+ end
66
+
54
67
  def schema_path
55
68
  @schema_path ||= raise("No schema_path defined! Set Graphiti.config.schema_path to save your schema.")
56
69
  end
@@ -36,7 +36,7 @@ module Graphiti
36
36
  json[:sideload] = sideload.name
37
37
  end
38
38
  if params
39
- query = "#{payload[:resource].class.name}.all(#{JSON.pretty_generate(params)}).data"
39
+ query = "#{payload[:resource].class.name}.#{payload[:action]}(#{JSON.pretty_generate(params)}).data"
40
40
  logs << [query, :cyan, true]
41
41
  logs << ["The error occurred when running the above query. Copy/paste it into a rake task or Rails console session to reproduce. Keep in mind you may have to set context.", :yellow, true]
42
42
  else
@@ -64,7 +64,7 @@ module Graphiti
64
64
  query = if sideload.class.scope_proc
65
65
  "#{payload[:resource].class.name}: Manual sideload via .scope"
66
66
  else
67
- "#{payload[:resource].class.name}.all(#{params.inspect})"
67
+ "#{payload[:resource].class.name}.#{payload[:action]}(#{params.inspect})"
68
68
  end
69
69
  logs << [" #{query}", :cyan, true]
70
70
  json[:query] = query
@@ -82,7 +82,7 @@ module Graphiti
82
82
  title = "Top Level Data Retrieval (+ sideloads):"
83
83
  logs << [title, :green, true]
84
84
  json[:title] = title
85
- query = "#{payload[:resource].class.name}.all(#{params.inspect})"
85
+ query = "#{payload[:resource].class.name}.#{payload[:action]}(#{params.inspect})"
86
86
  logs << [query, :cyan, true]
87
87
  json[:query] = query
88
88
  logs << ["Returned Models: #{results}"] if debug_models
@@ -98,7 +98,30 @@ module Graphiti
98
98
  took = ((stop - start) * 1000.0).round(2)
99
99
  logs << [""]
100
100
  logs << ["=== Graphiti Debug", :green, true]
101
- logs << ["Rendering:", :green, true]
101
+ if payload[:proxy]&.cached? && Graphiti.config.cache_rendering?
102
+ logs << ["Rendering (cached):", :green, true]
103
+
104
+ Graphiti::Util::CacheDebug.new(payload[:proxy]).analyze do |cache_debug|
105
+ logs << ["Cache key for #{cache_debug.name}", :blue, true]
106
+ logs << if cache_debug.volatile?
107
+ [" \\_ volatile | Request count: #{cache_debug.request_count} | Hit count: #{cache_debug.hit_count}", :red, true]
108
+ else
109
+ [" \\_ stable | Request count: #{cache_debug.request_count} | Hit count: #{cache_debug.hit_count}", :blue, true]
110
+ end
111
+
112
+ if cache_debug.changed_key?
113
+ logs << [" [x] cache key changed #{cache_debug.last_version[:etag]} -> #{cache_debug.current_version[:etag]}", :red]
114
+ logs << [" removed: #{cache_debug.removed_segments}", :red]
115
+ logs << [" added: #{cache_debug.added_segments}", :red]
116
+ elsif cache_debug.new_key?
117
+ logs << [" [+] cache key added #{cache_debug.current_version[:etag]}", :red, true]
118
+ else
119
+ logs << [" [✓] #{cache_debug.current_version[:etag]}", :green, true]
120
+ end
121
+ end
122
+ else
123
+ logs << ["Rendering:", :green, true]
124
+ end
102
125
  logs << ["Took: #{took}ms", :magenta, true]
103
126
  end
104
127
  end
@@ -140,7 +163,6 @@ module Graphiti
140
163
  params ||= {}
141
164
  params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
142
165
  params.reject! { |k, v| [:controller, :action, :format, :debug].include?(k.to_sym) }
143
- params.reject! { |k, v| k.to_sym == :include }
144
166
  params.deep_symbolize_keys
145
167
  end
146
168
 
@@ -1,3 +1,5 @@
1
+ require "digest"
2
+
1
3
  module Graphiti
2
4
  class Query
3
5
  attr_reader :resource, :association_name, :params, :action
@@ -76,11 +78,14 @@ module Graphiti
76
78
  end
77
79
  end
78
80
 
81
+ class RemoteSideloadResource < ::Graphiti::Resource
82
+ self.remote = "_remote_sideload_".freeze
83
+ self.abstract_class = true # exclude from schema
84
+ end
85
+
79
86
  def resource_for_sideload(sideload)
80
87
  if @resource.remote?
81
- Class.new(Graphiti::Resource) {
82
- self.remote = "_remote_sideload_"
83
- }.new
88
+ RemoteSideloadResource.new
84
89
  else
85
90
  sideload.resource
86
91
  end
@@ -229,8 +234,22 @@ module Graphiti
229
234
  ![false, "false"].include?(@params[:paginate])
230
235
  end
231
236
 
237
+ def cache_key
238
+ "args-#{query_cache_key}"
239
+ end
240
+
232
241
  private
233
242
 
243
+ def query_cache_key
244
+ attrs = {extra_fields: extra_fields,
245
+ fields: fields,
246
+ links: links?,
247
+ pagination_links: pagination_links?,
248
+ format: params[:format]}
249
+
250
+ Digest::SHA1.hexdigest(attrs.to_s)
251
+ end
252
+
234
253
  def cast_page_param(name, value)
235
254
  if [:before, :after].include?(name)
236
255
  decode_cursor(value)
@@ -68,7 +68,14 @@ module Graphiti
68
68
  options[:meta][:debug] = Debugger.to_a if debug_json?
69
69
  options[:proxy] = proxy
70
70
 
71
- renderer.render(records, options)
71
+ if proxy.cache? && Graphiti.config.cache_rendering?
72
+ Graphiti.cache.fetch("graphiti:render/#{proxy.cache_key}", version: proxy.updated_at, expires_in: proxy.cache_expires_in) do
73
+ options.delete(:cache) # ensure that we don't use JSONAPI-Resources's built-in caching logic
74
+ renderer.render(records, options)
75
+ end
76
+ else
77
+ renderer.render(records, options)
78
+ end
72
79
  end
73
80
  end
74
81
 
@@ -205,7 +205,7 @@ module Graphiti
205
205
  options[name] ||= send(:"relationships_#{name}_by_default")
206
206
  end
207
207
  end
208
- private :attribute_option
208
+ private :relationship_option
209
209
  end
210
210
  end
211
211
  end
@@ -4,8 +4,13 @@ module Graphiti
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  class_methods do
7
+ def cache_resource(expires_in: false)
8
+ @cache_resource = true
9
+ @cache_expires_in = expires_in
10
+ end
11
+
7
12
  def all(params = {}, base_scope = nil)
8
- validate!(params)
13
+ validate_request!(params)
9
14
  _all(params, {}, base_scope)
10
15
  end
11
16
 
@@ -13,11 +18,11 @@ module Graphiti
13
18
  def _all(params, opts, base_scope)
14
19
  runner = Runner.new(self, params, opts.delete(:query), :all)
15
20
  opts[:params] = params
16
- runner.proxy(base_scope, opts)
21
+ runner.proxy(base_scope, opts.merge(caching_options))
17
22
  end
18
23
 
19
24
  def find(params = {}, base_scope = nil)
20
- validate!(params)
25
+ validate_request!(params)
21
26
  _find(params, base_scope)
22
27
  end
23
28
 
@@ -31,21 +36,29 @@ module Graphiti
31
36
  params[:filter][:id] = id if id
32
37
 
33
38
  runner = Runner.new(self, params, nil, :find)
34
- runner.proxy base_scope,
39
+
40
+ find_options = {
35
41
  single: true,
36
42
  raise_on_missing: true,
37
43
  bypass_required_filters: true
44
+ }.merge(caching_options)
45
+
46
+ runner.proxy base_scope, find_options
38
47
  end
39
48
 
40
49
  def build(params, base_scope = nil)
41
- validate!(params)
50
+ validate_request!(params)
42
51
  runner = Runner.new(self, params)
43
52
  runner.proxy(base_scope, single: true, raise_on_missing: true)
44
53
  end
45
54
 
46
55
  private
47
56
 
48
- def validate!(params)
57
+ def caching_options
58
+ {cache: @cache_resource, cache_expires_in: @cache_expires_in}
59
+ end
60
+
61
+ def validate_request!(params)
49
62
  return if Graphiti.context[:graphql] || !validate_endpoints?
50
63
 
51
64
  if context&.respond_to?(:request)
@@ -76,7 +76,7 @@ module Graphiti
76
76
  path = request_path
77
77
  if [:update, :show, :destroy].include?(context_namespace) && has_id
78
78
  path = request_path.split("/")
79
- path.pop
79
+ path.pop if path.last == has_id.to_s
80
80
  path = path.join("/")
81
81
  end
82
82
  e[:full_path].to_s == path && e[:actions].include?(context_namespace)
@@ -68,7 +68,7 @@ module Graphiti
68
68
  model_ref = model
69
69
  has_many name, opts do
70
70
  params do |hash|
71
- hash[:filter][:"#{as}_type"] = { eql: model_ref.name }
71
+ hash[:filter][:"#{as}_type"] = {eql: model_ref.name}
72
72
  end
73
73
 
74
74
  instance_eval(&blk) if blk
@@ -82,7 +82,7 @@ module Graphiti
82
82
  model_ref = model
83
83
  has_one name, opts do
84
84
  params do |hash|
85
- hash[:filter][:"#{as}_type"] = { eql: model_ref.name }
85
+ hash[:filter][:"#{as}_type"] = {eql: model_ref.name}
86
86
  end
87
87
 
88
88
  instance_eval(&blk) if blk