sequel-packer 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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