Module: Sequel::Packer::Validation

Defined in:
lib/sequel/packer/validation.rb

Class Method Summary collapse

Class Method Details

.check_association_packer(model, association, packer_class, traits) ⇒ Object

Performs various checks when using

field(association, packer_class, *traits)
or
set_association_packer(association, packer_class, *traits)


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/sequel/packer/validation.rb', line 102

def self.check_association_packer(
  model,
  association,
  packer_class,
  traits
)
  if !model.associations.include?(association)
    raise(
      AssociationDoesNotExistError,
      "The association :#{association} does not exist on #{model}.",
    )
  end

  if !packer_class || !(packer_class < Sequel::Packer)
    raise(
      InvalidAssociationPackerError,
      'You must pass a Sequel::Packer class to use when packing the ' +
        ":#{association} association. #{packer_class} is not a " +
        "subclass of Sequel::Packer."
    )
  end

  association_model =
    model.association_reflections[association].associated_class
  packer_class_model = packer_class.instance_variable_get(:@model)

  if !(association_model <= packer_class_model)
    raise(
      InvalidAssociationPackerError,
      "Model for association packer (#{packer_class_model}) " +
        "doesn't match model for the #{association} association " +
        "(#{association_model})",
    )
  end

  packer_class_traits = packer_class.instance_variable_get(:@class_traits)
  traits.each do |trait|
    if !packer_class_traits.key?(trait)
      raise(
        UnknownTraitError,
        "Trait :#{trait} isn't defined for #{packer_class} used to " +
          "pack #{association} association.",
      )
    end
  end
end

.check_field_arguments(model, field_name, packer_class, traits, &block) ⇒ Object

Cheks for common errors when using the field method. Additional checks around the packer class and traits occur in check_association_packer.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/sequel/packer/validation.rb', line 17

def self.check_field_arguments(
  model,
  field_name,
  packer_class,
  traits,
  &block
)
  fail ModelNotYetDeclaredError if !model

  # This check applies to all invocations:
  if field_name && !field_name.is_a?(Symbol) && !field_name.is_a?(String)
    raise(
      FieldArgumentError,
      'Field name passed to Sequel::Packer::field must be a Symbol or ' +
        'a String.',
    )
  end

  if block
    # If the user passed a block, we'll assume they either want:
    #     field :foo {|model| ...}
    # or  field {|model, hash| ...}
    #
    if packer_class || traits.any?
      raise(
        FieldArgumentError,
        'When passing a block to Sequel::Packer::field, either pass the ' +
          'name of field as a single argument (e.g., field(:foo) ' +
          '{|model| ...}), or nothing at all to perform arbitrary ' +
          'modifications of the final hash (e.g., field {|model, hash| ' +
          '...}).',
      )
    end

    arity = block.arity

    # If passing a literal block, as in `field(:foo) {|model| ... }`, the block
    # will have arity 1 (1 required argument).
    #
    # When using Symbol.to_proc via `field(:foo, &:calculate_foo)`, the arity of
    # the block depends which version Ruby is running. Before Ruby 3 the arity of
    # the proc returned by `&:sym` had arity -1, but was updated to be -2 in Ruby 3.
    if field_name && arity != 1 && arity != SYM_TO_PROC_ARITY
      raise(
        FieldArgumentError,
        "The block used to define :#{field_name} must accept exactly " +
          'one argument.',
      )
    end

    if !field_name && arity != 2
      raise(
        FieldArgumentError,
        'When passing an arbitrary block to Sequel::Packer::field, the ' +
          'block must accept exactly two arguments: the model and the ' +
          'partially packed hash.',
      )
    end
  else
    # In this part of the if, block is not defined

    if !field_name
      # Note that this error isn't technically true, but usage of the
      # field {|model, hash| ...} variant is likely pretty rare.
      raise(
        FieldArgumentError,
        'Must pass a field name to Sequel::Packer::field.',
      )
    end

    if model.associations.include?(field_name) && !packer_class
      raise(
        InvalidAssociationPackerError,
        "#{field_name} is an association of #{model}. You must also " +
          'pass a Sequel::Packer class to be used when serializing ' +
          'this association.',
      )
    end
  end
end