graphiti 1.12.2 → 1.13.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/CHANGELOG.md +8 -0
- data/lib/graphiti/errors.rb +13 -0
- data/lib/graphiti/resource/interface.rb +20 -0
- data/lib/graphiti/resource/persistence.rb +38 -0
- data/lib/graphiti/resource_proxy.rb +6 -0
- data/lib/graphiti/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5b0c2234b78e4616fea8ab95f8b6f044d18aa4feafb103cb4eb7d0fed35f8dd6
|
|
4
|
+
data.tar.gz: 2b276253a3b5b802dbf143ccd6fdc7d17287ee542c60f352ab939a33f16da233
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 01ac700f8481142c1842488db436df2bedc508acabf3bde7fcd4d9e0e1a9882ab0df8c23ac5473b68a8ab1717b6041a34fde6b18125d269ccad88f23d8a3f3aa
|
|
7
|
+
data.tar.gz: be85a9c17b7b1df85c5ff755b4aebfeb6bd814e4a88a87b926f05056d776f5b77ec643ab1c8800e155cf541149c30d9c343471ef9427b0dcc69ae6c2e79b3295
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
graphiti changelog
|
|
2
2
|
|
|
3
|
+
# [1.13.0](https://github.com/graphiti-api/graphiti/compare/v1.12.2...v1.13.0) (2026-07-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add Resource.wrap as an easy way to use graphiti serialization on models fetched via other means (and not via graphiti's finders) ([#513](https://github.com/graphiti-api/graphiti/issues/513)) ([fcd19e2](https://github.com/graphiti-api/graphiti/commit/fcd19e2d023091d85947dbdd89259b587e0f582b))
|
|
9
|
+
* deprecate mutating attributes in around_persistence hooks ([#514](https://github.com/graphiti-api/graphiti/issues/514)) [skip ci] ([8410ab0](https://github.com/graphiti-api/graphiti/commit/8410ab0a916077601cf85d8260a05ef9098149eb))
|
|
10
|
+
|
|
3
11
|
## [1.12.2](https://github.com/graphiti-api/graphiti/compare/v1.12.1...v1.12.2) (2026-07-29)
|
|
4
12
|
|
|
5
13
|
|
data/lib/graphiti/errors.rb
CHANGED
|
@@ -467,6 +467,19 @@ module Graphiti
|
|
|
467
467
|
end
|
|
468
468
|
end
|
|
469
469
|
|
|
470
|
+
class InvalidWrapModel < Base
|
|
471
|
+
def initialize(resource_class, model)
|
|
472
|
+
@resource_class = resource_class
|
|
473
|
+
@model = model
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
def message
|
|
477
|
+
<<~MSG
|
|
478
|
+
#{@resource_class.name}.wrap was given a #{@model.class}, but this resource is for #{@resource_class.model} (subclasses are fine).
|
|
479
|
+
MSG
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
|
|
470
483
|
class ResourceEndpointConflict < Base
|
|
471
484
|
def initialize(path, action, resource_a, resource_b)
|
|
472
485
|
@path = path
|
|
@@ -53,8 +53,28 @@ module Graphiti
|
|
|
53
53
|
runner.proxy(base_scope, single: true, raise_on_missing: true)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
# Wrap models fetched outside graphiti so they render like any other proxy
|
|
57
|
+
def wrap(models, base_scope = nil)
|
|
58
|
+
validate_wrap_models!(models)
|
|
59
|
+
runner = Runner.new(self, {}, nil, :find)
|
|
60
|
+
runner.proxy(base_scope, bypass_required_filters: true).tap do |proxy|
|
|
61
|
+
proxy.data = models
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
56
65
|
private
|
|
57
66
|
|
|
67
|
+
# Skip polymorphic parents - resource_for_model raises a better error for unknown children
|
|
68
|
+
def validate_wrap_models!(models)
|
|
69
|
+
return if abstract_class? || (polymorphic? && !polymorphic_child?)
|
|
70
|
+
|
|
71
|
+
[models].flatten.compact.each do |model|
|
|
72
|
+
unless model.is_a?(self.model)
|
|
73
|
+
raise Errors::InvalidWrapModel.new(self, model)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
58
78
|
def caching_options
|
|
59
79
|
{cache: @cache_resource, cache_expires_in: @cache_expires_in, cache_tag: @cache_tag}
|
|
60
80
|
end
|
|
@@ -71,8 +71,11 @@ module Graphiti
|
|
|
71
71
|
|
|
72
72
|
def create(create_params, meta = nil)
|
|
73
73
|
model_instance = nil
|
|
74
|
+
snapshot = attributes_snapshot(:create, create_params)
|
|
74
75
|
|
|
75
76
|
run_callbacks :persistence, :create, create_params, meta do
|
|
77
|
+
warn_attributes_mutated_in_around_persistence(:create, snapshot, create_params)
|
|
78
|
+
|
|
76
79
|
run_callbacks :attributes, :create, create_params, meta do |params|
|
|
77
80
|
model_instance = call_with_meta(:build, model, meta)
|
|
78
81
|
call_with_meta(:assign_attributes, model_instance, params, meta)
|
|
@@ -92,7 +95,11 @@ module Graphiti
|
|
|
92
95
|
id = update_params[:id]
|
|
93
96
|
update_params = update_params.except(:id)
|
|
94
97
|
|
|
98
|
+
snapshot = attributes_snapshot(:update, update_params)
|
|
99
|
+
|
|
95
100
|
run_callbacks :persistence, :update, update_params, meta do
|
|
101
|
+
warn_attributes_mutated_in_around_persistence(:update, snapshot, update_params)
|
|
102
|
+
|
|
96
103
|
run_callbacks :attributes, :update, update_params, meta do |params|
|
|
97
104
|
model_instance = self.class._find(id: id).data
|
|
98
105
|
call_with_meta(:assign_attributes, model_instance, params, meta)
|
|
@@ -133,6 +140,37 @@ module Graphiti
|
|
|
133
140
|
|
|
134
141
|
private
|
|
135
142
|
|
|
143
|
+
# In Graphiti 2.0, attributes are assigned to the model before the
|
|
144
|
+
# persistence hooks fire, so hash modifications made by an
|
|
145
|
+
# around_persistence hook before its yield will no longer be applied.
|
|
146
|
+
# Snapshot-and-compare detects exactly those hooks: the comparison
|
|
147
|
+
# happens before any attributes-phase callback has run, so hooks that
|
|
148
|
+
# only wrap their yield never trigger the warning.
|
|
149
|
+
def attributes_snapshot(action, params)
|
|
150
|
+
return unless around_persistence_hooks?(action)
|
|
151
|
+
Util::Hash.deep_dup(params)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def around_persistence_hooks?(action)
|
|
155
|
+
hooks = self.class.config[:callbacks][:persistence].try(:[], :around) || []
|
|
156
|
+
hooks.any? { |hook| hook[:only].include?(action) }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def warn_attributes_mutated_in_around_persistence(action, snapshot, params)
|
|
160
|
+
return if snapshot.nil? || snapshot == params
|
|
161
|
+
|
|
162
|
+
changed_keys = (snapshot.keys | params.keys).reject { |key| snapshot[key] == params[key] }
|
|
163
|
+
Graphiti::DEPRECATOR.warn(<<~MSG)
|
|
164
|
+
#{self.class}'s around_persistence hook modified the attributes hash before yield (changed keys: #{changed_keys.map(&:inspect).join(", ")}). In Graphiti 2.0, attributes are assigned to the model before persistence hooks run, and these modifications will be silently ignored. Move the modification to a hook that runs before assignment:
|
|
165
|
+
|
|
166
|
+
before_attributes do |attributes|
|
|
167
|
+
attributes[#{changed_keys.first.inspect}] = ...
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
or set the value on the model itself in a before_save hook. See UPGRADING.md in the Graphiti 2.0 release.
|
|
171
|
+
MSG
|
|
172
|
+
end
|
|
173
|
+
|
|
136
174
|
def run_callbacks(kind, action, *args)
|
|
137
175
|
fire_around_callbacks(kind, action, *args) do |*yieldargs|
|
|
138
176
|
fire_callbacks(kind, :before, action, *yieldargs)
|
|
@@ -80,6 +80,12 @@ module Graphiti
|
|
|
80
80
|
Renderer.new(self, options).as_graphql
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
# Records supplied directly, no scope resolution
|
|
84
|
+
def data=(models)
|
|
85
|
+
@data = models
|
|
86
|
+
[@data].flatten.compact.each { |record| @resource.decorate_record(record) }
|
|
87
|
+
end
|
|
88
|
+
|
|
83
89
|
def data
|
|
84
90
|
@data ||= begin
|
|
85
91
|
records = @scope.resolve
|
data/lib/graphiti/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: graphiti
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lee Richmond
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: jsonapi-serializable
|