graphiti 1.0.alpha.4 → 1.0.alpha.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 736b8601bf09408a0fa6ed8f2a0c148a79f7c285
4
- data.tar.gz: 9b0adbc770aea3e609f15804db1b33ddba1dee13
3
+ metadata.gz: a97ae8d131e23bc5acf8f8a4fcb97e7cdce25fdc
4
+ data.tar.gz: 04ae2c8cc7d56ffea5dc0f8a3fec1a7506a5baeb
5
5
  SHA512:
6
- metadata.gz: 467e32b7154d37819d6bc4598872e66f3a138120ea2781253238ce4b6fc426b416184c79e5ce58a6d9b596b5754cc87bf7ffb2fc02ab2867bdc6eb00edbe8939
7
- data.tar.gz: c8ec00841469671ef261283f3dd6f556c095742be04d31f1bfa9d633ee5066cd009a790560bc65a61845b6d2db366cff5aa2da7b0226e0a4a2ff7146677c2b78
6
+ metadata.gz: 254a66e4e0bd21eef9038bc8e756b2195cf0d4f0b817944e2f5c71ca139c40da3d0c3a99d7d540b92f77b4bdb5a6acade53efce5ffb839f61ca1a6dcfd01d46e
7
+ data.tar.gz: 7790a1eb890eeff8bdf7690df749b3841fbff88487d6ef39dc7f3e9679bdabb9854898ad833e9ed8c5427712f14af416ff6dee4d9ba92cecfe34f773997b1adc
@@ -1,82 +1,27 @@
1
1
  module Graphiti
2
2
  module Adapters
3
- # Adapters DRY up common resource logic.
4
- #
5
- # For instance, there's no reason to write ActiveRecord logic like this in
6
- # every Resource:
7
- #
8
- # allow_filter :title do |scope, value|
9
- # scope.where(title: value)
10
- # end
11
- #
12
- # sort do |scope, att, dir|
13
- # scope.order(att => dir)
14
- # end
15
- #
16
- # paginate do |scope, current_page, per_page|
17
- # scope.page(current_page).per(per_page)
18
- # end
19
- #
20
- # This logic can be re-used through an *Adapter*:
21
- #
22
- # use_adapter Graphiti::Adapters::ActiveRecord
23
- # allow_filter :title
24
- #
25
- # Adapters are pretty simple to write. The corresponding code for the above
26
- # ActiveRecord adapter, which should look pretty familiar:
27
- #
28
- # class Graphiti::Adapters::ActiveRecord
29
- # def filter(scope, attribute, value)
30
- # scope.where(attribute => value)
31
- # end
32
- #
33
- # def order(scope, attribute, direction)
34
- # scope.order(attribute => direction)
35
- # end
36
- #
37
- # def paginate(scope, current_page, per_page)
38
- # scope.page(current_page).per(per_page)
39
- # end
40
- # end
41
- #
42
- # An adapter can have a corresponding +sideloading_module+. This module
43
- # gets mixed in to a Sideload. In other words, *Resource* is to
44
- # *Adapter* as *Sideload* is to *Adapter#sideloading_module*. Use this
45
- # module to define DSL methods that wrap #allow_sideload:
46
- #
47
- # class MyAdapter < Graphiti::Adapters::Abstract
48
- # # ... code ...
49
- # def sideloading_module
50
- # MySideloadingAdapter
51
- # end
52
- # end
53
- #
54
- # module MySideloadingAdapter
55
- # def belongs_to(association_name)
56
- # allow_sideload association_name do
57
- # # ... code ...
58
- # end
59
- # end
60
- # end
61
- #
62
- # # And now in your Resource:
63
- # class MyResource < ApplicationResource
64
- # # ... code ...
65
- # use_adapter MyAdapter
66
- #
67
- # belongs_to :my_association
68
- # end
69
- #
70
- # If you need the adapter to do *nothing*, because perhaps the API you
71
- # are hitting does not support sorting,
72
- # use +Graphiti::Adapters::Null+.
73
- #
74
- # @see Resource.use_adapter
75
- # @see Adapters::ActiveRecord
76
- # @see Adapters::ActiveRecordSideloading
77
- # @see Adapters::Null
78
3
  class Abstract
