graphiti-activegraph 1.3.1 → 1.3.3

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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/specs.yml +58 -59
  3. data/.gitignore +59 -59
  4. data/.hound.yml +4 -0
  5. data/.rspec +1 -1
  6. data/.rubocop.yml +6 -0
  7. data/CHANGELOG.md +71 -54
  8. data/CHANGELOG_PRE_1.0.0.md +70 -70
  9. data/Gemfile +3 -3
  10. data/LICENSE.txt +21 -21
  11. data/README.md +130 -130
  12. data/docs/deserializer.md +40 -40
  13. data/graphiti-activegraph.gemspec +35 -34
  14. data/lib/graphiti/active_graph/adapters/active_graph/function_sideload.rb +7 -7
  15. data/lib/graphiti/active_graph/adapters/active_graph/has_many_sideload.rb +7 -7
  16. data/lib/graphiti/active_graph/adapters/active_graph/has_one_sideload.rb +7 -7
  17. data/lib/graphiti/active_graph/adapters/active_graph/polymorphic_belongs_to.rb +11 -11
  18. data/lib/graphiti/active_graph/adapters/active_graph/sideload.rb +26 -26
  19. data/lib/graphiti/active_graph/adapters/active_graph.rb +183 -183
  20. data/lib/graphiti/active_graph/concerns/path_relationships.rb +44 -44
  21. data/lib/graphiti/active_graph/concerns/relationships.rb +15 -15
  22. data/lib/graphiti/active_graph/deserializer.rb +138 -138
  23. data/lib/graphiti/active_graph/extensions/context.rb +17 -17
  24. data/lib/graphiti/active_graph/extensions/grouping/params.rb +101 -52
  25. data/lib/graphiti/active_graph/extensions/query_dsl/performer.rb +38 -38
  26. data/lib/graphiti/active_graph/extensions/query_dsl/query_generator.rb +20 -20
  27. data/lib/graphiti/active_graph/extensions/query_params.rb +27 -27
  28. data/lib/graphiti/active_graph/extensions/resources/authorizationable.rb +29 -29
  29. data/lib/graphiti/active_graph/extensions/resources/payload_combinable.rb +24 -24
  30. data/lib/graphiti/active_graph/extensions/resources/preloadable.rb +19 -19
  31. data/lib/graphiti/active_graph/extensions/resources/rel.rb +19 -19
  32. data/lib/graphiti/active_graph/jsonapi_ext/include_directive.rb +66 -66
  33. data/lib/graphiti/active_graph/jsonapi_ext/serializable/resource_ext.rb +8 -8
  34. data/lib/graphiti/active_graph/query.rb +76 -76
  35. data/lib/graphiti/active_graph/request_validators/validator.rb +9 -9
  36. data/lib/graphiti/active_graph/resource.rb +103 -103
  37. data/lib/graphiti/active_graph/resource_proxy.rb +86 -86
  38. data/lib/graphiti/active_graph/resources/interface.rb +14 -14
  39. data/lib/graphiti/active_graph/resources/persistence.rb +25 -25
  40. data/lib/graphiti/active_graph/runner.rb +39 -39
  41. data/lib/graphiti/active_graph/scope.rb +28 -28
  42. data/lib/graphiti/active_graph/scoping/association_eager_load.rb +35 -34
  43. data/lib/graphiti/active_graph/scoping/filter.rb +49 -49
  44. data/lib/graphiti/active_graph/scoping/filterable.rb +12 -12
  45. data/lib/graphiti/active_graph/scoping/include.rb +48 -48
  46. data/lib/graphiti/active_graph/scoping/internal/extra_field_normalizer.rb +76 -76
  47. data/lib/graphiti/active_graph/scoping/internal/include_normalizer.rb +82 -82
  48. data/lib/graphiti/active_graph/scoping/internal/path_descriptor.rb +94 -94
  49. data/lib/graphiti/active_graph/scoping/internal/sort_normalizer.rb +54 -54
  50. data/lib/graphiti/active_graph/scoping/internal/sorting_aliases.rb +35 -35
  51. data/lib/graphiti/active_graph/scoping/internal/sparse_fields_eagerloading.rb +28 -28
  52. data/lib/graphiti/active_graph/serializer.rb +15 -15
  53. data/lib/graphiti/active_graph/sideload_resolve.rb +119 -119
  54. data/lib/graphiti/active_graph/util/parsers/rel_chain.rb +27 -27
  55. data/lib/graphiti/active_graph/util/relationship_payload.rb +33 -33
  56. data/lib/graphiti/active_graph/util/serializer_attribute.rb +17 -17
  57. data/lib/graphiti/active_graph/util/serializer_relationship.rb +28 -28
  58. data/lib/graphiti/active_graph/util/transformers/relation_param.rb +56 -56
  59. data/lib/graphiti/active_graph/version.rb +5 -5
  60. data/lib/graphiti/sidepost_configuration.rb +9 -9
  61. data/lib/graphiti-activegraph.rb +43 -43
  62. metadata +21 -5
