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.
- checksums.yaml +4 -4
- data/.github/workflows/specs.yml +58 -59
- data/.gitignore +59 -59
- data/.hound.yml +4 -0
- data/.rspec +1 -1
- data/.rubocop.yml +6 -0
- data/CHANGELOG.md +71 -54
- data/CHANGELOG_PRE_1.0.0.md +70 -70
- data/Gemfile +3 -3
- data/LICENSE.txt +21 -21
- data/README.md +130 -130
- data/docs/deserializer.md +40 -40
- data/graphiti-activegraph.gemspec +35 -34
- data/lib/graphiti/active_graph/adapters/active_graph/function_sideload.rb +7 -7
- data/lib/graphiti/active_graph/adapters/active_graph/has_many_sideload.rb +7 -7
- data/lib/graphiti/active_graph/adapters/active_graph/has_one_sideload.rb +7 -7
- data/lib/graphiti/active_graph/adapters/active_graph/polymorphic_belongs_to.rb +11 -11
- data/lib/graphiti/active_graph/adapters/active_graph/sideload.rb +26 -26
- data/lib/graphiti/active_graph/adapters/active_graph.rb +183 -183
- data/lib/graphiti/active_graph/concerns/path_relationships.rb +44 -44
- data/lib/graphiti/active_graph/concerns/relationships.rb +15 -15
- data/lib/graphiti/active_graph/deserializer.rb +138 -138
- data/lib/graphiti/active_graph/extensions/context.rb +17 -17
- data/lib/graphiti/active_graph/extensions/grouping/params.rb +101 -52
- data/lib/graphiti/active_graph/extensions/query_dsl/performer.rb +38 -38
- data/lib/graphiti/active_graph/extensions/query_dsl/query_generator.rb +20 -20
- data/lib/graphiti/active_graph/extensions/query_params.rb +27 -27
- data/lib/graphiti/active_graph/extensions/resources/authorizationable.rb +29 -29
- data/lib/graphiti/active_graph/extensions/resources/payload_combinable.rb +24 -24
- data/lib/graphiti/active_graph/extensions/resources/preloadable.rb +19 -19
- data/lib/graphiti/active_graph/extensions/resources/rel.rb +19 -19
- data/lib/graphiti/active_graph/jsonapi_ext/include_directive.rb +66 -66
- data/lib/graphiti/active_graph/jsonapi_ext/serializable/resource_ext.rb +8 -8
- data/lib/graphiti/active_graph/query.rb +76 -76
- data/lib/graphiti/active_graph/request_validators/validator.rb +9 -9
- data/lib/graphiti/active_graph/resource.rb +103 -103
- data/lib/graphiti/active_graph/resource_proxy.rb +86 -86
- data/lib/graphiti/active_graph/resources/interface.rb +14 -14
- data/lib/graphiti/active_graph/resources/persistence.rb +25 -25
- data/lib/graphiti/active_graph/runner.rb +39 -39
- data/lib/graphiti/active_graph/scope.rb +28 -28
- data/lib/graphiti/active_graph/scoping/association_eager_load.rb +35 -34
- data/lib/graphiti/active_graph/scoping/filter.rb +49 -49
- data/lib/graphiti/active_graph/scoping/filterable.rb +12 -12
- data/lib/graphiti/active_graph/scoping/include.rb +48 -48
- data/lib/graphiti/active_graph/scoping/internal/extra_field_normalizer.rb +76 -76
- data/lib/graphiti/active_graph/scoping/internal/include_normalizer.rb +82 -82
- data/lib/graphiti/active_graph/scoping/internal/path_descriptor.rb +94 -94
- data/lib/graphiti/active_graph/scoping/internal/sort_normalizer.rb +54 -54
- data/lib/graphiti/active_graph/scoping/internal/sorting_aliases.rb +35 -35
- data/lib/graphiti/active_graph/scoping/internal/sparse_fields_eagerloading.rb +28 -28
- data/lib/graphiti/active_graph/serializer.rb +15 -15
- data/lib/graphiti/active_graph/sideload_resolve.rb +119 -119
- data/lib/graphiti/active_graph/util/parsers/rel_chain.rb +27 -27
- data/lib/graphiti/active_graph/util/relationship_payload.rb +33 -33
- data/lib/graphiti/active_graph/util/serializer_attribute.rb +17 -17
- data/lib/graphiti/active_graph/util/serializer_relationship.rb +28 -28
- data/lib/graphiti/active_graph/util/transformers/relation_param.rb +56 -56
- data/lib/graphiti/active_graph/version.rb +5 -5
- data/lib/graphiti/sidepost_configuration.rb +9 -9
- data/lib/graphiti-activegraph.rb +43 -43
- metadata +21 -5
data/README.md
CHANGED
|
@@ -1,130 +1,130 @@
|
|
|
1
|
-
# Graphiti ActiveGraph
|
|
2
|
-
|
|
3
|
-
[](https://badge.fury.io/rb/graphiti-activegraph) [](https://github.com/mrhardikjoshi/graphiti-activegraph/actions?query=branch%3Amaster) [](LICENSE.txt)
|
|
4
|
-
|
|
5
|
-
An adapter to make Graphiti work with the ActiveGraph(former Neo4jrb) OGM. This gem allows you to easily build [jsonapi.org](https://jsonapi.org) compatible APIs for GraphDB using [Graphiti](https://www.graphiti.dev) and [ActiveGraph](https://github.com/neo4jrb/activegraph).
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
8
|
-
Add this line to your application's `Gemfile`:
|
|
9
|
-
```ruby
|
|
10
|
-
gem 'graphiti-activegraph'
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
And then execute:
|
|
14
|
-
```shell
|
|
15
|
-
bundle install
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Or install it yourself as:
|
|
19
|
-
```shell
|
|
20
|
-
gem install graphiti-activegraph
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Usage
|
|
24
|
-
While defining a Resource class, inherit it from `Graphiti::ActiveGraph::Resource`
|
|
25
|
-
```ruby
|
|
26
|
-
class PlanetResource < Graphiti::ActiveGraph::Resource
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
For model backed by `ApplicationRelationship` instead of `ApplicationNode`, we have to set `relationship_resource` to `true` while defining resource class.
|
|
30
|
-
```ruby
|
|
31
|
-
class RelationshipBackedResource < Graphiti::ActiveGraph::Resource
|
|
32
|
-
self.relationship_resource = true
|
|
33
|
-
end
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Documentation
|
|
37
|
-
### Key Differences from Graphiti
|
|
38
|
-
#### Efficient Sideloading:
|
|
39
|
-
Unlike Graphiti, which executes multiple queries for sideloading, graphiti-activegraph leverages `with_ordered_associations` from ActiveGraph to fetch sideloaded data in a single query, improving performance.
|
|
40
|
-
|
|
41
|
-
#### Sideposting Behavior:
|
|
42
|
-
graphiti-activegraph allows assigning and unassigning relationships via sideposting but does not support modifying a resource’s attributes through sideposting.
|
|
43
|
-
|
|
44
|
-
#### Thread Context Handling:
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
#### Rendering Preloaded Objects Without Extra Queries
|
|
54
|
-
graphiti-activegraph introduces two new methods on the Graphiti resource class:
|
|
55
|
-
`with_preloaded_obj(record, params)` – Renders a single preloaded ActiveGraph object without querying the database.
|
|
56
|
-
`all_with_preloaded(records, params)` – Renders multiple preloaded ActiveGraph objects without additional queries.
|
|
57
|
-
**Note:** These methods assume that the provided records are final and will not apply Graphiti’s filtering, sorting, or scoping logic.
|
|
58
|
-
|
|
59
|
-
#### Efficient Deep Sorting
|
|
60
|
-
Graphiti does not natively support deep sorting (i.e., sorting based on attributes of associated resources), `graphiti-activegraph` adds this feature by allowing you to chain associations using dot (.) notation.
|
|
61
|
-
For example, to sort Post records based on their Author's Country's name, you can use following query string:
|
|
62
|
-
```
|
|
63
|
-
sort=author.country.name&include=author.country
|
|
64
|
-
```
|
|
65
|
-
Here, `Author` and `Country` are associated resources, and `name` is an attribute on `Country`. The posts will be sorted by the country's name. You can chain any number of associations in this way to achieve deep sorting.
|
|
66
|
-
Note: The `include` parameter must be present and include the full association path (`author.country`) for the sorting to work correctly.
|
|
67
|
-
|
|
68
|
-
#### Response Payload Links control
|
|
69
|
-
Control the links in response payload via request query params:
|
|
70
|
-
- `pagination_links=true|false` — toggle top-level pagination links
|
|
71
|
-
- `links=true|false` — toggle links inside each resource object
|
|
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
|
-
|
|
117
|
-
## Contributing
|
|
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.
|
|
119
|
-
|
|
120
|
-
## Release
|
|
121
|
-
1. Make sure version file is updated/incremented in master branch
|
|
122
|
-
2. git checkout master
|
|
123
|
-
3. git pull origin master
|
|
124
|
-
4. git tag v1.2.3
|
|
125
|
-
5. git push origin v1.2.3
|
|
126
|
-
6. gem build graphiti-activegraph.gemspec
|
|
127
|
-
7. gem push graphiti-activegraph-1.2.3.gem
|
|
128
|
-
|
|
129
|
-
## License
|
|
130
|
-
The gem is available as open-source under the terms of the MIT License.
|
|
1
|
+
# Graphiti ActiveGraph
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/graphiti-activegraph) [](https://github.com/mrhardikjoshi/graphiti-activegraph/actions?query=branch%3Amaster) [](LICENSE.txt)
|
|
4
|
+
|
|
5
|
+
An adapter to make Graphiti work with the ActiveGraph(former Neo4jrb) OGM. This gem allows you to easily build [jsonapi.org](https://jsonapi.org) compatible APIs for GraphDB using [Graphiti](https://www.graphiti.dev) and [ActiveGraph](https://github.com/neo4jrb/activegraph).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
Add this line to your application's `Gemfile`:
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'graphiti-activegraph'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
```shell
|
|
15
|
+
bundle install
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or install it yourself as:
|
|
19
|
+
```shell
|
|
20
|
+
gem install graphiti-activegraph
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
While defining a Resource class, inherit it from `Graphiti::ActiveGraph::Resource`
|
|
25
|
+
```ruby
|
|
26
|
+
class PlanetResource < Graphiti::ActiveGraph::Resource
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For model backed by `ApplicationRelationship` instead of `ApplicationNode`, we have to set `relationship_resource` to `true` while defining resource class.
|
|
30
|
+
```ruby
|
|
31
|
+
class RelationshipBackedResource < Graphiti::ActiveGraph::Resource
|
|
32
|
+
self.relationship_resource = true
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Documentation
|
|
37
|
+
### Key Differences from Graphiti
|
|
38
|
+
#### Efficient Sideloading:
|
|
39
|
+
Unlike Graphiti, which executes multiple queries for sideloading, graphiti-activegraph leverages `with_ordered_associations` from ActiveGraph to fetch sideloaded data in a single query, improving performance.
|
|
40
|
+
|
|
41
|
+
#### Sideposting Behavior:
|
|
42
|
+
graphiti-activegraph allows assigning and unassigning relationships via sideposting but does not support modifying a resource’s attributes through sideposting.
|
|
43
|
+
|
|
44
|
+
#### Thread Context Handling:
|
|
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
|
+
|
|
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
|
+
|
|
53
|
+
#### Rendering Preloaded Objects Without Extra Queries
|
|
54
|
+
graphiti-activegraph introduces two new methods on the Graphiti resource class:
|
|
55
|
+
`with_preloaded_obj(record, params)` – Renders a single preloaded ActiveGraph object without querying the database.
|
|
56
|
+
`all_with_preloaded(records, params)` – Renders multiple preloaded ActiveGraph objects without additional queries.
|
|
57
|
+
**Note:** These methods assume that the provided records are final and will not apply Graphiti’s filtering, sorting, or scoping logic.
|
|
58
|
+
|
|
59
|
+
#### Efficient Deep Sorting
|
|
60
|
+
Graphiti does not natively support deep sorting (i.e., sorting based on attributes of associated resources), `graphiti-activegraph` adds this feature by allowing you to chain associations using dot (.) notation.
|
|
61
|
+
For example, to sort Post records based on their Author's Country's name, you can use following query string:
|
|
62
|
+
```
|
|
63
|
+
sort=author.country.name&include=author.country
|
|
64
|
+
```
|
|
65
|
+
Here, `Author` and `Country` are associated resources, and `name` is an attribute on `Country`. The posts will be sorted by the country's name. You can chain any number of associations in this way to achieve deep sorting.
|
|
66
|
+
Note: The `include` parameter must be present and include the full association path (`author.country`) for the sorting to work correctly.
|
|
67
|
+
|
|
68
|
+
#### Response Payload Links control
|
|
69
|
+
Control the links in response payload via request query params:
|
|
70
|
+
- `pagination_links=true|false` — toggle top-level pagination links
|
|
71
|
+
- `links=true|false` — toggle links inside each resource object
|
|
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
|
+
|
|
117
|
+
## Contributing
|
|
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.
|
|
119
|
+
|
|
120
|
+
## Release
|
|
121
|
+
1. Make sure version file is updated/incremented in master branch
|
|
122
|
+
2. git checkout master
|
|
123
|
+
3. git pull origin master
|
|
124
|
+
4. git tag v1.2.3
|
|
125
|
+
5. git push origin v1.2.3
|
|
126
|
+
6. gem build graphiti-activegraph.gemspec
|
|
127
|
+
7. gem push graphiti-activegraph-1.2.3.gem
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
The gem is available as open-source under the terms of the MIT License.
|
data/docs/deserializer.md
CHANGED
|
@@ -1,40 +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"
|
|
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"
|
|
@@ -1,34 +1,35 @@
|
|
|
1
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
-
require 'graphiti/active_graph/version'
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = 'graphiti-activegraph'
|
|
7
|
-
spec.version = Graphiti::ActiveGraph::VERSION
|
|
8
|
-
spec.authors = ['Hardik Joshi']
|
|
9
|
-
spec.email = ['hardikjoshi1991@gmail.com']
|
|
10
|
-
|
|
11
|
-
spec.summary = 'Easily build jsonapi.org-compatible APIs for GraphDB'
|
|
12
|
-
spec.homepage = 'https://github.com/mrhardikjoshi/graphiti-activegraph'
|
|
13
|
-
spec.license = 'MIT'
|
|
14
|
-
|
|
15
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
16
|
-
spec.bindir = 'exe'
|
|
17
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
18
|
-
spec.require_paths = ['lib']
|
|
19
|
-
|
|
20
|
-
spec.add_dependency 'graphiti', '>= 1.6.4', '<= 1.
|
|
21
|
-
spec.add_dependency 'activegraph', '>= 12.0.0.beta.5'
|
|
22
|
-
spec.add_dependency 'parslet', '>= 2.0.0'
|
|
23
|
-
spec.add_dependency 'activegraph-extensions', '>= 0.1.0'
|
|
24
|
-
|
|
25
|
-
spec.add_development_dependency 'graphiti_spec_helpers', '>= 1.0.0'
|
|
26
|
-
spec.add_development_dependency 'standard'
|
|
27
|
-
spec.add_development_dependency 'pry'
|
|
28
|
-
spec.add_development_dependency 'ffaker'
|
|
29
|
-
spec.add_development_dependency 'simplecov'
|
|
30
|
-
spec.add_development_dependency 'simplecov_json_formatter'
|
|
31
|
-
spec.add_development_dependency 'factory_bot_rails'
|
|
32
|
-
spec.add_development_dependency 'rake', '>= 10.0'
|
|
33
|
-
spec.add_development_dependency 'rspec', '>= 3.9.0'
|
|
34
|
-
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require 'graphiti/active_graph/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'graphiti-activegraph'
|
|
7
|
+
spec.version = Graphiti::ActiveGraph::VERSION
|
|
8
|
+
spec.authors = ['Hardik Joshi']
|
|
9
|
+
spec.email = ['hardikjoshi1991@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'Easily build jsonapi.org-compatible APIs for GraphDB'
|
|
12
|
+
spec.homepage = 'https://github.com/mrhardikjoshi/graphiti-activegraph'
|
|
13
|
+
spec.license = 'MIT'
|
|
14
|
+
|
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
16
|
+
spec.bindir = 'exe'
|
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
18
|
+
spec.require_paths = ['lib']
|
|
19
|
+
|
|
20
|
+
spec.add_dependency 'graphiti', '>= 1.6.4', '<= 1.9.0'
|
|
21
|
+
spec.add_dependency 'activegraph', '>= 12.0.0.beta.5'
|
|
22
|
+
spec.add_dependency 'parslet', '>= 2.0.0'
|
|
23
|
+
spec.add_dependency 'activegraph-extensions', '>= 0.1.0'
|
|
24
|
+
|
|
25
|
+
spec.add_development_dependency 'graphiti_spec_helpers', '>= 1.0.0'
|
|
26
|
+
spec.add_development_dependency 'standard'
|
|
27
|
+
spec.add_development_dependency 'pry'
|
|
28
|
+
spec.add_development_dependency 'ffaker'
|
|
29
|
+
spec.add_development_dependency 'simplecov'
|
|
30
|
+
spec.add_development_dependency 'simplecov_json_formatter'
|
|
31
|
+
spec.add_development_dependency 'factory_bot_rails'
|
|
32
|
+
spec.add_development_dependency 'rake', '>= 10.0'
|
|
33
|
+
spec.add_development_dependency 'rspec', '>= 3.9.0'
|
|
34
|
+
spec.add_development_dependency 'ostruct'
|
|
35
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
class Graphiti::ActiveGraph::Adapters::ActiveGraph::FunctionSideload < Graphiti::ActiveGraph::Adapters::ActiveGraph::HasOneSideload
|
|
2
|
-
class_attribute :function_proc, :param_proc
|
|
3
|
-
|
|
4
|
-
def association?
|
|
5
|
-
false
|
|
6
|
-
end
|
|
7
|
-
end
|
|
1
|
+
class Graphiti::ActiveGraph::Adapters::ActiveGraph::FunctionSideload < Graphiti::ActiveGraph::Adapters::ActiveGraph::HasOneSideload
|
|
2
|
+
class_attribute :function_proc, :param_proc
|
|
3
|
+
|
|
4
|
+
def association?
|
|
5
|
+
false
|
|
6
|
+
end
|
|
7
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
class Graphiti::ActiveGraph::Adapters::ActiveGraph::HasManySideload < Graphiti::Sideload::HasMany
|
|
2
|
-
include Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
|
3
|
-
|
|
4
|
-
def default_value_when_empty
|
|
5
|
-
[]
|
|
6
|
-
end
|
|
7
|
-
end
|
|
1
|
+
class Graphiti::ActiveGraph::Adapters::ActiveGraph::HasManySideload < Graphiti::Sideload::HasMany
|
|
2
|
+
include Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
|
3
|
+
|
|
4
|
+
def default_value_when_empty
|
|
5
|
+
[]
|
|
6
|
+
end
|
|
7
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
class Graphiti::ActiveGraph::Adapters::ActiveGraph::HasOneSideload < Graphiti::Sideload::HasOne
|
|
2
|
-
include Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
|
3
|
-
|
|
4
|
-
def default_value_when_empty
|
|
5
|
-
nil
|
|
6
|
-
end
|
|
7
|
-
end
|
|
1
|
+
class Graphiti::ActiveGraph::Adapters::ActiveGraph::HasOneSideload < Graphiti::Sideload::HasOne
|
|
2
|
+
include Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
|
3
|
+
|
|
4
|
+
def default_value_when_empty
|
|
5
|
+
nil
|
|
6
|
+
end
|
|
7
|
+
end
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
class Graphiti::ActiveGraph::Adapters::ActiveGraph::PolymorphicBelongsTo < Graphiti::Sideload::PolymorphicBelongsTo
|
|
2
|
-
include Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
|
3
|
-
|
|
4
|
-
def default_value_when_empty
|
|
5
|
-
nil
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def polymorphic?
|
|
9
|
-
true
|
|
10
|
-
end
|
|
11
|
-
end
|
|
1
|
+
class Graphiti::ActiveGraph::Adapters::ActiveGraph::PolymorphicBelongsTo < Graphiti::Sideload::PolymorphicBelongsTo
|
|
2
|
+
include Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
|
3
|
+
|
|
4
|
+
def default_value_when_empty
|
|
5
|
+
nil
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def polymorphic?
|
|
9
|
+
true
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
module Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
|
2
|
-
def self.included(base)
|
|
3
|
-
base.class_eval do
|
|
4
|
-
class_attribute :sideload_scope
|
|
5
|
-
end
|
|
6
|
-
base.extend(ClassMethods)
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
module ClassMethods
|
|
10
|
-
def sideload_scope(&blk)
|
|
11
|
-
self.sideload_scope = blk
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def default_base_scope
|
|
16
|
-
resource_class.model.all
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def infer_foreign_key
|
|
20
|
-
association_name.to_sym
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def polymorphic?
|
|
24
|
-
false
|
|
25
|
-
end
|
|
26
|
-
end
|
|
1
|
+
module Graphiti::ActiveGraph::Adapters::ActiveGraph::Sideload
|
|
2
|
+
def self.included(base)
|
|
3
|
+
base.class_eval do
|
|
4
|
+
class_attribute :sideload_scope
|
|
5
|
+
end
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def sideload_scope(&blk)
|
|
11
|
+
self.sideload_scope = blk
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def default_base_scope
|
|
16
|
+
resource_class.model.all
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def infer_foreign_key
|
|
20
|
+
association_name.to_sym
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def polymorphic?
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
end
|