sequel 2.11.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. data/CHANGELOG +168 -0
  2. data/README.rdoc +77 -95
  3. data/Rakefile +100 -80
  4. data/bin/sequel +2 -1
  5. data/doc/advanced_associations.rdoc +23 -32
  6. data/doc/cheat_sheet.rdoc +23 -40
  7. data/doc/dataset_filtering.rdoc +6 -6
  8. data/doc/prepared_statements.rdoc +22 -22
  9. data/doc/release_notes/2.12.0.txt +534 -0
  10. data/doc/schema.rdoc +3 -1
  11. data/doc/sharding.rdoc +8 -8
  12. data/doc/virtual_rows.rdoc +65 -0
  13. data/lib/sequel.rb +1 -1
  14. data/lib/{sequel_core → sequel}/adapters/ado.rb +3 -3
  15. data/lib/{sequel_core → sequel}/adapters/db2.rb +0 -0
  16. data/lib/{sequel_core → sequel}/adapters/dbi.rb +1 -1
  17. data/lib/{sequel_core → sequel}/adapters/do.rb +9 -5
  18. data/lib/{sequel_core → sequel}/adapters/do/mysql.rb +1 -1
  19. data/lib/{sequel_core → sequel}/adapters/do/postgres.rb +1 -1
  20. data/lib/{sequel_core → sequel}/adapters/do/sqlite.rb +1 -1
  21. data/lib/{sequel_core → sequel}/adapters/firebird.rb +84 -80
  22. data/lib/{sequel_core → sequel}/adapters/informix.rb +1 -1
  23. data/lib/{sequel_core → sequel}/adapters/jdbc.rb +21 -14
  24. data/lib/{sequel_core → sequel}/adapters/jdbc/h2.rb +14 -13
  25. data/lib/{sequel_core → sequel}/adapters/jdbc/mysql.rb +1 -1
  26. data/lib/{sequel_core → sequel}/adapters/jdbc/oracle.rb +1 -1
  27. data/lib/{sequel_core → sequel}/adapters/jdbc/postgresql.rb +1 -1
  28. data/lib/{sequel_core → sequel}/adapters/jdbc/sqlite.rb +1 -1
  29. data/lib/{sequel_core → sequel}/adapters/mysql.rb +60 -39
  30. data/lib/{sequel_core → sequel}/adapters/odbc.rb +8 -4
  31. data/lib/{sequel_core → sequel}/adapters/openbase.rb +0 -0
  32. data/lib/{sequel_core → sequel}/adapters/oracle.rb +38 -7
  33. data/lib/{sequel_core → sequel}/adapters/postgres.rb +24 -24
  34. data/lib/{sequel_core → sequel}/adapters/shared/mssql.rb +5 -5
  35. data/lib/{sequel_core → sequel}/adapters/shared/mysql.rb +126 -71
  36. data/lib/{sequel_core → sequel}/adapters/shared/oracle.rb +7 -10
  37. data/lib/{sequel_core → sequel}/adapters/shared/postgres.rb +159 -125
  38. data/lib/{sequel_core → sequel}/adapters/shared/progress.rb +1 -2
  39. data/lib/{sequel_core → sequel}/adapters/shared/sqlite.rb +72 -67
  40. data/lib/{sequel_core → sequel}/adapters/sqlite.rb +11 -7
  41. data/lib/{sequel_core → sequel}/adapters/utils/date_format.rb +0 -0
  42. data/lib/{sequel_core → sequel}/adapters/utils/stored_procedures.rb +0 -0
  43. data/lib/{sequel_core → sequel}/adapters/utils/unsupported.rb +19 -0
  44. data/lib/{sequel_core → sequel}/connection_pool.rb +7 -5
  45. data/lib/sequel/core.rb +221 -0
  46. data/lib/{sequel_core → sequel}/core_sql.rb +91 -49
  47. data/lib/{sequel_core → sequel}/database.rb +264 -149
  48. data/lib/{sequel_core/schema/generator.rb → sequel/database/schema_generator.rb} +6 -2
  49. data/lib/{sequel_core/database/schema.rb → sequel/database/schema_methods.rb} +12 -12
  50. data/lib/sequel/database/schema_sql.rb +224 -0
  51. data/lib/{sequel_core → sequel}/dataset.rb +78 -236
  52. data/lib/{sequel_core → sequel}/dataset/convenience.rb +99 -61
  53. data/lib/{sequel_core/object_graph.rb → sequel/dataset/graph.rb} +16 -14
  54. data/lib/{sequel_core → sequel}/dataset/prepared_statements.rb +1 -1
  55. data/lib/{sequel_core → sequel}/dataset/sql.rb +150 -99
  56. data/lib/sequel/deprecated.rb +593 -0
  57. data/lib/sequel/deprecated_migration.rb +91 -0
  58. data/lib/sequel/exceptions.rb +48 -0
  59. data/lib/sequel/extensions/blank.rb +42 -0
  60. data/lib/{sequel_model → sequel/extensions}/inflector.rb +8 -1
  61. data/lib/{sequel_core → sequel/extensions}/migration.rb +1 -1
  62. data/lib/{sequel_core/dataset → sequel/extensions}/pagination.rb +0 -0
  63. data/lib/{sequel_core → sequel/extensions}/pretty_table.rb +7 -0
  64. data/lib/{sequel_core/dataset → sequel/extensions}/query.rb +7 -0
  65. data/lib/sequel/extensions/string_date_time.rb +47 -0
  66. data/lib/sequel/metaprogramming.rb +43 -0
  67. data/lib/sequel/model.rb +110 -0
  68. data/lib/sequel/model/associations.rb +1300 -0
  69. data/lib/sequel/model/base.rb +937 -0
  70. data/lib/sequel/model/deprecated.rb +204 -0
  71. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  72. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  73. data/lib/sequel/model/deprecated_validations.rb +388 -0
  74. data/lib/sequel/model/errors.rb +39 -0
  75. data/lib/{sequel_model → sequel/model}/exceptions.rb +4 -4
  76. data/lib/sequel/model/inflections.rb +208 -0
  77. data/lib/sequel/model/plugins.rb +76 -0
  78. data/lib/sequel/plugins/caching.rb +122 -0
  79. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  80. data/lib/sequel/plugins/schema.rb +53 -0
  81. data/lib/sequel/plugins/serialization.rb +117 -0
  82. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  83. data/lib/sequel/plugins/validation_class_methods.rb +384 -0
  84. data/lib/sequel/plugins/validation_helpers.rb +150 -0
  85. data/lib/{sequel_core → sequel}/sql.rb +125 -190
  86. data/lib/{sequel_core → sequel}/version.rb +2 -1
  87. data/lib/sequel_core.rb +1 -172
  88. data/lib/sequel_model.rb +1 -91
  89. data/spec/adapters/firebird_spec.rb +5 -5
  90. data/spec/adapters/informix_spec.rb +1 -1
  91. data/spec/adapters/mysql_spec.rb +128 -42
  92. data/spec/adapters/oracle_spec.rb +47 -19
  93. data/spec/adapters/postgres_spec.rb +64 -52
  94. data/spec/adapters/spec_helper.rb +1 -1
  95. data/spec/adapters/sqlite_spec.rb +12 -17
  96. data/spec/{sequel_core → core}/connection_pool_spec.rb +10 -10
  97. data/spec/{sequel_core → core}/core_ext_spec.rb +19 -19
  98. data/spec/{sequel_core → core}/core_sql_spec.rb +68 -71
  99. data/spec/{sequel_core → core}/database_spec.rb +135 -99
  100. data/spec/{sequel_core → core}/dataset_spec.rb +398 -242
  101. data/spec/{sequel_core → core}/expression_filters_spec.rb +13 -13
  102. data/spec/core/migration_spec.rb +263 -0
  103. data/spec/{sequel_core → core}/object_graph_spec.rb +10 -10
  104. data/spec/{sequel_core → core}/pretty_table_spec.rb +2 -2
  105. data/spec/{sequel_core → core}/schema_generator_spec.rb +0 -0
  106. data/spec/{sequel_core → core}/schema_spec.rb +8 -10
  107. data/spec/{sequel_core → core}/spec_helper.rb +29 -2
  108. data/spec/{sequel_core → core}/version_spec.rb +0 -0
  109. data/spec/extensions/blank_spec.rb +67 -0
  110. data/spec/extensions/caching_spec.rb +201 -0
  111. data/spec/{sequel_model/hooks_spec.rb → extensions/hook_class_methods_spec.rb} +8 -23
  112. data/spec/{sequel_model → extensions}/inflector_spec.rb +3 -0
  113. data/spec/{sequel_core → extensions}/migration_spec.rb +4 -4
  114. data/spec/extensions/pagination_spec.rb +99 -0
  115. data/spec/extensions/pretty_table_spec.rb +91 -0
  116. data/spec/extensions/query_spec.rb +85 -0
  117. data/spec/{sequel_model → extensions}/schema_spec.rb +22 -1
  118. data/spec/extensions/serialization_spec.rb +109 -0
  119. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  120. data/spec/{sequel_model → extensions}/spec_helper.rb +13 -4
  121. data/spec/extensions/string_date_time_spec.rb +93 -0
  122. data/spec/{sequel_model/validations_spec.rb → extensions/validation_class_methods_spec.rb} +15 -103
  123. data/spec/extensions/validation_helpers_spec.rb +291 -0
  124. data/spec/integration/dataset_test.rb +31 -0
  125. data/spec/integration/eager_loader_test.rb +17 -30
  126. data/spec/integration/schema_test.rb +8 -5
  127. data/spec/integration/spec_helper.rb +17 -0
  128. data/spec/integration/transaction_test.rb +68 -0
  129. data/spec/{sequel_model → model}/association_reflection_spec.rb +0 -0
  130. data/spec/{sequel_model → model}/associations_spec.rb +23 -10
  131. data/spec/{sequel_model → model}/base_spec.rb +29 -20
  132. data/spec/{sequel_model → model}/caching_spec.rb +16 -14
  133. data/spec/{sequel_model → model}/dataset_methods_spec.rb +0 -0
  134. data/spec/{sequel_model → model}/eager_loading_spec.rb +8 -8
  135. data/spec/model/hooks_spec.rb +472 -0
  136. data/spec/model/inflector_spec.rb +126 -0
  137. data/spec/{sequel_model → model}/model_spec.rb +25 -20
  138. data/spec/model/plugins_spec.rb +142 -0
  139. data/spec/{sequel_model → model}/record_spec.rb +121 -62
  140. data/spec/model/schema_spec.rb +92 -0
  141. data/spec/model/spec_helper.rb +124 -0
  142. data/spec/model/validations_spec.rb +1080 -0
  143. metadata +136 -107
  144. data/lib/sequel_core/core_ext.rb +0 -217
  145. data/lib/sequel_core/dataset/callback.rb +0 -13
  146. data/lib/sequel_core/dataset/schema.rb +0 -15
  147. data/lib/sequel_core/deprecated.rb +0 -26
  148. data/lib/sequel_core/exceptions.rb +0 -44
  149. data/lib/sequel_core/schema.rb +0 -2
  150. data/lib/sequel_core/schema/sql.rb +0 -325
  151. data/lib/sequel_model/association_reflection.rb +0 -267
  152. data/lib/sequel_model/associations.rb +0 -499
  153. data/lib/sequel_model/base.rb +0 -539
  154. data/lib/sequel_model/caching.rb +0 -82
  155. data/lib/sequel_model/dataset_methods.rb +0 -26
  156. data/lib/sequel_model/eager_loading.rb +0 -370
  157. data/lib/sequel_model/hooks.rb +0 -101
  158. data/lib/sequel_model/plugins.rb +0 -62
  159. data/lib/sequel_model/record.rb +0 -568
  160. data/lib/sequel_model/schema.rb +0 -49
  161. data/lib/sequel_model/validations.rb +0 -429
  162. data/spec/sequel_model/plugins_spec.rb +0 -80
