Skip to content

Commit

Permalink
Merge branch 'new-views' into views-based-associations
Browse files Browse the repository at this point in the history
  • Loading branch information
yrashk committed Apr 29, 2008
2 parents 07d858a + 224495e commit 5d48e1a
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 26 deletions.
7 changes: 4 additions & 3 deletions lib/strokedb/document/meta.rb
Expand Up @@ -86,9 +86,10 @@ def +(meta)
new_meta.module_eval do
extend Meta
end
new_meta_name = new_meta.instance_variable_get(:@metas).map{|m| m.name}.join('__')
Object.send(:remove_const, new_meta_name) rescue nil
Object.const_set(new_meta_name, new_meta)
new_meta_name = new_meta.instance_variable_get(:@metas).map{|m| m.name.demodulize}.join('__')
mod = self.name.modulize.constantize rescue Object
mod.send(:remove_const, new_meta_name) rescue nil
mod.const_set(new_meta_name, new_meta)
new_meta
elsif is_a?(Document) && meta.is_a?(Document)
(Document.new(store, self.to_raw.except('uuid','version','previous_version'), true) +
Expand Down
6 changes: 5 additions & 1 deletion lib/strokedb/store.rb
Expand Up @@ -37,7 +37,10 @@ def head_version(uuid)
def save!(doc)
next_timestamp!
storage.save!(doc, timestamp)
#

update_views!(doc)

# TODO: remove this shit
if @index_store
if doc.previous_version
raw_pdoc = find(doc.uuid,doc.previous_version,:no_instantiation => true)
Expand All @@ -52,6 +55,7 @@ def save!(doc)

def save_as_head!(doc)
@storage.save_as_head!(doc,timestamp)
update_views!(doc)
end


Expand Down
5 changes: 3 additions & 2 deletions lib/strokedb/views.rb
@@ -1,4 +1,5 @@
require 'views/view'
require 'views/store_ext'
require 'views/default_key_encoder'
require 'views/raw_data_meta'
require 'views/view_storage'
require 'views/view_storage'
require 'views/view'
55 changes: 55 additions & 0 deletions lib/strokedb/views/store_ext.rb
@@ -0,0 +1,55 @@
module StrokeDB
class Store

# Tells a store to update a view on document save.
#
def register_view(v, metas = nil) #:nodoc:
initialize_views_list
if !metas || metas.empty?
@registered_views[:rest] << v
else
metas.each do |meta_name|
meta_name = meta_name.name if meta_name.is_a?(Meta)
meta_name = meta_name.to_s
@registered_views[meta_name] ||= [].to_set
@registered_views[meta_name] << v
end
end
end

# This is called when new document version is created.
#
def update_views!(doc) #:nodoc:
# Update generic views
@registered_views[:rest].each do |view|
view.update(doc)
end
doc.metas.each do |meta|
views = @registered_views[meta.name]
if views
views.each do |view|
view.update(doc)
end
end
end
end

# Lazy initialization (to avoid Store polluting)
#
alias :work_update_views! :update_views!
def update_views!(doc)
initialize_views_list
class << self
alias :update_views! :work_update_views!
end
update_views!(doc)
end

def initialize_views_list
@registered_views ||= {
:rest => [].to_set
# meta_name => [...].to_set
}
end
end
end
13 changes: 9 additions & 4 deletions lib/strokedb/views/view.rb
Expand Up @@ -33,6 +33,7 @@ module StrokeDB
if initialization_block = viewdoc.instance_variable_get(:@initialization_block) || initialization_block = VIEW_CACHE[viewdoc.uuid]
initialization_block.call(viewdoc)
end
viewdoc.store.register_view(viewdoc, viewdoc['only'])
end

after_save do |viewdoc|
Expand Down Expand Up @@ -243,10 +244,14 @@ def [](name, nsurl = name.modulize.empty? ? Module.nsurl : name.modulize.constan
# Define a view.
#
# Examples
# View.define("view_name", :option => "value") do |viewdoc| ... end
# View.define(:name => "view_name", :option => "value") do |viewdoc| ... end
# View.new("view_name", :option => "value") do |viewdoc| ... end
# View.new(:name => "view_name", :option => "value") do |viewdoc| ... end
# View.new(store, "view_name", :option => "value") do |viewdoc| ... end
# View.new(store, :name => "view_name", :option => "value") do |viewdoc| ... end
#
def new(*args, &block)
store = args.first.is_a?(Store) ? args.shift : StrokeDB.default_store

if args.first.is_a? String
options = args[1] || {}
options['name'] = args.first
Expand All @@ -265,11 +270,11 @@ def new(*args, &block)
options['uuid'] = ::Util.sha1_uuid("view:#{nsurl}##{name}")

unless v = find(options['uuid'])
v = original_new(options, &block)
v = original_new(store, options, &block)
end
v
end

alias :define :new
alias :define! :create!

Expand Down
6 changes: 3 additions & 3 deletions lib/strokedb/volumes/skiplist_volume.rb
Expand Up @@ -137,8 +137,8 @@ def close!
self
class <<self
alias :insert :raise_volume_closed
alias :close! :raise_volume_crashed
alias :dump! :raise_volume_crashed
alias :close! :raise_volume_closed
alias :dump! :raise_volume_closed
def closed?; true; end
end
end
Expand Down Expand Up @@ -178,7 +178,7 @@ def crash!(err = nil)
class <<self
alias :insert :raise_volume_crashed
alias :close! :raise_volume_crashed
alias :dump! :raise_volume_crashed
alias :dump! :raise_volume_crashed
end
end

Expand Down
73 changes: 60 additions & 13 deletions spec/lib/strokedb/views/view_spec.rb
Expand Up @@ -17,12 +17,21 @@
describe View, "without #map method defined" do
before(:each) do
setup_default_store
@post_comments = View.define!(:name => "post_comments")
end

it "should raise exception when view is created" do
lambda {
View.define!(:name => "post_comments_invalid")
}.should raise_error(InvalidViewError)
end

it "should raise exception when #map is used" do
lambda { @post_comments.map("key","value") }.should raise_error(InvalidViewError)
Comment = Meta.new
@post_comments = View.define!(:name => "post_comments_invalid", :only => ["comment"])
c = Comment.new :text => "hello"
lambda { @post_comments.map(c.uuid, c) }.should raise_error(InvalidViewError)
end

end

describe "'Has many comments' view" do
Expand All @@ -45,16 +54,6 @@ def view.map(uuid, doc)

@comment21 = Document.create! :type => "comment21", :parent => @article2, :created_at => Time.now
@comment22 = Document.create! :type => "comment22", :parent => @article2, :created_at => Time.now

# shuffled order to ensure, items are sorted correctly afterwards
@view.update(@article3)
@view.update(@comment22)
@view.update(@comment11)
@view.update(@article2)
@view.update(@comment12)
@view.update(@comment13)
@view.update(@article1)
@view.update(@comment21)
end

it "should find all the comments sorted by date" do
Expand Down Expand Up @@ -87,9 +86,57 @@ def view.map(uuid, doc)
@view.find(:key => @article2, :offset => 1, :limit => 2).should == [@comment22]
@view.find(:key => @article3, :offset => 1, :limit => 2).should == [ ]
end

end


describe View, "with :only option" do
before(:each) do
setup_default_store
block = proc {|view|
view.updated = "false"
class << view
def map(uuid, doc)
self.updated.replace "true"
nil # don't index
end
def updated?
self.updated == "true"
end
end
}
module A; end
A.send!(:remove_const, 'Article') if defined?(A::Article)
A.send!(:remove_const, 'SponsoredArticle') if defined?(A::SponsoredArticle)
A.send!(:remove_const, 'Comment') if defined?(A::Comment)

module A
Article = Meta.new
SponsoredArticle = Meta.new
Comment = Meta.new
end

@generic = View.new("generic", &block)
@comments = View.new("comments", :only => ["Comment"], &block)
@c_and_a = View.new("comments_and_articles", :only => ["Comment", "Article"], &block)
@sponsored = View.new("sponsored", :only => ["SponsoredArticle"], &block)
end
it "should update articles only" do
a = (A::Article + A::SponsoredArticle).create!(:title => "This is a sponsored article")
@generic.should be_updated
@comments.should_not be_updated
@c_and_a.should be_updated
@sponsored.should be_updated
end
it "should update comments only" do
c = A::Comment.create!(:text => "Hello")
@generic.should be_updated
@comments.should be_updated
@c_and_a.should be_updated
@sponsored.should_not be_updated
end
end


describe View, "with block defined and saved" do

before(:each) do
Expand Down

0 comments on commit 5d48e1a

Please sign in to comment.