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.



152
153
154
# File 'lib/makura/model.rb', line 152

def defaults
  @defaults
end

#makura_relationObject

Returns the value of attribute makura_relation.



152
153
154
# File 'lib/makura/model.rb', line 152

def makura_relation
  @makura_relation
end

#property_typeObject

Returns the value of attribute property_type.



152
153
154
# File 'lib/makura/model.rb', line 152

def property_type
  @property_type
end

Instance Method Details

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



239
240
241
242
243
# File 'lib/makura/model.rb', line 239

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

#belongs_to(name, model = nil) ⇒ Object



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

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



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

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



168
169
170
# File 'lib/makura/model.rb', line 168

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

#database=(name) ⇒ Object



164
165
166
# File 'lib/makura/model.rb', line 164

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

#designObject



245
246
247
# File 'lib/makura/model.rb', line 245

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

#has_many(name, model = nil) ⇒ Object



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

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



199
200
201
202
203
204
# File 'lib/makura/model.rb', line 199

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

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



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

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

  unless opts[:map] || opts[:reduce]
    prefix = self.name.gsub('::', '/')
  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.


323
324
325
326
327
328
# File 'lib/makura/model.rb', line 323

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

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



330
331
332
333
# File 'lib/makura/model.rb', line 330

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

#plugin(name) ⇒ Object



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

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



172
173
174
# File 'lib/makura/model.rb', line 172

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

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



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

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



265
266
267
268
269
270
271
272
273
274
275
# File 'lib/makura/model.rb', line 265

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



277
278
279
# File 'lib/makura/model.rb', line 277

def save
  design.save
end

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



347
348
349
350
351
352
# File 'lib/makura/model.rb', line 347

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.



340
341
342
343
# File 'lib/makura/model.rb', line 340

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