graphiti-activegraph 1.3.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 +4 -4
- data/.github/workflows/specs.yml +8 -0
- data/CHANGELOG.md +4 -0
- data/README.md +7 -0
- data/docs/deserializer.md +40 -0
- data/graphiti-activegraph.gemspec +2 -0
- data/lib/graphiti/active_graph/concerns/relationships.rb +15 -0
- data/lib/graphiti/active_graph/deserializer.rb +1 -4
- data/lib/graphiti/active_graph/extensions/query_dsl/performer.rb +38 -0
- data/lib/graphiti/active_graph/extensions/query_dsl/query_generator.rb +20 -0
- data/lib/graphiti/active_graph/scoping/filter.rb +9 -0
- data/lib/graphiti/active_graph/version.rb +1 -1
- metadata +34 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 99c8c00fe58ed3146c7feae681bac89ec82989b09f88dfa97aa6a54ef7e9930b
|
|
4
|
+
data.tar.gz: c21e632e4fa1a4f6b24315c01c76d89f91158ae9996a73cdf6da83e97805e2ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8942c7a92552d7554cdc78e5183b970bab9c6d9cee23e5d21e23244c84c45491bbd5a3085671cde7919ca3f7e531cd2e7c6388f0ad367cecc430b77597c0db9c
|
|
7
|
+
data.tar.gz: e31a9631f62d743899851ea815c2158c801f550a5d7ec86eafab260045441fbbd84813f0c5511f9cadc3ad2a7fe8b750d315effc65cbc46866235d31f136731a
|
data/.github/workflows/specs.yml
CHANGED
|
@@ -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,10 @@ 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
|
+
|
|
10
14
|
## [1.3.0] - 2025-10-13
|
|
11
15
|
### Added
|
|
12
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)
|
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.
|
|
@@ -107,6 +112,8 @@ Currently, this feature does not support preloading for deep sideloads such as `
|
|
|
107
112
|
|
|
108
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.
|
|
109
114
|
|
|
115
|
+
## [CHANGELOG](CHANGELOG.md)
|
|
116
|
+
|
|
110
117
|
## Contributing
|
|
111
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.
|
|
112
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
|
|
@@ -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|
|
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.3.
|
|
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-
|
|
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
|