datastax_rails 1.2.3 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +20 -8
  4. data/config/schema.xml.erb +22 -19
  5. data/config/solrconfig.xml.erb +1 -1
  6. data/lib/cql-rb_extensions.rb +27 -0
  7. data/lib/datastax_rails.rb +13 -17
  8. data/lib/datastax_rails/associations/association.rb +1 -4
  9. data/lib/datastax_rails/associations/collection_proxy.rb +0 -13
  10. data/lib/datastax_rails/attribute_assignment.rb +28 -91
  11. data/lib/datastax_rails/attribute_methods.rb +109 -44
  12. data/lib/datastax_rails/attribute_methods/before_type_cast.rb +71 -0
  13. data/lib/datastax_rails/attribute_methods/dirty.rb +52 -11
  14. data/lib/datastax_rails/attribute_methods/primary_key.rb +87 -0
  15. data/lib/datastax_rails/attribute_methods/read.rb +120 -0
  16. data/lib/datastax_rails/attribute_methods/typecasting.rb +52 -21
  17. data/lib/datastax_rails/attribute_methods/write.rb +59 -0
  18. data/lib/datastax_rails/base.rb +227 -236
  19. data/lib/datastax_rails/cassandra_only_model.rb +25 -19
  20. data/lib/datastax_rails/column.rb +384 -0
  21. data/lib/datastax_rails/connection.rb +12 -13
  22. data/lib/datastax_rails/cql/alter_column_family.rb +0 -1
  23. data/lib/datastax_rails/cql/base.rb +15 -3
  24. data/lib/datastax_rails/cql/column_family.rb +2 -2
  25. data/lib/datastax_rails/cql/create_column_family.rb +7 -18
  26. data/lib/datastax_rails/cql/delete.rb +4 -9
  27. data/lib/datastax_rails/cql/insert.rb +2 -8
  28. data/lib/datastax_rails/cql/select.rb +4 -4
  29. data/lib/datastax_rails/cql/update.rb +8 -17
  30. data/lib/datastax_rails/dynamic_model.rb +98 -0
  31. data/lib/datastax_rails/payload_model.rb +19 -31
  32. data/lib/datastax_rails/persistence.rb +39 -54
  33. data/lib/datastax_rails/railtie.rb +1 -0
  34. data/lib/datastax_rails/reflection.rb +1 -1
  35. data/lib/datastax_rails/relation.rb +20 -20
  36. data/lib/datastax_rails/relation/batches.rb +18 -16
  37. data/lib/datastax_rails/relation/facet_methods.rb +1 -1
  38. data/lib/datastax_rails/relation/finder_methods.rb +6 -10
  39. data/lib/datastax_rails/relation/search_methods.rb +62 -48
  40. data/lib/datastax_rails/rsolr_client_wrapper.rb +1 -1
  41. data/lib/datastax_rails/schema/cassandra.rb +34 -62
  42. data/lib/datastax_rails/schema/migrator.rb +9 -24
  43. data/lib/datastax_rails/schema/solr.rb +13 -30
  44. data/lib/datastax_rails/schema_cache.rb +67 -0
  45. data/lib/datastax_rails/timestamps.rb +84 -11
  46. data/lib/datastax_rails/types/dirty_collection.rb +88 -0
  47. data/lib/datastax_rails/types/dynamic_list.rb +14 -0
  48. data/lib/datastax_rails/types/dynamic_map.rb +32 -0
  49. data/lib/datastax_rails/types/dynamic_set.rb +10 -0
  50. data/lib/datastax_rails/util/solr_repair.rb +4 -5
  51. data/lib/datastax_rails/validations.rb +6 -12
  52. data/lib/datastax_rails/validations/uniqueness.rb +0 -4
  53. data/lib/datastax_rails/version.rb +1 -1
  54. data/lib/datastax_rails/wide_storage_model.rb +13 -29
  55. data/lib/schema_migration.rb +4 -0
  56. data/spec/datastax_rails/associations_spec.rb +0 -1
  57. data/spec/datastax_rails/attribute_methods_spec.rb +9 -6
  58. data/spec/datastax_rails/base_spec.rb +26 -0
  59. data/spec/datastax_rails/column_spec.rb +238 -0
  60. data/spec/datastax_rails/cql/select_spec.rb +1 -1
  61. data/spec/datastax_rails/cql/update_spec.rb +2 -2
  62. data/spec/datastax_rails/persistence_spec.rb +29 -15
  63. data/spec/datastax_rails/relation/batches_spec.rb +5 -5
  64. data/spec/datastax_rails/relation/finder_methods_spec.rb +0 -20
  65. data/spec/datastax_rails/relation/search_methods_spec.rb +8 -0
  66. data/spec/datastax_rails/relation_spec.rb +7 -0
  67. data/spec/datastax_rails/schema/migrator_spec.rb +5 -10
  68. data/spec/datastax_rails/schema/solr_spec.rb +1 -1
  69. data/spec/datastax_rails/types/dynamic_list_spec.rb +20 -0
  70. data/spec/datastax_rails/types/dynamic_map_spec.rb +22 -0
  71. data/spec/datastax_rails/types/dynamic_set_spec.rb +16 -0
  72. data/spec/dummy/config/application.rb +2 -1
  73. data/spec/dummy/config/datastax.yml +6 -3
  74. data/spec/dummy/config/environments/development.rb +4 -5
  75. data/spec/dummy/config/environments/test.rb +0 -5
  76. data/spec/dummy/log/development.log +18 -0
  77. data/spec/dummy/log/test.log +36 -0
  78. data/spec/feature/dynamic_fields_spec.rb +9 -0
  79. data/spec/feature/overloaded_tables_spec.rb +24 -0
  80. data/spec/spec_helper.rb +1 -1
  81. data/spec/support/default_consistency_shared_examples.rb +2 -2
  82. data/spec/support/models.rb +28 -14
  83. metadata +212 -188
  84. data/lib/datastax_rails/identity.rb +0 -64
  85. data/lib/datastax_rails/identity/abstract_key_factory.rb +0 -29
  86. data/lib/datastax_rails/identity/custom_key_factory.rb +0 -37
  87. data/lib/datastax_rails/identity/hashed_natural_key_factory.rb +0 -10
  88. data/lib/datastax_rails/identity/natural_key_factory.rb +0 -39
  89. data/lib/datastax_rails/identity/uuid_key_factory.rb +0 -27
  90. data/lib/datastax_rails/type.rb +0 -16
  91. data/lib/datastax_rails/types.rb +0 -9
  92. data/lib/datastax_rails/types/array_type.rb +0 -86
  93. data/lib/datastax_rails/types/base_type.rb +0 -42
  94. data/lib/datastax_rails/types/binary_type.rb +0 -19
  95. data/lib/datastax_rails/types/boolean_type.rb +0 -22
  96. data/lib/datastax_rails/types/date_type.rb +0 -23
  97. data/lib/datastax_rails/types/float_type.rb +0 -18
  98. data/lib/datastax_rails/types/integer_type.rb +0 -18
  99. data/lib/datastax_rails/types/string_type.rb +0 -16
  100. data/lib/datastax_rails/types/text_type.rb +0 -15
  101. data/lib/datastax_rails/types/time_type.rb +0 -23
  102. data/spec/datastax_rails/types/float_type_spec.rb +0 -31
  103. data/spec/datastax_rails/types/integer_type_spec.rb +0 -31
  104. data/spec/datastax_rails/types/time_type_spec.rb +0 -28