@@ -1,49 +0,0 @@
1
- module Sequel
2
- class Model
3
- # Creates table, using the column information from set_schema.
4
- def self.create_table
5
- db.create_table(table_name, :generator=>@schema)
6
- @db_schema = get_db_schema(true)
7
- columns
8
- end
9
-
10
- # Drops the table if it exists and then runs create_table. Should probably
11
- # not be used except in testing.
12
- def self.create_table!
13
- drop_table rescue nil
14
- create_table
15
- end
16
-
17
- # Drops table.
18
- def self.drop_table
19
- db.drop_table(table_name)
20
- end
21
-
22
- # Returns table schema created with set_schema for direct descendant of Model.
23
- # Does not retreive schema information from the database, see db_schema if you
24
- # want that.
25
- def self.schema
26
- @schema || (superclass.schema unless superclass == Model)
27
- end
28
-
29
- # Defines a table schema (see Schema::Generator for more information).
30
- #
31
- # This is only needed if you want to use the create_table/create_table! methods.
32
- # Will also set the dataset if you provide a name, as well as setting
33
- # the primary key if you defined one in the passed block.
34
- #
35
- # In general, it is a better idea to use migrations for production code, as
36
- # migrations allow changes to existing schema. set_schema is mostly useful for
37
- # test code or simple examples.
38
- def self.set_schema(name = nil, &block)
39
- set_dataset(db[name]) if name
40
- @schema = Schema::Generator.new(db, &block)
41
- set_primary_key(@schema.primary_key_name) if @schema.primary_key_name
42
- end
43
-
44
- # Returns true if table exists, false otherwise.
45
- def self.table_exists?
46
- db.table_exists?(table_name)
47
- end
48
- end
49
- end
@@ -1,429 +0,0 @@
1
- module Sequel
2
- class Model
3
- # Validations without an :if option are always run
4
- DEFAULT_VALIDATION_IF_PROC = proc{true}
5
-
6
- # The Validation module houses a couple of classes used by Sequel's
7
- # validation code.
8
- module Validation
9
- # Validation::Errors represents validation errors, a simple hash subclass
10
- # with a few convenience methods.
11
- class Errors < ::Hash
12
- # Assign an array of messages for each attribute on access
13
- def initialize
14
- super{|h,k| h[k] = []}
15
- end
16
-
17
- # Adds an error for the given attribute.
18
- def add(att, msg)
19
- self[att] << msg
20
- end
21
-
22
- # Return the total number of error messages.
23
- def count
24
- full_messages.length
25
- end
26
-
27
- # Returns an array of fully-formatted error messages.
28
- def full_messages
29
- inject([]) do |m, kv|
30
- att, errors = *kv
31
- errors.each {|e| m << "#{Array(att).join(' and ')} #{e}"}
32
- m
33
- end
34
- end
35
-
36
- # Returns the array of errors for the given attribute, or nil
37
- # if there are no errors for the attribute.
38
- def on(att)
39
- self[att] if include?(att)
40
- end
41
- end
42
-
43
- # The Generator class is used to generate validation definitions using
44
- # the validates {} idiom.
45
- class Generator
46
- # Initializes a new generator.
47
- def initialize(receiver ,&block)
48
- @receiver = receiver
49
- instance_eval(&block)
50
- end
51
-
52
- # Delegates method calls to the receiver by calling receiver.validates_xxx.
53
- def method_missing(m, *args, &block)
54
- @receiver.send(:"validates_#{m}", *args, &block)
55
- end
56
- end
57
- end
58
-
59
- # Returns true if validations are defined.
60
- def self.has_validations?
61
- !validations.empty?
62
- end
63
-
64
- # Instructs the model to skip validations defined in superclasses
65
- def self.skip_superclass_validations
66
- @skip_superclass_validations = true
67
- end
68
-
69
- # Defines validations by converting a longhand block into a series of
70
- # shorthand definitions. For example:
71
- #
72
- # class MyClass < Sequel::Model
73
- # validates do
74
- # length_of :name, :minimum => 6
75
- # length_of :password, :minimum => 8
76
- # end
77
- # end
78
- #
79
- # is equivalent to:
80
- # class MyClass < Sequel::Model
81
- # validates_length_of :name, :minimum => 6
82
- # validates_length_of :password, :minimum => 8
83
- # end
84
- def self.validates(&block)
85
- Validation::Generator.new(self, &block)
86
- end
87
-
88
- # Validates the given instance.
89
- def self.validate(o)
90
- if superclass.respond_to?(:validate) && !@skip_superclass_validations
91
- superclass.validate(o)
92
- end
93
- validations.each do |att, procs|
94
- v = case att
95
- when Array
96
- att.collect{|a| o.send(a)}
97
- else
98
- o.send(att)
99
- end
100
- procs.each {|tag, p| p.call(o, att, v)}
101
- end
102
- end
103
-
104
- # Validates acceptance of an attribute. Just checks that the value
105
- # is equal to the :accept option. This method is unique in that
106
- # :allow_nil is assumed to be true instead of false.
107
- #
108
- # Possible Options:
109
- # * :accept - The value required for the object to be valid (default: '1')
110
- # * :message - The message to use (default: 'is not accepted')
111
- def self.validates_acceptance_of(*atts)
112
- opts = {
113
- :message => 'is not accepted',
114
- :allow_nil => true,
115
- :accept => '1',
116
- :tag => :acceptance,
117
- }.merge!(atts.extract_options!)
118
- atts << opts
119
- validates_each(*atts) do |o, a, v|
120
- o.errors[a] << opts[:message] unless v == opts[:accept]
121
- end
122
- end
123
-
124
- # Validates confirmation of an attribute. Checks that the object has
125
- # a _confirmation value matching the current value. For example:
126
- #
127
- # validates_confirmation_of :blah
128
- #
129
- # Just makes sure that object.blah = object.blah_confirmation. Often used for passwords
130
- # or email addresses on web forms.
131
- #
132
- # Possible Options:
133
- # * :message - The message to use (default: 'is not confirmed')
134
- def self.validates_confirmation_of(*atts)
135
- opts = {
136
- :message => 'is not confirmed',
137
- :tag => :confirmation,
138
- }.merge!(atts.extract_options!)
139
- atts << opts
140
- validates_each(*atts) do |o, a, v|
141
- o.errors[a] << opts[:message] unless v == o.send(:"#{a}_confirmation")
142
- end
143
- end
144
-
145
- # Adds a validation for each of the given attributes using the supplied
146
- # block. The block must accept three arguments: instance, attribute and
147
- # value, e.g.:
148
- #
149
- # validates_each :name, :password do |object, attribute, value|
150
- # object.errors[attribute] << 'is not nice' unless value.nice?
151
- # end
152
- #
153
- # Possible Options:
154
- # * :allow_blank - Whether to skip the validation if the value is blank.
155
- # * :allow_missing - Whether to skip the validation if the attribute isn't a key in the
156
- # values hash. This is different from allow_nil, because Sequel only sends the attributes
157
- # in the values when doing an insert or update. If the attribute is not present, Sequel
158
- # doesn't specify it, so the database will use the table's default value. This is different
159
- # from having an attribute in values with a value of nil, which Sequel will send as NULL.
160
- # If your database table has a non NULL default, this may be a good option to use. You
161
- # don't want to use allow_nil, because if the attribute is in values but has a value nil,
162
- # Sequel will attempt to insert a NULL value into the database, instead of using the
163
- # database's default.
164
- # * :allow_nil - Whether to skip the validation if the value is nil.
165
- # * :if - A symbol (indicating an instance_method) or proc (which is instance_evaled)
166
- # skipping this validation if it returns nil or false.
167
- # * :tag - The tag to use for this validation.
168
- def self.validates_each(*atts, &block)
169
- opts = atts.extract_options!
170
- blk = if (i = opts[:if]) || (am = opts[:allow_missing]) || (an = opts[:allow_nil]) || (ab = opts[:allow_blank])
171
- proc do |o,a,v|
172
- next if i && !o.instance_eval(&if_proc(opts))
173
- next if an && Array(v).all?{|x| x.nil?}
174
- next if ab && Array(v).all?{|x| x.blank?}
175
- next if am && Array(a).all?{|x| !o.values.has_key?(x)}
176
- block.call(o,a,v)
177
- end
178
- else
179
- block
180
- end
181
- tag = opts[:tag]
182
- atts.each do |a|
183
- a_vals = validations[a]
184
- if tag && (old = a_vals.find{|x| x[0] == tag})
185
- old[1] = blk
186
- else
187
- a_vals << [tag, blk]
188
- end
189
- end
190
- end
191
-
192
- # Validates the format of an attribute, checking the string representation of the
193
- # value against the regular expression provided by the :with option.
194
- #
195
- # Possible Options:
196
- # * :message - The message to use (default: 'is invalid')
197
- # * :with - The regular expression to validate the value with (required).
198
- def self.validates_format_of(*atts)
199
- opts = {
200
- :message => 'is invalid',
201
- :tag => :format,
202
- }.merge!(atts.extract_options!)
203
-
204
- unless opts[:with].is_a?(Regexp)
205
- raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash"
206
- end
207
-
208
- atts << opts
209
- validates_each(*atts) do |o, a, v|
210
- o.errors[a] << opts[:message] unless v.to_s =~ opts[:with]
211
- end
212
- end
213
-
214
- # Validates the length of an attribute.
215
- #
216
- # Possible Options:
217
- # * :is - The exact size required for the value to be valid (no default)
218
- # * :maximum - The maximum size allowed for the value (no default)
219
- # * :message - The message to use (no default, overrides :too_long, :too_short, and :wrong_length
220
- # options if present)
221
- # * :minimum - The minimum size allowed for the value (no default)
222
- # * :too_long - The message to use use if it the value is too long (default: 'is too long')
223
- # * :too_short - The message to use use if it the value is too short (default: 'is too short')
224
- # * :within - The array/range that must include the size of the value for it to be valid (no default)
225
- # * :wrong_length - The message to use use if it the value is not valid (default: 'is the wrong length')
226
- def self.validates_length_of(*atts)
227
- opts = {
228
- :too_long => 'is too long',
229
- :too_short => 'is too short',
230
- :wrong_length => 'is the wrong length'
231
- }.merge!(atts.extract_options!)
232
-
233
- opts[:tag] ||= ([:length] + [:maximum, :minimum, :is, :within].reject{|x| !opts.include?(x)}).join('-').to_sym
234
- atts << opts
235
- validates_each(*atts) do |o, a, v|
236
- if m = opts[:maximum]
237
- o.errors[a] << (opts[:message] || opts[:too_long]) unless v && v.size <= m
238
- end
239
- if m = opts[:minimum]
240
- o.errors[a] << (opts[:message] || opts[:too_short]) unless v && v.size >= m
241
- end
242
- if i = opts[:is]
243
- o.errors[a] << (opts[:message] || opts[:wrong_length]) unless v && v.size == i
244
- end
245
- if w = opts[:within]
246
- o.errors[a] << (opts[:message] || opts[:wrong_length]) unless v && w.include?(v.size)
247
- end
248
- end
249
- end
250
-
251
- # Validates whether an attribute is not a string. This is generally useful
252
- # in conjunction with raise_on_typecast_failure = false, where you are
253
- # passing in string values for non-string attributes (such as numbers and dates).
254
- # If typecasting fails (invalid number or date), the value of the attribute will
255
- # be a string in an invalid format, and if typecasting succeeds, the value will
256
- # not be a string.
257
- #
258
- # Possible Options:
259
- # * :message - The message to use (default: 'is a string' or 'is not a valid (integer|datetime|etc.)' if the type is known)
260
- def self.validates_not_string(*atts)
261
- opts = {
262
- :tag => :not_string,
263
- }.merge!(atts.extract_options!)
264
- atts << opts
265
- validates_each(*atts) do |o, a, v|
266
- if v.is_a?(String)
267
- unless message = opts[:message]
268
- message = if sch = o.db_schema[a] and typ = sch[:type]
269
- "is not a valid #{typ}"
270
- else
271
- "is a string"
272
- end
273
- end
274
- o.errors[a] << message
275
- end
276
- end
277
- end
278
-
279
- # Validates whether an attribute is a number.
280
- #
281
- # Possible Options:
282
- # * :message - The message to use (default: 'is not a number')
283
- # * :only_integer - Whether only integers are valid values (default: false)
284
- def self.validates_numericality_of(*atts)
285
- opts = {
286
- :message => 'is not a number',
287
- :tag => :numericality,
288
- }.merge!(atts.extract_options!)
289
- atts << opts
290
- validates_each(*atts) do |o, a, v|
291
- begin
292
- if opts[:only_integer]
293
- Kernel.Integer(v.to_s)
294
- else
295
- Kernel.Float(v.to_s)
296
- end
297
- rescue
298
- o.errors[a] << opts[:message]
299
- end
300
- end
301
- end
302
-
303
- # Validates the presence of an attribute. Requires the value not be blank,
304
- # with false considered present instead of absent.
305
- #
306
- # Possible Options:
307
- # * :message - The message to use (default: 'is not present')
308
- def self.validates_presence_of(*atts)
309
- opts = {
310
- :message => 'is not present',
311
- :tag => :presence,
312
- }.merge!(atts.extract_options!)
313
- atts << opts
314
- validates_each(*atts) do |o, a, v|
315
- o.errors[a] << opts[:message] if v.blank? && v != false
316
- end
317
- end
318
-
319
- # Validates that an attribute is within a specified range or set of values.
320
- #
321
- # Possible Options:
322
- # * :in - An array or range of values to check for validity (required)
323
- # * :message - The message to use (default: 'is not in range or set: <specified range>')
324
- def self.validates_inclusion_of(*atts)
325
- opts = atts.extract_options!
326
- unless opts[:in] && opts[:in].respond_to?(:include?)
327
- raise ArgumentError, "The :in parameter is required, and respond to include?"
328
- end
329
- opts[:message] ||= "is not in range or set: #{opts[:in].inspect}"
330
- atts << opts
331
- validates_each(*atts) do |o, a, v|
332
- o.errors[a] << opts[:message] unless opts[:in].include?(v)
333
- end
334
- end
335
-
336
- # Validates only if the fields in the model (specified by atts) are
337
- # unique in the database. Pass an array of fields instead of multiple
338
- # fields to specify that the combination of fields must be unique,
339
- # instead of that each field should have a unique value.
340
- #
341
- # This means that the code:
342
- # validates_uniqueness_of([:column1, :column2])
343
- # validates the grouping of column1 and column2 while
344
- # validates_uniqueness_of(:column1, :column2)
345
- # validates them separately.
346
- #
347
- # You should also add a unique index in the
348
- # database, as this suffers from a fairly obvious race condition.
349
- #
350
- # Possible Options:
351
- # * :message - The message to use (default: 'is already taken')
352
- def self.validates_uniqueness_of(*atts)
353
- opts = {
354
- :message => 'is already taken',
355
- :tag => :uniqueness,
356
- }.merge!(atts.extract_options!)
357
-
358
- atts << opts
359
- validates_each(*atts) do |o, a, v|
360
- error_field = a
361
- a = Array(a)
362
- v = Array(v)
363
- ds = o.class.filter(a.zip(v))
364
- num_dups = ds.count
365
- allow = if num_dups == 0
366
- # No unique value in the database
367
- true
368
- elsif num_dups > 1
369
- # Multiple "unique" values in the database!!
370
- # Someone didn't add a unique index
371
- false
372
- elsif o.new?
373
- # New record, but unique value already exists in the database
374
- false
375
- elsif ds.first === o
376
- # Unique value exists in database, but for the same record, so the update won't cause a duplicate record
377
- true
378
- else
379
- false
380
- end
381
- o.errors[error_field] << opts[:message] unless allow
382
- end
383
- end
384
-
385
- # Returns the validations hash for the class.
386
- def self.validations
387
- @validations ||= Hash.new {|h, k| h[k] = []}
388
- end
389
-
390
- ### Private Class Methods ###
391
-
392
- def self.if_proc(opts) # :nodoc:
393
- case opts[:if]
394
- when Symbol then proc{send opts[:if]}
395
- when Proc then opts[:if]
396
- when nil then DEFAULT_VALIDATION_IF_PROC
397
- else raise(::Sequel::Error, "invalid value for :if validation option")
398
- end
399
- end
400
-
401
- private_class_method :if_proc
402
-
403
- ### Instance Methods ###
404
-
405
- # Returns the validation errors associated with the object.
406
- def errors
407
- @errors ||= Validation::Errors.new
408
- end
409
-
410
- # Validates the object.
411
- def validate
412
- errors.clear
413
- if before_validation == false
414
- save_failure(:validation)
415
- false
416
- else
417
- self.class.validate(self)
418
- after_validation
419
- nil
420
- end
421
- end
422
-
423
- # Validates the object and returns true if no errors are reported.
424
- def valid?
425
- return false if validate == false
426
- errors.empty?
427
- end
428
- end
429
- end