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,539 +0,0 @@
1
- module Sequel
2
- class Model
3
- @allowed_columns = nil
4
- @association_reflections = {}
5
- @cache_store = nil
6
- @cache_ttl = nil
7
- @db = nil
8
- @db_schema = nil
9
- @dataset_methods = {}
10
- @hooks = {}
11
- @overridable_methods_module = nil
12
- @primary_key = :id
13
- @raise_on_save_failure = true
14
- @raise_on_typecast_failure = true
15
- @restrict_primary_key = true
16
- @restricted_columns = nil
17
- @simple_pk = nil
18
- @simple_table = nil
19
- @skip_superclass_validations = nil
20
- @sti_dataset = nil
21
- @sti_key = nil
22
- @strict_param_setting = true
23
- @transform = nil
24
- @typecast_empty_string_to_nil = true
25
- @typecast_on_assignment = true
26
-
27
- # Which columns should be the only columns allowed in a call to set
28
- # (default: all columns).
29
- metaattr_reader :allowed_columns
30
-
31
- # All association reflections defined for this model (default: none).
32
- metaattr_reader :association_reflections
33
-
34
- # Hash of dataset methods to add to this class and subclasses when
35
- # set_dataset is called.
36
- metaattr_reader :dataset_methods
37
-
38
- # The default primary key for classes (default: :id)
39
- metaattr_reader :primary_key
40
-
41
- # Whether to raise an error instead of returning nil on a failure
42
- # to save/create/save_changes/etc.
43
- metaattr_accessor :raise_on_save_failure
44
-
45
- # Whether to raise an error when unable to typecast data for a column
46
- # (default: true)
47
- metaattr_accessor :raise_on_typecast_failure
48
-
49
- # Which columns should not be update in a call to set
50
- # (default: no columns).
51
- metaattr_reader :restricted_columns
52
-
53
- # Should be the literal primary key column name if this Model's table has a simple primary key, or
54
- # nil if the model has a compound primary key or no primary key.
55
- metaattr_reader :simple_pk
56
-
57
- # Should be the literal table name if this Model's dataset is a simple table (no select, order, join, etc.),
58
- # or nil otherwise.
59
- metaattr_reader :simple_table
60
-
61
- # The base dataset for STI, to which filters are added to get
62
- # only the models for the specific STI subclass.
63
- metaattr_reader :sti_dataset
64
-
65
- # The column name holding the STI key for this model
66
- metaattr_reader :sti_key
67
-
68
- # Whether new/set/update and their variants should raise an error
69
- # if an invalid key is used (either that doesn't exist or that
70
- # access is restricted to it).
71
- metaattr_accessor :strict_param_setting
72
-
73
- # Whether to typecast the empty string ('') to nil for columns that
74
- # are not string or blob.
75
- metaattr_accessor :typecast_empty_string_to_nil
76
-
77
- # Whether to typecast attribute values on assignment (default: true)
78
- metaattr_accessor :typecast_on_assignment
79
-
80
- # Dataset methods to proxy via metaprogramming
81
- DATASET_METHODS = %w'<< all avg count delete distinct eager eager_graph each each_page
82
- empty? except exclude filter first from from_self full_outer_join get graph
83
- group group_and_count group_by having import inner_join insert
84
- insert_multiple intersect interval invert_order join join_table last
85
- left_outer_join limit map multi_insert naked order order_by order_more
86
- paginate print query range reverse_order right_outer_join select
87
- select_all select_more server set set_graph_aliases single_value size to_csv to_hash
88
- transform union uniq unfiltered unordered update where with_sql'.map{|x| x.to_sym}
89
-
90
- # Instance variables that are inherited in subclasses
91
- INHERITED_INSTANCE_VARIABLES = {:@allowed_columns=>:dup, :@cache_store=>nil,
92
- :@cache_ttl=>nil, :@dataset_methods=>:dup, :@primary_key=>nil,
93
- :@raise_on_save_failure=>nil, :@restricted_columns=>:dup, :@restrict_primary_key=>nil,
94
- :@simple_pk=>nil, :@simple_table=>nil,
95
- :@sti_dataset=>nil, :@sti_key=>nil, :@strict_param_setting=>nil,
96
- :@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil,
97
- :@raise_on_typecast_failure=>nil, :@association_reflections=>:dup}
98
-
99
- # Empty instance variables, for -w compliance
100
- EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@transform, :@db, :@skip_superclass_validations]
101
-
102
- # Returns the first record from the database matching the conditions.
103
- # If a hash is given, it is used as the conditions. If another
104
- # object is given, it finds the first record whose primary key(s) match
105
- # the given argument(s). If caching is used, the cache is checked
106
- # first before a dataset lookup is attempted unless a hash is supplied.
107
- def self.[](*args)
108
- args = args.first if (args.size == 1)
109
- return dataset[args] if args.is_a?(Hash)
110
- return cache_lookup(args) if @cache_store
111
- if t = simple_table and p = simple_pk
112
- with_sql("SELECT * FROM #{t} WHERE #{p} = #{dataset.literal(args)} LIMIT 1").first
113
- else
114
- dataset[primary_key_hash(args)]
115
- end
116
- end
117
-
118
- # Returns the columns in the result set in their original order.
119
- # Generally, this will used the columns determined via the database
120
- # schema, but in certain cases (e.g. models that are based on a joined
121
- # dataset) it will use Dataset#columns to find the columns, which
122
- # may be empty if the Dataset has no records.
123
- def self.columns
124
- @columns || set_columns(dataset.naked.columns)
125
- end
126
-
127
- # Creates new instance with values set to passed-in Hash, saves it
128
- # (running any callbacks), and returns the instance if the object
129
- # was saved correctly. If there was an error saving the object,
130
- # returns false.
131
- def self.create(values = {}, &block)
132
- obj = new(values, &block)
133
- return unless obj.save
134
- obj
135
- end
136
-
137
- # Returns the dataset associated with the Model class.
138
- def self.dataset
139
- @dataset || raise(Error, "No dataset associated with #{self}")
140
- end
141
-
142
- # Returns the database associated with the Model class.
143
- def self.db
144
- return @db if @db
145
- @db = self == Model ? DATABASES.first : superclass.db
146
- raise(Error, "No database associated with #{self}") unless @db
147
- @db
148
- end
149
-
150
- # Sets the database associated with the Model class.
151
- def self.db=(db)
152
- @db = db
153
- if @dataset
154
- set_dataset(db[table_name])
155
- end
156
- end
157
-
158
- # Returns the cached schema information if available or gets it
159
- # from the database.
160
- def self.db_schema
161
- @db_schema ||= get_db_schema
162
- end
163
-
164
- # If a block is given, define a method on the dataset with the given argument name using
165
- # the given block as well as a method on the model that calls the
166
- # dataset method.
167
- #
168
- # If a block is not given, define a method on the model for each argument
169
- # that calls the dataset method of the same argument name.
170
- def self.def_dataset_method(*args, &block)
171
- raise(Error, "No arguments given") if args.empty?
172
- if block_given?
173
- raise(Error, "Defining a dataset method using a block requires only one argument") if args.length > 1
174
- meth = args.first
175
- @dataset_methods[meth] = block
176
- dataset.meta_def(meth, &block)
177
- end
178
- args.each{|arg| instance_eval("def #{arg}(*args, &block); dataset.#{arg}(*args, &block) end", __FILE__, __LINE__)}
179
- end
180
-
181
- # Deletes all records in the model's table.
182
- def self.delete_all
183
- dataset.delete
184
- end
185
-
186
- # Like delete_all, but invokes before_destroy and after_destroy hooks if used.
187
- def self.destroy_all
188
- dataset.destroy
189
- end
190
-
191
- # Returns a dataset with custom SQL that yields model objects.
192
- def self.fetch(*args)
193
- db.fetch(*args).set_model(self)
194
- end
195
-
196
- # Modify and return eager loading dataset based on association options
197
- def self.eager_loading_dataset(opts, ds, select, associations)
198
- ds = ds.select(*select) if select
199
- ds = ds.filter(opts[:conditions]) if opts[:conditions]
200
- ds = ds.order(*opts[:order]) if opts[:order]
201
- ds = ds.eager(opts[:eager]) if opts[:eager]
202
- ds = ds.eager_graph(opts[:eager_graph]) if opts[:eager_graph]
203
- ds = ds.eager(associations) unless associations.blank?
204
- ds = opts[:eager_block].call(ds) if opts[:eager_block]
205
- ds
206
- end
207
-
208
- # Finds a single record according to the supplied filter, e.g.:
209
- #
210
- # Ticket.find :author => 'Sharon' # => record
211
- def self.find(*args, &block)
212
- dataset.filter(*args, &block).first
213
- end
214
-
215
- # Like find but invokes create with given conditions when record does not
216
- # exists.
217
- def self.find_or_create(cond)
218
- find(cond) || create(cond)
219
- end
220
-
221
- # If possible, set the dataset for the model subclass as soon as it
222
- # is created. Also, inherit the INHERITED_INSTANCE_VARIABLES
223
- # from the parent class.
224
- def self.inherited(subclass)
225
- sup_class = subclass.superclass
226
- ivs = subclass.instance_variables.collect{|x| x.to_s}
227
- EMPTY_INSTANCE_VARIABLES.each{|iv| subclass.instance_variable_set(iv, nil) unless ivs.include?(iv.to_s)}
228
- INHERITED_INSTANCE_VARIABLES.each do |iv, dup|
229
- next if ivs.include?(iv.to_s)
230
- sup_class_value = sup_class.instance_variable_get(iv)
231
- sup_class_value = sup_class_value.dup if dup == :dup && sup_class_value
232
- subclass.instance_variable_set(iv, sup_class_value)
233
- end
234
- unless ivs.include?("@dataset")
235
- db
236
- begin
237
- if sup_class == Model
238
- subclass.set_dataset(subclass.implicit_table_name) unless subclass.name.blank?
239
- elsif ds = sup_class.instance_variable_get(:@dataset)
240
- subclass.set_dataset(sup_class.sti_key ? sup_class.sti_dataset.filter(sup_class.sti_key=>subclass.name.to_s) : ds.clone, :inherited=>true)
241
- end
242
- rescue
243
- nil
244
- end
245
- end
246
- hooks = subclass.instance_variable_set(:@hooks, {})
247
- sup_class.instance_variable_get(:@hooks).each{|k,v| hooks[k] = v.dup}
248
- end
249
-
250
- # Returns the implicit table name for the model class.
251
- def self.implicit_table_name
252
- name.demodulize.underscore.pluralize.to_sym
253
- end
254
-
255
- # Initializes a model instance as an existing record. This constructor is
256
- # used by Sequel to initialize model instances when fetching records.
257
- # #load requires that values be a hash where all keys are symbols. It
258
- # probably should not be used by external code.
259
- def self.load(values)
260
- new(values, true)
261
- end
262
-
263
- # Mark the model as not having a primary key. Not having a primary key
264
- # can cause issues, among which is that you won't be able to update records.
265
- def self.no_primary_key
266
- @simple_pk = @primary_key = nil
267
- end
268
-
269
- # Returns primary key attribute hash. If using a composite primary key
270
- # value such be an array with values for each primary key in the correct
271
- # order. For a standard primary key, value should be an object with a
272
- # compatible type for the key. If the model does not have a primary key,
273
- # raises an Error.
274
- def self.primary_key_hash(value)
275
- raise(Error, "#{self} does not have a primary key") unless key = @primary_key
276
- case key
277
- when Array
278
- hash = {}
279
- key.each_with_index{|k,i| hash[k] = value[i]}
280
- hash
281
- else
282
- {key => value}
283
- end
284
- end
285
-
286
- # Restrict the setting of the primary key(s) inside new/set/update. Because
287
- # this is the default, this only make sense to use in a subclass where the
288
- # parent class has used unrestrict_primary_key.
289
- def self.restrict_primary_key
290
- @restrict_primary_key = true
291
- end
292
-
293
- # Whether or not setting the primary key inside new/set/update is
294
- # restricted, true by default.
295
- def self.restrict_primary_key?
296
- @restrict_primary_key
297
- end
298
-
299
- # Serializes column with YAML or through marshalling. Arguments should be
300
- # column symbols, with an optional trailing hash with a :format key
301
- # set to :yaml or :marshal (:yaml is the default). Setting this adds
302
- # a transform to the model and dataset so that columns values will be serialized
303
- # when saved and deserialized when returned from the database.
304
- def self.serialize(*columns)
305
- format = columns.extract_options![:format] || :yaml
306
- @transform = columns.inject({}) do |m, c|
307
- m[c] = format
308
- m
309
- end
310
- @dataset.transform(@transform) if @dataset
311
- end
312
-
313
- # Whether or not the given column is serialized for this model.
314
- def self.serialized?(column)
315
- @transform ? @transform.include?(column) : false
316
- end
317
-
318
- # Set the columns to allow in new/set/update. Using this means that
319
- # any columns not listed here will not be modified. If you have any virtual
320
- # setter methods (methods that end in =) that you want to be used in
321
- # new/set/update, they need to be listed here as well (without the =).
322
- #
323
- # It may be better to use (set|update)_only instead of this in places where
324
- # only certain columns may be allowed.
325
- def self.set_allowed_columns(*cols)
326
- @allowed_columns = cols
327
- end
328
-
329
- # Sets the dataset associated with the Model class. ds can be a Symbol
330
- # (specifying a table name in the current database), or a Dataset.
331
- # If a dataset is used, the model's database is changed to the given
332
- # dataset. If a symbol is used, a dataset is created from the current
333
- # database with the table name given. Other arguments raise an Error.
334
- #
335
- # This sets the model of the the given/created dataset to the current model
336
- # and adds a destroy method to it. It also extends the dataset with
337
- # the Associations::EagerLoading methods, and assigns a transform to it
338
- # if there is one associated with the model. Finally, it attempts to
339
- # determine the database schema based on the given/created dataset.
340
- def self.set_dataset(ds, opts={})
341
- inherited = opts[:inherited]
342
- @dataset = case ds
343
- when Symbol
344
- @simple_table = db.literal(ds)
345
- db[ds]
346
- when Dataset
347
- @simple_table = nil
348
- @db = ds.db
349
- ds
350
- else
351
- raise(Error, "Model.set_dataset takes a Symbol or a Sequel::Dataset")
352
- end
353
- @dataset.set_model(self)
354
- @dataset.transform(@transform) if @transform
355
- if inherited
356
- @simple_table = sti_key ? nil : superclass.simple_table
357
- @columns = @dataset.columns rescue nil
358
- else
359
- @dataset.extend(DatasetMethods)
360
- @dataset.extend(Associations::EagerLoading)
361
- @dataset_methods.each{|meth, block| @dataset.meta_def(meth, &block)} if @dataset_methods
362
- end
363
- @db_schema = (inherited ? superclass.db_schema : get_db_schema) rescue nil
364
- self
365
- end
366
- metaalias :dataset=, :set_dataset
367
-
368
- # Sets primary key, regular and composite are possible.
369
- #
370
- # Example:
371
- # class Tagging < Sequel::Model
372
- # # composite key
373
- # set_primary_key :taggable_id, :tag_id
374
- # end
375
- #
376
- # class Person < Sequel::Model
377
- # # regular key
378
- # set_primary_key :person_id
379
- # end
380
- #
381
- # You can set it to nil to not have a primary key, but that
382
- # cause certain things not to work, see #no_primary_key.
383
- def self.set_primary_key(*key)
384
- @simple_pk = key.length == 1 ? db.literal(key.first) : nil
385
- @primary_key = (key.length == 1) ? key[0] : key.flatten
386
- end
387
-
388
- # Set the columns to restrict in new/set/update. Using this means that
389
- # any columns listed here will not be modified. If you have any virtual
390
- # setter methods (methods that end in =) that you want not to be used in
391
- # new/set/update, they need to be listed here as well (without the =).
392
- #
393
- # It may be better to use (set|update)_except instead of this in places where
394
- # only certain columns may be allowed.
395
- def self.set_restricted_columns(*cols)
396
- @restricted_columns = cols
397
- end
398
-
399
- # Makes this model a polymorphic model with the given key being a string
400
- # field in the database holding the name of the class to use. If the
401
- # key given has a NULL value or there are any problems looking up the
402
- # class, uses the current class.
403
- #
404
- # This should be used to set up single table inheritance for the model,
405
- # and it only makes sense to use this in the parent class.
406
- #
407
- # You should call sti_key after any calls to set_dataset in the model,
408
- # otherwise subclasses might not have the filters set up correctly.
409
- #
410
- # The filters that sti_key sets up in subclasses will not work if
411
- # those subclasses have further subclasses. For those middle subclasses,
412
- # you will need to call set_dataset manually with the correct filter set.
413
- def self.set_sti_key(key)
414
- m = self
415
- @sti_key = key
416
- @sti_dataset = dataset
417
- dataset.set_model(key, Hash.new{|h,k| h[k] = (k.constantize rescue m)})
418
- before_create(:set_sti_key){send("#{key}=", model.name.to_s)}
419
- end
420
-
421
- # Returns the columns as a list of frozen strings instead
422
- # of a list of symbols. This makes it possible to check
423
- # whether a column exists without creating a symbol, which
424
- # would be a memory leak if called with user input.
425
- def self.str_columns
426
- @str_columns ||= columns.map{|c| c.to_s.freeze}
427
- end
428
-
429
- # Defines a method that returns a filtered dataset. Subsets
430
- # create dataset methods, so they can be chained for scoping.
431
- # For example:
432
- #
433
- # Topic.subset(:popular, :num_posts.sql_number > 100)
434
- # Topic.subset(:recent, :created_on + 7 > Date.today)
435
- #
436
- # Allows you to do:
437
- #
438
- # Topic.filter(:username.like('%joe%')).popular.recent
439
- #
440
- # to get topics with a username that includes joe that
441
- # have more than 100 posts and were created less than
442
- # 7 days ago.
443
- def self.subset(name, *args, &block)
444
- def_dataset_method(name){filter(*args, &block)}
445
- end
446
-
447
- # Returns name of primary table for the dataset.
448
- def self.table_name
449
- dataset.opts[:from].first
450
- end
451
-
452
- # Allow the setting of the primary key(s) inside new/set/update.
453
- def self.unrestrict_primary_key
454
- @restrict_primary_key = false
455
- end
456
-
457
- # Add model methods that call dataset methods
458
- def_dataset_method(*DATASET_METHODS)
459
-
460
- ### Private Class Methods ###
461
-
462
- # Create the column accessors
463
- def self.def_column_accessor(*columns) # :nodoc:
464
- columns.each do |column|
465
- im = instance_methods.collect{|x| x.to_s}
466
- meth = "#{column}="
467
- overridable_methods_module.module_eval do
468
- define_method(column){self[column]} unless im.include?(column.to_s)
469
- unless im.include?(meth)
470
- define_method(meth) do |*v|
471
- len = v.length
472
- raise(ArgumentError, "wrong number of arguments (#{len} for 1)") unless len == 1
473
- self[column] = v.first
474
- end
475
- end
476
- end
477
- end
478
- end
479
-
480
- # Get the schema from the database, fall back on checking the columns
481
- # via the database if that will return inaccurate results or if
482
- # it raises an error.
483
- def self.get_db_schema(reload = false) # :nodoc:
484
- set_columns(nil)
485
- return nil unless @dataset
486
- schema_hash = {}
487
- ds_opts = dataset.opts
488
- single_table = ds_opts[:from] && (ds_opts[:from].length == 1) \
489
- && !ds_opts.include?(:join) && !ds_opts.include?(:sql)
490
- get_columns = proc{columns rescue []}
491
- if single_table && (schema_array = (db.schema(table_name, :reload=>reload) rescue nil))
492
- schema_array.each{|k,v| schema_hash[k] = v}
493
- if ds_opts.include?(:select)
494
- # Dataset only selects certain columns, delete the other
495
- # columns from the schema
496
- cols = get_columns.call
497
- schema_hash.delete_if{|k,v| !cols.include?(k)}
498
- cols.each{|c| schema_hash[c] ||= {}}
499
- else
500
- # Dataset is for a single table with all columns,
501
- # so set the columns based on the order they were
502
- # returned by the schema.
503
- cols = schema_array.collect{|k,v| k}
504
- set_columns(cols)
505
- # Set the primary key(s) based on the schema information
506
- pks = schema_array.collect{|k,v| k if v[:primary_key]}.compact
507
- pks.length > 0 ? set_primary_key(*pks) : no_primary_key
508
- # Also set the columns for the dataset, so the dataset
509
- # doesn't have to do a query to get them.
510
- dataset.instance_variable_set(:@columns, cols)
511
- end
512
- else
513
- # If the dataset uses multiple tables or custom sql or getting
514
- # the schema raised an error, just get the columns and
515
- # create an empty schema hash for it.
516
- get_columns.call.each{|c| schema_hash[c] = {}}
517
- end
518
- schema_hash
519
- end
520
-
521
- # Module that the class includes that holds methods the class adds for column accessors and
522
- # associations so that the methods can be overridden with super
523
- def self.overridable_methods_module # :nodoc:
524
- include(@overridable_methods_module = Module.new) unless @overridable_methods_module
525
- @overridable_methods_module
526
- end
527
-
528
- # Set the columns for this model, reset the str_columns,
529
- # and create accessor methods for each column.
530
- def self.set_columns(new_columns) # :nodoc:
531
- @columns = new_columns
532
- def_column_accessor(*new_columns) if new_columns
533
- @str_columns = nil
534
- @columns
535
- end
536
-
537
- private_class_method :def_column_accessor, :get_db_schema, :overridable_methods_module, :set_columns
538
- end
539
- end