friendly 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +23 -0
- data/APACHE-LICENSE +202 -0
- data/LICENSE +20 -0
- data/README.md +173 -0
- data/Rakefile +67 -0
- data/VERSION +1 -0
- data/examples/friendly.yml +7 -0
- data/friendly.gemspec +201 -0
- data/lib/friendly/attribute.rb +65 -0
- data/lib/friendly/boolean.rb +6 -0
- data/lib/friendly/cache/by_id.rb +33 -0
- data/lib/friendly/cache.rb +24 -0
- data/lib/friendly/config.rb +5 -0
- data/lib/friendly/data_store.rb +72 -0
- data/lib/friendly/document.rb +165 -0
- data/lib/friendly/document_table.rb +56 -0
- data/lib/friendly/index.rb +73 -0
- data/lib/friendly/memcached.rb +48 -0
- data/lib/friendly/newrelic.rb +6 -0
- data/lib/friendly/query.rb +42 -0
- data/lib/friendly/sequel_monkey_patches.rb +35 -0
- data/lib/friendly/storage.rb +31 -0
- data/lib/friendly/storage_factory.rb +24 -0
- data/lib/friendly/storage_proxy.rb +103 -0
- data/lib/friendly/table.rb +15 -0
- data/lib/friendly/table_creator.rb +43 -0
- data/lib/friendly/time.rb +14 -0
- data/lib/friendly/translator.rb +32 -0
- data/lib/friendly/uuid.rb +143 -0
- data/lib/friendly.rb +49 -0
- data/rails/init.rb +3 -0
- data/spec/fakes/data_store_fake.rb +29 -0
- data/spec/fakes/database_fake.rb +12 -0
- data/spec/fakes/dataset_fake.rb +28 -0
- data/spec/fakes/document.rb +18 -0
- data/spec/fakes/serializer_fake.rb +12 -0
- data/spec/fakes/time_fake.rb +12 -0
- data/spec/integration/basic_object_lifecycle_spec.rb +114 -0
- data/spec/integration/batch_insertion_spec.rb +29 -0
- data/spec/integration/convenience_api_spec.rb +25 -0
- data/spec/integration/count_spec.rb +12 -0
- data/spec/integration/default_value_spec.rb +15 -0
- data/spec/integration/find_via_cache_spec.rb +101 -0
- data/spec/integration/finder_spec.rb +64 -0
- data/spec/integration/index_spec.rb +57 -0
- data/spec/integration/pagination_spec.rb +63 -0
- data/spec/integration/table_creator_spec.rb +52 -0
- data/spec/integration/write_through_cache_spec.rb +53 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +90 -0
- data/spec/unit/attribute_spec.rb +64 -0
- data/spec/unit/cache_by_id_spec.rb +102 -0
- data/spec/unit/cache_spec.rb +21 -0
- data/spec/unit/config_spec.rb +4 -0
- data/spec/unit/data_store_spec.rb +188 -0
- data/spec/unit/document_spec.rb +311 -0
- data/spec/unit/document_table_spec.rb +126 -0
- data/spec/unit/friendly_spec.rb +25 -0
- data/spec/unit/index_spec.rb +196 -0
- data/spec/unit/memcached_spec.rb +114 -0
- data/spec/unit/query_spec.rb +104 -0
- data/spec/unit/storage_factory_spec.rb +59 -0
- data/spec/unit/storage_proxy_spec.rb +218 -0
- data/spec/unit/translator_spec.rb +96 -0
- data/website/index.html +210 -0
- data/website/scripts/clipboard.swf +0 -0
- data/website/scripts/shBrushAS3.js +61 -0
- data/website/scripts/shBrushBash.js +66 -0
- data/website/scripts/shBrushCSharp.js +67 -0
- data/website/scripts/shBrushColdFusion.js +102 -0
- data/website/scripts/shBrushCpp.js +99 -0
- data/website/scripts/shBrushCss.js +93 -0
- data/website/scripts/shBrushDelphi.js +57 -0
- data/website/scripts/shBrushDiff.js +43 -0
- data/website/scripts/shBrushErlang.js +54 -0
- data/website/scripts/shBrushGroovy.js +69 -0
- data/website/scripts/shBrushJScript.js +52 -0
- data/website/scripts/shBrushJava.js +59 -0
- data/website/scripts/shBrushJavaFX.js +60 -0
- data/website/scripts/shBrushPerl.js +74 -0
- data/website/scripts/shBrushPhp.js +91 -0
- data/website/scripts/shBrushPlain.js +35 -0
- data/website/scripts/shBrushPowerShell.js +76 -0
- data/website/scripts/shBrushPython.js +66 -0
- data/website/scripts/shBrushRuby.js +57 -0
- data/website/scripts/shBrushScala.js +53 -0
- data/website/scripts/shBrushSql.js +68 -0
- data/website/scripts/shBrushVb.js +58 -0
- data/website/scripts/shBrushXml.js +71 -0
- data/website/scripts/shCore.js +30 -0
- data/website/scripts/shLegacy.js +30 -0
- data/website/styles/friendly.css +103 -0
- data/website/styles/help.png +0 -0
- data/website/styles/ie.css +35 -0
- data/website/styles/magnifier.png +0 -0
- data/website/styles/page_white_code.png +0 -0
- data/website/styles/page_white_copy.png +0 -0
- data/website/styles/print.css +29 -0
- data/website/styles/printer.png +0 -0
- data/website/styles/screen.css +257 -0
- data/website/styles/shCore.css +330 -0
- data/website/styles/shThemeDefault.css +173 -0
- data/website/styles/shThemeDjango.css +176 -0
- data/website/styles/shThemeEclipse.css +190 -0
- data/website/styles/shThemeEmacs.css +175 -0
- data/website/styles/shThemeFadeToGrey.css +177 -0
- data/website/styles/shThemeMidnight.css +175 -0
- data/website/styles/shThemeRDark.css +175 -0
- metadata +264 -0
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
3
|
+
Dir[File.expand_path(File.dirname(__FILE__)) + "/fakes/*.rb"].each do |f|
|
|
4
|
+
require f
|
|
5
|
+
end
|
|
6
|
+
require 'rubygems'
|
|
7
|
+
require 'spec'
|
|
8
|
+
require 'spec/autorun'
|
|
9
|
+
require 'sequel'
|
|
10
|
+
require 'json'
|
|
11
|
+
gem 'jferris-mocha'
|
|
12
|
+
require 'mocha'
|
|
13
|
+
require 'memcached'
|
|
14
|
+
require 'friendly'
|
|
15
|
+
|
|
16
|
+
Friendly.configure "mysql://root@localhost/friendly_test"
|
|
17
|
+
$db = Friendly.db
|
|
18
|
+
Sequel::MySQL.default_engine = "InnoDB"
|
|
19
|
+
|
|
20
|
+
$db.drop_table :users if $db.table_exists?("users")
|
|
21
|
+
$db.drop_table :index_users_on_name if $db.table_exists?("index_users_on_name")
|
|
22
|
+
if $db.table_exists?("index_users_on_name_and_created_at")
|
|
23
|
+
$db.drop_table :index_users_on_name_and_created_at
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
datastore = Friendly::DataStore.new($db)
|
|
27
|
+
Friendly.datastore = datastore
|
|
28
|
+
|
|
29
|
+
$cache = Memcached.new
|
|
30
|
+
Friendly.cache = Friendly::Memcached.new($cache)
|
|
31
|
+
|
|
32
|
+
class User
|
|
33
|
+
include Friendly::Document
|
|
34
|
+
|
|
35
|
+
attribute :name, String
|
|
36
|
+
attribute :age, Integer
|
|
37
|
+
attribute :happy, Friendly::Boolean, :default => true
|
|
38
|
+
attribute :sad, Friendly::Boolean, :default => false
|
|
39
|
+
|
|
40
|
+
indexes :name
|
|
41
|
+
indexes :name, :created_at
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
User.create_tables!
|
|
45
|
+
|
|
46
|
+
class Address
|
|
47
|
+
include Friendly::Document
|
|
48
|
+
|
|
49
|
+
attribute :user_id, Friendly::UUID
|
|
50
|
+
attribute :street, String
|
|
51
|
+
|
|
52
|
+
indexes :user_id
|
|
53
|
+
indexes :street
|
|
54
|
+
caches_by :id
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
Address.create_tables!
|
|
58
|
+
|
|
59
|
+
module Mocha
|
|
60
|
+
module API
|
|
61
|
+
def setup_mocks_for_rspec
|
|
62
|
+
mocha_setup
|
|
63
|
+
end
|
|
64
|
+
def verify_mocks_for_rspec
|
|
65
|
+
mocha_verify
|
|
66
|
+
end
|
|
67
|
+
def teardown_mocks_for_rspec
|
|
68
|
+
mocha_teardown
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
module Factory
|
|
74
|
+
def row(opts = {})
|
|
75
|
+
{ :id => 1, :created_at => Time.new, :updated_at => Time.new }.merge(opts)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def query(conditions)
|
|
79
|
+
stub(:order => conditions.delete(:order!),
|
|
80
|
+
:limit => conditions.delete(:limit!),
|
|
81
|
+
:preserve_order? => conditions.delete(:preserve_order!),
|
|
82
|
+
:conditions => conditions,
|
|
83
|
+
:offset => conditions.delete(:offset!))
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
Spec::Runner.configure do |config|
|
|
88
|
+
config.mock_with Mocha::API
|
|
89
|
+
config.include Factory
|
|
90
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
|
2
|
+
|
|
3
|
+
describe "Friendly::Attribute" do
|
|
4
|
+
before do
|
|
5
|
+
@klass = Class.new
|
|
6
|
+
@name = Friendly::Attribute.new(@klass, :name, String)
|
|
7
|
+
@id = Friendly::Attribute.new(@klass, :id, Friendly::UUID)
|
|
8
|
+
@no_type = Friendly::Attribute.new(@klass, :no_type, nil)
|
|
9
|
+
@default = Friendly::Attribute.new(@klass, :default, String, :default => "asdf")
|
|
10
|
+
@false = Friendly::Attribute.new(@klass, :default, String, :default => false)
|
|
11
|
+
@klass.stubs(:attributes).returns({:name => @name,
|
|
12
|
+
:id => @id,
|
|
13
|
+
:default => @default,
|
|
14
|
+
:false => @false})
|
|
15
|
+
@object = @klass.new
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "creates a setter and a getter on klass" do
|
|
19
|
+
@object.name = "Something"
|
|
20
|
+
@object.name.should == "Something"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "typecasts values using the converter function" do
|
|
24
|
+
uuid = Friendly::UUID.new
|
|
25
|
+
@id.typecast(uuid.to_s).should == uuid
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "doesn't typecast values if they are of the right type" do
|
|
29
|
+
uuid = Friendly::UUID.new
|
|
30
|
+
@id.typecast(uuid).should == uuid
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "raises a useful error if it can't typecast" do
|
|
34
|
+
attribute = Friendly::Attribute.new(@klass, :weird, Class)
|
|
35
|
+
lambda {
|
|
36
|
+
attribute.typecast("ASDF")
|
|
37
|
+
}.should raise_error(Friendly::NoConverterExists)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "creates a getter with a default value" do
|
|
41
|
+
@object.id.should be_instance_of(Friendly::UUID)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "has a default value of type.new" do
|
|
45
|
+
@id.default.should be_instance_of(Friendly::UUID)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "has a default of nil if the type doesn't respond to :new" do
|
|
49
|
+
Friendly::Attribute.new(@klass, :age, Integer).default.should be_nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "doesn't try to convert when there's no type" do
|
|
53
|
+
@no_type.typecast(true).should == true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "can have a default value" do
|
|
57
|
+
@default.default.should == "asdf"
|
|
58
|
+
@klass.new.default.should == "asdf"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "has a default value even if it's false" do
|
|
62
|
+
@false.default.should be_false
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
|
2
|
+
|
|
3
|
+
describe "Friendly::Cache::ByID" do
|
|
4
|
+
before do
|
|
5
|
+
@cache = stub(:set => nil)
|
|
6
|
+
@klass = stub(:name => "Product")
|
|
7
|
+
@id_cache = Friendly::Cache::ByID.new(@klass, [:id], {}, @cache)
|
|
8
|
+
@subject = @id_cache
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it { should be_satisfies(query(:id => "asdf")) }
|
|
12
|
+
it { should be_satisfies(query(:id => ["asdf"])) }
|
|
13
|
+
it { should_not be_satisfies(query(:id => ["asdf"], :name => "asdf")) }
|
|
14
|
+
it { should_not be_satisfies(query(:name => "asdf")) }
|
|
15
|
+
|
|
16
|
+
it "has a default version of 0" do
|
|
17
|
+
@id_cache.version.should == 0
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "is possible to override version" do
|
|
21
|
+
Friendly::Cache::ByID.new(@klass, [:id], {:version => 1}).version.should == 1
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "when an object is created" do
|
|
25
|
+
before do
|
|
26
|
+
@uuid = stub(:to_guid => "xxxx-xxx-xxx-xxxx")
|
|
27
|
+
@doc = stub(:id => @uuid)
|
|
28
|
+
@id_cache.create(@doc)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "sets the cache value in the db" do
|
|
32
|
+
@cache.should have_received(:set).with("Product/0/#{@uuid.to_guid}", @doc)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "when an object is updated" do
|
|
37
|
+
before do
|
|
38
|
+
@uuid = stub(:to_guid => "xxxx-xxx-xxx-xxxx")
|
|
39
|
+
@doc = stub(:id => @uuid)
|
|
40
|
+
@id_cache.update(@doc)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "sets the cache value in the db" do
|
|
44
|
+
@cache.should have_received(:set).with("Product/0/#{@uuid.to_guid}", @doc)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe "when an object is destroyed" do
|
|
49
|
+
before do
|
|
50
|
+
@cache.stubs(:delete)
|
|
51
|
+
@uuid = stub(:to_guid => "xxxx-xxx-xxx-xxxx")
|
|
52
|
+
@doc = stub(:id => @uuid)
|
|
53
|
+
@id_cache.destroy(@doc)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "deletes the object from cache" do
|
|
57
|
+
@cache.should have_received(:delete).with("Product/0/#{@uuid.to_guid}")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe "finding a single object in cache" do
|
|
62
|
+
before do
|
|
63
|
+
@uuid = stub(:to_guid => "xxxx-xxx-xxx-xxxx")
|
|
64
|
+
@doc = stub
|
|
65
|
+
@cache.stubs(:get).with("Product/0/xxxx-xxx-xxx-xxxx").returns(@doc).yields
|
|
66
|
+
@block_called = true
|
|
67
|
+
@returned = @id_cache.first(query(:id => @uuid)) do
|
|
68
|
+
@block_called = true
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "returns the document" do
|
|
73
|
+
@returned.should == @doc
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "passes along the block to the memcached object" do
|
|
77
|
+
@block_called.should be_true
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "finding many objects in the cache" do
|
|
82
|
+
before do
|
|
83
|
+
@uuid = stub(:to_guid => "xxxx-xxx-xxx-xxxx")
|
|
84
|
+
@doc = stub
|
|
85
|
+
@key = "Product/0/xxxx-xxx-xxx-xxxx"
|
|
86
|
+
@cache.stubs(:multiget).with([@key, @key]).
|
|
87
|
+
returns({@uuid.to_guid => @doc}).yields(@uuid.to_guid)
|
|
88
|
+
@block_called = []
|
|
89
|
+
@returned = @id_cache.all(query(:id => [@uuid, @uuid])) do |id|
|
|
90
|
+
@block_called << id
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "returns the values from the hash" do
|
|
95
|
+
@returned.should == [@doc]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "passes the block along to the cache" do
|
|
99
|
+
@block_called.should == [@uuid.to_guid]
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
|
2
|
+
|
|
3
|
+
describe "Friendly::Cache" do
|
|
4
|
+
describe "getting a cache object for :id" do
|
|
5
|
+
before do
|
|
6
|
+
@cache = Friendly::Cache.cache_for(stub, [:id], {})
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "instantiates a Cache::ByID" do
|
|
10
|
+
@cache.should be_instance_of(Friendly::Cache::ByID)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "for other fields" do
|
|
15
|
+
it "raises NotSupported" do
|
|
16
|
+
lambda {
|
|
17
|
+
Friendly::Cache.cache_for(stub, [:asdf], {})
|
|
18
|
+
}.should raise_error(Friendly::NotSupported)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
|
2
|
+
|
|
3
|
+
describe "Friendly::DataStore" do
|
|
4
|
+
before do
|
|
5
|
+
@users = DatasetFake.new(:insert => 42)
|
|
6
|
+
@db = DatabaseFake.new("users" => @users)
|
|
7
|
+
@datastore = Friendly::DataStore.new(@db)
|
|
8
|
+
@klass = stub(:table_name => "users")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "inserting data" do
|
|
12
|
+
before do
|
|
13
|
+
@return = @datastore.insert(@klass, :name => "Stewie")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "inserts it in to the table in the datastore" do
|
|
17
|
+
@users.inserts.length.should == 1
|
|
18
|
+
@users.inserts.should include(:name => "Stewie")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "returns the id from the dataset" do
|
|
22
|
+
@return.should == 42
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "retrieving all based on a query" do
|
|
27
|
+
before do
|
|
28
|
+
@users.where = {{:name => "Stewie"} => stub(:map => [{:id => 1}])}
|
|
29
|
+
@return = @datastore.all(@klass, query(:name => "Stewie"))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "gets the data from the dataset for the klass and makes it an arary" do
|
|
33
|
+
@return.should == [{:id => 1}]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe "retrieving all with a limit" do
|
|
38
|
+
before do
|
|
39
|
+
@filtered = stub
|
|
40
|
+
@filtered.stubs(:limit).with(10, nil).returns(stub(:map => [{:id => 1}]))
|
|
41
|
+
@users.where = {{:name => "Stewie"} => @filtered}
|
|
42
|
+
@query = query(:name => "Stewie", :limit! => 10)
|
|
43
|
+
@return = @datastore.all(@klass, @query)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "limits the filtered dataset and returns the results" do
|
|
47
|
+
@return.should == [{:id => 1}]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe "retrieving all with a offset" do
|
|
52
|
+
before do
|
|
53
|
+
@filtered = stub
|
|
54
|
+
@filtered.stubs(:limit).with(nil, 10).returns(stub(:map => [{:id => 1}]))
|
|
55
|
+
@users.where = {{:name => "Stewie"} => @filtered}
|
|
56
|
+
@query = query(:name => "Stewie", :offset! => 10)
|
|
57
|
+
@return = @datastore.all(@klass, @query)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "offsets the filtered dataset and returns the results" do
|
|
61
|
+
@return.should == [{:id => 1}]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "retrieving all with order" do
|
|
66
|
+
before do
|
|
67
|
+
@filtered = stub
|
|
68
|
+
@filtered.stubs(:order).with(:created_at).returns(stub(:map => [{:id => 1}]))
|
|
69
|
+
@users.where = {{:name => "Stewie"} => @filtered}
|
|
70
|
+
@query = query(:name => "Stewie", :order! => :created_at)
|
|
71
|
+
@return = @datastore.all(@klass, @query)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "orders the filtered dataset and returns the results" do
|
|
75
|
+
@return.should == [{:id => 1}]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe "retrieving first with conditions" do
|
|
80
|
+
before do
|
|
81
|
+
@users.first = {{:id => 1} => {:id => 1}}
|
|
82
|
+
@return = @datastore.first(@klass, query(:id => 1))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "gets the first object matching the conditions from the dataset" do
|
|
86
|
+
@return.should == {:id => 1}
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe "updating data" do
|
|
91
|
+
before do
|
|
92
|
+
@filtered = DatasetFake.new(:update => true)
|
|
93
|
+
@users.where = {{:id => 1} => @filtered}
|
|
94
|
+
@return = @datastore.update(@klass, 1, :name => "Peter")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "filter the dataset by id and update the filtered row" do
|
|
98
|
+
@filtered.updates.length.should == 1
|
|
99
|
+
@filtered.updates.should include(:name => "Peter")
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe "deleting data" do
|
|
104
|
+
before do
|
|
105
|
+
@filtered = stub
|
|
106
|
+
@filtered.stubs(:delete)
|
|
107
|
+
@users.where = {{:id => 1} => @filtered}
|
|
108
|
+
@datastore.delete(@klass, 1)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "filters the dataset by id and deletes" do
|
|
112
|
+
@filtered.should have_received(:delete)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe "when a batch transaction has been started" do
|
|
117
|
+
before do
|
|
118
|
+
@datastore.start_batch
|
|
119
|
+
@persistable = stub(:table_name => "some_table")
|
|
120
|
+
@datastore.insert(@persistable, {:some => "attrs"})
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
after { Thread.current[:friendly_batch] = nil }
|
|
124
|
+
|
|
125
|
+
it "adds the attributes to the batch for that table" do
|
|
126
|
+
inserts = Thread.current[:friendly_batch]["some_table"]
|
|
127
|
+
inserts.length.should == 1
|
|
128
|
+
inserts.should include(:some => "attrs")
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
describe "starting a batch" do
|
|
133
|
+
before do
|
|
134
|
+
@datastore.start_batch
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
after { Thread.current[:friendly_batch] = nil }
|
|
138
|
+
|
|
139
|
+
it "sets Thread.current[:friendly_batch] to empty hash" do
|
|
140
|
+
Thread.current[:friendly_batch].should == {}
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe "resetting a batch transaction" do
|
|
145
|
+
before do
|
|
146
|
+
@db.stubs(:from)
|
|
147
|
+
Thread.current[:friendly_batch] = {"users" => [{:a => "b"}]}
|
|
148
|
+
@datastore.reset_batch
|
|
149
|
+
end
|
|
150
|
+
after { Thread.current[:friendly_batch] = nil }
|
|
151
|
+
|
|
152
|
+
it "sets Thread.current[:friendly_batch] to nil without inserting" do
|
|
153
|
+
Thread.current[:friendly_batch].should be_nil
|
|
154
|
+
@db.should have_received(:from).never
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
describe "flushing a batch" do
|
|
159
|
+
before do
|
|
160
|
+
@records = [{:name => "Stewie"}, {:name => "Brian"}]
|
|
161
|
+
Thread.current[:friendly_batch] = {"users" => @records}
|
|
162
|
+
@users.stubs(:multi_insert)
|
|
163
|
+
@datastore.flush_batch
|
|
164
|
+
end
|
|
165
|
+
after { Thread.current[:friendly_batch] = nil }
|
|
166
|
+
|
|
167
|
+
it "performs the multi_insert on each table" do
|
|
168
|
+
@users.should have_received(:multi_insert).
|
|
169
|
+
with(@records, :commit_every => 1000)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "resets the batch" do
|
|
173
|
+
Thread.current[:friendly_batch].should be_nil
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
describe "counting" do
|
|
178
|
+
before do
|
|
179
|
+
@filtered = stub(:count => 10)
|
|
180
|
+
@users.stubs(:where).with(:name => "James").returns(@filtered)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it "fitlers and counts in the db" do
|
|
184
|
+
@datastore.count(@klass, query(:name => "James")).should == 10
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|