graphiti-activegraph 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96124388fd7da0f681746c33d199a96431291363f8ec3acd1a1ef2533fba7e3b
4
- data.tar.gz: ba13ae0e3229a1e31a3e575d8d7b1e8c502a58d6d774ab3326b1936138e09d5c
3
+ metadata.gz: 99c8c00fe58ed3146c7feae681bac89ec82989b09f88dfa97aa6a54ef7e9930b
4
+ data.tar.gz: c21e632e4fa1a4f6b24315c01c76d89f91158ae9996a73cdf6da83e97805e2ce
5
5
  SHA512:
6
- metadata.gz: 9985ef640559045360fc73f8dc41daf8ce09b43d92010cddff64bec9967e031cea3d806683865793c0dcca9f3e3092539cee81501b9bcc06e0a6f1bf4b0f1104
7
- data.tar.gz: 711c568f287e85dc68d39fcf09b87425c7e8f1c61e20ce656578d1eee12bee57a2c62258a30f9df4e20380d9cebebb020c1951e557ff61d1eb82944dd0eeae64
6
+ metadata.gz: 8942c7a92552d7554cdc78e5183b970bab9c6d9cee23e5d21e23244c84c45491bbd5a3085671cde7919ca3f7e531cd2e7c6388f0ad367cecc430b77597c0db9c
7
+ data.tar.gz: e31a9631f62d743899851ea815c2158c801f550a5d7ec86eafab260045441fbbd84813f0c5511f9cadc3ad2a7fe8b750d315effc65cbc46866235d31f136731a
@@ -10,11 +10,14 @@ on:
10
10
  workflow_dispatch:
11
11
 
12
12
  permissions:
13
+ actions: write
13
14
  contents: read
14
15
 
15
16
  jobs:
16
17
  test:
17
18
  runs-on: ubuntu-latest
19
+ permissions:
20
+ id-token: write
18
21
  strategy:
19
22
  fail-fast: false
20
23
  matrix:
@@ -49,3 +52,8 @@ jobs:
49
52
 
50
53
  - name: Run tests
51
54
  run: bundle exec rspec
