sequel-packer 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00bbe557f19cf23a18afe4e5d23173a3fb699977680fae2efa99670240f81847
4
- data.tar.gz: 324688d708be91fa8e89eb99a65701f35dc8f3f5a799719588fa84adff877c95
3
+ metadata.gz: 7f7666c0db1cac9f34075e40a398a5963b33e6756d38507953dc14c59d5712d2
4
+ data.tar.gz: 10bf3ff431ba9fab4ff6bdfec84e51f1243cf3da1b5eff3ea66d6b7b45f94fbc
5
5
  SHA512:
6
- metadata.gz: a626e68bd1053d818bd830a198bfe92b13bcbc0286a2ce985a996049ba7858a229aeabb00181e144fadfa8dbcc63ca90adef89619ddc32d86076ee53b718b424
7
- data.tar.gz: 0344f7b561e830c58dd01c68da86728f57594a8073b920e4de70401e038e7a0cf92907f37726d84d9243268c12d3b256195df523d224224b69f53ee16f26136a
6
+ metadata.gz: 67d08fbd8aef15f7005ae59b411f87a237d83b53aeb26e7e92efff2a628e6ae29bf14724cfedea03f34b5f7cf61e4c8d28be6cc4e01027535d04519fa681f7e1
7
+ data.tar.gz: c96e1f683319af1a20d6cb775f6b0ac8a479297947b6a26008082e4a8aa8e35a677de7d3a8f66a7a74fc57079fb8ecab1b678201a214f5768fc57eef61b4b150
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ### 0.3.0 (2020-05-14)
2
+
3
+ * Add `self.set_association_packer(association, packer_class, *traits)` and
4
+ `self.pack_association(association, models)` for more flexible packing of
5
+ associations.
6
+ * Improve internal code quality.
7
+
1
8
  ### 0.2.0 (2020-05-13)
2
9
 
3
10
  * Add support for `Sequel::Packer.eager(*associations)`
data/README.md CHANGED
@@ -12,8 +12,8 @@ ORM offering the following features:
12
12
  * *Reusable:* The Packer library naturally composes well with itself. Nested
13
13
  data can be serialized in the same way no matter what endpoint it's fetched
14
14
  from.