79
- def default_operators
4
+ attr_reader :resource
5
+
6
+ def initialize(resource)
7
+ @resource = resource
8
+ end
9
+
10
+ # You want to override this!
11
+ # Map of association_type => sideload_class
12
+ # e.g.
13
+ # { has_many: Adapters::ActiveRecord::HasManySideload }
14
+ def self.sideloading_classes
15
+ {
16
+ has_many: ::Graphiti::Sideload::HasMany,
17
+ belongs_to: ::Graphiti::Sideload::BelongsTo,
18
+ has_one: ::Graphiti::Sideload::HasOne,
19
+ many_to_many: ::Graphiti::Sideload::ManyToMany,
20
+ polymorphic_belongs_to: ::Graphiti::Sideload::PolymorphicBelongsTo
21
+ }
22
+ end
23
+
24
+ def self.default_operators
80
25
  {
81
26
  string: [
82
27
  :eq,
@@ -423,7 +368,11 @@ module Graphiti
423
368
  parent, child, association_name, association_type
424
369
  else
425
370
  if [:has_many, :many_to_many].include?(association_type)
426
- parent.send(:"#{association_name}") << child
371
+ if parent.send(:"#{association_name}").nil?
372
+ parent.send(:"#{association_name}=", [child])
373
+ else
374
+ parent.send(:"#{association_name}") << child
375
+ end
427
376
  else
428
377
  parent.send(:"#{association_name}=", child)
429
378
  end
@@ -470,20 +419,6 @@ module Graphiti
470
419
  raise 'you must override #disassociate in an adapter subclass'
471
420
  end
472
421
 
473
- # You want to override this!
474
- # Map of association_type => sideload_class
475
- # e.g.
476
- # { has_many: Adapters::ActiveRecord::HasManySideload }
477
- def sideloading_classes
478
- {
479
- has_many: ::Graphiti::Sideload::HasMany,
480
- belongs_to: ::Graphiti::Sideload::BelongsTo,
481
- has_one: ::Graphiti::Sideload::HasOne,
482
- many_to_many: ::Graphiti::Sideload::ManyToMany,
483
- polymorphic_belongs_to: ::Graphiti::Sideload::PolymorphicBelongsTo
484
- }
485
- end
486
-
487
422
  # @param [Class] model_class The configured model class (see Resource.model)
488
423
  # @param [Hash] create_params Attributes + id
489
424
  # @return the model instance just created
@@ -528,13 +463,13 @@ module Graphiti
528
463
 
529
464
  private
530
465
 
531
- def numerical_operators
466
+ def self.numerical_operators
532
467
  [:eq, :not_eq, :gt, :gte, :lt, :lte]
533
468
  end
534
469
 
535
470
  def activerecord_adapter
536
471
  @activerecord_adapter ||=
537
- ::Graphiti::Adapters::ActiveRecord::Base.new
472
+ ::Graphiti::Adapters::ActiveRecord::Base.new(resource)
538
473
  end
539
474
 
540
475
  def activerecord_associate?(parent, child, association_name)
@@ -2,6 +2,24 @@ module Graphiti
2
2
  module Adapters
3
3
  module ActiveRecord
4
4
  class Base < ::Graphiti::Adapters::Abstract
5
+ def filter_eq(scope, attribute, value)
6
+ scope.where(attribute => value)
7
+ end
8
+ alias :filter_integer_eq :filter_eq
9
+ alias :filter_float_eq :filter_eq
10
+ alias :filter_big_decimal_eq :filter_eq
11
+ alias :filter_date_eq :filter_eq
12
+ alias :filter_boolean_eq :filter_eq
13
+
14
+ def filter_not_eq(scope, attribute, value)
15
+ scope.where.not(attribute => value)
16
+ end
17
+ alias :filter_integer_not_eq :filter_not_eq
18
+ alias :filter_float_not_eq :filter_not_eq
19
+ alias :filter_big_decimal_not_eq :filter_not_eq
20
+ alias :filter_date_not_eq :filter_not_eq
21
+ alias :filter_boolean_not_eq :filter_not_eq
22
+
5
23
  def filter_string_eq(scope, attribute, value, is_not: false)
6
24
  column = scope.klass.arel_table[attribute]
7
25
  clause = column.lower.eq_any(value.map(&:downcase))
@@ -54,56 +72,44 @@ module Graphiti
54
72
  filter_string_match(scope, attribute, value, is_not: true)
55
73
  end
56
74
 
57
- def filter_integer_eq(scope, attribute, value, is_not: false)
58
- clause = { attribute => value }
59
- is_not ? scope.where.not(clause) : scope.where(clause)
60
- end
61
- alias :filter_float_eq :filter_integer_eq
62
- alias :filter_big_decimal_eq :filter_integer_eq
63
- alias :filter_date_eq :filter_integer_eq
64
- alias :filter_boolean_eq :filter_integer_eq
65
-
66
- def filter_integer_not_eq(scope, attribute, value)
67
- filter_integer_eq(scope, attribute, value, is_not: true)
68
- end
69
- alias :filter_float_not_eq :filter_integer_not_eq
70
- alias :filter_big_decimal_not_eq :filter_integer_not_eq
71
- alias :filter_date_not_eq :filter_integer_not_eq
72
-
73
- def filter_integer_gt(scope, attribute, value)
75
+ def filter_gt(scope, attribute, value)
74
76
  column = scope.klass.arel_table[attribute]
75
77
  scope.where(column.gt_any(value))
76
78
  end
77
- alias :filter_float_gt :filter_integer_gt
78
- alias :filter_big_decimal_gt :filter_integer_gt
79
- alias :filter_datetime_gt :filter_integer_gt
80
- alias :filter_date_gt :filter_integer_gt
79
+ alias :filter_integer_gt :filter_gt
80
+ alias :filter_float_gt :filter_gt
81
+ alias :filter_big_decimal_gt :filter_gt
82
+ alias :filter_datetime_gt :filter_gt
83
+ alias :filter_date_gt :filter_gt
81
84
 
82
- def filter_integer_gte(scope, attribute, value)
85
+ def filter_gte(scope, attribute, value)
83
86
  column = scope.klass.arel_table[attribute]
84
87
  scope.where(column.gteq_any(value))
85
88
  end
86
- alias :filter_float_gte :filter_integer_gte
87
- alias :filter_big_decimal_gte :filter_integer_gte
88
- alias :filter_datetime_gte :filter_integer_gte
89
- alias :filter_date_gte :filter_integer_gte
89
+ alias :filter_integer_gte :filter_gte
90
+ alias :filter_float_gte :filter_gte
91
+ alias :filter_big_decimal_gte :filter_gte
92
+ alias :filter_datetime_gte :filter_gte
93
+ alias :filter_date_gte :filter_gte
90
94
 
91
- def filter_integer_lt(scope, attribute, value)
95
+ def filter_lt(scope, attribute, value)
92
96
  column = scope.klass.arel_table[attribute]
93
97
  scope.where(column.lt_any(value))
94
98
  end
95
- alias :filter_float_lt :filter_integer_lt
96
- alias :filter_big_decimal_lt :filter_integer_lt
97
- alias :filter_datetime_lt :filter_integer_lt
98
- alias :filter_date_lt :filter_integer_lt
99
+ alias :filter_integer_lt :filter_lt
100
+ alias :filter_float_lt :filter_lt
101
+ alias :filter_big_decimal_lt :filter_lt
102
+ alias :filter_datetime_lt :filter_lt
103
+ alias :filter_date_lt :filter_lt
99
104
 
100
- def filter_integer_lte(scope, attribute, value)
105
+ def filter_lte(scope, attribute, value)
101
106
  column = scope.klass.arel_table[attribute]
102
107
  scope.where(column.lteq_any(value))
103
108
  end
104
- alias :filter_float_lte :filter_integer_lte
105
- alias :filter_big_decimal_lte :filter_integer_lte
106
- alias :filter_date_lte :filter_integer_lte
109
+ alias :filter_integer_lte :filter_lte
110
+ alias :filter_float_lte :filter_lte
111
+ alias :filter_big_decimal_lte :filter_lte
112
+ alias :filter_date_lte :filter_lte
107
113
 
108
114
  # Ensure fractional seconds don't matter
109
115
  def filter_datetime_eq(scope, attribute, value, is_not: false)
@@ -180,7 +186,7 @@ module Graphiti
180
186
  end
181
187
  end
182
188
 
183
- def sideloading_classes
189
+ def self.sideloading_classes
184
190
  {
185
191
  has_many: HasManySideload,
186
192
  has_one: HasOneSideload,
@@ -198,26 +204,34 @@ module Graphiti
198
204
  end
199
205
 
200
206
  def associate_all(parent, children, association_name, association_type)
201
- association = parent.association(association_name)
202
- association.loaded!
203
-
204
- children.each do |child|
205
- if association_type == :many_to_many &&
206
- !parent.send(association_name).exists?(child.id) &&
207
- [:create, :update].include?(Graphiti.context[:namespace])
208
- parent.send(association_name) << child
209
- else
210
- target = association.instance_variable_get(:@target)
211
- target |= [child]
212
- association.instance_variable_set(:@target, target)
207
+ if activerecord_associate?(parent, children[0], association_name)
208
+ association = parent.association(association_name)
209
+ association.loaded!
210
+
211
+ children.each do |child|
212
+ if association_type == :many_to_many &&
213
+ !parent.send(association_name).exists?(child.id) &&
214
+ [:create, :update].include?(Graphiti.context[:namespace])
215
+ parent.send(association_name) << child
216
+ else
217
+ target = association.instance_variable_get(:@target)
218
+ target |= [child]
219
+ association.instance_variable_set(:@target, target)
220
+ end
213
221
  end
222
+ else
223
+ super
214
224
  end
215
225
  end
216
226
 
217
227
  def associate(parent, child, association_name, association_type)
218
- association = parent.association(association_name)
219
- association.loaded!
220
- association.instance_variable_set(:@target, child)
228
+ if activerecord_associate?(parent, child, association_name)
229
+ association = parent.association(association_name)
230
+ association.loaded!
231
+ association.instance_variable_set(:@target, child)
232
+ else
233
+ super
234
+ end
221
235
  end
222
236
 
223
237
  # When a has_and_belongs_to_many relationship, we don't have a foreign
@@ -16,23 +16,59 @@ The adapter #{@adapter.class} does not implement method '#{@method}', which was
16
16
  end
17
17
  end
18
18
 
19
+ class InvalidFilterValue < Base
20
+ def initialize(resource, filter, value)
21
+ @resource = resource
22
+ @filter = filter
23
+ @value = value
24
+ end
25
+
26
+ def message
27
+ allow = @filter.values[0][:allow]
28
+ reject = @filter.values[0][:reject]
29
+ msg = <<-MSG
30
+ #{@resource.class.name}: tried to filter on #{@filter.keys[0].inspect}, but passed invalid value #{@value.inspect}.
31
+ MSG
32
+ msg << "\nWhitelist: #{allow.inspect}" if allow
33
+ msg << "\nBlacklist: #{reject.inspect}" if reject
34
+ msg
35
+ end
36
+ end
37
+
19
38
  class InvalidLink < Base
20
- def initialize(resource_class, sideload)
39
+ def initialize(resource_class, sideload, action)
21
40
  @resource_class = resource_class
22
41
  @sideload = sideload
42
+ @action = action
23
43
  end
24
44
 
25
45
  def message
26
46
  <<-MSG
27
47
  #{@resource_class.name}: Cannot link to sideload #{@sideload.name.inspect}!
28
48
 
29
- Make sure the endpoint "#{@sideload.resource.endpoint[:full_path]}" exists, or customize the endpoint for #{@sideload.resource.class.name}.
49
+ Make sure the endpoint "#{@sideload.resource.endpoint[:full_path]}" exists with action #{@action.inspect}, or customize the endpoint for #{@sideload.resource.class.name}.
30
50
 
31
51
  If you do not wish to generate a link, pass link: false or set self.relationship_links_by_default = false.
32
52
  MSG
33
53
  end
34
54
  end
35
55
 
56
+ class SingularFilter < Base
57
+ def initialize(resource, filter, value)
58
+ @resource = resource
59
+ @filter = filter
60
+ @value = value
61
+ end
62
+
63
+ def message
64
+ <<-MSG
65
+ #{@resource.class.name}: passed multiple values to filter #{@filter.keys[0].inspect}, which was marked single: true.
66
+
67
+ Value was: #{@value.inspect}
68
+ MSG
69
+ end
70
+ end
71
+
36
72
  class Unlinkable < Base
37
73
  def initialize(resource_class, sideload)
38
74
  @resource_class = resource_class
@@ -49,6 +49,7 @@ module Graphiti
49
49
  def typecast(name, value, flag)
50
50
  att = get_attr!(name, flag)
51
51
  type = Graphiti::Types[att[:type]]
52
+ return if value.nil? && type[:kind] != 'array'
52
53
  begin
53
54
  flag = :read if flag == :readable
54
55
  flag = :write if flag == :writable
@@ -44,8 +44,8 @@ module Graphiti
44
44
  attr_writer :config
45
45
  end
46
46
 
47
- class_attribute :adapter,
48
- :model,
47
+ class_attribute :adapter, instance_reader: false
48
+ class_attribute :model,
49
49
  :type,
50
50
  :polymorphic,
51
51
  :polymorphic_child,
@@ -66,7 +66,7 @@ module Graphiti
66
66
  def self.inherited(klass)
67
67
  super
68
68
  klass.config = Util::Hash.deep_dup(config)
69
- klass.adapter ||= Adapters::Abstract.new
69
+ klass.adapter ||= Adapters::Abstract
70
70
  klass.default_sort ||= []
71
71
  klass.default_page_size ||= 20
72
72
  # re-assigning causes a new Class.new
@@ -200,6 +200,10 @@ module Graphiti
200
200
  Util::AttributeCheck.run(self, name, flag, request, raise_error)
201
201
  end
202
202
 
203
+ def adapter
204
+ @adapter ||= self.class.adapter.new(self)
205
+ end
206
+
203
207
  def filters
204
208
  self.class.filters
205
209
  end
@@ -10,9 +10,17 @@ module Graphiti
10
10
  if att = get_attr(name, :filterable, raise_error: :only_unsupported)
11
11
  aliases = [name, opts[:aliases]].flatten.compact
12
12
  operators = FilterOperators.build(self, att[:type], opts, &blk)
13
+
14
+ if Graphiti::Types[att[:type]][:canonical_name] == :boolean
15
+ opts[:single] = true
16
+ end
17
+
13
18
  config[:filters][name.to_sym] = {
14
19
  aliases: aliases,
15
20
  type: att[:type],
21
+ allow: opts[:allow],
22
+ reject: opts[:reject],
23
+ single: !!opts[:single],
16
24
  operators: operators.to_hash
17
25
  }
18
26
  else
@@ -53,7 +61,7 @@ module Graphiti
53
61
  end
54
62
 
55
63
  def stat(symbol_or_hash, &blk)
56
- dsl = Stats::DSL.new(adapter, symbol_or_hash)
64
+ dsl = Stats::DSL.new(new.adapter, symbol_or_hash)
57
65
  dsl.instance_eval(&blk) if blk
58
66
  config[:stats][dsl.name] = dsl
59
67
  end
@@ -25,7 +25,7 @@ module Graphiti
25
25
  def associate(parent, child, association_name, type)
26
26
  child_resource = self.class.resource_for_model(parent)
27
27
  if child_resource.sideloads[association_name]
28
- child_resource.adapter
28
+ child_resource.new.adapter
29
29
  .associate(parent, child, association_name, type)
30
30
  end
31
31
  end
@@ -61,10 +61,10 @@ module Graphiti
61
61
  resource = resource ||= Util::Class.infer_resource_class(self, name)
62
62
  sideload = resource.sideload(as)
63
63
 
64
- _adapter = adapter
64
+ _resource = resource
65
65
  filter sideload.true_foreign_key, resource.attributes[:id][:type] do
66
66
  eq do |scope, value|
67
- _adapter.belongs_to_many_filter(sideload, scope, value)
67
+ _resource.new.adapter.belongs_to_many_filter(sideload, scope, value)
68
68
  end
69
69
  end
70
70
  end
@@ -132,11 +132,15 @@ module Graphiti
132
132
 
133
133
  def filters(resource)
134
134
  {}.tap do |f|
135
- resource.filters.each_pair do |name, config|
135
+ resource.filters.each_pair do |name, filter|
136
136
  config = {
137
- type: config[:type].to_s,
138
- operators: config[:operators].keys.map(&:to_s)
137
+ type: filter[:type].to_s,
138
+ operators: filter[:operators].keys.map(&:to_s)
139
139
  }
140
+ config[:single] = true if filter[:single]
141
+ config[:allow] = filter[:allow] if filter[:allow]
142
+ config[:reject] = filter[:reject] if filter[:reject]
143
+
140
144
  attr = resource.attributes[name]
141
145
  if attr[:filterable].is_a?(Symbol)
142
146
  if attr[:filterable] == :required
@@ -94,6 +94,28 @@ module Graphiti
94
94
  next
95
95
  end
96
96
 
97
+ if new_filter[:single] && !old_filter[:single]
98
+ @errors << "#{old_resource[:name]}: filter #{name.inspect} became singular."
99
+ end
100
+
101
+ if new_filter[:allow] != old_filter[:allow]
102
+ new = new_filter[:allow] || []
103
+ old = old_filter[:allow] || []
104
+ diff = new - old
105
+ if diff.length > 0
106
+ @errors << "#{old_resource[:name]}: filter #{name.inspect} whitelist went from #{old.inspect} to #{new.inspect}."
107
+ end
108
+ end
109
+
110
+ if new_filter[:reject] != old_filter[:reject]
111
+ new = new_filter[:reject] || []
112
+ old = old_filter[:reject] || []
113
+ diff = new - old
114
+ if diff.length > 0
115
+ @errors << "#{old_resource[:name]}: filter #{name.inspect} blacklist went from #{old.inspect} to #{new.inspect}."
116
+ end
117
+ end
118
+
97
119
  if (diff = old_filter[:operators] - new_filter[:operators]).length > 0
98
120
  diff.each do |op|
99
121
  @errors << "#{old_resource[:name]}: filter #{name.inspect} removed operator #{op.inspect}."
@@ -72,7 +72,28 @@ module Graphiti
72
72
  operator = param_value.keys.first
73
73
  value = param_value.values.first unless filter.values[0][:type] == :hash
74
74
  value = value.split(',') if value.is_a?(String) && value.include?(',')
75
+
76
+ if filter.values[0][:single] && value.is_a?(Array)
77
+ raise Errors::SingularFilter.new(resource, filter, value)
78
+ end
79
+
75
80
  value = coerce_types(param_name.to_sym, value)
81
+
82
+ value.each do |v|
83
+ if allow = filter.values[0][:allow]
84
+ unless allow.include?(v)
85
+ raise Errors::InvalidFilterValue.new(resource, filter, value)
86
+ end
87
+ end
88
+
89
+ if reject = filter.values[0][:reject]
90
+ if reject.include?(v)
91
+ raise Errors::InvalidFilterValue.new(resource, filter, value)
92
+ end
93
+ end
94
+ end
95
+
96
+ value = value[0] if filter.values[0][:single]
76
97
  yield filter, operator, value
77
98
  end
78
99
  end
@@ -68,6 +68,7 @@ module Graphiti
68
68
  end
69
69
 
70
70
  def check!
71
+ return if scope_proc
71
72
  case type
72
73
  when :has_many, :has_one
73
74
  unless resource.filters[foreign_key]
@@ -14,14 +14,33 @@ module Graphiti
14
14
  end
15
15
 
16
16
  def generate
17
- if params.empty?
18
- path
17
+ on_demand_links(raw_url)
18
+ end
19
+
20
+ private
21
+
22
+ def raw_url
23
+ if @sideload.link_proc
24
+ @sideload.link_proc.call(@model)
19
25
  else
20
- "#{path}?#{URI.unescape(params.to_query)}"
26
+ if params.empty?
27
+ path
28
+ else
29
+ "#{path}?#{URI.unescape(params.to_query)}"
30
+ end
21
31
  end
22
32
  end
23
33
 
24
- private
34
+ def on_demand_links(url)
35
+ return url unless Graphiti.config.links_on_demand
36
+
37
+ if url.include?('?')
38
+ url << '&links=true'
39
+ else
40
+ url << '?links=true'
41
+ end
42
+ url
43
+ end
25
44
 
26
45
  def params
27
46
  @params ||= {}.tap do |params|
@@ -66,10 +66,11 @@ module Graphiti
66
66
  end
67
67
 
68
68
  def wrap_proc(inner)
69
- type_name = @attr[:type]
69
+ _resource = @resource.new
70
+ _name = @name
70
71
  ->(serializer_instance = nil) {
71
- type = Graphiti::Types[type_name]
72
- type[:read][serializer_instance.instance_eval(&inner)]
72
+ value = serializer_instance.instance_eval(&inner)
73
+ _resource.typecast(_name, value, :readable)
73
74
  }
74
75
  end
75
76
 
@@ -44,11 +44,7 @@ module Graphiti
44
44
  proc do
45
45
  if @proxy.query.links?
46
46
  link(:related) do
47
- if prc = sl.link_proc
48
- prc.call(@object)
49
- else
50
- ::Graphiti::Util::Link.new(sl, @object).generate
51
- end
47
+ ::Graphiti::Util::Link.new(sl, @object).generate
52
48
  end
53
49
  end
54
50
  end
@@ -75,7 +71,7 @@ module Graphiti
75
71
  action = sideload.type == :belongs_to ? :show : :index
76
72
  prc = Graphiti.config.context_for_endpoint
77
73
  unless prc.call(sideload.resource.endpoint[:full_path], action)
78
- raise Errors::InvalidLink.new(@resource_class, sideload)
74
+ raise Errors::InvalidLink.new(@resource_class, sideload, action)
79
75
  end
80
76
  end
81
77
 
@@ -1,3 +1,3 @@
1
1
  module Graphiti
2
- VERSION = "1.0.alpha.4"
2
+ VERSION = "1.0.alpha.5"
3
3
  end
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.0.alpha.4
4
+ version: 1.0.alpha.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-07 00:00:00.000000000 Z
11
+ date: 2018-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsonapi-serializable