graphiti-activegraph 0.2.0 → 1.1.0
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 +17 -3
- data/.gitignore +3 -0
- data/CHANGELOG.md +22 -67
- data/CHANGELOG_PRE_1.0.0.md +70 -0
- data/README.md +81 -0
- data/graphiti-activegraph.gemspec +4 -0
- data/lib/graphiti/active_graph/adapters/active_graph.rb +1 -1
- data/lib/graphiti/active_graph/extensions/context.rb +17 -0
- data/lib/graphiti/active_graph/extensions/resources/authorizationable.rb +29 -0
- data/lib/graphiti/active_graph/extensions/resources/payload_combinable.rb +24 -0
- data/lib/graphiti/active_graph/extensions/resources/preloadable.rb +19 -0
- data/lib/graphiti/active_graph/extensions/resources/rel.rb +19 -0
- data/lib/graphiti/active_graph/jsonapi_ext/include_directive.rb +66 -0
- data/lib/graphiti/active_graph/query.rb +27 -0
- data/lib/graphiti/active_graph/resource.rb +45 -20
- data/lib/graphiti/active_graph/{resource → resources}/interface.rb +1 -1
- data/lib/graphiti/active_graph/{resource → resources}/persistence.rb +1 -1
- data/lib/graphiti/active_graph/scope.rb +28 -0
- data/lib/graphiti/active_graph/scoping/association_eager_load.rb +34 -0
- data/lib/graphiti/active_graph/scoping/include.rb +43 -0
- data/lib/graphiti/active_graph/scoping/internal/include_normalizer.rb +82 -0
- data/lib/graphiti/active_graph/scoping/internal/path_descriptor.rb +94 -0
- data/lib/graphiti/active_graph/scoping/internal/sort_normalizer.rb +54 -0
- data/lib/graphiti/active_graph/scoping/internal/sorting_aliases.rb +25 -0
- data/lib/graphiti/active_graph/scoping/internal/sparse_fields_eagerloading.rb +28 -0
- data/lib/graphiti/active_graph/util/parsers/rel_chain.rb +27 -0
- data/lib/graphiti/active_graph/util/transformers/relation_param.rb +56 -0
- data/lib/graphiti/active_graph/version.rb +1 -1
- data/lib/graphiti/sidepost_configuration.rb +1 -2
- data/lib/graphiti-activegraph.rb +6 -4
- metadata +79 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c387f138fe40ab7a304c5d587a0281258e2bf4e8304d7e0f0967295adeeef6d7
|
4
|
+
data.tar.gz: 6154b76796fef327e488b722d1075b05f448be9fd499e4b8525e58b3544399d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16cf1d53448e132be9dd3c45dc755f933f434114dc13d7414b3670becaf97c4696ba0c57e3f10075f984b60516d1286d3ccee01bad8baa4bc2bad1143ea1d1f4
|
7
|
+
data.tar.gz: 69a336f08b80474be83a0d0111e74a7cfbed451e5dc3ca2dba41318e3212c0e10565f799be327fdc9a26eed111b7ef1a7a46d90f24e85151a4f0d1e719b909d9
|
data/.github/workflows/specs.yml
CHANGED
@@ -18,20 +18,34 @@ jobs:
|
|
18
18
|
strategy:
|
19
19
|
fail-fast: false
|
20
20
|
matrix:
|
21
|
-
ruby-version: [
|
21
|
+
ruby-version: [ ruby-3.4.2, ruby-3.3.7, ruby-3.2.7 ] # Removed 'jruby' till https://github.com/jruby/jruby/issues/8642 is fixed
|
22
|
+
neo4j: [ 5.23.0 ]
|
23
|
+
include:
|
24
|
+
- ruby: jruby
|
25
|
+
java-version: 17
|
22
26
|
env:
|
23
27
|
JRUBY_OPTS: --debug -J-Xmx1280m -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF
|
24
28
|
steps:
|
29
|
+
- name: Start neo4j
|
30
|
+
run: docker run --name neo4j --env NEO4J_AUTH=neo4j/password --env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes --env NEO4J_dbms_directories_import= -p7687:7687 -p7474:7474 -v `pwd`/tmp:/var/lib/neo4j/import --rm neo4j:${{ matrix.neo4j }}-enterprise &
|
31
|
+
|
25
32
|
- uses: actions/checkout@v3
|
33
|
+
|
26
34
|
- name: Set up Ruby
|
27
35
|
uses: ruby/setup-ruby@v1
|
28
36
|
with:
|
29
37
|
ruby-version: ${{ matrix.ruby-version }}
|
30
38
|
bundler-cache: true
|
39
|
+
|
31
40
|
- name: Set up Java
|
32
|
-
uses: actions/setup-java@
|
41
|
+
uses: actions/setup-java@v4
|
42
|
+
if: matrix.java-version
|
33
43
|
with:
|
34
44
|
distribution: 'temurin'
|
35
|
-
java-version:
|
45
|
+
java-version: ${{ matrix.java-version }}
|
46
|
+
|
47
|
+
- name: Wait for neo4j
|
48
|
+
run: while [ $((curl localhost:7474/ > /dev/null 2>&1); echo $?) -ne 0 ]; do sleep 1; done
|
49
|
+
|
36
50
|
- name: Run tests
|
37
51
|
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,80 +1,35 @@
|
|
1
|
-
|
1
|
+
# Changelog
|
2
2
|
|
3
|
-
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
-
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
7
|
|
7
|
-
|
8
|
+
## [Unreleased]
|
8
9
|
|
9
|
-
|
10
|
+
## [1.1.0] - 2025-05-2
|
10
11
|
|
11
|
-
|
12
|
+
### Added
|
12
13
|
|
13
|
-
|
14
|
+
- **Deep sideloading**: introduced Include scoping class to support deep sideloading using single query (e.g. include='author.posts')
|
15
|
+
- **Deep sorting**: added SortNormalizer to support sorting by deep sideloaded resource's attribute (e.g. sort='author.posts.title')
|
16
|
+
- **Links control**: Control the links(pagination and resource) in response via request query params (pagination_links=true|false, links=true|false)
|
14
17
|
|
15
|
-
|
18
|
+
## [1.0.0] - 2025-03-18
|
16
19
|
|
17
|
-
|
20
|
+
### Added
|
18
21
|
|
19
|
-
|
22
|
+
- **MRI Support**: Introduced compatibility with MRI (Matz's Ruby Interpreter), expanding the gem's usability beyond JRuby (#38).
|
23
|
+
- **Documentation Updates**: Expanded the README to provide clearer guidance on gem usage and integration (#38).
|
24
|
+
- **Sideloading Workflow**: Enhanced scoping mechanisms and added support for eager loading associations to improve data retrieval efficiency and flexibility (#38).
|
20
25
|
|
21
|
-
|
26
|
+
### Changed
|
27
|
+
- **Resource Class**: Instead of modifying the `Graphiti::Resource` class, we now define `Graphiti::ActiveGraph::Resource`,
|
28
|
+
which must be inherited in all resource classes to enable ActiveGraph support (#38).
|
22
29
|
|
23
|
-
|
30
|
+
---
|
24
31
|
|
25
|
-
|
32
|
+
*Note: For details on changes prior to version 1.0.0, please refer to the [`CHANGELOG_PRE_1.0.0.md`](CHANGELOG_PRE_1.0.0.md) file.*
|
26
33
|
|
27
|
-
-
|
28
|
-
|
29
|
-
## 0.1.20
|
30
|
-
|
31
|
-
Features:
|
32
|
-
|
33
|
-
- With graphiti config variable "allow_sidepost" you can allow/disallow sideposting, by default it is allowed.
|
34
|
-
|
35
|
-
## 0.1.21
|
36
|
-
|
37
|
-
Fixes:
|
38
|
-
|
39
|
-
- Runner#proxy keyword arguments
|
40
|
-
|
41
|
-
## 0.1.22
|
42
|
-
|
43
|
-
Fixes:
|
44
|
-
|
45
|
-
- when rendering preloaded resources, we were not applying scoping. Now we are skipping around_scoping callback too.
|
46
|
-
|
47
|
-
## 0.1.23 (29-04-2024)
|
48
|
-
|
49
|
-
Features:
|
50
|
-
|
51
|
-
- Added support for UUID
|
52
|
-
|
53
|
-
## 0.1.24 (18-06-2024)
|
54
|
-
|
55
|
-
Features:
|
56
|
-
|
57
|
-
- Added preliminary support for Sideload backed by function instead of model association
|
58
|
-
|
59
|
-
## 0.1.25 (04-12-2024)
|
60
|
-
|
61
|
-
Features:
|
62
|
-
|
63
|
-
- Added support to preload extra_fields for the main resource, replacing N+1 queries with a single query. This does not apply to sideloaded resources.
|
64
|
-
|
65
|
-
## 0.2.0 (01-24-2025)
|
66
|
-
|
67
|
-
Features:
|
68
|
-
|
69
|
-
- Added MRI support
|
70
|
-
- Added support for rails 8
|
71
|
-
|
72
|
-
Breaking changes:
|
73
|
-
|
74
|
-
- Removed support for graphiti <= 1.6.3
|
75
|
-
|
76
|
-
<!-- ### [version (DD-MM-YYYY)] -->
|
77
|
-
<!-- Breaking changes:-->
|
78
|
-
<!-- Features:-->
|
79
|
-
<!-- Fixes:-->
|
80
|
-
<!-- Misc:-->
|
34
|
+
[unreleased]: https://github.com/mrhardikjoshi/graphiti-activegraph/compare/v1.0.0...master
|
35
|
+
[1.0.0]: https://github.com/mrhardikjoshi/graphiti-activegraph/compare/9f837108ae57287c65b0f6fd2609dd56a95cd461...v1.0.0
|
@@ -0,0 +1,70 @@
|
|
1
|
+
## 0.1.8 (09-06-2021)
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- Added support for polymorphic relationship.
|
6
|
+
|
7
|
+
## 0.1.13 (21-12-2021)
|
8
|
+
|
9
|
+
Features:
|
10
|
+
|
11
|
+
- Supports Jruby-9.3.2.0
|
12
|
+
|
13
|
+
## 0.1.14 (21-12-2021)
|
14
|
+
|
15
|
+
Features:
|
16
|
+
|
17
|
+
- Adding unpaginated query to resource proxy with preloaded records. This will help in getting count on API.
|
18
|
+
|
19
|
+
## 0.1.15 (21-06-2022)
|
20
|
+
|
21
|
+
Features:
|
22
|
+
|
23
|
+
- Relationships mentioned in sparse field param (and not in include), will now be returned in relationship block of response
|
24
|
+
|
25
|
+
## 0.1.20
|
26
|
+
|
27
|
+
Features:
|
28
|
+
|
29
|
+
- With graphiti config variable "allow_sidepost" you can allow/disallow sideposting, by default it is allowed.
|
30
|
+
|
31
|
+
## 0.1.21
|
32
|
+
|
33
|
+
Fixes:
|
34
|
+
|
35
|
+
- Runner#proxy keyword arguments
|
36
|
+
|
37
|
+
## 0.1.22
|
38
|
+
|
39
|
+
Fixes:
|
40
|
+
|
41
|
+
- when rendering preloaded resources, we were not applying scoping. Now we are skipping around_scoping callback too.
|
42
|
+
|
43
|
+
## 0.1.23 (29-04-2024)
|
44
|
+
|
45
|
+
Features:
|
46
|
+
|
47
|
+
- Added support for UUID
|
48
|
+
|
49
|
+
## 0.1.24 (18-06-2024)
|
50
|
+
|
51
|
+
Features:
|
52
|
+
|
53
|
+
- Added preliminary support for Sideload backed by function instead of model association
|
54
|
+
|
55
|
+
## 0.1.25 (04-12-2024)
|
56
|
+
|
57
|
+
Features:
|
58
|
+
|
59
|
+
- Added support to preload extra_fields for the main resource, replacing N+1 queries with a single query. This does not apply to sideloaded resources.
|
60
|
+
|
61
|
+
## 0.2.0 (01-24-2025)
|
62
|
+
|
63
|
+
Features:
|
64
|
+
|
65
|
+
- Added MRI support
|
66
|
+
- Added support for rails 8
|
67
|
+
|
68
|
+
Breaking changes:
|
69
|
+
|
70
|
+
- Removed support for graphiti <= 1.6.3
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
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
|
+
#### Rendering Preloaded Objects Without Extra Queries
|
49
|
+
graphiti-activegraph introduces two new methods on the Graphiti resource class:
|
50
|
+
`with_preloaded_obj(record, params)` – Renders a single preloaded ActiveGraph object without querying the database.
|
51
|
+
`all_with_preloaded(records, params)` – Renders multiple preloaded ActiveGraph objects without additional queries.
|
52
|
+
**Note:** These methods assume that the provided records are final and will not apply Graphiti’s filtering, sorting, or scoping logic.
|
53
|
+
|
54
|
+
#### Efficient Deep Sorting
|
55
|
+
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.
|
56
|
+
For example, to sort Post records based on their Author's Country's name, you can use following query string:
|
57
|
+
```
|
58
|
+
sort=author.country.name&include=author.country
|
59
|
+
```
|
60
|
+
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.
|
61
|
+
Note: The `include` parameter must be present and include the full association path (`author.country`) for the sorting to work correctly.
|
62
|
+
|
63
|
+
#### Response Payload Links control
|
64
|
+
Control the links in response payload via request query params:
|
65
|
+
- `pagination_links=true|false` — toggle top-level pagination links
|
66
|
+
- `links=true|false` — toggle links inside each resource object
|
67
|
+
|
68
|
+
## Contributing
|
69
|
+
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
|
+
|
71
|
+
## Release
|
72
|
+
1. Make sure version file is updated/incremented in master branch
|
73
|
+
2. git checkout master
|
74
|
+
3. git pull origin master
|
75
|
+
4. git tag v1.2.3
|
76
|
+
5. git push origin v1.2.3
|
77
|
+
6. gem build graphiti-activegraph.gemspec
|
78
|
+
7. gem push graphiti-activegraph-1.2.3.gem
|
79
|
+
|
80
|
+
## License
|
81
|
+
The gem is available as open-source under the terms of the MIT License.
|
@@ -19,10 +19,14 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_dependency 'graphiti', '>= 1.6.4'
|
21
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'
|
22
24
|
|
23
25
|
spec.add_development_dependency 'graphiti_spec_helpers', '>= 1.0.0'
|
24
26
|
spec.add_development_dependency 'standard'
|
25
27
|
spec.add_development_dependency 'pry'
|
28
|
+
spec.add_development_dependency 'ffaker'
|
29
|
+
spec.add_development_dependency 'factory_bot_rails'
|
26
30
|
spec.add_development_dependency 'rake', '>= 10.0'
|
27
31
|
spec.add_development_dependency 'rspec', '>= 3.9.0'
|
28
32
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Graphiti::ActiveGraph::Extensions
|
2
|
+
require 'ostruct' if RUBY_PLATFORM != 'java'
|
3
|
+
|
4
|
+
module Context
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
class_methods do
|
8
|
+
def context
|
9
|
+
Thread.current.thread_variable_get(:context) || {}.tap(&method(:context=))
|
10
|
+
end
|
11
|
+
|
12
|
+
def context=(val)
|
13
|
+
Thread.current.thread_variable_set(:context, val)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Graphiti::ActiveGraph::Extensions::Resources
|
2
|
+
module Authorizationable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class << self
|
7
|
+
attr_reader :authorize_attributes
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
def attribute_authorization
|
13
|
+
@authorize_attributes = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def authorize_attributes?
|
17
|
+
@authorize_attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
def readable_attributes
|
21
|
+
attributes.select { |_attr_name, options_map| options_map[:readable] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def readable_sideloads
|
25
|
+
sideloads.select { |_sideloads_name, sideload_obj| sideload_obj.readable? }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Graphiti::ActiveGraph::Extensions::Resources
|
2
|
+
module PayloadCombinable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class_methods do
|
6
|
+
def combine(attributes, relationships)
|
7
|
+
attributes.merge(relationship_attributes(relationships))
|
8
|
+
end
|
9
|
+
|
10
|
+
def relationship_attributes(relationships)
|
11
|
+
relationships.map { |k, v| [k, extract_ids(v)] }.to_h
|
12
|
+
end
|
13
|
+
|
14
|
+
def extract_ids(object)
|
15
|
+
object.is_a?(Array) ? object.map { |o| extract_ids(o) } : object[:attributes][:id]
|
16
|
+
end
|
17
|
+
|
18
|
+
def remove_undeclared_attributes(attr_map)
|
19
|
+
permitted_attrs = all_attributes.keys
|
20
|
+
attr_map.select! { |attr_name, _value| permitted_attrs.include?(attr_name.to_sym) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Graphiti::ActiveGraph::Extensions::Resources
|
2
|
+
module Preloadable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class_methods do
|
6
|
+
def with_preloaded_obj(obj, params)
|
7
|
+
id = params[:data].try(:[], :id) || params.delete(:id)
|
8
|
+
params[:filter] ||= {}
|
9
|
+
params[:filter][:id] = id if id
|
10
|
+
|
11
|
+
build(params, nil, raise_on_missing: false, preloaded: obj)
|
12
|
+
end
|
13
|
+
|
14
|
+
def all_with_preloaded(obj_arr, params)
|
15
|
+
build(params, nil, single: false, raise_on_missing: false, preloaded: obj_arr)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Graphiti::ActiveGraph::Extensions::Resources
|
2
|
+
module Rel
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def relation_resource?
|
6
|
+
self.class.relation_resource?
|
7
|
+
end
|
8
|
+
|
9
|
+
class_methods do
|
10
|
+
def relation_resource?
|
11
|
+
config[:relation_resource] || false
|
12
|
+
end
|
13
|
+
|
14
|
+
def relationship_resource=(value)
|
15
|
+
config[:relation_resource] = value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Graphiti::ActiveGraph::JsonapiExt
|
2
|
+
class IncludeDirective < JSONAPI::IncludeDirective
|
3
|
+
attr_accessor :length, :retain_rel_limit
|
4
|
+
|
5
|
+
def initialize(include_args, options = {})
|
6
|
+
include_hash = JSONAPI::IncludeDirective::Parser.parse_include_args(include_args)
|
7
|
+
@retain_rel_limit = options.delete(:retain_rel_limit)
|
8
|
+
@hash = formulate_hash(include_hash, options)
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def keys
|
13
|
+
super.select(&method(:key?))
|
14
|
+
end
|
15
|
+
|
16
|
+
alias get []
|
17
|
+
|
18
|
+
def key?(key)
|
19
|
+
super && get(key).valid_length?
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](key)
|
23
|
+
super&.descend(key) || {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def descend(key)
|
27
|
+
length && length != '' ? dup.tap { |dup| dup.add_self_reference(key, length.to_i - 1) } : self
|
28
|
+
end
|
29
|
+
|
30
|
+
def valid_length?
|
31
|
+
length.nil? || length == '' || length.to_i.positive?
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_hash
|
35
|
+
@hash.each_with_object({}) do |(key, value), hash|
|
36
|
+
key = "#{key}*#{value.length}".to_sym if value.length
|
37
|
+
hash[key] = value.to_hash unless value == self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_self_reference(key, length)
|
42
|
+
@hash = @hash.merge(key => self)
|
43
|
+
self.length = length
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def formulate_hash(include_hash, options)
|
49
|
+
include_hash.each_with_object({}) do |(key, value), hash|
|
50
|
+
rel_name, rel_length = extract_rel_meta(key)
|
51
|
+
|
52
|
+
hash[rel_name] = self.class.new(value, options_with_retain_rel_limit(options)).tap do |directive|
|
53
|
+
directive.add_self_reference(rel_name, rel_length) if key.to_s.match?(/.+\*(\d*)\z/)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def extract_rel_meta(key)
|
59
|
+
Graphiti::ActiveGraph::Util::Transformers::RelationParam.new(key).split_rel_length(retain_rel_limit)
|
60
|
+
end
|
61
|
+
|
62
|
+
def options_with_retain_rel_limit(options)
|
63
|
+
options.merge(retain_rel_limit:)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -36,12 +36,39 @@ module Graphiti::ActiveGraph
|
|
36
36
|
[]
|
37
37
|
end
|
38
38
|
|
39
|
+
def include_directive
|
40
|
+
@include_directive ||= Graphiti::ActiveGraph::JsonapiExt::IncludeDirective.new(@include_param, retain_rel_limit: true)
|
41
|
+
end
|
42
|
+
|
39
43
|
def parse_sort_criteria_hash(hash)
|
40
44
|
hash.map { |key, value| [key.to_s.split('.').map(&:to_sym), value] }.to_h
|
41
45
|
end
|
42
46
|
|
47
|
+
def links?
|
48
|
+
[:json, :xml, 'json', 'xml'].exclude?(params[:format]) && show_resource_links?
|
49
|
+
end
|
50
|
+
|
51
|
+
def pagination_links?
|
52
|
+
action != :find && show_pagination_links?
|
53
|
+
end
|
54
|
+
|
43
55
|
private
|
44
56
|
|
57
|
+
def show_pagination_links?
|
58
|
+
return @show_pagination_links unless @show_pagination_links.nil?
|
59
|
+
@show_pagination_links = read_link_params(:pagination_links)
|
60
|
+
end
|
61
|
+
|
62
|
+
def show_resource_links?
|
63
|
+
return @show_resource_links unless @show_resource_links.nil?
|
64
|
+
|
65
|
+
@show_resource_links = read_link_params(:links)
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_link_params(name)
|
69
|
+
ActiveModel::Type::Boolean.new.cast(params[name]) != false
|
70
|
+
end
|
71
|
+
|
45
72
|
def sort_criteria(sort)
|
46
73
|
sort.split(',').map(&method(:sort_hash)).map(&method(:parse_sort_criteria_hash))
|
47
74
|
end
|
@@ -1,41 +1,52 @@
|
|
1
1
|
module Graphiti
|
2
2
|
module ActiveGraph
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
class Resource < Graphiti::Resource
|
4
|
+
include Extensions::Resources::Authorizationable
|
5
|
+
include Extensions::Resources::PayloadCombinable
|
6
|
+
include Extensions::Resources::Preloadable
|
7
|
+
include Extensions::Resources::Rel
|
8
|
+
|
9
|
+
self.adapter = Adapters::ActiveGraph
|
10
|
+
self.abstract_class = true
|
11
|
+
|
12
|
+
def self.use_uuid
|
13
|
+
define_singleton_method(:inherited) do |klass|
|
14
|
+
super(klass)
|
15
|
+
klass.attribute :id, :uuid
|
16
|
+
end
|
6
17
|
end
|
7
18
|
|
8
|
-
def
|
9
|
-
config[:relation_resource] = value
|
19
|
+
def self.guard_nil_id!(params)
|
10
20
|
end
|
11
21
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
params[:filter][:id] = id if id
|
22
|
+
def self.extra_attribute?(name)
|
23
|
+
extra_attributes.has_key?(name)
|
24
|
+
end
|
16
25
|
|
17
|
-
|
26
|
+
def self.sideload_config(sideload_name)
|
27
|
+
config[:sideloads][sideload_name]
|
18
28
|
end
|
19
29
|
|
20
|
-
def
|
21
|
-
|
30
|
+
def self.sideload_resource_class(sideload_name)
|
31
|
+
sideload_config(sideload_name)&.resource_class
|
22
32
|
end
|
23
33
|
|
24
|
-
def
|
34
|
+
def self.custom_eagerload(sideload_name)
|
35
|
+
sideload_config(sideload_name)&.custom_eagerload
|
25
36
|
end
|
26
37
|
|
27
38
|
def extra_attribute?(name)
|
28
|
-
|
39
|
+
self.class.extra_attribute?(name)
|
29
40
|
end
|
30
|
-
end
|
31
41
|
|
32
|
-
|
33
|
-
|
34
|
-
self.class.relation_resource?
|
42
|
+
def build_scope(base, query, opts = {})
|
43
|
+
scoping_class.new(base, self, query, opts)
|
35
44
|
end
|
36
45
|
|
37
|
-
def
|
38
|
-
|
46
|
+
def handle_includes(scope, includes, sorts, **opts)
|
47
|
+
includes_str = JSONAPI::IncludeDirective.new(includes, retain_rel_limit: true).to_string.split(',')
|
48
|
+
options = opts.merge(max_page_size:).merge!(authorize_scope_params)
|
49
|
+
scope.with_ordered_associations(includes_str, sorts, options)
|
39
50
|
end
|
40
51
|
|
41
52
|
def sideload_name_arr(query)
|
@@ -68,6 +79,20 @@ module Graphiti
|
|
68
79
|
raise Errors::TypecastFailed.new(self, name, value, e, type_name)
|
69
80
|
end
|
70
81
|
end
|
82
|
+
|
83
|
+
def authorize_scope_params
|
84
|
+
{}
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def scoping_class
|
90
|
+
Scope
|
91
|
+
end
|
92
|
+
|
93
|
+
def update_foreign_key(*)
|
94
|
+
true
|
95
|
+
end
|
71
96
|
end
|
72
97
|
end
|
73
98
|
end
|