15
- * *Efficient:* When not using Sequel's [`TacticalEagerLoading`]
16
- (https://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/TacticalEagerLoading.html)
15
+ * *Efficient:* When not using Sequel's
16
+ [`TacticalEagerLoading`](https://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/TacticalEagerLoading.html)
17
17
  plugin, the Packer library will intelligently determine which associations
18
18
  and nested associations it needs to eager load in order to avoid any N+1 query
19
19
  issues.
@@ -58,8 +58,12 @@ DB.create_table(:comments) do
58
58
  String :content
59
59
  end
60
60
 
61
- class User < Sequel::Model(:users); end
62
- class Post < Sequel::Model(:posts); end
61
+ class User < Sequel::Model(:users)
62
+ one_to_many :posts, key: :author_id, class: :Post
63
+ end
64
+ class Post < Sequel::Model(:posts)
65
+ one_to_many :comments, key: :post_id, class: :Comment
66
+ end
63
67
  class Comment < Sequel::Model(:comments)
64
68
  many_to_one :author, key: :author_id, class: :User
65
69
  end
@@ -318,7 +322,8 @@ end
318
322
  ```
319
323
 
320
324
  Though this version of course would result in many more queries to the database,
321
- which are not required when using the shorthand form.
325
+ which are not required when using the shorthand form, and also requires creating
326
+ a new instance of `packer_class` for every packed model.
322
327
 
323
328
  ### `self.field(&block)`
324
329
 
@@ -383,7 +388,7 @@ class UserPacker < Sequel::Packer
383
388
 
384
389
  eager(:posts)
385
390
  field(:num_posts) do |user|
386
- user.posts.counts
391
+ user.posts.count
387
392
  end
388
393
  end
389
394
 
@@ -396,8 +401,7 @@ UserPacker.new.pack(User.dataset)
396
401
  ```
397
402
 
398
403
  This helps prevent N+1 query problems when not using Sequel's
399
- [`TacticalEagerLoading`]
400
- (https://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/TacticalEagerLoading.html)
404
+ [`TacticalEagerLoading`](https://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/TacticalEagerLoading.html)
401
405
  plugin.
402
406
 
403
407
  Another use of `eager`, even when using `TacticalEagerLoading`, is to modify or
@@ -425,6 +429,70 @@ Also, it's important to note that if `eager` is called multiple times, with
425
429
  multiple procs, each proc will get applied to the dataset, likely resulting in
426
430
  overly restrictive filtering.
427
431
 
432
+ ### `self.set_association_packer(association, packer_class, *traits)`
433
+
434
+ See `self.pack_association(association, models)` below.
435
+
436
+ ### `self.pack_association(association, models)`
437
+
438
+ The simplest way to pack an association is to use
439
+ `self.field(association, packer_class, *traits)`, but sometimes this doesn't do
440
+ exactly what we want. We may want to pack the association under a different key
441
+ than the name of the association. Or we may only want to pack some of the
442
+ associated models (and it may be difficult or impossible to express which subset
443
+ we want to pack using `eager`). Or perhaps we have a `one_to_many` association
444
+ and instead of packing an array, we want to pack a single associated object
445
+ under a key. The two methods, `set_association_packer` and `pack_association`
446
+ are designed to handle these cases.
447
+
448
+ First, we'll note that following are exactly equivalent:
449
+
450
+ ```ruby
451
+ field :my_assoc, MyAssocPacker, :trait1, :trait2
452
+ ```
453
+
454
+ and
455
+
456
+ ```ruby
457
+ set_association_packer :my_assoc, MyAssocPacker, :trait1, :trait2
458
+ field :my_assoc do |model|
459
+ pack_association(:my_assoc, model.my_assoc)
460
+ end
461
+ ```
462
+
463
+ `set_association_packer` tells the Packer class that we will want to pack models
464
+ from a particular association using the designated Packer with the specified
465
+ traits. Declaring this ahead of time allows the Packer to ensure that the
466
+ association is eager loaded, as well as any nested associations used when using
467
+ the designated Packer with the specified traits.
468
+
469
+ `pack_association` can then be used in a `field` block to use that Packer after
470
+ the data has been fetched and we are actually packing the data. The key things
471
+ here are that we don't need to use the name of the association as the name of
472
+ the field, and that we can choose which models get serialized. If
473
+ `pack_association` is passed an array, it will return an array of packed models,
474
+ but if it is passed a single model, it will return just that packed model.
475
+
476
+ Examples:
477
+
478
+ #### Use a different field name than the name of the association
479
+ ```ruby
480
+ set_association_packer :ugly_internal_names, InternalPacker
481
+ field :nice_external_names do |model|
482
+ pack_association(:ugly_internal_names, model.ugly_internal_names)
483
+ end
484
+ ```
485
+
486
+ #### Pack a single instance of a `one_to_many` association
487
+ ```ruby
488
+ class PostPacker < Sequel::Packer
489
+ set_association_packer :comments, CommentPacker
490
+ field :top_comment do |model|
491
+ pack_association(:comments, model.comments.max_by(&:num_likes))
492
+ end
493
+ end
494
+ ```
495
+
428
496
 
429
497
  ### `initialize(*traits)`
430
498
 
@@ -0,0 +1,137 @@
1
+ require 'sequel'
2
+
3
+ module Sequel
4
+ class Packer
5
+ module Validation
6
+ # Cheks for common errors when using the field method. Additional
7
+ # checks around the packer class and traits occur in
8
+ # check_association_packer.
9
+ def self.check_field_arguments(
10
+ model,
11
+ field_name,
12
+ packer_class,
13
+ traits,
14
+ &block
15
+ )
16
+ fail ModelNotYetDeclaredError if !model
17
+
18
+ # This check applies to all invocations:
19
+ if field_name && !field_name.is_a?(Symbol) && !field_name.is_a?(String)
20
+ raise(
21
+ FieldArgumentError,
22
+ 'Field name passed to Sequel::Packer::field must be a Symbol or ' +
23
+ 'a String.',
24
+ )
25
+ end
26
+
27
+ if block
28
+ # If the user passed a block, we'll assume they either want:
29
+ # field :foo {|model| ...}
30
+ # or field {|model, hash| ...}
31
+ #
32
+ if packer_class || traits.any?
33
+ raise(
34
+ FieldArgumentError,
35
+ 'When passing a block to Sequel::Packer::field, either pass the ' +
36
+ 'name of field as a single argument (e.g., field(:foo) ' +
37
+ '{|model| ...}), or nothing at all to perform arbitrary ' +
38
+ 'modifications of the final hash (e.g., field {|model, hash| ' +
39
+ '...}).',
40
+ )
41
+ end
42
+
43
+ arity = block.arity
44
+
45
+ # When using Symbol.to_proc (field(:foo, &:calculate_foo)), the block has arity -1.
46
+ if field_name && arity != 1 && arity != -1
47
+ raise(
48
+ FieldArgumentError,
49
+ "The block used to define :#{field_name} must accept exactly " +
50
+ 'one argument.',
51
+ )
52
+ end
53
+
54
+ if !field_name && arity != 2
55
+ raise(
56
+ FieldArgumentError,
57
+ 'When passing an arbitrary block to Sequel::Packer::field, the ' +
58
+ 'block must accept exactly two arguments: the model and the ' +
59
+ 'partially packed hash.',
60
+ )
61
+ end
62
+ else
63
+ # In this part of the if, block is not defined
64
+
65
+ if !field_name
66
+ # Note that this error isn't technically true, but usage of the
67
+ # field {|model, hash| ...} variant is likely pretty rare.
68
+ raise(
69
+ FieldArgumentError,
70
+ 'Must pass a field name to Sequel::Packer::field.',
71
+ )
72
+ end
73
+
74
+ if model.associations.include?(field_name) && !packer_class
75
+ raise(
76
+ InvalidAssociationPackerError,
77
+ "#{field_name} is an association of #{model}. You must also " +
78
+ 'pass a Sequel::Packer class to be used when serializing ' +
79
+ 'this association.',
80
+ )
81
+ end
82
+ end
83
+ end
84
+
85
+ # Performs various checks when using
86
+ # field(association, packer_class, *traits)
87
+ # or
88
+ # set_association_packer(association, packer_class, *traits)
89
+ def self.check_association_packer(
90
+ model,
91
+ association,
92
+ packer_class,
93
+ traits
94
+ )
95
+ if !model.associations.include?(association)
96
+ raise(
97
+ AssociationDoesNotExistError,
98
+ "The association :#{association} does not exist on #{model}.",
99
+ )
100
+ end
101
+
102
+ if !packer_class || !(packer_class < Sequel::Packer)
103
+ raise(
104
+ InvalidAssociationPackerError,
105
+ 'You must pass a Sequel::Packer class to use when packing the ' +
106
+ ":#{association} association. #{packer_class} is not a " +
107
+ "subclass of Sequel::Packer."
108
+ )
109
+ end
110
+
111
+ association_model =
112
+ model.association_reflections[association].associated_class
113
+ packer_class_model = packer_class.instance_variable_get(:@model)
114
+
115
+ if !(association_model <= packer_class_model)
116
+ raise(
117
+ InvalidAssociationPackerError,
118
+ "Model for association packer (#{packer_class_model}) " +
119
+ "doesn't match model for the #{association} association " +
120
+ "(#{association_model})",
121
+ )
122
+ end
123
+
124
+ packer_class_traits = packer_class.instance_variable_get(:@class_traits)
125
+ traits.each do |trait|
126
+ if !packer_class_traits.key?(trait)
127
+ raise(
128
+ UnknownTraitError,
129
+ "Trait :#{trait} isn't defined for #{packer_class} used to " +
130
+ "pack #{association} association.",
131
+ )
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -1,5 +1,5 @@
1
1
  module Sequel
2
2
  class Packer
3
- VERSION = "0.2.0"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
data/lib/sequel/packer.rb CHANGED
@@ -4,11 +4,15 @@ module Sequel
4
4
  class FieldArgumentError < ArgumentError; end
5
5
  # Must declare a model with `model MyModel` before calling field.
6
6
  class ModelNotYetDeclaredError < StandardError; end
7
+ class AssociationDoesNotExistError < StandardError; end
8
+ class InvalidAssociationPackerError < StandardError; end
9
+ class UnknownTraitError < StandardError; end
7
10
 
8
11
  def self.inherited(subclass)
9
- subclass.instance_variable_set(:@fields, [])
10
- subclass.instance_variable_set(:@traits, {})
11
- subclass.instance_variable_set(:@eager_hash, nil)
12
+ subclass.instance_variable_set(:@class_fields, [])
13
+ subclass.instance_variable_set(:@class_traits, {})
14
+ subclass.instance_variable_set(:@class_packers, {})
15
+ subclass.instance_variable_set(:@class_eager_hash, nil)
12
16
  end
13
17
 
14
18
  def self.model(klass)
@@ -34,22 +38,31 @@ module Sequel
34
38
  ARBITRARY_MODIFICATION_FIELD = :arbitrary_modification_field
35
39
 
36
40
  def self.field(field_name=nil, packer_class=nil, *traits, &block)
37
- validate_field_args(field_name, packer_class, *traits, &block)
38
- field_type = determine_field_type(field_name, packer_class, &block)
41
+ Validation.check_field_arguments(
42
+ @model, field_name, packer_class, traits, &block)
43
+ field_type = determine_field_type(field_name, packer_class, block)
39
44
 
40
- @fields << {
45
+ if field_type == ASSOCIATION_FIELD
46
+ set_association_packer(field_name, packer_class, *traits)
47
+ end
48
+
49
+ @class_fields << {
41
50
  type: field_type,
42
51
  name: field_name,
43
- packer: packer_class,
44
- packer_traits: traits,
45
52
  block: block,
46
53
  }
47
54
  end
48
55
 
56
+ def self.set_association_packer(association, packer_class, *traits)
57
+ Validation.check_association_packer(
58
+ @model, association, packer_class, traits)
59
+ @class_packers[association] = [packer_class, traits]
60
+ end
61
+
49
62
  private_class_method def self.determine_field_type(
50
- field_name=nil,
51
- packer_class=nil,
52
- &block
63
+ field_name,
64
+ packer_class,
65
+ block
53
66
  )
54
67
  if block
55
68
  if field_name
@@ -66,175 +79,65 @@ module Sequel
66
79
  end
67
80
  end
68
81
 
69
- private_class_method def self.validate_field_args(
70
- field_name=nil,
71
- packer_class=nil,
72
- *traits,
73
- &block
74
- )
75
- fail ModelNotYetDeclaredError if !@model
76
-
77
- # This check applies to all invocations:
78
- if field_name && !field_name.is_a?(Symbol) && !field_name.is_a?(String)
79
- raise(
80
- FieldArgumentError,
81
- 'Field name passed to Sequel::Packer::field must be a Symbol or ' +
82
- 'a String.',
83
- )
84
- end
85
-
86
- if block
87
- # If the user passed a block, we'll assume they either want:
88
- # field :foo {|model| ...}
89
- # or field {|model, hash| ...}
90
- #
91
- if packer_class || traits.any?
92
- raise(
93
- FieldArgumentError,
94
- 'When passing a block to Sequel::Packer::field, either pass the ' +
95
- 'name of field as a single argument (e.g., field(:foo) ' +
96
- '{|model| ...}), or nothing at all to perform arbitrary ' +
97
- 'modifications of the final hash (e.g., field {|model, hash| ' +
98
- '...}).',
99
- )
100
- end
101
-
102
- arity = block.arity
103
-
104
- # When using Symbol.to_proc (field(:foo, &:calculate_foo)), the block has arity -1.
105
- if field_name && arity != 1 && arity != -1
106
- raise(
107
- FieldArgumentError,
108
- "The block used to define :#{field_name} must accept exactly " +
109
- 'one argument.',
110
- )
111
- end
112
-
113
- if !field_name && arity != 2
114
- raise(
115
- FieldArgumentError,
116
- 'When passing an arbitrary block to Sequel::Packer::field, the ' +
117
- 'block must accept exactly two arguments: the model and the ' +
118
- 'partially packed hash.',
119
- )
120
- end
121
- else
122
- # In this part of the if, block is not defined
123
-
124
- if !field_name
125
- # Note that this error isn't technically true, but usage of the
126
- # field {|model, hash| ...} variant is likely pretty rare.
127
- raise(
128
- FieldArgumentError,
129
- 'Must pass a field name to Sequel::Packer::field.',
130
- )
131
- end
132
-
133
- if packer_class || traits.any?
134
- if !@model.associations.include?(field_name)
135
- raise(
136
- FieldArgumentError,
137
- 'Passing multiple arguments to Sequel::Packer::field ' +
138
- 'is used to serialize associations with designated ' +
139
- "packers, but the association #{field_name} does not " +
140
- "exist on #{@model}.",
141
- )
142
- end
143
-
144
- if !(packer_class < Sequel::Packer)
145
- raise(
146
- FieldArgumentError,
147
- 'When declaring the serialization behavior for an ' +
148
- 'association, the second argument must be a Sequel::Packer ' +
149
- "subclass. #{packer_class} is not a subclass of " +
150
- 'Sequel::Packer.',
151
- )
152
- end
153
-
154
- association_model =
155
- @model.association_reflections[field_name].associated_class
156
- packer_class_model = packer_class.instance_variable_get(:@model)
157
-
158
- if !(association_model <= packer_class_model)
159
- raise(
160
- FieldArgumentError,
161
- "Model for association packer (#{packer_class_model}) " +
162
- "doesn't match model for the #{field_name} association " +
163
- "(#{association_model})",
164
- )
165
- end
166
-
167
- packer_class_traits = packer_class.instance_variable_get(:@traits)
168
- traits.each do |trait|
169
- if !packer_class_traits.key?(trait)
170
- raise(
171
- FieldArgumentError,
172
- "Trait :#{trait} isn't defined for #{packer_class} used to " +
173
- "pack #{field_name} association.",
174
- )
175
- end
176
- end
177
- else
178
- if @model.associations.include?(field_name)
179
- raise(
180
- FieldArgumentError,
181
- 'When declaring a field for a model association, you must ' +
182
- 'also pass a Sequel::Packer class to use as the second ' +
183
- 'argument to field.',
184
- )
185
- end
186
- end
187
- end
188
- end
189
-
190
82
  def self.trait(name, &block)
191
- raise ArgumentError, "Trait :#{name} already defined" if @traits.key?(name)
83
+ if @class_traits.key?(name)
84
+ raise ArgumentError, "Trait :#{name} already defined"
85
+ end
192
86
  if !block_given?
193
87
  raise ArgumentError, 'Must give a block when defining a trait'
194
88
  end
195
- @traits[name] = block
89
+ @class_traits[name] = block
196
90
  end
197
91
 
198
92
  def self.eager(*associations)
199
- @eager_hash = EagerHash.merge!(
200
- @eager_hash,
93
+ @class_eager_hash = EagerHash.merge!(
94
+ @class_eager_hash,
201
95
  EagerHash.normalize_eager_args(*associations),
202
96
  )
203
97
  end
204
98
 
205
99
  def initialize(*traits)
206
- @packers = nil
207
- @fields = traits.any? ? packer_fields.dup : packer_fields
208
- @eager_hash = traits.any? ? EagerHash.deep_dup(packer_eager_hash) : packer_eager_hash
100
+ @subpackers = nil
101
+
102
+ # If there aren't any traits, we can just re-use the class variables.
103
+ if traits.empty?
104
+ @instance_fields = class_fields
105
+ @instance_packers = class_packers
106
+ @instance_eager_hash = class_eager_hash
107
+ else
108
+ @instance_fields = class_fields.dup
109
+ @instance_packers = class_packers.dup
110
+ @instance_eager_hash = EagerHash.deep_dup(class_eager_hash)
111
+ end
209
112
 
113
+ # Evaluate trait blocks, which might add new fields to @instance_fields,
114
+ # new packers to @instance_packers, and/or new associations to
115
+ # @instance_eager_hash.
210
116
  traits.each do |trait|
211
- trait_block = trait_blocks[trait]
117
+ trait_block = class_traits[trait]
212
118
  if !trait_block
213
- raise ArgumentError, "Unknown trait for #{self.class}: :#{trait}"
119
+ raise UnknownTraitError, "Unknown trait for #{self.class}: :#{trait}"
214
120
  end
215
121
 
216
122
  self.instance_exec(&trait_block)
217
123
  end
218
124
 
219
- @fields.each do |field_options|
220
- if field_options[:type] == ASSOCIATION_FIELD
221
- association = field_options[:name]
222
- association_packer =
223
- field_options[:packer].new(*field_options[:packer_traits])
125
+ # Create all the subpackers, and merge in their eager hashes.
126
+ @instance_packers.each do |association, (packer_class, traits)|
127
+ association_packer = packer_class.new(*traits)
224
128
 
225
- @packers ||= {}
226
- @packers[association] = association_packer
129
+ @subpackers ||= {}
130
+ @subpackers[association] = association_packer
227
131
 
228
- @eager_hash = EagerHash.merge!(
229
- @eager_hash,
230
- {association => association_packer.send(:eager_hash)},
231
- )
232
- end
132
+ @instance_eager_hash = EagerHash.merge!(
133
+ @instance_eager_hash,
134
+ {association => association_packer.send(:eager_hash)},
135
+ )
233
136
  end
234
137
  end
235
138
 
236
139
  def pack(dataset)
237
- dataset = dataset.eager(@eager_hash) if @eager_hash
140
+ dataset = dataset.eager(@instance_eager_hash) if @instance_eager_hash
238
141
  models = dataset.all
239
142
  pack_models(models)
240
143
  end
@@ -242,26 +145,19 @@ module Sequel
242
145
  def pack_model(model)
243
146
  h = {}
244
147
 
245
- @fields.each do |field_options|
148
+ @instance_fields.each do |field_options|
246
149
  field_name = field_options[:name]
247
150
 
248
151
  case field_options[:type]
249
152
  when METHOD_FIELD
250
153
  h[field_name] = model.send(field_name)
251
154
  when BLOCK_FIELD
252
- h[field_name] = field_options[:block].call(model)
155
+ h[field_name] = instance_exec(model, &field_options[:block])
253
156
  when ASSOCIATION_FIELD
254
157
  associated_objects = model.send(field_name)
255
-
256
- if !associated_objects
257
- h[field_name] = nil
258
- elsif associated_objects.is_a?(Array)
259
- h[field_name] = @packers[field_name].pack_models(associated_objects)
260
- else
261
- h[field_name] = @packers[field_name].pack_model(associated_objects)
262
- end
158
+ h[field_name] = pack_association(field_name, associated_objects)
263
159
  when ARBITRARY_MODIFICATION_FIELD
264
- field_options[:block].call(model, h)
160
+ instance_exec(model, h, &field_options[:block])
265
161
  end
266
162
  end
267
163
 
@@ -272,48 +168,77 @@ module Sequel
272
168
  models.map {|m| pack_model(m)}
273
169
  end
274
170
 
171
+ def pack_association(association, associated_models)
172
+ return nil if !associated_models
173
+
174
+ packer = @subpackers[association]
175
+
176
+ if associated_models.is_a?(Array)
177
+ packer.pack_models(associated_models)
178
+ else
179
+ packer.pack_model(associated_models)
180
+ end
181
+ end
182
+
275
183
  private
276
184
 
277
185
  def field(field_name=nil, packer_class=nil, *traits, &block)
278
186
  klass = self.class
279
- klass.send(
280
- :validate_field_args, field_name, packer_class, *traits, &block)
187
+ model = klass.instance_variable_get(:@model)
188
+
189
+ Validation.check_field_arguments(
190
+ model, field_name, packer_class, traits, &block)
281
191
  field_type =
282
- klass.send(:determine_field_type, field_name, packer_class, &block)
192
+ klass.send(:determine_field_type, field_name, packer_class, block)
193
+
194
+ if field_type == ASSOCIATION_FIELD
195
+ set_association_packer(field_name, packer_class, *traits)
196
+ end
283
197
 
284
- @fields << {
198
+ @instance_fields << {
285
199
  type: field_type,
286
200
  name: field_name,
287
- packer: packer_class,
288
- packer_traits: traits,
289
201
  block: block,
290
202
  }
291
203
  end
292
204
 
205
+ def set_association_packer(association, packer_class, *traits)
206
+ model = self.class.instance_variable_get(:@model)
207
+ Validation.check_association_packer(
208
+ model, association, packer_class, traits)
209
+
210
+ @instance_packers[association] = [packer_class, traits]
211
+ end
212
+
293
213
  def eager_hash
294
- @eager_hash
214
+ @instance_eager_hash
295
215
  end
296
216
 
297
217
  def eager(*associations)
298
- @eager_hash = EagerHash.merge!(
299
- @eager_hash,
218
+ @instance_eager_hash = EagerHash.merge!(
219
+ @instance_eager_hash,
300
220
  EagerHash.normalize_eager_args(*associations),
301
221
  )
302
222
  end
303
223
 
304
- def packer_fields
305
- self.class.instance_variable_get(:@fields)
224
+ def class_fields
225
+ self.class.instance_variable_get(:@class_fields)
226
+ end
227
+
228
+ def class_eager_hash
229
+ self.class.instance_variable_get(:@class_eager_hash)
306
230
  end
307
231
 
308
- def packer_eager_hash
309
- self.class.instance_variable_get(:@eager_hash)
232
+ def class_packers
233
+ self.class.instance_variable_get(:@class_packers)
310
234
  end
311
235
 
312
- def trait_blocks
313
- self.class.instance_variable_get(:@traits)
236
+ def class_traits
237
+ self.class.instance_variable_get(:@class_traits)
314
238
  end
315
239
  end
316
240
  end
317
241
 
318
242
  require 'sequel/packer/eager_hash'
243
+ require 'sequel/packer/validation'
319
244
  require "sequel/packer/version"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel-packer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Julius Martinez
@@ -128,6 +128,7 @@ files:
128
128
  - bin/setup
129
129
  - lib/sequel/packer.rb
130
130
  - lib/sequel/packer/eager_hash.rb
131
+ - lib/sequel/packer/validation.rb
131
132
  - lib/sequel/packer/version.rb
132
133
  - sequel-packer.gemspec
133
134
  homepage: https://github.com/PaulJuliusMartinez/sequel-packer