Class: CouchRest::Model::Designs::Design

Inherits:
Design
  • Object
show all
Defined in:
lib/couchrest/model/designs/design.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, prefix = nil) ⇒ Design

Instantiate a new design document for this model



17
18
19
20
21
22
23
# File 'lib/couchrest/model/designs/design.rb', line 17

def initialize(model, prefix = nil)
  self.model       = model
  self.method_name = self.class.method_name(prefix)
  suffix = prefix ? "_#{prefix}" : ''
  self["_id"] = "_design/#{model.to_s}#{suffix}"
  apply_defaults
end

Instance Attribute Details

#auto_updateObject

Can this design save itself to the database? If false, the design will be loaded automatically before a view is executed.



13
14
15
# File 'lib/couchrest/model/designs/design.rb', line 13

def auto_update
  @auto_update
end

#method_nameObject

The model Class that this design belongs to and method name



9
10
11
# File 'lib/couchrest/model/designs/design.rb', line 9

def method_name
  @method_name
end

#modelObject

The model Class that this design belongs to and method name



9
10
11
# File 'lib/couchrest/model/designs/design.rb', line 9

def model
  @model
end

Class Method Details

.method_name(prefix = nil) ⇒ Object



273
274
275
# File 'lib/couchrest/model/designs/design.rb', line 273

def method_name(prefix = nil)
  (prefix ? "#{prefix}_" : '') + 'design_doc'
end

Instance Method Details

#checksumObject



162
163
164
165
166
167
168
169
# File 'lib/couchrest/model/designs/design.rb', line 162

def checksum
  sum = self['couchrest-hash']
  if sum && (@_original_hash == to_hash)
    sum
  else
    checksum!
  end
end

#create_filter(name, function) ⇒ Object

FILTER HANDLING ########



208
209
210
211
# File 'lib/couchrest/model/designs/design.rb', line 208

def create_filter(name, function)
  filters = (self['filters'] ||= {})
  filters[name.to_s] = function
end

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

Add the specified view to the design doc the definition was made in and create quick access methods in the model.



202
203
204
# File 'lib/couchrest/model/designs/design.rb', line 202

def create_view(name, opts = {})
  View.define_and_create(self, name, opts)
end

#databaseObject



171
172
173
# File 'lib/couchrest/model/designs/design.rb', line 171

def database
  model.database
end

#has_view?(name) ⇒ Boolean

Returns:

  • (Boolean)


196
197
198
# File 'lib/couchrest/model/designs/design.rb', line 196

def has_view?(name)
  view_names.include?(name.to_s)
end

#migrate(db = nil) {|result| ... } ⇒ Object

Migrate the design document preventing downtime on a production system. Typically this will be used when auto updates are disabled.

Steps taken are:

1. Compare the checksum with the current version
2. If different, create a new design doc with timestamp
3. Wait until the view returns a result
4. Copy over the original design doc

If a block is provided, it will be called with the result of the migration:

* :no_change - Nothing performed as there are no changes.
* :created   - Add a new design doc as non existed
* :migrated  - Migrated the existing design doc.

This can be used for progressivly printing the results of the migration.

After completion, either a "cleanup" Proc object will be provided to finalize the process and copy the document into place, or simply nil if no cleanup is required. For example:

print "Synchronising Cat model designs: "
callback = Cat.design_doc.migrate do |res|
  puts res.to_s
end
if callback
  puts "Cleaning up."
  callback.call
end

Yields:

  • (result)


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/couchrest/model/designs/design.rb', line 91

def migrate(db = nil, &block)
  db    ||= database
  doc     = load_from_database(db)
  cleanup = nil
  id      = self['_id']

  if !doc
    # no need to migrate, just save it
    new_doc = to_hash.dup
    db.save_doc(new_doc)

    result = :created
  elsif doc['couchrest-hash'] != checksum
    id += "_migration"

    # Delete current migration if there is one
    old_migration = load_from_database(db, id)
    db.delete_doc(old_migration) if old_migration

    # Save new design doc
    new_doc = doc.merge(to_hash)
    new_doc['_id'] = id
    new_doc.delete('_rev')
    db.save_doc(new_doc)

    # Proc definition to copy the migration doc over the original
    cleanup = Proc.new do
      db.copy_doc(new_doc, doc)
      db.delete_doc(new_doc)
      self
    end

    result = :migrated
  else
    # Already up to date
    result = :no_change
  end

  if new_doc && !new_doc['views'].empty?
    # Create a view query and send
    name = new_doc['views'].keys.first
    view = new_doc['views'][name]
    params = {:limit => 1}
    params[:reduce] = false if view['reduce']
    db.view("#{id}/_view/#{name}", params) do |res|
      # Block to use streamer!
    end
  end

  # Provide the result in block
  yield result if block_given?

  cleanup
end

#migrate!(db = nil, &block) ⇒ Object

Perform a single migration and inmediatly request a cleanup operation:

print "Synchronising Cat model designs: "
Cat.design_doc.migrate! do |res|
  puts res.to_s
end


153
154
155
156
157
158
159
160
# File 'lib/couchrest/model/designs/design.rb', line 153

def migrate!(db = nil, &block)
  callback = migrate(db, &block)
  if callback.is_a?(Proc)
    callback.call
  else
    callback
  end
end

#sync(db = nil) ⇒ Object



25
26
27
28
29
30
31
32
33
34
# File 'lib/couchrest/model/designs/design.rb', line 25

def sync(db = nil)
  if auto_update
    db ||= database
    if cache_checksum(db) != checksum
      sync!(db)
      set_cache_checksum(db, checksum)
    end
  end
  self
end

#sync!(db = nil) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/couchrest/model/designs/design.rb', line 36

def sync!(db = nil)
  db ||= database

  # Load up the last copy. We never blindly overwrite the remote copy
  # as it may contain views that are not used or known about by
  # our model.
  doc = load_from_database(db)

  if !doc || doc['couchrest-hash'] != checksum
    # We need to save something
    if doc
      # Different! Update.
      doc.merge!(to_hash)
    else
      # No previous doc, use a *copy* of our version.
      # Using a copy prevents reverse updates.
      doc = to_hash.dup
    end
    db.save_doc(doc)
  end

  self
end

#uri(db = database) ⇒ Object

Override the default #uri method for one that accepts the current database. This is used by the caching code.



178
179
180
# File 'lib/couchrest/model/designs/design.rb', line 178

def uri(db = database)
  "#{db.root}/#{self['_id']}"
end

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

Create a new view object. This overrides the normal CouchRest Design view method



187
188
189
# File 'lib/couchrest/model/designs/design.rb', line 187

def view(name, opts = {})
  CouchRest::Model::Designs::View.new(self, model, opts, name)
end

#view_namesObject

Helper method to provide a list of all the views



192
193
194
# File 'lib/couchrest/model/designs/design.rb', line 192

def view_names
  self['views'].keys
end