sequel_model 0.5.0.2 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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