55
+
56
+ - uses: qltysh/qlty-action/coverage@v1
57
+ with:
58
+ oidc: true
59
+ files: coverage/coverage.json
data/CHANGELOG.md CHANGED
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.1] - 2025-11-5
11
+ ### Added
12
+ - **Deserializer: relationship id(s) helpers**: introduced `relationship_id` and `relationship_ids` methods in `Deserializer` to fetch relationship id(s) by association name from request payload. (PR #49)
13
+
14
+ ## [1.3.0] - 2025-10-13
15
+ ### Added
16
+ - **Extra fields preloading in main query**: Support preloading associations for `extra_fields` for main and sideloaded records. Adds `preload` option to `extra_attribute` in resource classes. Example: `extra_attribute :full_post_title, :string, preload: :author`. (PR #45)
17
+ - **Extra fields preloading in separate query**: Collect IDs from the main query result and run a single separate query to load and calculate `extra_fields` values for all records. does not support preloading for deep sideloads. (PR #47)
18
+
10
19
  ## [1.2.0] - 2025-05-20
11
20
 
12
21
  ### Added
data/README.md CHANGED
@@ -45,6 +45,11 @@ graphiti-activegraph allows assigning and unassigning relationships via sidepost
45
45
  Graphiti stores context using `Thread.current[]`, which does not persist across different fibers within the same thread. In graphiti-activegraph, when running on MRI (non-JRuby environments), the gem uses `thread_variable_get` and `thread_variable_set`. Ensuring the context remains consistent across different fibers in the same thread.
46
46
 
47
47
  ### New Features in graphiti-activegraph
48
+ For detailed API documentation and helper method behavior, see the [docs](./docs) directory.
49
+ - [Deserializer](./docs/deserializer.md)
50
+ - [Adapter](./docs/adapter.md) *(planned)*
51
+ - [Resource](./docs/resource.md) *(planned)*
52
+
48
53
  #### Rendering Preloaded Objects Without Extra Queries
49
54
  graphiti-activegraph introduces two new methods on the Graphiti resource class:
50
55
  `with_preloaded_obj(record, params)` – Renders a single preloaded ActiveGraph object without querying the database.
@@ -65,6 +70,50 @@ Control the links in response payload via request query params:
65
70
  - `pagination_links=true|false` — toggle top-level pagination links
66
71
  - `links=true|false` — toggle links inside each resource object
67
72
 
73
+ #### Preload Extra Attribute Associations via `preload:` option
74
+ You can declare an extra attribute on your resource and specify an association to preload using the `preload:` option.
75
+ Example:
76
+ ```ruby
77
+ extra_attribute :full_post_title, :string, preload: :author
78
+ ```
79
+ Check [spec/active_graph/scoping/internal/extra_field_normalizer_spec.rb](https://github.com/mrhardikjoshi/graphiti-activegraph/blob/master/spec/active_graph/scoping/internal/extra_field_normalizer_spec.rb) for examples of usage `preload:` option.
80
+
81
+ #### Preload Extra Fields via Model Preload Method
82
+ You can define a custom preload method with prefix `preload_` in your model (e.g., `preload_posts_number` for the posts_number extra field) that fetches values for the extra attribute.
83
+ When you request an extra field (e.g., `posts_number`) in your query, graphiti-activegraph will call this method, passing all relevant record IDs, and assign the returned values to each record’s extra attribute.
84
+ This works for both top-level results and sideloaded records of the matching resource type.
85
+
86
+ ##### Usage example
87
+ ```ruby
88
+ class Comment
89
+ # Allows assignment of the extra field value by the preloader
90
+ attr_writer :author_activity
91
+
92
+ def author_activity
93
+ @author_activity ||= author.comments.count + author.posts.count
94
+ end
95
+
96
+ # Preload method which fetches values for the extra_attribute
97
+ def self.preload_author_activity(comment_ids)
98
+ where(id: comment_ids).with_associations(author: [:posts, :comments]).to_h do |comment|
99
+ author = comment.author
100
+ [comment.id, author.posts.count + author.comments.count]
101
+ end
102
+ end
103
+ end
104
+
105
+ class CommentResource < Graphiti::ActiveGraph::Resource
106
+ extra_attribute :author_activity, :integer
107
+ end
108
+ ```
109
+
110
+ **Note:**
111
+ Currently, this feature does not support preloading for deep sideloads such as `posts.comment.author*`. Deeply sideloaded records will not appear in the array of relevant records for preload, and thus will not have extra fields assigned.
112
+
113
+ Check [spec/support/factory_bot_setup.rb](https://github.com/mrhardikjoshi/graphiti-activegraph/blob/master/spec/support/factory_bot_setup.rb) and [spec/active_graph/sideload_resolve_spec.rb](https://github.com/mrhardikjoshi/graphiti-activegraph/blob/master/spec/active_graph/sideload_resolve_spec.rb) for examples of usage.
114
+
115
+ ## [CHANGELOG](CHANGELOG.md)
116
+
68
117
  ## Contributing
69
118
  Bug reports and pull requests are welcome on GitHub at https://github.com/mrhardikjoshi/graphiti-activegraph. This project is intended to be a safe, welcoming space for collaboration.
70
119
 
@@ -0,0 +1,40 @@
1
+ # Deserializer
2
+
3
+ ### Overview
4
+ Handles incoming JSON:API payloads for Graphiti. Deserializes the request body and provides helper methods to extract and reconcile data, relationships and meta.
5
+
6
+ ### Methods
7
+
8
+ #### `relationship_id(name)`
9
+ Returns the single related id for the given association name.
10
+ Used when the relationship is `has_one`.
11
+
12
+ #### `relationship_ids(name)`
13
+ Returns an array of related ids for the given association name.
14
+ Used when the relationship is `has_many`.
15
+
16
+ #### `add_path_id_to_relationships!(params)`
17
+ Ensures that relationship ids passed in the request path are reflected in `params[:data][:relationships]` when missing in the request body.
18
+ If the request body already contains an id for the same relationship, it compares the path and body ids using `detect_conflict` to prevent mismatched identifiers.
19
+ The method is idempotent per request—subsequent calls are ignored once processed.
20
+
21
+ **Behavior summary:**
22
+ - Adds missing relationship ids to the request body.
23
+ - Detects and surfaces id mismatches between path and body.
24
+ - Updates the internal `relationships` hash for consistency.
25
+ - Marks the deserializer as updated to avoid repeated execution.
26
+
27
+ **Parameters:**
28
+ - `params` — Hash (usually the request parameters).
29
+
30
+ **Returns:**
31
+ - Modified `params` Hash with relationship ids added where necessary.
32
+
33
+ **Example:**
34
+ ```ruby
35
+ # Given a path like /authors/42/books
36
+ path_map = { author: "42" }
37
+ params = { data: { type: "books", attributes: { title: "Graph Databases" } } }
38
+
39
+ deserializer.add_path_id_to_relationships!(params)
40
+ # => params[:data][:relationships][:author][:data][:id] == "42"
@@ -26,6 +26,8 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'standard'
27
27
  spec.add_development_dependency 'pry'
28
28
  spec.add_development_dependency 'ffaker'
29
+ spec.add_development_dependency 'simplecov'
30
+ spec.add_development_dependency 'simplecov_json_formatter'
29
31
  spec.add_development_dependency 'factory_bot_rails'
30
32
  spec.add_development_dependency 'rake', '>= 10.0'
31
33
  spec.add_development_dependency 'rspec', '>= 3.9.0'
@@ -0,0 +1,15 @@
1
+ module Graphiti::ActiveGraph::Concerns
2
+ module Relationships
3
+ def relationship?(name)
4
+ relationships[name.to_sym].present?
5
+ end
6
+
7
+ def relationship_id(name)
8
+ relationships[name]&.dig(:attributes, :id)
9
+ end
10
+
11
+ def relationship_ids(name)
12
+ Array.wrap(relationships[name]).pluck(:attributes).pluck(:id)
13
+ end
14
+ end
15
+ end
@@ -1,6 +1,7 @@
1
1
  module Graphiti::ActiveGraph
2
2
  class Deserializer < Graphiti::Deserializer
3
3
  include Concerns::PathRelationships
4
+ include Concerns::Relationships
4
5
 
5
6
  class Conflict < StandardError
6
7
  attr_reader :key, :path_value, :body_value
@@ -55,10 +56,6 @@ module Graphiti::ActiveGraph
55
56
  end
56
57
  end
57
58
 
58
- def relationship?(name)
59
- relationships[name.to_sym].present?
60
- end
61
-
62
59
  # change empty relationship as `disassociate` hash so they will be removed
63
60
  def process_nil_relationship(name)
64
61
  attributes = {}
@@ -0,0 +1,38 @@
1
+ module Graphiti::ActiveGraph::Extensions::QueryDsl
2
+ module Performer
3
+ attr_accessor :with_vars, :skip_arrow_cypher_rels
4
+
5
+ def apply_query_dsl
6
+ query_param = resource.context&.params&.[](:query)
7
+ query_param.present? ? apply_query_param(query_param) : scope
8
+ end
9
+
10
+ def apply_query_param(query_param)
11
+ @scope = query_generator.new(query_param, **query_generator_config).tap do |qg|
12
+ qg.generate_functions_optional_match
13
+ qg.generate_with_clause_partition_query
14
+ qg.generate_match_query
15
+ qg.generate_with_clause_query
16
+ end.query
17
+ end
18
+
19
+ private
20
+
21
+ def query_generator
22
+ Graphiti::ActiveGraph::Extensions::QueryDsl::QueryGenerator
23
+ end
24
+
25
+ def query_generator_config
26
+ {
27
+ query: scope,
28
+ with_vars_to_carry:,
29
+ skip_arrow_cypher_rels: skip_arrow_cypher_rels || [],
30
+ resource: resource.class
31
+ }
32
+ end
33
+
34
+ def with_vars_to_carry
35
+ (query ? with_vars_for_sort : []).push(*with_vars).push(*Graphiti.context[:with_vars]).compact
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ module Graphiti::ActiveGraph::Extensions::QueryDsl
2
+ class QueryGenerator
3
+ def initialize(query_param, query:, **config)
4
+ @query_param = query_param
5
+ @query = query
6
+ end
7
+
8
+ def generate_functions_optional_match
9
+ end
10
+
11
+ def generate_with_clause_partition_query
12
+ end
13
+
14
+ def generate_match_query
15
+ end
16
+
17
+ def generate_with_clause_query
18
+ end
19
+ end
20
+ end
@@ -45,8 +45,9 @@ module Graphiti
45
45
 
46
46
  def handle_includes(scope, includes, sorts, **opts)
47
47
  includes_str = JSONAPI::IncludeDirective.new(includes, retain_rel_limit: true).to_string.split(',')
48
+ extra_includes_str = opts.delete(:extra_fields_includes) || []
48
49
  options = opts.merge(max_page_size:).merge!(authorize_scope_params)
49
- scope.with_ordered_associations(includes_str, sorts, options)
50
+ scope.with_ordered_associations(includes_str.union(extra_includes_str), sorts, options)
50
51
  end
51
52
 
52
53
  def sideload_name_arr(query)
@@ -2,6 +2,15 @@ module Graphiti::ActiveGraph
2
2
  module Scoping
3
3
  module Filter
4
4
  include Filterable
5
+ include Internal::SortingAliases
6
+ include Extensions::QueryDsl::Performer
7
+
8
+ attr_reader :scope
9
+
10
+ def apply
11
+ super
12
+ apply_query_dsl
13
+ end
5
14
 
6
15
  def each_filter
7
16
  filter_param.each_pair do |param_name, param_value|
@@ -10,9 +10,10 @@ module Graphiti::ActiveGraph
10
10
  end
11
11
 
12
12
  def apply_standard_scope
13
- return scope if normalized_includes.empty?
13
+ return scope if normalized_includes.empty? && extra_fields_includes.empty?
14
+
14
15
  self.scope = resource.handle_includes(scope, normalized_includes, normalized_sorts,
15
- with_vars: with_vars_for_sort, paginate: paginate?)
16
+ extra_fields_includes:, with_vars: with_vars_for_sort, paginate: paginate?)
16
17
  end
17
18
 
18
19
  private
@@ -23,6 +24,10 @@ module Graphiti::ActiveGraph
23
24
  @opts[:query_obj]
24
25
  end
25
26
 
27
+ def extra_fields_includes
28
+ @extra_fields_includes ||= Internal::ExtraFieldNormalizer.new(@query_hash[:extra_fields]).normalize(resource, normalized_includes)
29
+ end
30
+
26
31
  def paginate?
27
32
  Graphiti::Scoping::Paginate.new(@resource, @query_hash, scope, @opts).apply?
28
33
  end
@@ -0,0 +1,76 @@
1
+ module Graphiti::ActiveGraph
2
+ module Scoping
3
+ module Internal
4
+ class ExtraFieldNormalizer
5
+
6
+ def initialize(extra_fields)
7
+ @extra_fields = extra_fields
8
+ @extra_includes = []
9
+ end
10
+
11
+ def normalize(resource, normalized_includes)
12
+ return [] if @extra_fields.blank?
13
+
14
+ process_extra_fields_for_assoc(resource, [], '')
15
+ collect_extra_field_paths(resource, normalized_includes) unless normalized_includes.blank?
16
+ @extra_includes.uniq
17
+ end
18
+
19
+ private
20
+
21
+ def collect_extra_field_paths(resource, normalized_includes, parent_path = [])
22
+ normalized_includes.each do |assoc, nested_assoc|
23
+ assoc_resource = fetch_assoc_resource(resource, assoc)
24
+ next unless assoc_resource
25
+
26
+ process_extra_fields_for_assoc(assoc_resource, parent_path, assoc)
27
+ collect_extra_field_paths(assoc_resource, nested_assoc, parent_path + [assoc.to_s]) unless nested_assoc.empty?
28
+ end
29
+ end
30
+
31
+ def fetch_assoc_resource(resource, assoc)
32
+ rel_name = Util::Transformers::RelationParam.new(assoc).rel_name_sym
33
+ resource.class&.sideload_resource_class(rel_name)&.new
34
+ end
35
+
36
+ def process_extra_fields_for_assoc(assoc_resource, parent_path, assoc)
37
+ return unless @extra_fields.key?(assoc_resource.type)
38
+
39
+ Array(@extra_fields[assoc_resource.type]).each do |extra_field|
40
+ add_preload_paths_for_extra_field(extra_field_config(assoc_resource, extra_field), parent_path, assoc)
41
+ end
42
+ end
43
+
44
+ def extra_field_config(assoc_resource, extra_field)
45
+ assoc_resource.class&.config&.dig(:extra_attributes, extra_field)
46
+ end
47
+
48
+ def add_preload_paths_for_extra_field(config, parent_path, assoc)
49
+ return unless config && config[:preload].present?
50
+
51
+ flatten_preload_hash(config[:preload]).each do |preload|
52
+ @extra_includes << construct_preload_path(parent_path, assoc, preload)
53
+ end
54
+ end
55
+
56
+ def flatten_preload_hash(preload, prefix = [])
57
+ case preload
58
+ when Hash
59
+ preload.flat_map { |k, v| flatten_preload_hash(v, prefix + [k.to_s]) }
60
+ when Array
61
+ preload.flat_map { |v| flatten_preload_hash(v, prefix) }
62
+ else
63
+ value = preload.to_s
64
+ return [] if value.empty?
65
+
66
+ [(prefix + [value]).join('.')]
67
+ end
68
+ end
69
+
70
+ def construct_preload_path(parent_path, assoc, preload)
71
+ (parent_path + [assoc.to_s, preload.to_s]).compact_blank.join('.')
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -43,32 +43,77 @@ module Graphiti::ActiveGraph
43
43
  end
44
44
 
45
45
  def preload_extra_fields(results)
46
- requested_extra_fields.each do |extra_field_name|
47
- next unless preload_extra_field?(extra_field_name)
46
+ @query.extra_fields.each do |type, extra_field_names|
47
+ extra_field_names.each do |name|
48
+ next unless preload_extra_field?(type, name)
48
49
 
49
- result_map = fetch_preloaded_data(extra_field_name, results)
50
- assign_preloaded_data(results, extra_field_name, result_map)
50
+ records_for_preload = collect_records_for_preload(type, results)
51
+ result_map = fetch_preloaded_data(type, name, records_for_preload)
52
+ assign_preloaded_data(records_for_preload, name, result_map)
53
+ end
51
54
  end
52
55
  end
53
56
 
54
- def requested_extra_fields
55
- @query.extra_fields[@resource.type] || []
56
- end
57
-
58
- def fetch_preloaded_data(extra_field_name, results)
59
- @resource.model.public_send(default_preload_method(extra_field_name), results.pluck(:id))
57
+ def fetch_preloaded_data(type, extra_field_name, results)
58
+ resource_for_preload(type).model.public_send(default_preload_method(extra_field_name), results.pluck(:id).uniq)
60
59
  end
61
60
 
62
61
  def assign_preloaded_data(results, extra_field_name, result_map)
63
62
  results.each { |r| r.public_send("#{extra_field_name}=", result_map[r.id]) }
64
63
  end
65
64
 
66
- def preload_extra_field?(extra_field_name)
67
- @resource.extra_attribute?(extra_field_name) && @resource.model.respond_to?(default_preload_method(extra_field_name))
65
+ def preload_extra_field?(type, extra_field_name)
66
+ resource = resource_for_preload(type)
67
+ resource && resource.extra_attribute?(extra_field_name) && resource.model.respond_to?(default_preload_method(extra_field_name))
68
+ end
69
+
70
+ def resource_for_preload(type)
71
+ return @resource if type == @resource.type
72
+
73
+ find_resource_in_included_associations(type) unless @query.sideloads.empty?
74
+ end
75
+
76
+ def find_resource_in_included_associations(type, sideload_query = @query)
77
+ sideload_query.sideloads.values.each do |sideload|
78
+ return sideload.resource if sideload.resource.type == type
79
+
80
+ resource = find_resource_in_included_associations(type, sideload)
81
+ return resource if resource
82
+ end
83
+
84
+ nil
68
85
  end
69
86
 
70
87
  def default_preload_method(extra_field_name)
71
88
  "#{PRELOAD_METHOD_PREFIX}#{extra_field_name}"
72
89
  end
90
+
91
+ def collect_records_for_preload(type, results)
92
+ base_records = resource_matches_type?(@resource, type) ? Array(results) : []
93
+ sideloaded_records = collect_sideloaded_records(Array(results), @query, type)
94
+ (base_records + sideloaded_records).flatten.compact.uniq
95
+ end
96
+
97
+ def collect_sideloaded_records(source_records, sideload_query, type)
98
+ return [] if source_records.empty? || sideload_query.sideloads.empty?
99
+
100
+ sideload_query.sideloads.flat_map do |sideload_name, nested_query|
101
+ associated_records = collect_associated_records(source_records, sideload_name)
102
+ matched_records = resource_matches_type?(nested_query.resource, type) ? associated_records : []
103
+ matched_records + collect_sideloaded_records(associated_records, nested_query, type)
104
+ end
105
+ end
106
+
107
+ def resource_matches_type?(resource, type)
108
+ resource&.type == type
109
+ end
110
+
111
+ def collect_associated_records(source_records, sideload_name)
112
+ source_records.flat_map do |parent|
113
+ next [] unless parent.respond_to?(sideload_name)
114
+
115
+ Array(parent.public_send(sideload_name)).compact
116
+ end
117
+ end
73
118
  end
74
119
  end
@@ -1,5 +1,5 @@
1
1
  module Graphiti
2
2
  module ActiveGraph
3
- VERSION = '1.2.0'
3
+ VERSION = '1.3.1'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphiti-activegraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hardik Joshi
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-05-20 00:00:00.000000000 Z
10
+ date: 2025-11-05 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: graphiti
@@ -127,6 +127,34 @@ dependencies:
127
127
  - - ">="
128
128
  - !ruby/object:Gem::Version
129
129
  version: '0'
130
+ - !ruby/object:Gem::Dependency
131
+ name: simplecov
132
+ requirement: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ type: :development
138
+ prerelease: false
139
+ version_requirements: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ - !ruby/object:Gem::Dependency
145
+ name: simplecov_json_formatter
146
+ requirement: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ type: :development
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
130
158
  - !ruby/object:Gem::Dependency
131
159
  name: factory_bot_rails
132
160
  requirement: !ruby/object:Gem::Requirement
@@ -183,6 +211,7 @@ files:
183
211
  - Gemfile
184
212
  - LICENSE.txt
185
213
  - README.md
214
+ - docs/deserializer.md
186
215
  - graphiti-activegraph.gemspec
187
216
  - lib/graphiti-activegraph.rb
188
217
  - lib/graphiti/active_graph/adapters/active_graph.rb
@@ -192,9 +221,12 @@ files:
192
221
  - lib/graphiti/active_graph/adapters/active_graph/polymorphic_belongs_to.rb
193
222
  - lib/graphiti/active_graph/adapters/active_graph/sideload.rb
194
223
  - lib/graphiti/active_graph/concerns/path_relationships.rb
224
+ - lib/graphiti/active_graph/concerns/relationships.rb
195
225
  - lib/graphiti/active_graph/deserializer.rb
196
226
  - lib/graphiti/active_graph/extensions/context.rb
197
227
  - lib/graphiti/active_graph/extensions/grouping/params.rb
228
+ - lib/graphiti/active_graph/extensions/query_dsl/performer.rb
229
+ - lib/graphiti/active_graph/extensions/query_dsl/query_generator.rb
198
230
  - lib/graphiti/active_graph/extensions/query_params.rb
199
231
  - lib/graphiti/active_graph/extensions/resources/authorizationable.rb
200
232
  - lib/graphiti/active_graph/extensions/resources/payload_combinable.rb
@@ -214,6 +246,7 @@ files:
214
246
  - lib/graphiti/active_graph/scoping/filter.rb
215
247
  - lib/graphiti/active_graph/scoping/filterable.rb
216
248
  - lib/graphiti/active_graph/scoping/include.rb
249
+ - lib/graphiti/active_graph/scoping/internal/extra_field_normalizer.rb
217
250
  - lib/graphiti/active_graph/scoping/internal/include_normalizer.rb
218
251
  - lib/graphiti/active_graph/scoping/internal/path_descriptor.rb
219
252
  - lib/graphiti/active_graph/scoping/internal/sort_normalizer.rb