sequel_model 0.5.0.2 → 3.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,325 +0,0 @@
1
- # Associations are used in order to specify relationships between model classes
2
- # that reflect relations between tables in the database using foreign keys.
3
- #
4
- # Each kind of association adds a number of methods to the model class which
5
- # are specialized according to the association type and optional parameters
6
- # given in the definition. Example:
7
- #
8
- # class Project < Sequel::Model
9
- # belongs_to :portfolio
10
- # has_many :milestones
11
- # end
12
- #
13
- # The project class now has the following methods:
14
- # * Project#portfolio, Project#portfolio=
15
- # * Project#milestones, Project#add_milestone, Project#remove_milestone
16
- #
17
- # By default the classes for the associations are inferred from the association
18
- # name, so for example the Project#portfolio will return an instance of
19
- # Portfolio, and Project#milestones will return a dataset of Milestone
20
- # instances, in similar fashion to how ActiveRecord infers class names.
21
- #
22
- # Association definitions are also reflected by the class, e.g.:
23
- #
24
- # >> Project.associations
25
- # => [:portfolio, :milestones]
26
- # >> Project.association_reflection(:portfolio)
27
- # => {:kind => :many_to_one, :name => :portfolio, :class_name => "Portfolio"}
28
- #
29
- # The following association kinds are supported:
30
- # * :many_to_one - Foreign key in current model's table points to
31
- # associated model's primary key. Each associated model object can
32
- # be associated with more than one current model objects. Each current
33
- # model object can be associated with only one associated model object.
34
- # Similar to ActiveRecord/DataMapper's belongs_to.
35
- # * :one_to_many - Foreign key in associated model's table points to this
36
- # model's primary key. Each current model object can be associated with
37
- # more than one associated model objects. Each associated model object
38
- # can be associated with only one current model object.
39
- # Similar to ActiveRecord/DataMapper's has_many.
40
- # * :many_to_many - A join table is used that has a foreign key that points
41
- # to this model's primary key and a foreign key that points to the
42
- # associated model's primary key. Each current model object can be
43
- # associated with many associated model objects, and each associated
44
- # model object can be associated with many current model objects.
45
- # Similar to ActiveRecord/DataMapper's has_and_belongs_to_many.
46
- #
47
- # Associations can be defined by either using the associate method, or by
48
- # calling one of the three methods: many_to_one, one_to_many, many_to_many.
49
- # Sequel::Model also provides aliases for these methods that conform to
50
- # ActiveRecord conventions: belongs_to, has_many, has_and_belongs_to_many.
51
- # For example, the following two statements are equivalent:
52
- #
53
- # associate :one_to_many, :attributes
54
- # one_to_many :attributes
55
- module Sequel::Model::Associations
56
- # Array of all association reflections
57
- def all_association_reflections
58
- association_reflections.values
59
- end
60
-
61
- # Associates a related model with the current model. The following types are
62
- # supported:
63
- #
64
- # * :many_to_one - Foreign key in current model's table points to
65
- # associated model's primary key. Each associated model object can
66
- # be associated with more than one current model objects. Each current
67
- # model object can be associated with only one associated model object.
68
- # Similar to ActiveRecord/DataMapper's belongs_to.
69
- # * :one_to_many - Foreign key in associated model's table points to this
70
- # model's primary key. Each current model object can be associated with
71
- # more than one associated model objects. Each associated model object
72
- # can be associated with only one current model object.
73
- # Similar to ActiveRecord/DataMapper's has_many.
74
- # * :many_to_many - A join table is used that has a foreign key that points
75
- # to this model's primary key and a foreign key that points to the
76
- # associated model's primary key. Each current model object can be
77
- # associated with many associated model objects, and each associated
78
- # model object can be associated with many current model objects.
79
- # Similar to ActiveRecord/DataMapper's has_and_belongs_to_many.
80
- #
81
- # The following options can be supplied:
82
- # * *ALL types*:
83
- # - :class - The associated class or its name. If not
84
- # given, uses the association's name, which is camelized (and
85
- # singularized if type is :{one,many}_to_many)
86
- # * :many_to_one:
87
- # - :key - foreign_key in current model's table that references
88
- # associated model's primary key, as a symbol. Defaults to :"#{name}_id".
89
- # * :one_to_many:
90
- # - :key - foreign key in associated model's table that references
91
- # current model's primary key, as a symbol. Defaults to
92
- # :"#{self.name.underscore}_id".
93
- # - :order - the column by which to order the association dataset.
94
- # - :cache - set to true to cache and return an array of objects instead of a dataset.
95
- # * :many_to_many:
96
- # - :join_table - name of table that includes the foreign keys to both
97
- # the current model and the associated model, as a symbol. Defaults to the name
98
- # of current model and name of associated model, pluralized,
99
- # underscored, sorted, and joined with '_'.
100
- # - :left_key - foreign key in join table that points to current model's
101
- # primary key, as a symbol.
102
- # - :right_key - foreign key in join table that points to associated
103
- # model's primary key, as a symbol.
104
- # - :order - the column by which to order the association dataset.
105
- # - :cache - set to true to cache and return an array of objects instead of a dataset.
106
- def associate(type, name, opts = {}, &block)
107
- # check arguments
108
- raise ArgumentError unless [:many_to_one, :one_to_many, :many_to_many].include?(type) && Symbol === name
109
-
110
- # merge early so we don't modify opts
111
- opts = opts.merge(:type => type, :name => name, :block => block)
112
-
113
- # deprecation
114
- if opts[:from]
115
- STDERR << "The :from option is deprecated, please use the :class option instead.\r\n"
116
- opts[:class] = opts[:from]
117
- end
118
-
119
- # find class
120
- case opts[:class]
121
- when String, Symbol
122
- # Delete :class to allow late binding
123
- opts[:class_name] ||= opts.delete(:class).to_s
124
- when Class
125
- opts[:class_name] ||= opts[:class].name
126
- end
127
-
128
- send(:"def_#{type}", name, opts)
129
-
130
- # don't add to association_reflections until we are sure there are no errors
131
- association_reflections[name] = opts
132
- end
133
-
134
- # The association reflection hash for the association of the given name.
135
- def association_reflection(name)
136
- association_reflections[name]
137
- end
138
-
139
- # Array of association name symbols
140
- def associations
141
- association_reflections.keys
142
- end
143
-
144
- # Shortcut for adding a many_to_one association, see associate
145
- def many_to_one(*args, &block)
146
- associate(:many_to_one, *args, &block)
147
- end
148
- alias_method :belongs_to, :many_to_one
149
-
150
- # Shortcut for adding a one_to_many association, see associate
151
- def one_to_many(*args, &block)
152
- associate(:one_to_many, *args, &block)
153
- end
154
- alias_method :has_many, :one_to_many
155
-
156
- # deprecated, please use many_to_one instead
157
- def one_to_one(*args, &block)
158
- STDERR << "one_to_one relation definitions are deprecated, please use many_to_one instead.\r\n"
159
- many_to_one(*args, &block)
160
- end
161
-
162
- # Shortcut for adding a many_to_many association, see associate
163
- def many_to_many(*args, &block)
164
- associate(:many_to_many, *args, &block)
165
- end
166
- alias_method :has_and_belongs_to_many, :many_to_many
167
-
168
- private
169
- def association_ivar(name)
170
- :"@#{name}"
171
- end
172
-
173
- def association_add_method_name(name)
174
- :"add_#{name.to_s.singularize}"
175
- end
176
-
177
- def association_remove_method_name(name)
178
- :"remove_#{name.to_s.singularize}"
179
- end
180
-
181
- def default_remote_key
182
- :"#{name.demodulize.underscore}_id"
183
- end
184
-
185
- # The class related to the given association reflection
186
- def associated_class(opts)
187
- opts[:class] ||= opts[:class_name].constantize
188
- end
189
-
190
- # Hash storing the association reflections. Keys are association name
191
- # symbols, values are association reflection hashes.
192
- def association_reflections
193
- @association_reflections ||= {}
194
- end
195
-
196
- def def_many_to_one(name, opts)
197
- assoc_class = method(:associated_class) # late binding of association dataset
198
- ivar = association_ivar(name)
199
-
200
- key = (opts[:key] ||= :"#{name}_id")
201
- opts[:class_name] ||= name.to_s.camelize
202
-
203
- def_association_getter(name) {(fk = send(key)) ? assoc_class[opts][fk] : nil}
204
- class_def(:"#{name}=") do |o|
205
- instance_variable_set(ivar, o)
206
- send(:"#{key}=", (o.pk if o))
207
- end
208
- end
209
-
210
- def def_one_to_many(name, opts)
211
- assoc_class = method(:associated_class) # late binding of association dataset
212
- ivar = association_ivar(name)
213
- key = (opts[:key] ||= default_remote_key)
214
- opts[:class_name] ||= name.to_s.singularize.camelize
215
-
216
- def_association_dataset_methods(name, opts) {assoc_class[opts].filter(key => pk)}
217
-
218
- # define add_xxx, remove_xxx methods
219
- class_def(association_add_method_name(name)) do |o|
220
- o.send(:"#{key}=", pk); o.save!
221
- if arr = instance_variable_get(ivar)
222
- arr.push(o)
223
- end
224
- o
225
- end
226
- class_def(association_remove_method_name(name)) do |o|
227
- o.send(:"#{key}=", nil); o.save!
228
- if arr = instance_variable_get(ivar)
229
- arr.delete(o)
230
- end
231
- o
232
- end
233
- end
234
-
235
- def default_join_table_name(opts)
236
- ([opts[:class_name], self.name.demodulize]. \
237
- map{|i| i.pluralize.underscore}.sort.join('_')).to_sym
238
- end
239
-
240
- def def_many_to_many(name, opts)
241
- assoc_class = method(:associated_class) # late binding of association dataset
242
- ivar = association_ivar(name)
243
- left = (opts[:left_key] ||= default_remote_key)
244
- right = (opts[:right_key] ||= :"#{name.to_s.singularize}_id")
245
- opts[:class_name] ||= name.to_s.singularize.camelize
246
- join_table = (opts[:join_table] ||= default_join_table_name(opts))
247
- database = db
248
-
249
- def_association_dataset_methods(name, opts) do
250
- klass = assoc_class[opts]
251
- key = (opts[:right_primary_key] ||= :"#{klass.table_name}__#{klass.primary_key}")
252
- klass.inner_join(join_table, right => key, left => pk)
253
- end
254
-
255
- class_def(association_add_method_name(name)) do |o|
256
- database[join_table].insert(left => pk, right => o.pk)
257
- if arr = instance_variable_get(ivar)
258
- arr.push(o)
259
- end
260
- o
261
- end
262
- class_def(association_remove_method_name(name)) do |o|
263
- database[join_table].filter(left => pk, right => o.pk).delete
264
- if arr = instance_variable_get(ivar)
265
- arr.delete(o)
266
- end
267
- o
268
- end
269
- end
270
-
271
- # Defines an association getter method, caching the block result in an
272
- # instance variable. The defined method takes an optional reload parameter
273
- # that can be set to true in order to bypass the cache.
274
- def def_association_getter(name, &block)
275
- ivar = association_ivar(name)
276
- class_def(name) do |*reload|
277
- if !reload[0] && obj = instance_variable_get(ivar)
278
- obj
279
- else
280
- instance_variable_set(ivar, instance_eval(&block))
281
- end
282
- end
283
- end
284
-
285
- # Defines an association
286
- def def_association_dataset_methods(name, opts, &block)
287
- dataset_method = :"#{name}_dataset"
288
- dataset_block = opts[:block]
289
- ivar = association_ivar(name)
290
-
291
- # define a method returning the association dataset (with optional order)
292
- if order = opts[:order]
293
- class_def(dataset_method) {instance_eval(&block).order(order)}
294
- else
295
- class_def(dataset_method, &block)
296
- end
297
-
298
- if opts[:cache]
299
- # if the :cache option is set to true, the association method should return
300
- # an array of association objects
301
- class_def(name) do |*reload|
302
- if !reload[0] && obj = instance_variable_get(ivar)
303
- obj
304
- else
305
- ds = send(dataset_method)
306
- # if the a dataset block was specified, we need to call it and use
307
- # the result as the dataset to fetch records from.
308
- if dataset_block
309
- ds = dataset_block[ds]
310
- end
311
- instance_variable_set(ivar, ds.all)
312
- end
313
- end
314
- elsif dataset_block
315
- # no cache, but we still need to check if a dataset block was given.
316
- # define helper so the supplied block will be instance_eval'ed
317
- class_def(:"#{name}_helper", &dataset_block)
318
- class_def(name) {send(:"#{name}_helper", send(dataset_method))}
319
- else
320
- # otherwise (by default), the association method is an alias to the
321
- # association dataset method.
322
- alias_method name, dataset_method
323
- end
324
- end
325
- end
@@ -1,119 +0,0 @@
1
- module Sequel
2
- class Model
3
- # Returns the database associated with the Model class.
4
- def self.db
5
- @db ||= (superclass != Object) && superclass.db or
6
- raise Error, "No database associated with #{self}"
7
- end
8
-
9
- # Sets the database associated with the Model class.
10
- def self.db=(db)
11
- @db = db
12
- if @dataset
13
- set_dataset(db[table_name])
14
- end
15
- end
16
-
17
- # Called when a database is opened in order to automatically associate the
18
- # first opened database with model classes.
19
- def self.database_opened(db)
20
- @db = db if (self == Model) && !@db
21
- end
22
-
23
- # Returns the implicit table name for the model class.
24
- def self.implicit_table_name
25
- name.demodulize.underscore.pluralize.to_sym
26
- end
27
-
28
- # Returns the dataset associated with the Model class.
29
- def self.dataset
30
- unless @dataset
31
- if ds = super_dataset
32
- set_dataset(ds.clone)
33
- elsif !name.empty?
34
- set_dataset(db[implicit_table_name])
35
- else
36
- raise Error, "No dataset associated with #{self}"
37
- end
38
- end
39
- @dataset
40
- end
41
-
42
- # def self.dataset
43
- # @dataset ||= super_dataset ||
44
- # (!(n = name).empty? && db[n.underscore.pluralize.to_sym]) ||
45
- # (raise Error, "No dataset associated with #{self}")
46
- # end
47
-
48
- def self.super_dataset # :nodoc:
49
- superclass.dataset if (superclass != Sequel::Model) && superclass.respond_to?(:dataset)
50
- end
51
-
52
- # Returns the columns in the result set in their original order.
53
- #
54
- # See Dataset#columns for more information.
55
- def self.columns
56
- @columns ||= dataset.columns or
57
- raise Error, "Could not fetch columns for #{self}"
58
- end
59
-
60
- # Sets the dataset associated with the Model class.
61
- def self.set_dataset(ds)
62
- @db = ds.db
63
- @dataset = ds
64
- @dataset.set_model(self)
65
- @dataset.transform(@transform) if @transform
66
- end
67
-
68
- # Returns the database assoiated with the object's Model class.
69
- def db
70
- @db ||= model.db
71
- end
72
-
73
- # Returns the dataset assoiated with the object's Model class.
74
- #
75
- # See Dataset for more information.
76
- def dataset
77
- model.dataset
78
- end
79
-
80
- # Returns the columns associated with the object's Model class.
81
- def columns
82
- model.columns
83
- end
84
-
85
- # Serializes column with YAML or through marshalling.
86
- def self.serialize(*columns)
87
- format = columns.pop[:format] if Hash === columns.last
88
- format ||= :yaml
89
-
90
- @transform = columns.inject({}) do |m, c|
91
- m[c] = format
92
- m
93
- end
94
- @dataset.transform(@transform) if @dataset
95
- end
96
- end
97
-
98
- # Lets you create a Model class with its table name already set or reopen
99
- # an existing Model.
100
- #
101
- # Makes given dataset inherited.
102
- #
103
- # === Example:
104
- # class Comment < Sequel::Model(:something)
105
- # table_name # => :something
106
- #
107
- # # ...
108
- #
109
- # end
110
- def self.Model(source)
111
- @models ||= {}
112
- @models[source] ||= Class.new(Sequel::Model) do
113
- meta_def(:inherited) do |c|
114
- c.set_dataset(source.is_a?(Dataset) ? source : c.db[source])
115
- end
116
- end
117
- end
118
-
119
- end
@@ -1,42 +0,0 @@
1
- module Sequel
2
- class Model
3
- def self.set_cache(store, opts = {})
4
- @cache_store = store
5
- if (ttl = opts[:ttl])
6
- set_cache_ttl(ttl)
7
- end
8
-
9
- meta_def(:[]) do |*args|
10
- if (args.size == 1) && (Hash === (h = args.first))
11
- return dataset[h]
12
- end
13
-
14
- unless obj = @cache_store.get(cache_key_from_values(args))
15
- obj = dataset[primary_key_hash((args.size == 1) ? args.first : args)]
16
- @cache_store.set(cache_key_from_values(args), obj, cache_ttl)
17
- end
18
- obj
19
- end
20
-
21
- class_def(:set) {|v| store.delete(cache_key); super}
22
- class_def(:save) {store.delete(cache_key); super}
23
- class_def(:delete) {store.delete(cache_key); super}
24
- end
25
-
26
- def self.set_cache_ttl(ttl)
27
- @cache_ttl = ttl
28
- end
29
-
30
- def self.cache_store
31
- @cache_store
32
- end
33
-
34
- def self.cache_ttl
35
- @cache_ttl ||= 3600
36
- end
37
-
38
- def self.cache_key_from_values(values)
39
- "#{self}:#{values.join(',')}"
40
- end
41
- end
42
- end