Module: Makura::Model::SingletonMethods

Defined in:
lib/makura/model.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#defaultsObject

Returns the value of attribute defaults.



150
151
152
# File 'lib/makura/model.rb', line 150

def defaults
  @defaults
end

#makura_relationObject

Returns the value of attribute makura_relation.



150
151
152
# File 'lib/makura/model.rb', line 150

def makura_relation
  @makura_relation
end

#property_typeObject

Returns the value of attribute property_type.



150
151
152
# File 'lib/makura/model.rb', line 150

def property_type
  @property_type
end

Instance Method Details

#[](id, rev = nil) ⇒ Object



237
238
239
240
241
# File 'lib/makura/model.rb', line 237

def [](id, rev = nil)
  new(database[id, rev])
rescue Error::ResourceNotFound
  nil
end

#belongs_to(name, model = nil) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/makura/model.rb', line 204

def belongs_to(name, model = nil)
  name = name.to_s
  klass = (model || name.capitalize).to_s
  @makura_relation[:belongs_to][name] = klass

  class_eval("
    def #{name}()
      @#{name} ||= #{klass}[self[#{name.dump}]]
    end
    def #{name}=(obj)
      if obj.respond_to?(:_id)
        @_hash[#{name.dump}] = obj._id
      else
        @_hash[#{name.dump}] = obj
      end
    end")
end

#convert_raw(rows, flat = false) ⇒ Object



351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/makura/model.rb', line 351

def convert_raw(rows, flat = false)
  rows.map do |row|
    value = row['doc'] || row['value']

    if value.respond_to?(:to_hash)
      if not flat and type = value['type']
        Makura.constant(type).new(value)
      else
        row
      end
    elsif not row['key']
      value
    else
      row
    end
  end
end

#databaseObject



166
167
168
# File 'lib/makura/model.rb', line 166

def database
  @database || Makura::Model.database
end

#database=(name) ⇒ Object



162
163
164
# File 'lib/makura/model.rb', line 162

def database=(name)
  @database = Makura::Model.server.database(name)
end

#designObject



243
244
245
# File 'lib/makura/model.rb', line 243

def design
  @design ||= Design.new(name.to_s, database)
end

#has_many(name, model = nil) ⇒ Object



222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/makura/model.rb', line 222

def has_many(name, model = nil)
  name = name.to_s
  klass = (model || name.capitalize).to_s
  @makura_relation[:has_many][name] = klass

  class_eval("
    def #{name}()
      @#{name} ||= #{klass}[self[#{name.dump}]]
    end
    def #{name}=(obj)
      return unless obj
      raise RuntimeError, 'You many not assign here'
    end")
end

#id(name) ⇒ Object



197
198
199
200
201
202
# File 'lib/makura/model.rb', line 197

def id(name)
  @id = name
  class_eval("
    alias #{name} _id
    alias #{name}= _id=")
end

#layout(name, opts = {}) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/makura/model.rb', line 247

def layout(name, opts = {})
  design[name] = layout = Layout.new(name, design)
  unless opts[:map] or opts[:reduce]
    prefix = self.name.gsub(/\B[A-Z][^A-Z]/, '_\&')
  end

  map_name    = opts[:map]    || "#{prefix}_#{name}".downcase
  reduce_name = opts[:reduce] || "#{prefix}_#{name}".downcase

  layout.load_map(map_name)
  layout.load_reduce(reduce_name)

  return layout
end

#multi_fetch(name, opts = {}) ⇒ Object

opts must include a :keys or ‘keys’ key with something that responds to #to_a as value

Usage given a map named ‘Post/by_tags’ that does something like:

for(t in doc.tags){ emit([doc.tags[t]], null); }

You can use this like:

keys = ['ruby', 'couchdb']
Post.multi_fetch(:by_tags, :keys => keys)

And it will return all docs with the tags ‘ruby’ OR ‘couchdb’ This can be extended to match even more complex things

for(t in doc.tags){ emit([doc.author, doc.tags[t]], null); }

Now we do

keys = [['manveru', 'ruby'], ['mika', 'couchdb']]
Post.multi_fetch(:by_tags, :keys => keys)

This will return all docs match following:

((author == 'manveru' && tags.include?('ruby')) ||
 (author == 'mika' && tags.include?('couchdb')))

Of course you can add as many keys as you like:

keys = [['manveru', 'ruby'],
        ['manveru', 'couchdb'],
        ['mika', 'design']]
        ['mika', 'couchdb']]
Post.multi_fetch(:by_tags, :keys => keys)

From wiki.apache.org/couchdb/HTTP_view_API

A JSON structure of {"keys": ["key1", "key2", ...]} can be posted to
any user defined view or _all_docs to retrieve just the view rows
matching that set of keys. Rows are returned in the order of the keys
specified. Combining this feature with include_docs=true results in
the so-called multi-document-fetch feature.


320
321
322
323
324
325
# File 'lib/makura/model.rb', line 320

def multi_fetch(name, opts = {})
  keys = opts.delete(:keys) || opts.delete('keys')
  opts.merge!(:payload => {'keys' => Array(keys)})
  hash = database.post("_view/#{self}/#{name}", opts)
  convert_raw(hash['rows'])
end

#multi_fetch_with_docs(name, opts = {}) ⇒ Object Also known as: multi_document_fetch



327
328
329
330
# File 'lib/makura/model.rb', line 327

def multi_fetch_with_docs(name, opts = {})
  opts.merge!(:include_docs => true, :reduce => false)
  multi_fetch(name, opts)
end

#plugin(name) ⇒ Object



152
153
154
155
156
157
158
159
160
# File 'lib/makura/model.rb', line 152

def plugin(name)
  require "makura/plugin/#{name}".downcase

  name = name.to_s.capitalize
  mod = Makura::Plugin.const_get(name)

  include(mod::InstanceMethods) if defined?(mod::InstanceMethods)
  extend(mod::SingletonMethods) if defined?(mod::SingletonMethods)
end

#properties(*names) ⇒ Object



170
171
172
# File 'lib/makura/model.rb', line 170

def properties(*names)
  names.each{|name| property(name) }
end

#property(name, opts = {}) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/makura/model.rb', line 174

def property(name, opts = {})
  name = name.to_s
  defaults[name] = default = opts.delete(:default) if opts[:default]
  property_type[name] = type = opts.delete(:type) if opts[:type]

  if type == Time
    code = "
      def #{name}()
        Time.at(@_hash[#{name.dump}].to_i)
      end
      def #{name}=(obj)
        @_hash[#{name.dump}] = obj.to_i
      end"
    class_eval(code)
  else
    code = "
      def #{name}() @_hash[#{name.dump}] end
      def #{name}=(obj) @_hash[#{name.dump}] = obj end"
  end

  class_eval(code)
end

#proto_layout(common, name, opts = {}) ⇒ Object



262
263
264
265
266
267
268
269
270
271
272
# File 'lib/makura/model.rb', line 262

def proto_layout(common, name, opts = {})
  design[name] = layout = Layout.new(name, design)

  map_name    = opts.delete(:map)    || "#{self.name}_#{common}".downcase
  reduce_name = opts.delete(:reduce) || "#{self.name}_#{common}".downcase

  layout.load_proto_map(map_name, opts)
  layout.load_proto_reduce(reduce_name, opts)

  return layout
end

#saveObject



274
275
276
# File 'lib/makura/model.rb', line 274

def save
  design.save
end

#view(name, opts = {}) ⇒ Object



344
345
346
347
348
349
# File 'lib/makura/model.rb', line 344

def view(name, opts = {})
  flat = opts.delete(:flat)
  hash = database.view("#{Makura.escape(self)}/_view/#{name}", opts)

  convert_raw(hash['rows'], flat)
end

#view_with_docs(name, opts = {}) ⇒ Object Also known as: view_docs

It is generally recommended not to include the doc in the emit of the map function but to use include_docs=true. To make using this approach more convenient use this method.



337
338
339
340
# File 'lib/makura/model.rb', line 337

def view_with_docs(name, opts = {})
  opts.merge!(:include_docs => true, :reduce => false)
  view(name, opts)
end