@@ -1,94 +1,94 @@
1
- module Graphiti::ActiveGraph
2
- module Scoping
3
- module Internal
4
- # Determine valid paths specified in filter and sort API params and normalize them for neo4j
5
- class PathDescriptor
6
- attr_reader :scope, :path, :attribute, :rel
7
- delegate :relationship_class, to: :rel, allow_nil: true
8
-
9
- def initialize(scope, rel)
10
- self.scope = scope
11
- self.path = []
12
- self.attribute = :id
13
- self.rel = rel
14
- @has_next = true
15
- end
16
-
17
- def next?
18
- @has_next
19
- end
20
-
21
- def increment(key)
22
- raise Exception, 'no continuation on path possible' unless next?
23
- if rel
24
- increment_from_cache(key)
25
- else
26
- increment_from_scope(key)
27
- end
28
- end
29
-
30
- def declared_property
31
- (relationship_class || scope).attributes[attribute]
32
- end
33
-
34
- def self.parse(scope, path, rel = nil)
35
- path_desc = new(scope, rel)
36
- path_desc.increment(path.shift) while path_desc.next? && path.present?
37
- path_desc if path.empty?
38
- end
39
-
40
- def self.association_for_relationship(associations, key)
41
- key_class_name = key[:rel_name].classify
42
- key_assoc_name = key[:rel_name].gsub('_rel', '')
43
- assocs = associations.find_all { |_, value| value.relationship_class_name == key_class_name || value.name.to_s == key_assoc_name }
44
- assocs.size == 1 ? assocs.first : nil
45
- end
46
-
47
- def path_relationships
48
- path.map { |elm| elm[:rel_name].to_sym }
49
- end
50
-
51
- private
52
-
53
- attr_writer :scope, :path, :attribute, :rel
54
-
55
- def increment_from_cache(key)
56
- rel_name = key[:rel_name]
57
- if rel.target_class_names.map(&:demodulize).map(&:downcase).include?(rel_name)
58
- self.rel = nil
59
- else
60
- final_attribute(rel_name)
61
- end
62
- end
63
-
64
- def increment_from_scope(key)
65
- associations = scope.associations
66
- if associations.key?(key[:rel_name].to_sym)
67
- advance(key)
68
- else
69
- increment_from_rel(self.class.association_for_relationship(associations, key), key)
70
- end
71
- end
72
-
73
- def increment_from_rel(entry, key)
74
- if entry
75
- advance(rel_name: entry.first.to_s)
76
- self.rel = entry.last
77
- else
78
- final_attribute(key[:rel_name])
79
- end
80
- end
81
-
82
- def advance(key)
83
- path << key
84
- self.scope = scope.send(key[:rel_name], rel_length: key[:rel_length])
85
- end
86
-
87
- def final_attribute(key)
88
- self.attribute = key
89
- @has_next = false
90
- end
91
- end
92
- end
93
- end
94
- end
1
+ module Graphiti::ActiveGraph
2
+ module Scoping
3
+ module Internal
4
+ # Determine valid paths specified in filter and sort API params and normalize them for neo4j
5
+ class PathDescriptor
6
+ attr_reader :scope, :path, :attribute, :rel
7
+ delegate :relationship_class, to: :rel, allow_nil: true
8
+
9
+ def initialize(scope, rel)
10
+ self.scope = scope
11
+ self.path = []
12
+ self.attribute = :id
13
+ self.rel = rel
14
+ @has_next = true
15
+ end
16
+
17
+ def next?
18
+ @has_next
19
+ end
20
+
21
+ def increment(key)
22
+ raise Exception, 'no continuation on path possible' unless next?
23
+ if rel
24
+ increment_from_cache(key)
25
+ else
26
+ increment_from_scope(key)
27
+ end
28
+ end
29
+
30
+ def declared_property
31
+ (relationship_class || scope).attributes[attribute]
32
+ end
33
+
34
+ def self.parse(scope, path, rel = nil)
35
+ path_desc = new(scope, rel)
36
+ path_desc.increment(path.shift) while path_desc.next? && path.present?
37
+ path_desc if path.empty?
38
+ end
39
+
40
+ def self.association_for_relationship(associations, key)
41
+ key_class_name = key[:rel_name].classify
42
+ key_assoc_name = key[:rel_name].gsub('_rel', '')
43
+ assocs = associations.find_all { |_, value| value.relationship_class_name == key_class_name || value.name.to_s == key_assoc_name }
44
+ assocs.size == 1 ? assocs.first : nil
45
+ end
46
+
47
+ def path_relationships
48
+ path.map { |elm| elm[:rel_name].to_sym }
49
+ end
50
+
51
+ private
52
+
53
+ attr_writer :scope, :path, :attribute, :rel
54
+
55
+ def increment_from_cache(key)
56
+ rel_name = key[:rel_name]
57
+ if rel.target_class_names.map(&:demodulize).map(&:downcase).include?(rel_name)
58
+ self.rel = nil
59
+ else
60
+ final_attribute(rel_name)
61
+ end
62
+ end
63
+
64
+ def increment_from_scope(key)
65
+ associations = scope.associations
66
+ if associations.key?(key[:rel_name].to_sym)
67
+ advance(key)
68
+ else
69
+ increment_from_rel(self.class.association_for_relationship(associations, key), key)
70
+ end
71
+ end
72
+
73
+ def increment_from_rel(entry, key)
74
+ if entry
75
+ advance(rel_name: entry.first.to_s)
76
+ self.rel = entry.last
77
+ else
78
+ final_attribute(key[:rel_name])
79
+ end
80
+ end
81
+
82
+ def advance(key)
83
+ path << key
84
+ self.scope = scope.send(key[:rel_name], rel_length: key[:rel_length])
85
+ end
86
+
87
+ def final_attribute(key)
88
+ self.attribute = key
89
+ @has_next = false
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,54 +1,54 @@
1
- module Graphiti::ActiveGraph
2
- module Scoping
3
- module Internal
4
- class SortNormalizer
5
- attr_reader :scope
6
-
7
- def initialize(scope)
8
- @scope = scope
9
- end
10
-
11
- def normalize(includes_hash, sorts, deep_sorts)
12
- normalized_deep_sort = normalize_deep_sort(includes_hash, deep_sorts || [])
13
- normalized_base_sort = normalize_base_sort(sorts)
14
- normalized_deep_sort.merge(normalized_base_sort)
15
- end
16
-
17
- def normalize_base_sort(sorts)
18
- sorts.present? ? { '' => sorts.map { |sort| "#{sort.keys.first} #{sort.values.first}" } } : {}
19
- end
20
-
21
- def normalize_deep_sort(includes_hash, sorts)
22
- sorts
23
- .map { |sort| sort(includes_hash, sort) }
24
- .compact
25
- .group_by(&:first)
26
- .map { |key, value| combined_order_spec(key, value) }
27
- .to_h
28
- end
29
-
30
- private
31
-
32
- def combined_order_spec(key, value)
33
- [key.join('.'), value.map(&:last)]
34
- end
35
-
36
- def sort(includes_hash, sort)
37
- path = sort.keys.first.map { |key| { rel_name: key.to_s } }
38
- return nil unless (descriptor = PathDescriptor.parse(scope, path))
39
-
40
- sort_spec(descriptor, sort.values.first) if valid_sort?(includes_hash.deep_dup, descriptor.path_relationships)
41
- end
42
-
43
- def valid_sort?(hash, rels)
44
- rels.empty? || rels.all? { |rel| hash = hash[rel] || hash[:"#{rel.to_s + '*'}"] }
45
- end
46
-
47
- def sort_spec(descriptor, direction)
48
- sort_attr = [descriptor.attribute, direction].join(' ')
49
- [descriptor.path_relationships, descriptor.rel.present? ? { rel: sort_attr } : sort_attr]
50
- end
51
- end
52
- end
53
- end
54
- end
1
+ module Graphiti::ActiveGraph
2
+ module Scoping
3
+ module Internal
4
+ class SortNormalizer
5
+ attr_reader :scope
6
+
7
+ def initialize(scope)
8
+ @scope = scope
9
+ end
10
+
11
+ def normalize(includes_hash, sorts, deep_sorts)
12
+ normalized_deep_sort = normalize_deep_sort(includes_hash, deep_sorts || [])
13
+ normalized_base_sort = normalize_base_sort(sorts)
14
+ normalized_deep_sort.merge(normalized_base_sort)
15
+ end
16
+
17
+ def normalize_base_sort(sorts)
18
+ sorts.present? ? { '' => sorts.map { |sort| "#{sort.keys.first} #{sort.values.first}" } } : {}
19
+ end
20
+
21
+ def normalize_deep_sort(includes_hash, sorts)
22
+ sorts
23
+ .map { |sort| sort(includes_hash, sort) }
24
+ .compact
25
+ .group_by(&:first)
26
+ .map { |key, value| combined_order_spec(key, value) }
27
+ .to_h
28
+ end
29
+
30
+ private
31
+
32
+ def combined_order_spec(key, value)
33
+ [key.join('.'), value.map(&:last)]
34
+ end
35
+
36
+ def sort(includes_hash, sort)
37
+ path = sort.keys.first.map { |key| { rel_name: key.to_s } }
38
+ return nil unless (descriptor = PathDescriptor.parse(scope, path))
39
+
40
+ sort_spec(descriptor, sort.values.first) if valid_sort?(includes_hash, descriptor.path_relationships)
41
+ end
42
+
43
+ def valid_sort?(hash, rels)
44
+ rels.empty? || rels.all? { |rel| hash = hash[rel] || hash[:"#{rel.to_s + '*'}"] }
45
+ end
46
+
47
+ def sort_spec(descriptor, direction)
48
+ sort_attr = [descriptor.attribute, direction].join(' ')
49
+ [descriptor.path_relationships, descriptor.rel.present? ? { rel: sort_attr } : sort_attr]
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,35 +1,35 @@
1
- module Graphiti::ActiveGraph
2
- module Scoping
3
- module Internal
4
- # Carrying forward valriables from neo4j procedure call to sort with include
5
- module SortingAliases
6
- def with_vars_for_sort
7
- [] unless add_extra_vars_to_query?
8
- (deep_sort_keys + sort_keys) & resource.extra_attributes.keys - graphiti_query_vars.map(&:to_sym)
9
- end
10
-
11
- def add_extra_vars_to_query?
12
- resource.extra_attributes.present? && (query.sorts.present? || query.deep_sort.present?)
13
- end
14
-
15
- def deep_sort_keys
16
- (query.deep_sort || []).collect { |sort| sort.keys.first.first }
17
- end
18
-
19
- def sort_keys
20
- query.sorts.collect(&:keys).flatten
21
- end
22
-
23
- def query
24
- @opts[:query_obj]
25
- end
26
-
27
- private
28
-
29
- def graphiti_query_vars
30
- Graphiti.context.fetch(:with_vars, [])
31
- end
32
- end
33
- end
34
- end
35
- end
1
+ module Graphiti::ActiveGraph
2
+ module Scoping
3
+ module Internal
4
+ # Carrying forward valriables from neo4j procedure call to sort with include
5
+ module SortingAliases
6
+ def with_vars_for_sort
7
+ [] unless add_extra_vars_to_query?
8
+ (deep_sort_keys + sort_keys) & resource.extra_attributes.keys - graphiti_query_vars.map(&:to_sym)
9
+ end
10
+
11
+ def add_extra_vars_to_query?
12
+ resource.extra_attributes.present? && (query.sorts.present? || query.deep_sort.present?)
13
+ end
14
+
15
+ def deep_sort_keys
16
+ (query.deep_sort || []).collect { |sort| sort.keys.first.first }
17
+ end
18
+
19
+ def sort_keys
20
+ query.sorts.collect(&:keys).flatten
21
+ end
22
+
23
+ def query
24
+ @opts[:query_obj]
25
+ end
26
+
27
+ private
28
+
29
+ def graphiti_query_vars
30
+ Graphiti.context.fetch(:with_vars, [])
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,28 +1,28 @@
1
- module Graphiti::ActiveGraph
2
- module Scoping
3
- module Internal
4
- module SparseFieldsEagerloading
5
- private
6
-
7
- def add_relationships_from_sparse_fields(scope, includes_array)
8
- return if @fields.blank?
9
-
10
- related_fields(scope.model).each { |field_name| includes_array << process_field(field_name, scope) }
11
- end
12
-
13
- def process_field(field_name, _scope)
14
- field_name
15
- end
16
-
17
- def resource_name_of(model)
18
- model.model_name.plural.to_sym
19
- end
20
-
21
- def related_fields(model)
22
- attr_and_rel_fields = @fields[resource_name_of(model)] || []
23
- attr_and_rel_fields.select { |field_name| model.associations[field_name] }
24
- end
25
- end
26
- end
27
- end
28
- end
1
+ module Graphiti::ActiveGraph
2
+ module Scoping
3
+ module Internal
4
+ module SparseFieldsEagerloading
5
+ private
6
+
7
+ def add_relationships_from_sparse_fields(scope, includes_array)
8
+ return if @fields.blank?
9
+
10
+ related_fields(scope.model).each { |field_name| includes_array << process_field(field_name, scope) }
11
+ end
12
+
13
+ def process_field(field_name, _scope)
14
+ field_name
15
+ end
16
+
17
+ def resource_name_of(model)
18
+ model.model_name.plural.to_sym
19
+ end
20
+
21
+ def related_fields(model)
22
+ attr_and_rel_fields = @fields[resource_name_of(model)] || []
23
+ attr_and_rel_fields.select { |field_name| model.associations[field_name] }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,15 +1,15 @@
1
- module Graphiti::ActiveGraph
2
- module Serializer
3
- def jsonapi_resource_class
4
- if polymorphic?
5
- "#{jsonapi_type.to_s.singularize.camelize}Resource".constantize
6
- else
7
- @resource.class
8
- end
9
- end
10
-
11
- def resource_class_name
12
- @_type.to_s.singularize.camelize
13
- end
14
- end
15
- end
1
+ module Graphiti::ActiveGraph
2
+ module Serializer
3
+ def jsonapi_resource_class
4
+ if polymorphic?
5
+ "#{jsonapi_type.to_s.singularize.camelize}Resource".constantize
6
+ else
7
+ @resource.class
8
+ end
9
+ end
10
+
11
+ def resource_class_name
12
+ @_type.to_s.singularize.camelize
13
+ end
14
+ end
15
+ end