datastax_rails 1.1.0.3 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.rdoc +13 -13
- data/Rakefile +1 -0
- data/config/schema.xml.erb +0 -1
- data/config/{solrconfig.xml → solrconfig.xml.erb} +1 -1
- data/lib/blankslate.rb +1 -1
- data/lib/datastax_rails/associations/collection_proxy.rb +6 -2
- data/lib/datastax_rails/attribute_assignment.rb +114 -0
- data/lib/datastax_rails/attribute_methods/definition.rb +8 -2
- data/lib/datastax_rails/attribute_methods/typecasting.rb +2 -5
- data/lib/datastax_rails/attribute_methods.rb +9 -7
- data/lib/datastax_rails/base.rb +127 -109
- data/lib/datastax_rails/callbacks.rb +11 -7
- data/lib/datastax_rails/cassandra_only_model.rb +27 -0
- data/lib/datastax_rails/collection.rb +3 -1
- data/lib/datastax_rails/cql/base.rb +4 -0
- data/lib/datastax_rails/cql/select.rb +12 -2
- data/lib/datastax_rails/identity/abstract_key_factory.rb +1 -0
- data/lib/datastax_rails/identity/custom_key_factory.rb +1 -0
- data/lib/datastax_rails/identity/natural_key_factory.rb +1 -0
- data/lib/datastax_rails/identity/uuid_key_factory.rb +4 -0
- data/lib/datastax_rails/identity.rb +2 -1
- data/lib/datastax_rails/inheritance.rb +61 -0
- data/lib/datastax_rails/payload_model.rb +2 -5
- data/lib/datastax_rails/persistence.rb +63 -20
- data/lib/datastax_rails/railtie.rb +5 -1
- data/lib/datastax_rails/relation/batches.rb +2 -2
- data/lib/datastax_rails/relation/facet_methods.rb +56 -5
- data/lib/datastax_rails/relation/finder_methods.rb +55 -1
- data/lib/datastax_rails/relation/search_methods.rb +103 -32
- data/lib/datastax_rails/relation/spawn_methods.rb +3 -1
- data/lib/datastax_rails/relation/stats_methods.rb +1 -1
- data/lib/datastax_rails/relation.rb +166 -30
- data/lib/datastax_rails/schema/cassandra.rb +165 -0
- data/lib/datastax_rails/schema/migrator.rb +85 -193
- data/lib/datastax_rails/schema/solr.rb +158 -0
- data/lib/datastax_rails/schema.rb +2 -30
- data/lib/datastax_rails/scoping/default.rb +142 -0
- data/lib/datastax_rails/scoping/named.rb +200 -0
- data/lib/datastax_rails/scoping.rb +106 -349
- data/lib/datastax_rails/tasks/ds.rake +41 -42
- data/lib/datastax_rails/types/array_type.rb +1 -1
- data/lib/datastax_rails/types/base_type.rb +2 -2
- data/lib/datastax_rails/types/binary_type.rb +1 -1
- data/lib/datastax_rails/types/boolean_type.rb +1 -1
- data/lib/datastax_rails/types/date_type.rb +1 -1
- data/lib/datastax_rails/types/float_type.rb +4 -4
- data/lib/datastax_rails/types/integer_type.rb +3 -3
- data/lib/datastax_rails/types/string_type.rb +1 -1
- data/lib/datastax_rails/types/text_type.rb +1 -1
- data/lib/datastax_rails/types/time_type.rb +3 -3
- data/lib/datastax_rails/validations/uniqueness.rb +1 -1
- data/lib/datastax_rails/version.rb +1 -1
- data/lib/datastax_rails/wide_storage_model.rb +44 -0
- data/lib/datastax_rails.rb +16 -18
- data/spec/datastax_rails/associations_spec.rb +7 -3
- data/spec/datastax_rails/attribute_methods_spec.rb +23 -0
- data/spec/datastax_rails/base_spec.rb +1 -6
- data/spec/datastax_rails/inheritance_spec.rb +41 -0
- data/spec/datastax_rails/persistence_spec.rb +13 -3
- data/spec/datastax_rails/relation/batches_spec.rb +1 -1
- data/spec/datastax_rails/relation/facet_methods_spec.rb +52 -0
- data/spec/datastax_rails/relation/finder_methods_spec.rb +22 -1
- data/spec/datastax_rails/relation/search_methods_spec.rb +51 -1
- data/spec/datastax_rails/relation_spec.rb +14 -3
- data/spec/datastax_rails/schema/migrator_spec.rb +92 -0
- data/spec/datastax_rails/schema/solr_spec.rb +34 -0
- data/spec/datastax_rails/scoping/default_spec.rb +17 -0
- data/spec/datastax_rails/types/float_type_spec.rb +5 -9
- data/spec/datastax_rails/types/integer_type_spec.rb +5 -9
- data/spec/datastax_rails/types/time_type_spec.rb +28 -0
- data/spec/datastax_rails/validations/uniqueness_spec.rb +3 -1
- data/spec/dummy/config/application.rb +1 -4
- data/spec/dummy/config/datastax.yml +1 -1
- data/spec/dummy/config/environments/test.rb +2 -0
- data/spec/dummy/config/solr/articles-schema.xml.erb +1 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +2 -0
- data/spec/dummy/log/production.log +2 -0
- data/spec/dummy/log/test.log +523 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/models.rb +14 -0
- metadata +66 -22
- data/lib/datastax_rails/log_subscriber.rb +0 -37
- data/lib/datastax_rails/migrations/migration.rb +0 -15
- data/lib/datastax_rails/migrations.rb +0 -36
- data/lib/datastax_rails/mocking.rb +0 -15
- data/lib/datastax_rails/schema/migration.rb +0 -106
- data/lib/datastax_rails/schema/migration_proxy.rb +0 -25
- data/lib/datastax_rails/tasks/column_family.rb +0 -329
- data/lib/datastax_rails/tasks/keyspace.rb +0 -57
- data/spec/support/connection_double.rb +0 -6
@@ -1,7 +1,7 @@
|
|
1
1
|
module DatastaxRails
|
2
2
|
module Types
|
3
3
|
class DateType < BaseType
|
4
|
-
DEFAULTS = {:solr_type => 'date', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false}
|
4
|
+
DEFAULTS = {:solr_type => 'date', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false, :cassandra_type => 'timestamp'}
|
5
5
|
FORMAT = '%Y-%m-%dT%H:%M:%SZ'
|
6
6
|
|
7
7
|
def encode(value)
|
@@ -1,16 +1,16 @@
|
|
1
1
|
module DatastaxRails
|
2
2
|
module Types
|
3
3
|
class FloatType < BaseType
|
4
|
-
DEFAULTS = {:solr_type => 'float', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false}
|
4
|
+
DEFAULTS = {:solr_type => 'float', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false, :cassandra_type => 'float'}
|
5
5
|
REGEX = /\A[-+]?(\d+(\.\d+)?|\.\d+)\Z/
|
6
6
|
def encode(float)
|
7
|
-
return -10191980.0 if float.blank?
|
7
|
+
return "-10191980.0" if float.blank?
|
8
8
|
raise ArgumentError.new("#{self} requires a Float. You passed #{float.to_s}") unless float.kind_of?(Float) || (float.kind_of?(String) && float.match(REGEX)) || float.kind_of?(Fixnum)
|
9
|
-
float.to_f
|
9
|
+
float.to_f.to_s
|
10
10
|
end
|
11
11
|
|
12
12
|
def decode(float)
|
13
|
-
return nil if float.blank? ||
|
13
|
+
return nil if float.blank? || float.to_s == '-10191980.0'
|
14
14
|
float.to_f
|
15
15
|
end
|
16
16
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module DatastaxRails
|
2
2
|
module Types
|
3
3
|
class IntegerType < BaseType
|
4
|
-
DEFAULTS = {:solr_type => 'int', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false}
|
4
|
+
DEFAULTS = {:solr_type => 'int', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false, :cassandra_type => 'int'}
|
5
5
|
REGEX = /\A[-+]?\d+\Z/
|
6
6
|
def encode(int)
|
7
|
-
return -10191980 if int.blank?
|
7
|
+
return "-10191980" if int.blank?
|
8
8
|
raise ArgumentError.new("#{self} requires an Integer. You passed #{int.to_s}") unless int.kind_of?(Integer) || (int.kind_of?(String) && int.match(REGEX))
|
9
|
-
int.to_i
|
9
|
+
int.to_i.to_s
|
10
10
|
end
|
11
11
|
|
12
12
|
def decode(int)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module DatastaxRails
|
2
2
|
module Types
|
3
3
|
class StringType < BaseType
|
4
|
-
DEFAULTS = {:solr_type => 'string', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => true}
|
4
|
+
DEFAULTS = {:solr_type => 'string', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => true, :cassandra_type => 'text'}
|
5
5
|
def encode(str)
|
6
6
|
str = "" unless str
|
7
7
|
str.to_s
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module DatastaxRails
|
2
2
|
module Types
|
3
3
|
class TextType < BaseType
|
4
|
-
DEFAULTS = {:solr_type => 'text', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => false, :tokenized => true, :fulltext => true}
|
4
|
+
DEFAULTS = {:solr_type => 'text', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => false, :tokenized => true, :fulltext => true, :cassandra_type => 'text'}
|
5
5
|
def encode(str)
|
6
6
|
str.to_s.dup
|
7
7
|
end
|
@@ -1,18 +1,18 @@
|
|
1
1
|
module DatastaxRails
|
2
2
|
module Types
|
3
3
|
class TimeType < BaseType
|
4
|
-
DEFAULTS = {:solr_type => 'date', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false}
|
4
|
+
DEFAULTS = {:solr_type => 'date', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false, :cassandra_type => 'timestamp'}
|
5
5
|
FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
6
6
|
|
7
7
|
def encode(time)
|
8
8
|
return unless time
|
9
9
|
raise ArgumentError.new("#{self} requires a Time") unless time.kind_of?(Time)
|
10
|
-
time.strftime(FORMAT)
|
10
|
+
time.utc.strftime(FORMAT)
|
11
11
|
end
|
12
12
|
|
13
13
|
def decode(str)
|
14
14
|
return str if str.kind_of?(Time)
|
15
|
-
Time.parse(str) rescue nil
|
15
|
+
Time.zone.parse(str) rescue nil
|
16
16
|
end
|
17
17
|
|
18
18
|
def full_solr_range
|
@@ -17,7 +17,7 @@ module DatastaxRails
|
|
17
17
|
# are implemented in datastax_rails (such as STI)
|
18
18
|
finder_class = record.class
|
19
19
|
|
20
|
-
scope = finder_class.
|
20
|
+
scope = finder_class.where(attribute => value)
|
21
21
|
scope = scope.where_not(:id => record.id) if record.persisted?
|
22
22
|
|
23
23
|
Array.wrap(options[:scope]).each do |scope_item|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module DatastaxRails
|
2
|
+
# A special model that is designed to efficiently store very wide data.
|
3
|
+
# This model type assumes that you have a unique ID and want to either
|
4
|
+
# search or sort on a second piece of data. The store the data as a
|
5
|
+
# single, very wide row; however you can safely treat them as if
|
6
|
+
# there were multiple rows.
|
7
|
+
#
|
8
|
+
# CAVEATS:
|
9
|
+
# * Wide Storage Models cannot be indexed into Solr.
|
10
|
+
# * Once the cluster is set, it cannot be changed as it becomes the column header in Cassandra
|
11
|
+
#
|
12
|
+
# class AuditLog < DatastaxRails::WideStorageModel
|
13
|
+
# self.column_family = 'audit_logs'
|
14
|
+
#
|
15
|
+
# key :natural, :attributes => [:uuid]
|
16
|
+
# cluster_by :created_at => :desc
|
17
|
+
#
|
18
|
+
# string :uuid
|
19
|
+
# string :message
|
20
|
+
# timestamps
|
21
|
+
# end
|
22
|
+
class WideStorageModel < CassandraOnlyModel
|
23
|
+
self.abstract_class = true
|
24
|
+
|
25
|
+
def self.cluster_by(attr = nil)
|
26
|
+
@cluster_by ||= attr.is_a?(Hash) ? attr : {attr => :asc}
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.write(key, attributes, options = {})
|
30
|
+
attributes = encode_attributes(attributes)
|
31
|
+
level = (options[:consistency] || self.default_consistency).to_s.upcase
|
32
|
+
if(valid_consistency?(level))
|
33
|
+
options[:consistency] = level
|
34
|
+
else
|
35
|
+
raise ArgumentError, "'#{level}' is not a valid Cassandra consistency level"
|
36
|
+
end
|
37
|
+
key.tap do |key|
|
38
|
+
ActiveSupport::Notifications.instrument("insert.datastax_rails", :column_family => column_family, :key => key, :attributes => attributes) do
|
39
|
+
cql.insert.using(level).columns(attributes).execute
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/datastax_rails.rb
CHANGED
@@ -8,16 +8,19 @@ module DatastaxRails
|
|
8
8
|
extend ActiveSupport::Autoload
|
9
9
|
|
10
10
|
autoload :Associations
|
11
|
+
autoload :AttributeAssignment
|
11
12
|
autoload :AttributeMethods
|
12
13
|
autoload :Base
|
13
14
|
autoload :Batches
|
14
15
|
autoload :Callbacks
|
16
|
+
autoload :CassandraOnlyModel
|
15
17
|
autoload :Collection
|
16
18
|
autoload :Connection
|
17
19
|
autoload :Cql
|
18
20
|
autoload :GroupedCollection
|
19
21
|
autoload :Identity
|
20
|
-
autoload :
|
22
|
+
autoload :Index
|
23
|
+
autoload :Inheritance
|
21
24
|
autoload :PayloadModel
|
22
25
|
autoload :Persistence
|
23
26
|
autoload :Reflection
|
@@ -30,6 +33,7 @@ module DatastaxRails
|
|
30
33
|
autoload :SpawnMethods
|
31
34
|
autoload :StatsMethods
|
32
35
|
autoload :Batches
|
36
|
+
autoload :FacetMethods
|
33
37
|
end
|
34
38
|
|
35
39
|
autoload :RSolrClientWrapper, 'datastax_rails/rsolr_client_wrapper'
|
@@ -42,6 +46,8 @@ module DatastaxRails
|
|
42
46
|
autoload :SolrRepair
|
43
47
|
end
|
44
48
|
autoload :Validations
|
49
|
+
autoload :Version
|
50
|
+
autoload :WideStorageModel
|
45
51
|
|
46
52
|
module AttributeMethods
|
47
53
|
extend ActiveSupport::Autoload
|
@@ -52,6 +58,15 @@ module DatastaxRails
|
|
52
58
|
autoload :Typecasting
|
53
59
|
end
|
54
60
|
end
|
61
|
+
|
62
|
+
module Scoping
|
63
|
+
extend ActiveSupport::Autoload
|
64
|
+
|
65
|
+
eager_autoload do
|
66
|
+
autoload :Named
|
67
|
+
autoload :Default
|
68
|
+
end
|
69
|
+
end
|
55
70
|
|
56
71
|
module Tasks
|
57
72
|
extend ActiveSupport::Autoload
|
@@ -77,23 +92,6 @@ module DatastaxRails
|
|
77
92
|
end
|
78
93
|
end
|
79
94
|
|
80
|
-
require "thrift"
|
81
|
-
# Thrift is how we communicate with Cassandra. We need to do a little fixup
|
82
|
-
# work to handle UTF-8 properly in Ruby 1.8.6.
|
83
|
-
# module Thrift
|
84
|
-
# class BinaryProtocol
|
85
|
-
# def write_string(str)
|
86
|
-
# if(str.respond_to?(:bytesize))
|
87
|
-
# size = str.bytesize
|
88
|
-
# else
|
89
|
-
# size = str.size
|
90
|
-
# end
|
91
|
-
# write_i32(size)
|
92
|
-
# trans.write(str)
|
93
|
-
# end
|
94
|
-
# end
|
95
|
-
# end
|
96
|
-
|
97
95
|
require 'datastax_rails/railtie' if defined?(Rails)
|
98
96
|
require 'datastax_rails/errors'
|
99
97
|
|
@@ -1,18 +1,22 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe DatastaxRails::Base do
|
4
|
-
describe "
|
4
|
+
describe "Associations" do
|
5
5
|
describe "belongs_to" do
|
6
6
|
it "should set the id when setting the object" do
|
7
7
|
person = Person.create(:name => "Jason")
|
8
8
|
job = Job.create(:title => "Developer")
|
9
|
+
Person.commit_solr
|
9
10
|
job.person = person
|
10
11
|
job.person_id.should == person.id
|
11
12
|
end
|
12
13
|
|
13
14
|
it "should look up the owning model by id" do
|
14
|
-
|
15
|
-
|
15
|
+
Job.truncate
|
16
|
+
Job.commit_solr
|
17
|
+
person = Person.create!(:name => "John")
|
18
|
+
job = Job.create!(:title => "Developer", :person_id => person.id)
|
19
|
+
Person.commit_solr
|
16
20
|
Person.commit_solr
|
17
21
|
Job.commit_solr
|
18
22
|
Job.first.person.should == person
|
@@ -5,6 +5,11 @@ class AttributeMethodsTester < DatastaxRails::Base
|
|
5
5
|
string :non_search_string, :searchable => false
|
6
6
|
end
|
7
7
|
|
8
|
+
class CassandraOnlyTester < DatastaxRails::CassandraOnlyModel
|
9
|
+
string :test_string
|
10
|
+
string :test_string2, :indexed => :both
|
11
|
+
end
|
12
|
+
|
8
13
|
describe DatastaxRails::Base do
|
9
14
|
def tester
|
10
15
|
@tester ||= AttributeMethodsTester.new
|
@@ -20,4 +25,22 @@ describe DatastaxRails::Base do
|
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
28
|
+
describe "#attribute" do
|
29
|
+
context "Cassandra-only models" do
|
30
|
+
it "does not index columns by default" do
|
31
|
+
expect(CassandraOnlyTester.attribute_definitions[:test_string].coder.options[:indexed]).to be_false
|
32
|
+
end
|
33
|
+
|
34
|
+
it "does not index into solr" do
|
35
|
+
expect(CassandraOnlyTester.attribute_definitions[:test_string2].coder.options[:indexed]).to eq(:cassandra)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "Normal models" do
|
40
|
+
it "indexes data into solr by default" do
|
41
|
+
expect(AttributeMethodsTester.attribute_definitions[:test_string].coder.options[:indexed]).to eq(:solr)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
23
46
|
end
|
@@ -8,6 +8,7 @@ describe DatastaxRails::Base do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should run after_save" do
|
11
|
+
Person.commit_solr
|
11
12
|
p = Person.new(:name => "Jason")
|
12
13
|
p.save!
|
13
14
|
p.instance_variable_get(:@after_save_ran).should == "yup"
|
@@ -16,10 +17,4 @@ describe DatastaxRails::Base do
|
|
16
17
|
it "should raise RecordNotFound when finding a bogus ID" do
|
17
18
|
lambda { Person.find("xyzzy") }.should raise_exception(DatastaxRails::RecordNotFound)
|
18
19
|
end
|
19
|
-
|
20
|
-
xit "should skip records that are missing dsr in cassandra" do
|
21
|
-
p = Person.create(:name => 'Jason')
|
22
|
-
Person.cql.delete(p.id).columns(['dsr']).execute
|
23
|
-
Person.find_by_name('Jason').should be_nil
|
24
|
-
end
|
25
20
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class InheritanceTesterBase < DatastaxRails::Base
|
4
|
+
self.abstract_class = true
|
5
|
+
end
|
6
|
+
|
7
|
+
class InheritanceTesterChild < InheritanceTesterBase
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
class InheritanceTesterGrandChild < InheritanceTesterChild
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
class InheritanceTesterNonAbstract < DatastaxRails::Base
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe DatastaxRails::Base do
|
20
|
+
context "Inheritance" do
|
21
|
+
it "raises NotImplementedError if DatastaxRails::Base is instantiated" do
|
22
|
+
expect { DatastaxRails::Base.new }.to raise_error(NotImplementedError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "raises NotImplementedError if an abstract class is instantiated" do
|
26
|
+
expect { InheritanceTesterBase.new }.to raise_error(NotImplementedError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "identifies the abstract class as base for direct decendants" do
|
30
|
+
expect(InheritanceTesterChild.base_class).to eq(InheritanceTesterBase)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "identifies the abstract class as base for its indirect decendants" do
|
34
|
+
expect(InheritanceTesterGrandChild.base_class).to eq(InheritanceTesterBase)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "identifies a child of DatastaxRails::Base as base" do
|
38
|
+
expect(InheritanceTesterNonAbstract.base_class).to eq(InheritanceTesterNonAbstract)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -2,6 +2,16 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe "DatastaxRails::Base" do
|
4
4
|
describe "persistence" do
|
5
|
+
describe "#update_attributes" do
|
6
|
+
it "only overwrites attributes that are passed in as part of the hash" do
|
7
|
+
person = Person.create(:name => 'Jason', :birthdate => Date.parse("Oct 19, 1981"), :nickname => 'Jas')
|
8
|
+
person.birthdate = Date.parse("Oct 19, 1980")
|
9
|
+
person.update_attributes(:nickname => 'Jace')
|
10
|
+
person.birthdate.should eql(Date.parse("Oct 19, 1980"))
|
11
|
+
person.nickname.should eql('Jace')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
5
15
|
describe "with cql" do
|
6
16
|
describe "#create" do
|
7
17
|
it "should persist at the given consistency level" do
|
@@ -62,19 +72,19 @@ describe "DatastaxRails::Base" do
|
|
62
72
|
end
|
63
73
|
|
64
74
|
describe "#store_file" do
|
65
|
-
it "should store a file" do
|
75
|
+
it "should store a file", :slow => true do
|
66
76
|
file = "abcd"*1.megabyte
|
67
77
|
CarPayload.create(:digest => 'limo', :payload => file)
|
68
78
|
CarPayload.find('limo').payload.should == file
|
69
79
|
end
|
70
80
|
|
71
|
-
it "should store really large files" do
|
81
|
+
it "should store really large files", :slow => true do
|
72
82
|
file = IO.read("/dev/zero", 25.megabyte)
|
73
83
|
CarPayload.create(:digest => 'limo', :payload => file)
|
74
84
|
CarPayload.find('limo').payload.should == file
|
75
85
|
end
|
76
86
|
|
77
|
-
it "should successfully overwrite a larger file with a smaller one" do
|
87
|
+
it "should successfully overwrite a larger file with a smaller one", :slow => true do
|
78
88
|
file = "abcd"*1.megabyte
|
79
89
|
car = CarPayload.create(:digest => 'limo', :payload => file)
|
80
90
|
smallfile = "e"*1.kilobyte
|
@@ -8,12 +8,12 @@ describe DatastaxRails::Relation do
|
|
8
8
|
sleep(1) if idx % 5 == 4 # Performance hack
|
9
9
|
end
|
10
10
|
Hobby.commit_solr
|
11
|
-
Hobby.commit_solr
|
12
11
|
end
|
13
12
|
|
14
13
|
['cassandra', 'solr'].each do |method|
|
15
14
|
describe "#find_each" do
|
16
15
|
it "returns each record one at a time with #{method}" do
|
16
|
+
sleep(1)
|
17
17
|
missed_hobbies = ('a'..'l').to_a
|
18
18
|
@relation.send('with_'+method).find_each(:batch_size => 5) do |hobby|
|
19
19
|
missed_hobbies.delete_if {|h| h == hobby.name}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DatastaxRails::Relation do
|
4
|
+
before(:each) do
|
5
|
+
@relation = DatastaxRails::Relation.new(Hobby, "hobbies")
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#field_facet" do
|
9
|
+
|
10
|
+
it "should return facets on a field" do
|
11
|
+
Hobby.create(:name => 'skiing')
|
12
|
+
Hobby.create(:name => 'boating')
|
13
|
+
Hobby.create(:name => 'fishing')
|
14
|
+
Hobby.create(:name => 'skiing')
|
15
|
+
Hobby.commit_solr
|
16
|
+
@relation.field_facet(:name).all.facets['name'].should == ["skiing", 2, "boating", 1, "fishing", 1]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should allow options to be specified" do
|
20
|
+
Hobby.create(:name => 'skiing')
|
21
|
+
Hobby.create(:name => 'singing')
|
22
|
+
Hobby.create(:name => 'reading')
|
23
|
+
Hobby.commit_solr
|
24
|
+
@relation.field_facet(:name, :prefix => 's').all.facets['name'].should == ["singing", 1, "skiing", 1]
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#range_facet" do
|
30
|
+
|
31
|
+
it "should return facets on a field" do
|
32
|
+
Hobby.create(:complexity => 1.0)
|
33
|
+
Hobby.create(:complexity => 5.0)
|
34
|
+
Hobby.create(:complexity => 8.0)
|
35
|
+
Hobby.create(:complexity => 9.0)
|
36
|
+
Hobby.create(:complexity => 10.0)
|
37
|
+
Hobby.commit_solr
|
38
|
+
@relation.range_facet(:complexity, 1.0, 10.0, 2.0).all.facets['complexity'].should == {"counts"=>["1.0", 1, "3.0", 0, "5.0", 1, "7.0", 1, "9.0", 2], "gap"=>2.0, "start"=>1.0, "end"=>11.0}
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should allow options to be specified" do
|
42
|
+
Hobby.create(:complexity => 1.0)
|
43
|
+
Hobby.create(:complexity => 5.0)
|
44
|
+
Hobby.create(:complexity => 8.0)
|
45
|
+
Hobby.create(:complexity => 9.0)
|
46
|
+
Hobby.create(:complexity => 10.0)
|
47
|
+
Hobby.commit_solr
|
48
|
+
@relation.range_facet(:complexity, 1.0, 10.0, 2.0, :include => 'upper').all.facets['complexity'].should == {"counts"=>["1.0", 0, "3.0", 1, "5.0", 0, "7.0", 2, "9.0", 1], "gap"=>2.0, "start"=>1.0, "end"=>11.0}
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -3,6 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe DatastaxRails::Relation do
|
4
4
|
before(:each) do
|
5
5
|
@relation = DatastaxRails::Relation.new(Hobby, "hobbies")
|
6
|
+
Hobby.commit_solr
|
6
7
|
end
|
7
8
|
|
8
9
|
describe "#first" do
|
@@ -56,7 +57,7 @@ describe DatastaxRails::Relation do
|
|
56
57
|
it "finds a record by an attribute" do
|
57
58
|
Boat.create(:name => 'Spooner')
|
58
59
|
Boat.commit_solr
|
59
|
-
Boat.
|
60
|
+
Boat.find_all_by_name('Spooner').should_not be_nil
|
60
61
|
end
|
61
62
|
|
62
63
|
it "finds a record by an attribute with a space in it" do
|
@@ -71,4 +72,24 @@ describe DatastaxRails::Relation do
|
|
71
72
|
Boat.find_by_name('Dumb: Name').should_not be_nil
|
72
73
|
end
|
73
74
|
end
|
75
|
+
|
76
|
+
describe "#find_by" do
|
77
|
+
it "finds a record by an attribute" do
|
78
|
+
Boat.create(:name => 'Spooner')
|
79
|
+
Boat.commit_solr
|
80
|
+
Boat.find_by(name: 'Spooner').should_not be_nil
|
81
|
+
end
|
82
|
+
|
83
|
+
it "finds a record by an attribute with a space in it" do
|
84
|
+
Boat.create(:name => 'Water Lily')
|
85
|
+
Boat.commit_solr
|
86
|
+
Boat.find_by(name: 'Water Lily').should_not be_nil
|
87
|
+
end
|
88
|
+
|
89
|
+
it "finds a record by an attribute with a colon in it" do
|
90
|
+
Boat.create(:name => 'Dumb: Name')
|
91
|
+
Boat.commit_solr
|
92
|
+
Boat.find_by(name: 'Dumb: Name').should_not be_nil
|
93
|
+
end
|
94
|
+
end
|
74
95
|
end
|
@@ -58,13 +58,29 @@ describe DatastaxRails::Relation do
|
|
58
58
|
|
59
59
|
it "should return items in descending order" do
|
60
60
|
%w[fishing hiking boating jogging swimming chess].each do |word|
|
61
|
-
Hobby.create(:name => word)
|
61
|
+
Hobby.create!(:name => word)
|
62
62
|
end
|
63
63
|
@relation.commit_solr
|
64
64
|
@relation.order(:name => :desc).collect {|h| h.name}.should == %w[swimming jogging hiking fishing chess boating]
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
describe "#slow_order" do
|
69
|
+
it "should manually order items coming from Cassandra" do
|
70
|
+
%w[john jason michael tony billy jim phil].each_with_index do |name,i|
|
71
|
+
AuditLog.create!(:uuid => "c1401540-f092-11e2-9001-6a5ab73a986#{i}", :user => name, :message => 'changed')
|
72
|
+
end
|
73
|
+
AuditLog.unscoped.slow_order(:user => :asc).collect {|log| log.user}.should == %w[billy jason jim john michael phil tony]
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should manually order items coming from Cassandra in descending order" do
|
77
|
+
%w[john jason michael tony billy jim phil].each_with_index do |name,i|
|
78
|
+
AuditLog.create!(:uuid => "c1401540-f092-11e2-9001-6a5ab73a986#{i}", :user => name, :message => 'changed')
|
79
|
+
end
|
80
|
+
AuditLog.unscoped.slow_order(:user => :desc).collect {|log| log.user}.should == %w[tony phil michael john jim jason billy]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
68
84
|
describe "#where" do
|
69
85
|
it "should return documents where a field is nil (does not exist)" do
|
70
86
|
Hobby.create(:name => 'Swimming')
|
@@ -186,4 +202,38 @@ describe DatastaxRails::Relation do
|
|
186
202
|
@relation.fulltext("swimming").should_not be_empty
|
187
203
|
end
|
188
204
|
end
|
205
|
+
|
206
|
+
describe '#highlight' do
|
207
|
+
let(:hl) { @relation.highlight(:name, :description, :snippet => 3, :fragsize => 200) }
|
208
|
+
|
209
|
+
it { expect(hl.highlight_options[:fields]).to eq [:name, :description] }
|
210
|
+
it { expect(hl.highlight_options[:snippet]).to eq 3 }
|
211
|
+
it { expect(hl.highlight_options[:fragsize]).to eq 200 }
|
212
|
+
|
213
|
+
context 'with duplicate fields' do
|
214
|
+
let(:hl) { @relation.highlight(:name, :description, :name) }
|
215
|
+
|
216
|
+
it { expect(hl.highlight_options[:fields]).to eq [:name, :description] }
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe '#solr_format' do
|
221
|
+
context 'when formatting Time' do
|
222
|
+
let(:time) { Time.new 2011, 10, 9, 8, 7, 6, "-05:00" }
|
223
|
+
|
224
|
+
it { expect(@relation.solr_format(time)).to eq '2011-10-09T13:07:06Z' }
|
225
|
+
end
|
226
|
+
|
227
|
+
context 'when formatting Date' do
|
228
|
+
let(:date) { Date.new 2001, 2, 3 }
|
229
|
+
|
230
|
+
it { expect(@relation.solr_format(date)).to eq '2001-02-03T00:00:00Z' }
|
231
|
+
end
|
232
|
+
|
233
|
+
context 'when formatting DateTime' do
|
234
|
+
let(:datetime) { DateTime.new 2001, 2, 3, 4, 5, 6, "-07:00" }
|
235
|
+
|
236
|
+
it { expect(@relation.solr_format(datetime)).to eq '2001-02-03T11:05:06Z' }
|
237
|
+
end
|
238
|
+
end
|
189
239
|
end
|
@@ -3,6 +3,8 @@ require 'spec_helper'
|
|
3
3
|
describe DatastaxRails::Relation do
|
4
4
|
before(:each) do
|
5
5
|
@relation = DatastaxRails::Relation.new(Hobby, "hobbies")
|
6
|
+
@relation.default_scoped = true
|
7
|
+
@relation.commit_solr
|
6
8
|
end
|
7
9
|
|
8
10
|
describe "#==" do
|
@@ -30,14 +32,16 @@ describe DatastaxRails::Relation do
|
|
30
32
|
end
|
31
33
|
|
32
34
|
it "should cache the total count on any solr query" do
|
33
|
-
@relation
|
35
|
+
@relation = @relation.with_solr
|
36
|
+
@relation.should_receive(:query_via_solr).and_return(double("ResultSet", :total_entries => 42))
|
34
37
|
@relation.all
|
35
38
|
@relation.count.should == 42
|
36
39
|
end
|
37
40
|
|
38
41
|
it "should execute a fast search to determine the count" do
|
39
|
-
mock_relation =
|
42
|
+
mock_relation = double(DatastaxRails::Relation)
|
40
43
|
mock_relation.stub_chain(:select, :to_a, :total_entries).and_return(37)
|
44
|
+
@relation = @relation.with_solr
|
41
45
|
@relation.should_receive(:limit).with(1).and_return(mock_relation)
|
42
46
|
@relation.count.should == 37
|
43
47
|
end
|
@@ -62,6 +66,12 @@ describe DatastaxRails::Relation do
|
|
62
66
|
relation.count.should == 0
|
63
67
|
relation.default_scope.count.should == 1
|
64
68
|
end
|
69
|
+
|
70
|
+
it "should return a relation that has a default scope set" do
|
71
|
+
relation = DatastaxRails::Relation.new(Boat, "boats")
|
72
|
+
relation.default_scoped = true
|
73
|
+
relation.default_scope.order_values.should_not be_empty
|
74
|
+
end
|
65
75
|
end
|
66
76
|
|
67
77
|
describe "#empty?" do
|
@@ -130,6 +140,7 @@ describe DatastaxRails::Relation do
|
|
130
140
|
|
131
141
|
describe "grouped queries" do
|
132
142
|
before(:each) do
|
143
|
+
Person.commit_solr
|
133
144
|
Person.create(:name => 'John', :nickname => 'J')
|
134
145
|
Person.create(:name => 'Jason', :nickname => 'J')
|
135
146
|
Person.create(:name => 'James', :nickname => 'J')
|
@@ -146,7 +157,7 @@ describe DatastaxRails::Relation do
|
|
146
157
|
results['steve'].should have(1).item
|
147
158
|
end
|
148
159
|
|
149
|
-
it "should return
|
160
|
+
it "should return total_entries as the highest value of any group" do
|
150
161
|
results = Person.group(:nickname).all
|
151
162
|
results.total_entries.should eq(3)
|
152
163
|
end
|