Class: Couchbase::Model
- Defined in:
- lib/couchbase/model.rb,
lib/couchbase/model/uuid.rb,
lib/couchbase/model/version.rb,
lib/couchbase/model/configuration.rb
Overview
Declarative layer for Couchbase gem
You can also let the library generate the unique identifier for you:
p = Post.create(:title => 'How to generate ID',
:body => 'Open up the editor...')
p.id #=> "74f43c3116e788d09853226603000809"
There are several algorithms available. By default it use ‘:sequential` algorithm, but you can change it to more suitable one for you:
class Post < Couchbase::Model
attribute :title
attribute :body
attribute :draft
uuid_algorithm :random
end
You can define connection options on per model basis:
class Post < Couchbase::Model
attribute :title
attribute :body
attribute :draft
connect :port => 80, :bucket => 'blog'
end
Defined Under Namespace
Modules: Configuration Classes: UUID
Constant Summary collapse
- VERSION =
"0.2.0"
Instance Attribute Summary collapse
- #doc ⇒ Object readonly
-
#id ⇒ Object
Each model must have identifier.
- #key ⇒ Object readonly
- #meta ⇒ Object readonly
- #value ⇒ Object readonly
Class Method Summary collapse
-
.attribute(*names) ⇒ Object
Defines an attribute for the model.
-
.attributes ⇒ Hash
All defined attributes within a class.
-
.connect(*options) ⇒ Couchbase::Bucket
Use custom connection options.
-
.create(*args) ⇒ Couchbase::Model
Create the model with given attributes.
-
.design_document(name = nil) ⇒ String
Associate custom design document with the model.
-
.ensure_design_document! ⇒ Object
Ensure that design document is up to date.
-
.exists?(id) ⇒ true, false
Check if the key exists in the bucket.
-
.find(id) ⇒ Couchbase::Model
Find the model using
id
attribute. -
.find_by_id(id) ⇒ Couchbase::Model?
Find the model using
id
attribute. - .inspect ⇒ Object
-
.uuid_algorithm(algorithm) ⇒ Symbol
Choose the UUID generation algorithms.
-
.view(*names) ⇒ Object
Defines a view for the model.
-
.views ⇒ Array
All defined views within a class.
Instance Method Summary collapse
-
#attributes ⇒ Hash
All the attributes of the current instance.
-
#create ⇒ Couchbase::Model
Create this model and assign new id if necessary.
-
#delete ⇒ Couchbase::Model
Delete this object from the bucket.
-
#exists? ⇒ true, false
Check if this model exists in the bucket.
-
#initialize(attrs = {}) ⇒ Model
constructor
Constructor for all subclasses of Couchbase::Model.
-
#new? ⇒ true, false
Check if the record have
id
attribute. -
#reload ⇒ Model
Reload all the model attributes from the bucket.
-
#save ⇒ Couchbase::Model
Create or update this object based on the state of #new?.
-
#update(attrs) ⇒ Couchbase::Model
Update this object, optionally accepting new attributes.
-
#update_attributes(attrs) ⇒ Object
Update all attributes without persisting the changes.
Constructor Details
#initialize(attrs = {}) ⇒ Model
Constructor for all subclasses of Couchbase::Model
Optionally takes a Hash of attribute value pairs.
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
# File 'lib/couchbase/model.rb', line 373 def initialize(attrs = {}) if attrs.respond_to?(:with_indifferent_access) attrs = attrs.with_indifferent_access end @id = attrs.delete(:id) @key = attrs.delete(:key) @value = attrs.delete(:value) @doc = attrs.delete(:doc) @meta = attrs.delete(:meta) @_attributes = ::Hash.new do |h, k| default = self.class.attributes[k] h[k] = if default.respond_to?(:call) default.call else default end end update_attributes(@doc || attrs) end |
Instance Attribute Details
#id ⇒ Object
Each model must have identifier
87 88 89 |
# File 'lib/couchbase/model.rb', line 87 def id @id end |
Class Method Details
.attribute(*names) ⇒ Object
Defines an attribute for the model
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/couchbase/model.rb', line 271 def self.attribute(*names) = {} if names.last.is_a?(Hash) = names.pop end names.each do |name| attributes[name] = [:default] name = name.to_sym next if self.instance_methods.include?(name) define_method(name) do @_attributes[name] end define_method(:"#{name}=") do |value| @_attributes[name] = value end end end |
.attributes ⇒ Hash
All defined attributes within a class.
498 499 500 |
# File 'lib/couchbase/model.rb', line 498 def self.attributes @@attributes[self] end |
.connect(*options) ⇒ Couchbase::Bucket
Use custom connection options
122 123 124 |
# File 'lib/couchbase/model.rb', line 122 def self.connect(*) self.bucket = Couchbase.connect(*) end |
.create(*args) ⇒ Couchbase::Model
Create the model with given attributes
362 363 364 |
# File 'lib/couchbase/model.rb', line 362 def self.create(*args) new(*args).create end |
.design_document(name = nil) ⇒ String
Associate custom design document with the model
Design document is the special document which contains views, the chunks of code for building map/reduce indexes. When this method called without argument, it just returns the effective design document name.
146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/couchbase/model.rb', line 146 def self.design_document(name = nil) if name @_design_doc = name.to_s else @_design_doc ||= begin name = self.name.dup name.gsub!(/::/, '_') name.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2') name.gsub!(/([a-z\d])([A-Z])/,'\1_\2') name.downcase! end end end |
.ensure_design_document! ⇒ Object
Ensure that design document is up to date.
This method also cares about organizing view in separate javascript files. The general structure is the following ([root]
is the directory, one of the Couchbase::Model::Configuration#design_documents_paths):
[root]
|
`- link
| |
| `- by_created_at
| | |
| | `- map.js
| |
| `- by_session_id
| | |
| | `- map.js
| |
| `- total_views
| | |
| | `- map.js
| | |
| | `- reduce.js
The directory structure above demonstrate layout for design document with id _design/link
and three views: by_create_at
, +by_session_id` and ‘total_views`.
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/couchbase/model.rb', line 189 def self.ensure_design_document! unless Configuration.design_documents_paths raise "Configuration.design_documents_path must be directory" end doc = {'_id' => "_design/#{design_document}", 'views' => {}} digest = Digest::MD5.new mtime = 0 views.each do |name, _| doc['views'][name] = {} doc['spatial'] = {} ['map', 'reduce', 'spatial'].each do |type| Configuration.design_documents_paths.each do |path| ff = File.join(path, design_document.to_s, name.to_s, "#{type}.js") if File.file?(ff) contents = File.read(ff).strip next if contents.empty? mtime = [mtime, File.mtime(ff).to_i].max digest << contents case type when 'map', 'reduce' doc['views'][name][type] = contents when 'spatial' doc['spatial'][name] = contents end break # pick first matching file end end end end doc['views'].delete_if {|_, v| v.empty? } doc.delete('spatial') if doc['spatial'].empty? doc['signature'] = digest.to_s doc['timestamp'] = mtime if doc['signature'] != thread_storage[:signature] && doc['timestamp'] > thread_storage[:timestamp].to_i current_doc = bucket.design_docs[design_document.to_s] if current_doc.nil? || (current_doc['signature'] != doc['signature'] && doc['timestamp'] > current_doc[:timestamp].to_i) bucket.save_design_doc(doc) current_doc = doc end thread_storage[:signature] = current_doc['signature'] thread_storage[:timestamp] = current_doc['timestamp'].to_i end end |
.exists?(id) ⇒ true, false
Check if the key exists in the bucket
477 478 479 |
# File 'lib/couchbase/model.rb', line 477 def self.exists?(id) !!bucket.get(id, :quiet => true) end |
.find(id) ⇒ Couchbase::Model
Find the model using id
attribute
332 333 334 335 336 337 |
# File 'lib/couchbase/model.rb', line 332 def self.find(id) if id && (res = bucket.get(id, :quiet => false, :extended => true)) obj, flags, cas = res new({:id => id, :meta => {'flags' => flags, 'cas' => cas}}.merge(obj)) end end |
.find_by_id(id) ⇒ Couchbase::Model?
Find the model using id
attribute
349 350 351 352 353 354 |
# File 'lib/couchbase/model.rb', line 349 def self.find_by_id(id) if id && (res = bucket.get(id, :quiet => true)) obj, flags, cas = res new({:id => id, :meta => {'flags' => flags, 'cas' => cas}}.merge(obj)) end end |
.inspect ⇒ Object
622 623 624 625 626 627 628 |
# File 'lib/couchbase/model.rb', line 622 def self.inspect buf = "#{name}" if self != Couchbase::Model buf << "(#{['id', attributes.map(&:first)].flatten.join(', ')})" end buf end |
.uuid_algorithm(algorithm) ⇒ Symbol
Choose the UUID generation algorithms
251 252 253 |
# File 'lib/couchbase/model.rb', line 251 def self.uuid_algorithm(algorithm) self.thread_storage[:uuid_algorithm] = algorithm end |
.view(*names) ⇒ Object
Defines a view for the model
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/couchbase/model.rb', line 306 def self.view(*names) = {:wrapper_class => self, :include_docs => true} if names.last.is_a?(Hash) .update(names.pop) end is_spatial = .delete(:spatial) names.each do |name| path = "_design/%s/_%s/%s" % [design_document, is_spatial ? "spatial" : "view", name] views[name] = lambda do |*params| params = .merge(params.first || {}) View.new(bucket, path, params) end singleton_class.send(:define_method, name, &views[name]) end end |
.views ⇒ Array
All defined views within a class.
509 510 511 |
# File 'lib/couchbase/model.rb', line 509 def self.views @@views[self] end |
Instance Method Details
#attributes ⇒ Hash
All the attributes of the current instance
518 519 520 |
# File 'lib/couchbase/model.rb', line 518 def attributes @_attributes end |
#create ⇒ Couchbase::Model
Create this model and assign new id if necessary
405 406 407 408 409 |
# File 'lib/couchbase/model.rb', line 405 def create @id ||= Couchbase::Model::UUID.generator.next(1, model.thread_storage[:uuid_algorithm]) model.bucket.add(@id, attributes_with_values) self end |
#delete ⇒ Couchbase::Model
This method will reset id
attribute
Delete this object from the bucket
450 451 452 453 454 455 |
# File 'lib/couchbase/model.rb', line 450 def delete raise Couchbase::Error::MissingId, "missing id attribute" unless @id model.bucket.delete(@id) @id = nil self end |
#exists? ⇒ true, false
Check if this model exists in the bucket.
487 488 489 |
# File 'lib/couchbase/model.rb', line 487 def exists? model.exists?(@id) end |
#new? ⇒ true, false
true
doesn’t mean that record exists in the database
Check if the record have id
attribute
466 467 468 |
# File 'lib/couchbase/model.rb', line 466 def new? !@id end |
#reload ⇒ Model
Reload all the model attributes from the bucket
545 546 547 548 549 550 |
# File 'lib/couchbase/model.rb', line 545 def reload raise Couchbase::Error::MissingId, "missing id attribute" unless @id attrs = model.find(@id).attributes update_attributes(attrs) self end |
#save ⇒ Couchbase::Model
Create or update this object based on the state of #new?.
421 422 423 424 425 |
# File 'lib/couchbase/model.rb', line 421 def save return create if new? model.bucket.set(@id, attributes_with_values) self end |
#update(attrs) ⇒ Couchbase::Model
Update this object, optionally accepting new attributes.
434 435 436 437 |
# File 'lib/couchbase/model.rb', line 434 def update(attrs) update_attributes(attrs) save end |
#update_attributes(attrs) ⇒ Object
Update all attributes without persisting the changes.
527 528 529 530 531 532 533 534 535 |
# File 'lib/couchbase/model.rb', line 527 def update_attributes(attrs) if id = attrs.delete(:id) @id = id end attrs.each do |key, value| setter = :"#{key}=" send(setter, value) if respond_to?(setter) end end |