@@ -1,64 +0,0 @@
1
- module DatastaxRails #:nodoc:
2
- module Identity
3
- extend ActiveSupport::Concern
4
- extend ActiveSupport::Autoload
5
-
6
- autoload :Key
7
- autoload :AbstractKeyFactory
8
- autoload :UUIDKeyFactory
9
- autoload :NaturalKeyFactory
10
- autoload :HashedNaturalKeyFactory
11
- autoload :CustomKeyFactory
12
-
13
- module ClassMethods
14
- attr_accessor :key_factory
15
- # Indicate what kind of key the model will have: uuid or natural
16
- #
17
- # @param [:uuid, :natural] name_or_factory the type of key
18
- # @param [Hash] options the options you want to pass along to the key factory (like :attributes => :name, for a natural key).
19
- #
20
- def key(name_or_factory = :uuid, *options)
21
- @key_factory = case name_or_factory
22
- when :uuid
23
- UUIDKeyFactory.new(*options)
24
- when :natural
25
- NaturalKeyFactory.new(*options)
26
- when :custom
27
- CustomKeyFactory.new(*options)
28
- else
29
- name_or_factory
30
- end
31
- end
32
-
33
- # The next key for the given object. Delegates the actual work to the factory which may
34
- # or may not use the passed in object to generate the key.
35
- #
36
- # @param [DatastaxRails::Base] object the object for which the key is being generated
37
- # @return [String] a key for this object
38
- def next_key(object = nil)
39
- @key_factory.next_key(object).tap do |key|
40
- raise "Keys may not be nil" if key.nil?
41
- end
42
- end
43
-
44
- # Parses out a key from the given string. Delegates the actual work to the factory.
45
- # Return type varies depending on what type of key is used.
46
- #
47
- # @param [String] string a string representing a primary key
48
- # @return an object representing the same key
49
- def parse_key(string)
50
- @key_factory.parse(string)
51
- end
52
- end
53
-
54
- def id
55
- key.to_s
56
- end
57
-
58
- # TODO test this
59
- def id=(key)
60
- self.key = self.class.parse_key(key)
61
- id
62
- end
63
- end
64
- end
@@ -1,29 +0,0 @@
1
- module DatastaxRails
2
- module Identity
3
- # Key factories need to support 3 operations
4
- class AbstractKeyFactory
5
- attr_accessor :key_columns
6
- # Next key takes an object and returns the key object it should use.
7
- # object will be ignored with synthetic keys but could be useful with natural ones
8
- #
9
- # @abstract
10
- # @param [DatastaxRails::Base] object the object that needs a new key
11
- # @return [DatastaxRails::Identity::Key] the key
12
- #
13
- def next_key(object)
14
- raise NotImplementedError, "#{self.class.name}#next_key isn't implemented."
15
- end
16
-
17
- # Parse should create a new key object from the 'to_param' format
18
- #
19
- # @abstract
20
- # @param [String] string the result of calling key.to_param
21
- # @return [DatastaxRails::Identity::Key] the parsed key
22
- #
23
- def parse(string)
24
- raise NotImplementedError, "#{self.class.name}#parse isn't implemented."
25
- end
26
- end
27
- end
28
- end
29
-
@@ -1,37 +0,0 @@
1
- module DatastaxRails
2
- module Identity
3
- class CustomKeyFactory < AbstractKeyFactory
4
- class CustomKey
5
- attr_reader :value
6
-
7
- def initialize(value)
8
- @value = value
9
- end
10
-
11
- def to_s
12
- value
13
- end
14
-
15
- def ==(other)
16
- other.to_s == value
17
- end
18
- end
19
-
20
- attr_reader :method
21
-
22
- def initialize(options)
23
- @method = options[:method]
24
- @key_columns = Array.wrap(options[:column])
25
- end
26
-
27
- def next_key(object)
28
- CustomKey.new(object.send(@method))
29
- end
30
-
31
- def parse(value)
32
- value
33
- end
34
- end
35
- end
36
- end
37
-
@@ -1,10 +0,0 @@
1
- require 'digest/sha1'
2
- module DatastaxRails
3
- module Identity
4
- class HashedNaturalKeyFactory < NaturalKeyFactory
5
- def next_key(object)
6
- NaturalKey.new(Digest::SHA1.hexdigest(attributes.map { |a| object.attributes[a.to_s] }.join(separator)))
7
- end
8
- end
9
- end
10
- end
@@ -1,39 +0,0 @@
1
- module DatastaxRails
2
- module Identity
3
- class NaturalKeyFactory < AbstractKeyFactory
4
- class NaturalKey
5
- attr_reader :value
6
-
7
- delegate :size, :bytesize, :to => :value
8
- def initialize(value)
9
- @value = value
10
- end
11
-
12
- def to_s
13
- value
14
- end
15
-
16
- def ==(other)
17
- other.to_s == to_s
18
- end
19
- end
20
-
21
- attr_reader :attributes, :separator
22
-
23
- def initialize(options)
24
- @attributes = [*options[:attributes]]
25
- @separator = options[:separator] || "-"
26
- @key_columns = options[:column].blank? ? @attributes.dup : Array.wrap(options[:column])
27
- end
28
-
29
- def next_key(object)
30
- NaturalKey.new(attributes.map { |a| object.attributes[a.to_s] }.join(separator))
31
- end
32
-
33
- def parse(paramized_key)
34
- NaturalKey.new(paramized_key)
35
- end
36
- end
37
- end
38
- end
39
-
@@ -1,27 +0,0 @@
1
- module DatastaxRails
2
- module Identity
3
- # Key factories need to support 3 operations
4
- class UUIDKeyFactory < AbstractKeyFactory
5
- class UUID < SimpleUUID::UUID
6
- def to_s
7
- to_guid
8
- end
9
- end
10
-
11
- def initialize(options = {})
12
- @key_columns = options[:column].blank? ? ['key'] : Array.wrap(options[:column])
13
- end
14
-
15
- def next_key(object)
16
- UUID.new
17
- end
18
-
19
- def parse(string)
20
- UUID.new(string) if string
21
- rescue
22
- nil
23
- end
24
- end
25
- end
26
- end
27
-
@@ -1,16 +0,0 @@
1
- module DatastaxRails
2
- class Type
3
- cattr_accessor :attribute_types
4
- self.attribute_types = {}.with_indifferent_access
5
-
6
- class << self
7
- def register(name, coder)
8
- attribute_types[name] = coder
9
- end
10
-
11
- def get_coder(name)
12
- attribute_types[name]
13
- end
14
- end
15
- end
16
- end
@@ -1,9 +0,0 @@
1
- DatastaxRails::Type.register(:array, DatastaxRails::Types::ArrayType)
2
- DatastaxRails::Type.register(:binary, DatastaxRails::Types::BinaryType)
3
- DatastaxRails::Type.register(:boolean, DatastaxRails::Types::BooleanType)
4
- DatastaxRails::Type.register(:date, DatastaxRails::Types::DateType)
5
- DatastaxRails::Type.register(:float, DatastaxRails::Types::FloatType)
6
- DatastaxRails::Type.register(:integer, DatastaxRails::Types::IntegerType)
7
- DatastaxRails::Type.register(:time, DatastaxRails::Types::TimeType)
8
- DatastaxRails::Type.register(:string, DatastaxRails::Types::StringType)
9
- DatastaxRails::Type.register(:text, DatastaxRails::Types::TextType)
@@ -1,86 +0,0 @@
1
- module DatastaxRails
2
- module Types
3
- # ArrayType is used for storing arrays in Datastax Enterprise.
4
- # They are indexed into SOLR as discrete values so that you can do something like this:
5
- #
6
- # Post.where(:tags => 'Technology')
7
- #
8
- # That would give you all the posts that have Technology somewhere in the tags array.
9
- class ArrayType < BaseType
10
- DEFAULTS = {:solr_type => 'array', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => false, :tokenized => true, :fulltext => true, :cassandra_type => 'text'}
11
-
12
- # An extension to normal arrays that allow for tracking of dirty values. This is
13
- # used by ActiveModel's change tracking framework.
14
- class DirtyArray < Array
15
- attr_accessor :record, :name, :options
16
- def initialize(record, name, array, options)
17
- @record = record
18
- @name = name.to_s
19
- @options = options
20
-
21
- super(array)
22
- setify!
23
- end
24
-
25
- def <<(obj)
26
- modifying do
27
- super
28
- setify!
29
- end
30
- end
31
-
32
- def delete(obj)
33
- modifying do
34
- super
35
- end
36
- end
37
-
38
- private
39
- def setify!
40
- if options[:unique]
41
- compact!
42
- uniq!
43
- begin sort! rescue ArgumentError end
44
- end
45
- end
46
-
47
- def modifying
48
- unless record.changed_attributes.include?(name)
49
- original = dup
50
- end
51
-
52
- result = yield
53
-
54
- if !record.changed_attributes.key?(name) && original != self
55
- record.changed_attributes[name] = original
56
- end
57
-
58
- record.send("#{name}=", self)
59
-
60
- result
61
- end
62
- end
63
-
64
- def default
65
- []
66
- end
67
-
68
- def encode(array)
69
- raise ArgumentError.new("#{self} requires an Array") unless array.kind_of?(Array)
70
- ar = Array(array)
71
- ar.uniq! if options[:unique]
72
- ar.join("$$$$")
73
- end
74
-
75
- def decode(str)
76
- return [] if str.blank?
77
- # Temporary fix
78
- str.is_a?(Array) ? str.flatten : str.gsub(/&&&&/,'$$$$').split(/\$\$\$\$/).reject{|a|a.blank?}
79
- end
80
-
81
- def wrap(record, name, value)
82
- DirtyArray.new(record, name, value, options)
83
- end
84
- end
85
- end
86
- end
@@ -1,42 +0,0 @@
1
- module DatastaxRails
2
- module Types
3
- # All of the DSR type classes inherit from here. It sets up some default options and doesn basic conversion
4
- # to strings. Subclasses can override these methods as needed.
5
- #
6
- # NOTE: All subclasses MUST declare a +DEFAULTS+ constant that specifies the indexing defaults. Defaults may of
7
- # course be overridden when the attribute is declared.
8
- class BaseType
9
- attr_accessor :options
10
- # Default initializer. Sets the indexing options based on the DEFAULTS
11
- def initialize(options = {})
12
- @options = self.class::DEFAULTS.merge(options)
13
- end
14
-
15
- def default
16
- if options.has_key?(:default)
17
- options[:default].duplicable? ? options[:default].dup : options[:default]
18
- end
19
- end
20
-
21
- def encode(value, format = :solr)
22
- value.to_s
23
- end
24
-
25
- def decode(str)
26
- str
27
- end
28
-
29
- def wrap(record, name, value)
30
- value
31
- end
32
-
33
- def type
34
- self.class.name.sub(/^DatastaxRails::Types::/,'').sub(/Type$/,'').underscore.to_sym
35
- end
36
-
37
- def full_solr_range
38
- '[\"\" TO *]'
39
- end
40
- end
41
- end
42
- end
@@ -1,19 +0,0 @@
1
- module DatastaxRails
2
- module Types
3
- class BinaryType < BaseType
4
- DEFAULTS = {:solr_type => false, :indexed => false, :stored => false, :multi_valued => false, :sortable => false, :tokenized => false, :fulltext => false, :cassandra_type => 'blob'}
5
- def encode(str)
6
- raise ArgumentError.new("#{self} requires a String") unless str.kind_of?(String)
7
- Base64.encode64(str)
8
- end
9
-
10
- def decode(str)
11
- Base64.decode64(str)
12
- end
13
-
14
- def wrap(record, name, value)
15
- (value.frozen? ? value.dup : value)
16
- end
17
- end
18
- end
19
- end
@@ -1,22 +0,0 @@
1
- module DatastaxRails
2
- module Types
3
- class BooleanType < BaseType
4
- DEFAULTS = {:solr_type => 'boolean', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false, :cassandra_type => 'boolean'}
5
- TRUE_VALS = [true, 'true', '1', 'Y']
6
- FALSE_VALS = [false, 'false', '0', '', 'N', nil, 'null']
7
- VALID_VALS = TRUE_VALS + FALSE_VALS
8
-
9
- def encode(bool)
10
- unless VALID_VALS.include?(bool)
11
- raise ArgumentError.new("#{self} requires a boolean")
12
- end
13
- TRUE_VALS.include?(bool) ? '1' : '0'
14
- end
15
-
16
- def decode(str)
17
- raise ArgumentError.new("Cannot convert #{str} into a boolean") unless VALID_VALS.include?(str)
18
- TRUE_VALS.include?(str)
19
- end
20
- end
21
- end
22
- end
@@ -1,23 +0,0 @@
1
- module DatastaxRails
2
- module Types
3
- class DateType < BaseType
4
- DEFAULTS = {:solr_type => 'date', :indexed => :solr, :stored => true, :multi_valued => false, :sortable => true, :tokenized => false, :fulltext => false, :cassandra_type => 'timestamp'}
5
- FORMAT = '%Y-%m-%dT%H:%M:%SZ'
6
-
7
- def encode(value)
8
- return unless value
9
- raise ArgumentError.new("#{self} requires a Date") unless value.kind_of?(Date) || value.kind_of?(Time)
10
- value.to_date.strftime(FORMAT)
11
- end
12
-
13
- def decode(str)
14
- return str if str.kind_of?(Date)
15
- Date.parse(str) rescue nil
16
- end
17
-
18
- def full_solr_range
19
- '[* TO *]'
20
- end
21
- end
22
- end
23
- end