move to class_inheritable_accessor
This commit is contained in:
parent
c170008deb
commit
355d408730
2 changed files with 96 additions and 39 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
require 'rubygems'
|
||||||
|
require 'extlib'
|
||||||
require 'digest/md5'
|
require 'digest/md5'
|
||||||
|
|
||||||
# = CouchRest::Model - ORM, the CouchDB way
|
# = CouchRest::Model - ORM, the CouchDB way
|
||||||
|
@ -62,20 +64,26 @@ module CouchRest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
# this is the CouchRest::Database that model classes will use unless
|
||||||
# this is the CouchRest::Database that model classes will use unless
|
# they override it with <tt>use_database</tt>
|
||||||
# they override it with <tt>use_database</tt>
|
cattr_accessor :default_database
|
||||||
attr_accessor :default_database
|
|
||||||
attr_accessor :template
|
|
||||||
|
|
||||||
|
class_inheritable_accessor :casts
|
||||||
|
class_inheritable_accessor :default_obj
|
||||||
|
class_inheritable_accessor :class_database
|
||||||
|
class_inheritable_accessor :generated_design_doc
|
||||||
|
class_inheritable_accessor :design_doc_slug_cache
|
||||||
|
class_inheritable_accessor :design_doc_fresh
|
||||||
|
|
||||||
|
class << self
|
||||||
# override the CouchRest::Model-wide default_database
|
# override the CouchRest::Model-wide default_database
|
||||||
def use_database db
|
def use_database db
|
||||||
@database = db
|
self.class_database = db
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns the CouchRest::Database instance that this class uses
|
# returns the CouchRest::Database instance that this class uses
|
||||||
def database
|
def database
|
||||||
@database || CouchRest::Model.default_database
|
self.class_database || CouchRest::Model.default_database
|
||||||
end
|
end
|
||||||
|
|
||||||
# load a document from the database
|
# load a document from the database
|
||||||
|
@ -84,18 +92,21 @@ module CouchRest
|
||||||
new(doc)
|
new(doc)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def all opts = {}
|
||||||
|
view_name = "#{design_doc_slug}/all"
|
||||||
|
raw = opts.delete(:raw)
|
||||||
|
view = fetch_view(view_name, opts)
|
||||||
|
process_view_results view, raw
|
||||||
|
end
|
||||||
|
|
||||||
# Cast a field as another class. The class must be happy to have the
|
# Cast a field as another class. The class must be happy to have the
|
||||||
# field's primitive type as the argument to it's constucture. Classes
|
# field's primitive type as the argument to it's constucture. Classes
|
||||||
# which inherit from CouchRest::Model are happy to act as sub-objects
|
# which inherit from CouchRest::Model are happy to act as sub-objects
|
||||||
# for any fields that are stored in JSON as object (and therefore are
|
# for any fields that are stored in JSON as object (and therefore are
|
||||||
# parsed from the JSON as Ruby Hashes).
|
# parsed from the JSON as Ruby Hashes).
|
||||||
def cast field, opts = {}
|
def cast field, opts = {}
|
||||||
@casts ||= {}
|
self.casts ||= {}
|
||||||
@casts[field.to_s] = opts
|
self.casts[field.to_s] = opts
|
||||||
end
|
|
||||||
|
|
||||||
def casts
|
|
||||||
@casts
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Defines methods for reading and writing from fields in the document.
|
# Defines methods for reading and writing from fields in the document.
|
||||||
|
@ -128,11 +139,11 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
def default
|
def default
|
||||||
@default
|
self.default_obj
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_default hash
|
def set_default hash
|
||||||
@default = hash
|
self.default_obj = hash
|
||||||
end
|
end
|
||||||
|
|
||||||
# Automatically set <tt>updated_at</tt> and <tt>created_at</tt> fields
|
# Automatically set <tt>updated_at</tt> and <tt>created_at</tt> fields
|
||||||
|
@ -236,7 +247,7 @@ module CouchRest
|
||||||
type = self.to_s
|
type = self.to_s
|
||||||
|
|
||||||
method_name = "by_#{keys.join('_and_')}"
|
method_name = "by_#{keys.join('_and_')}"
|
||||||
@@design_doc ||= default_design_doc
|
self.generated_design_doc ||= default_design_doc
|
||||||
|
|
||||||
if opts[:map]
|
if opts[:map]
|
||||||
view = {}
|
view = {}
|
||||||
|
@ -245,7 +256,7 @@ module CouchRest
|
||||||
view['reduce'] = opts.delete(:reduce)
|
view['reduce'] = opts.delete(:reduce)
|
||||||
opts[:reduce] = false
|
opts[:reduce] = false
|
||||||
end
|
end
|
||||||
@@design_doc['views'][method_name] = view
|
generated_design_doc['views'][method_name] = view
|
||||||
else
|
else
|
||||||
doc_keys = keys.collect{|k|"doc['#{k}']"}
|
doc_keys = keys.collect{|k|"doc['#{k}']"}
|
||||||
key_protection = doc_keys.join(' && ')
|
key_protection = doc_keys.join(' && ')
|
||||||
|
@ -257,30 +268,24 @@ module CouchRest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JAVASCRIPT
|
JAVASCRIPT
|
||||||
@@design_doc['views'][method_name] = {
|
generated_design_doc['views'][method_name] = {
|
||||||
'map' => map_function
|
'map' => map_function
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@design_doc_fresh = false
|
self.design_doc_fresh = false
|
||||||
|
|
||||||
self.meta_class.instance_eval do
|
self.meta_class.instance_eval do
|
||||||
define_method method_name do |*args|
|
define_method method_name do |*args|
|
||||||
query = opts.merge(args[0] || {})
|
query = opts.merge(args[0] || {})
|
||||||
query[:raw] = true if query[:reduce]
|
query[:raw] = true if query[:reduce]
|
||||||
unless @@design_doc_fresh
|
unless design_doc_fresh
|
||||||
refresh_design_doc
|
refresh_design_doc
|
||||||
end
|
end
|
||||||
raw = query.delete(:raw)
|
raw = query.delete(:raw)
|
||||||
view_name = "#{design_doc_slug}/#{method_name}"
|
view_name = "#{design_doc_slug}/#{method_name}"
|
||||||
|
|
||||||
view = fetch_view(view_name, query)
|
view = fetch_view(view_name, query)
|
||||||
if raw
|
process_view_results view, raw
|
||||||
view
|
|
||||||
else
|
|
||||||
# TODO this can be optimized once the include-docs patch is applied
|
|
||||||
view['rows'].collect{|r|new(database.get(r['id']))}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -292,6 +297,15 @@ module CouchRest
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def process_view_results view, raw=false
|
||||||
|
if raw
|
||||||
|
view
|
||||||
|
else
|
||||||
|
# TODO this can be optimized once the include-docs patch is applied
|
||||||
|
view['rows'].collect{|r|new(database.get(r['id']))}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def fetch_view view_name, opts
|
def fetch_view view_name, opts
|
||||||
retryable = true
|
retryable = true
|
||||||
begin
|
begin
|
||||||
|
@ -309,19 +323,27 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
def design_doc_slug
|
def design_doc_slug
|
||||||
return @design_doc_slug if @design_doc_slug && @@design_doc_fresh
|
return design_doc_slug_cache if design_doc_slug_cache && design_doc_fresh
|
||||||
funcs = []
|
funcs = []
|
||||||
@@design_doc['views'].each do |name, view|
|
generated_design_doc['views'].each do |name, view|
|
||||||
funcs << "#{name}/#{view}"
|
funcs << "#{name}/#{view['map']}#{view['reduce']}"
|
||||||
end
|
end
|
||||||
md5 = Digest::MD5.hexdigest(funcs.sort.join(''))
|
md5 = Digest::MD5.hexdigest(funcs.sort.join(''))
|
||||||
@design_doc_slug = "#{self.to_s}-#{md5}"
|
self.design_doc_slug_cache = "#{self.to_s}-#{md5}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_design_doc
|
def default_design_doc
|
||||||
{
|
{
|
||||||
"language" => "javascript",
|
"language" => "javascript",
|
||||||
"views" => {}
|
"views" => {
|
||||||
|
'all' => {
|
||||||
|
'map' => "function(doc) {
|
||||||
|
if (doc['couchrest-type'] == '#{self.to_s}') {
|
||||||
|
emit(null,null);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -329,21 +351,19 @@ module CouchRest
|
||||||
did = "_design/#{design_doc_slug}"
|
did = "_design/#{design_doc_slug}"
|
||||||
saved = database.get(did) rescue nil
|
saved = database.get(did) rescue nil
|
||||||
if saved
|
if saved
|
||||||
@@design_doc['views'].each do |name, view|
|
generated_design_doc['views'].each do |name, view|
|
||||||
saved['views'][name] = view
|
saved['views'][name] = view
|
||||||
end
|
end
|
||||||
database.save(saved)
|
database.save(saved)
|
||||||
else
|
else
|
||||||
@@design_doc['_id'] = did
|
generated_design_doc['_id'] = did
|
||||||
database.save(@@design_doc)
|
database.save(generated_design_doc)
|
||||||
end
|
end
|
||||||
@@design_doc_fresh = true
|
self.design_doc_fresh = true
|
||||||
end
|
end
|
||||||
|
|
||||||
end # class << self
|
end # class << self
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# returns the database used by this model's class
|
# returns the database used by this model's class
|
||||||
def database
|
def database
|
||||||
self.class.database
|
self.class.database
|
||||||
|
|
|
@ -29,6 +29,7 @@ class Course < CouchRest::Model
|
||||||
key_accessor :title
|
key_accessor :title
|
||||||
cast :questions, :as => [Question]
|
cast :questions, :as => [Question]
|
||||||
cast :professor, :as => Person
|
cast :professor, :as => Person
|
||||||
|
view_by :title
|
||||||
end
|
end
|
||||||
|
|
||||||
class Article < CouchRest::Model
|
class Article < CouchRest::Model
|
||||||
|
@ -177,6 +178,25 @@ describe CouchRest::Model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "finding all instances of a model" do
|
||||||
|
before(:all) do
|
||||||
|
WithTemplate.new('important-field' => '1').save
|
||||||
|
WithTemplate.new('important-field' => '2').save
|
||||||
|
WithTemplate.new('important-field' => '3').save
|
||||||
|
WithTemplate.new('important-field' => '4').save
|
||||||
|
end
|
||||||
|
it "should make the design doc" do
|
||||||
|
WithTemplate.all
|
||||||
|
puts d = WithTemplate.design_doc.to_json
|
||||||
|
d.should == 'xs'
|
||||||
|
end
|
||||||
|
it "should find all" do
|
||||||
|
rs = WithTemplate.all :raw => true
|
||||||
|
rs.should == 'x'
|
||||||
|
rs.length.should == 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "getting a model with a subobject field" do
|
describe "getting a model with a subobject field" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
course_doc = {
|
course_doc = {
|
||||||
|
@ -356,6 +376,23 @@ describe CouchRest::Model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "another model with a simple view" do
|
||||||
|
before(:all) do
|
||||||
|
Course.database.delete! rescue nil
|
||||||
|
@db = @cr.create_db(TESTDB) rescue nil
|
||||||
|
Course.new(:title => 'aaa').save
|
||||||
|
Course.new(:title => 'bbb').save
|
||||||
|
end
|
||||||
|
it "should make the design doc" do
|
||||||
|
doc = Course.design_doc
|
||||||
|
doc['views']['all']['map'].should include('Course')
|
||||||
|
end
|
||||||
|
it "should get them" do
|
||||||
|
rs = Course.by_title
|
||||||
|
rs.length.should == 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "a model with a compound key view" do
|
describe "a model with a compound key view" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
written_at = Time.now - 24 * 3600 * 7
|
written_at = Time.now - 24 * 3600 * 7
|
||||||
|
|
Loading…
Add table
Reference in a new issue