quandl_cassandra 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE +7 -0
  4. data/README.md +7 -0
  5. data/Rakefile +11 -0
  6. data/UPGRADE.md +3 -0
  7. data/lib/quandl/cassandra/base/attributes.rb +103 -0
  8. data/lib/quandl/cassandra/base/callbacks.rb +15 -0
  9. data/lib/quandl/cassandra/base/connection.rb +49 -0
  10. data/lib/quandl/cassandra/base/logging.rb +40 -0
  11. data/lib/quandl/cassandra/base/naming.rb +19 -0
  12. data/lib/quandl/cassandra/base/persistence.rb +67 -0
  13. data/lib/quandl/cassandra/base/sanitization.rb +38 -0
  14. data/lib/quandl/cassandra/base/schema.rb +79 -0
  15. data/lib/quandl/cassandra/base/scoping.rb +122 -0
  16. data/lib/quandl/cassandra/base.rb +51 -0
  17. data/lib/quandl/cassandra/configuration.rb +34 -0
  18. data/lib/quandl/cassandra/error.rb +10 -0
  19. data/lib/quandl/cassandra/types/abstract_type.rb +33 -0
  20. data/lib/quandl/cassandra/types/boolean_type.rb +10 -0
  21. data/lib/quandl/cassandra/types/decimal_type.rb +9 -0
  22. data/lib/quandl/cassandra/types/double_type.rb +9 -0
  23. data/lib/quandl/cassandra/types/float_type.rb +9 -0
  24. data/lib/quandl/cassandra/types/integer_type.rb +9 -0
  25. data/lib/quandl/cassandra/types/long_type.rb +9 -0
  26. data/lib/quandl/cassandra/types/timestamp_type.rb +15 -0
  27. data/lib/quandl/cassandra/types/utf8_type.rb +13 -0
  28. data/lib/quandl/cassandra/types/uuid_type.rb +21 -0
  29. data/lib/quandl/cassandra/types.rb +42 -0
  30. data/lib/quandl/cassandra/version.rb +5 -0
  31. data/lib/quandl/cassandra.rb +30 -0
  32. data/lib/quandl/cassandra_models/column/read/collapse.rb +64 -0
  33. data/lib/quandl/cassandra_models/column/read/column.rb +18 -0
  34. data/lib/quandl/cassandra_models/column/read/data_table.rb +57 -0
  35. data/lib/quandl/cassandra_models/column/read/offset.rb +114 -0
  36. data/lib/quandl/cassandra_models/column/read/query.rb +55 -0
  37. data/lib/quandl/cassandra_models/column/read/row.rb +20 -0
  38. data/lib/quandl/cassandra_models/column/read/transform.rb +53 -0
  39. data/lib/quandl/cassandra_models/column/read/type.rb +25 -0
  40. data/lib/quandl/cassandra_models/column/read.rb +28 -0
  41. data/lib/quandl/cassandra_models/column/write/group_data_by_column.rb +42 -0
  42. data/lib/quandl/cassandra_models/column/write/group_data_by_frequency.rb +24 -0
  43. data/lib/quandl/cassandra_models/column/write/insert_columns.rb +22 -0
  44. data/lib/quandl/cassandra_models/column/write/insert_data.rb +39 -0
  45. data/lib/quandl/cassandra_models/column/write.rb +22 -0
  46. data/lib/quandl/cassandra_models/column.rb +20 -0
  47. data/lib/quandl/cassandra_models/column_attribute.rb +11 -0
  48. data/lib/quandl/cassandra_models/data.rb +52 -0
  49. data/lib/quandl/cassandra_models/dataset.rb +83 -0
  50. data/lib/quandl/cassandra_models/dataset_attribute.rb +6 -0
  51. data/lib/quandl/cassandra_models/multiset.rb +50 -0
  52. data/lib/quandl/strategy.rb +59 -0
  53. data/quandl_cassandra.gemspec +35 -0
  54. data/spec/expectations/string.rb +5 -0
  55. data/spec/expectations/time.rb +5 -0
  56. data/spec/factories/dataset.rb +8 -0
  57. data/spec/lib/quandl/cassandra/base/scoping_spec.rb +40 -0
  58. data/spec/lib/quandl/cassandra_models/column/write/group_data_by_frequency_spec.rb +28 -0
  59. data/spec/lib/quandl/cassandra_models/column/write_spec.rb +15 -0
  60. data/spec/lib/quandl/cassandra_models/column_attribute_spec.rb +16 -0
  61. data/spec/lib/quandl/cassandra_models/column_spec.rb +17 -0
  62. data/spec/lib/quandl/cassandra_models/data_spec.rb +34 -0
  63. data/spec/lib/quandl/cassandra_models/dataset/collapse_spec.rb +41 -0
  64. data/spec/lib/quandl/cassandra_models/dataset/column_spec.rb +25 -0
  65. data/spec/lib/quandl/cassandra_models/dataset/persistence_spec.rb +24 -0
  66. data/spec/lib/quandl/cassandra_models/dataset/row_spec.rb +26 -0
  67. data/spec/lib/quandl/cassandra_models/dataset/transform_spec.rb +16 -0
  68. data/spec/lib/quandl/cassandra_models/dataset/trim_spec.rb +74 -0
  69. data/spec/lib/quandl/cassandra_models/dataset/update_spec.rb +37 -0
  70. data/spec/lib/quandl/cassandra_models/dataset_attribute_spec.rb +18 -0
  71. data/spec/lib/quandl/cassandra_models/dataset_spec.rb +63 -0
  72. data/spec/lib/quandl/cassandra_models/multiset/collapse_spec.rb +122 -0
  73. data/spec/lib/quandl/cassandra_models/multiset/columns_spec.rb +57 -0
  74. data/spec/lib/quandl/cassandra_models/multiset/data_spec.rb +25 -0
  75. data/spec/lib/quandl/cassandra_models/multiset/transform_spec.rb +68 -0
  76. data/spec/lib/quandl/cassandra_spec.rb +12 -0
  77. data/spec/spec_helper.rb +37 -0
  78. metadata +339 -0
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ /Gemfile.lock
2
+ /pkg
3
+ /tmp
4
+ quandl_cassandra-*
5
+ .rvmrc
6
+ *.gem
7
+ *.log
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2012-2013 Blake Hilscher
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # Installation
2
+
3
+ ```ruby
4
+
5
+ gem 'quandl_cassandra'
6
+
7
+ ```
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler"
2
+ require "rake"
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ task :default => :spec
7
+
8
+ desc "Run all specs"
9
+ RSpec::Core::RakeTask.new(:spec) do |task|
10
+ task.pattern = "spec/**/*_spec.rb"
11
+ end
data/UPGRADE.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 0.0.1
2
+
3
+ * Begin
@@ -0,0 +1,103 @@
1
+ module Quandl
2
+ module Cassandra
3
+ class Base
4
+
5
+ module Attributes
6
+
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ include ActiveModel::AttributeMethods
11
+ include ActiveModel::Dirty
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ def define_attributes(*names)
17
+ Array(names).each{|name| define_attribute(name) }
18
+ end
19
+
20
+ def define_attribute(name)
21
+ name = name.to_sym
22
+ self.class_eval do
23
+ define_attribute_methods [name.to_sym]
24
+ end
25
+ define_method(name) do
26
+ read_attribute(name)
27
+ end
28
+ define_method("#{name}=") do |value|
29
+ write_attribute(name, value)
30
+ end
31
+ define_method("#{name}?") do
32
+ read_attribute(name).present?
33
+ end
34
+ # store an array of defined attriubte names
35
+ attribute_names << name unless attribute_names.include?(name)
36
+ end
37
+
38
+ def attribute_names
39
+ @attribute_names ||= []
40
+ end
41
+
42
+ end
43
+
44
+ def initialize(*args)
45
+ self.assign_attributes(args.extract_options!)
46
+ end
47
+
48
+ def inspect
49
+ "#{self.class.name} " + attributes.inspect
50
+ end
51
+
52
+ def assign_attributes(hash)
53
+ hash.each do |k,v|
54
+ send("#{k}=", v) if self.class.attribute_names.include?(k) && respond_to?("#{k}=")
55
+ end
56
+ end
57
+
58
+ def attributes
59
+ @attributes ||= self.class.attribute_names.inject({}){|m,k| m[k] ||= nil; m }
60
+ end
61
+
62
+ def attributes=(value)
63
+ @attributes = value.symbolize_keys! if value.is_a?(Hash)
64
+ end
65
+
66
+ def save
67
+ cycle_changes!
68
+ end
69
+
70
+ def reload
71
+ clear_changes!
72
+ end
73
+
74
+ protected
75
+
76
+ def write_attribute(attribute, value)
77
+ self.send(:"#{attribute}_will_change!") if self.attributes[:"#{attribute}"] != value
78
+ @attributes[:"#{attribute}"] = value
79
+ end
80
+
81
+ def read_attribute(attribute)
82
+ @attributes[:"#{attribute}"]
83
+ end
84
+
85
+ def attribute_changed?(attribute)
86
+ !changes[attribute.to_s].nil?
87
+ end
88
+
89
+ def clear_changes!
90
+ @previously_changed = {}
91
+ @changed_attributes.clear
92
+ end
93
+
94
+ def cycle_changes!
95
+ @previously_changed = changes
96
+ @changed_attributes.clear
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,15 @@
1
+ module Quandl::Cassandra::Base::Callbacks
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ extend ActiveModel::Callbacks
7
+ define_model_callbacks :create, :update, :save, :find, :destroy, :initialize
8
+ end
9
+
10
+ def initialize(*args)
11
+ super if defined?(super)
12
+ run_callbacks :initialize
13
+ end
14
+
15
+ end
@@ -0,0 +1,49 @@
1
+ module Quandl::Cassandra::Base::Connection
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ def delete(*ids)
8
+ statement = prepare("DELETE FROM #{table_name} WHERE id = ?")
9
+ Array(ids).flatten.
10
+ collect{|id| statement.async.execute(id, consistency) }.
11
+ collect(&:value)
12
+ end
13
+
14
+ def prepare(statement)
15
+ connection.prepare(statement)
16
+ end
17
+
18
+ def execute_async(statement, query_consistency = nil)
19
+ query_consistency = consistency unless query_consistency.present?
20
+ connection.async.execute( statement, query_consistency )
21
+ end
22
+
23
+ def execute(statement, query_consistency = nil)
24
+ query_consistency = consistency unless query_consistency.present?
25
+ connection.execute( statement, query_consistency )
26
+ end
27
+
28
+ def connection
29
+ @connection ||= connect
30
+ end
31
+
32
+ def consistency
33
+ Quandl::Cassandra.configuration.consistency
34
+ end
35
+
36
+ protected
37
+
38
+ def connect
39
+ c = Cql::Client.connect(
40
+ hosts: Quandl::Cassandra.configuration.hosts,
41
+ consistency: Quandl::Cassandra.configuration.consistency )
42
+ # switch keyspace
43
+ c.use( Quandl::Cassandra.configuration.keyspace )
44
+ c
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,40 @@
1
+ module Quandl::Cassandra::Base::Logging
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ def prepare(*args, &block)
8
+ statement = args.first.to_s
9
+ statement = "#{statement[0..200]} ... #{statement.length} chars" if statement.length > 200
10
+ Quandl::Logger.debug(statement)
11
+ super if defined?(super)
12
+ end
13
+
14
+ def execute_async(*args, &block)
15
+ statement = args.first.to_s
16
+ statement = "#{statement[0..200]} ... #{statement.length} chars" if statement.length > 200
17
+ t1 = Time.now
18
+ begin
19
+ r = super if defined?(super)
20
+ ensure
21
+ Quandl::Logger.debug("(#{t1.elapsed_ms}) #{statement}")
22
+ end
23
+ r
24
+ end
25
+
26
+ def execute(*args, &block)
27
+ statement = args.first.to_s
28
+ statement = "#{statement[0..200]} ... #{statement.length} chars" if statement.length > 200
29
+ t1 = Time.now
30
+ begin
31
+ r = super if defined?(super)
32
+ ensure
33
+ Quandl::Logger.debug("(#{t1.elapsed_ms}) #{statement}")
34
+ end
35
+ r
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,19 @@
1
+ module Quandl::Cassandra::Base::Naming
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include ActiveModel::Conversion
7
+ include ActiveModel::Naming
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ def table_name(*args)
13
+ @table_name = args.first.to_s if args.first.present?
14
+ @table_name ||= model_name.plural
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,67 @@
1
+ module Quandl::Cassandra::Base::Persistence
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ def autosave_changes(*args)
8
+ @autosave_changes = (args.first == true) unless args.first.nil?
9
+ @autosave_changes = true if @autosave_changes.nil?
10
+ @autosave_changes
11
+ end
12
+
13
+ def find_or_build(id)
14
+ find(id) || new( id: id )
15
+ end
16
+
17
+ def create(*args)
18
+ r = self.new(*args)
19
+ r.save
20
+ r
21
+ end
22
+
23
+ def new_from_query_result(result)
24
+ return nil if result.blank?
25
+ r = self.new
26
+ r.attributes = result
27
+ r
28
+ end
29
+
30
+ end
31
+
32
+ def save!
33
+ save
34
+ end
35
+
36
+ def save
37
+ run_callbacks :save do
38
+ touch
39
+ save_changes! if self.class.autosave_changes == true
40
+ clear_changes!
41
+ end
42
+ end
43
+
44
+ def touch
45
+ self.created_at = Time.now if respond_to?(:created_at=) && created_at.blank?
46
+ self.updated_at = Time.now if respond_to?(:updated_at=)
47
+ end
48
+
49
+ def update_attributes(values)
50
+ values = self.class.sanitize_attributes(values)
51
+ # add primary key parts to values
52
+ self.class.primary_key.each do |attribute|
53
+ values[attribute.to_s] = sanitized_attribute(attribute) unless values.has_key?(attribute.to_s)
54
+ end
55
+ # update
56
+ self.class.execute("INSERT INTO #{self.class.table_name} (#{values.keys.join(', ')}) VALUES (#{values.values.join(', ')})")
57
+ end
58
+
59
+ private
60
+
61
+ def save_changes!
62
+ attrs = {}
63
+ changes.each{|k,v| attrs[k] = v[1] }
64
+ update_attributes(attrs)
65
+ end
66
+
67
+ end
@@ -0,0 +1,38 @@
1
+ module Quandl::Cassandra::Base::Sanitization
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ def bind_primary_key(*args)
8
+ if args.count > primary_key.count
9
+ message = "wrong number of arguments (#{args.count} for 1..#{primary_key.count}) expected: #{primary_key.join(', ')}"
10
+ raise(ArgumentError, message)
11
+ end
12
+ attrs = {}
13
+ primary_key.each_with_index { |k, i| attrs[k] = args[i] if args[i].present? }
14
+ attrs
15
+ end
16
+
17
+ def sanitize_attributes(attrs)
18
+ values = {}
19
+ attrs.each do |attribute, value|
20
+ # exclude attributes that are not present in columns
21
+ next unless column_type(attribute)
22
+ # sanitize value for cql
23
+ values[attribute] = sanitize_attribute(attribute, value)# unless value.nil?
24
+ end
25
+ values
26
+ end
27
+
28
+ def sanitize_attribute(attribute, value)
29
+ column_type(attribute).sanitize_for_cql( value )
30
+ end
31
+
32
+ end
33
+
34
+ def sanitized_attribute(attribute)
35
+ self.class.sanitize_attribute(attribute, read_attribute(attribute))
36
+ end
37
+
38
+ end
@@ -0,0 +1,79 @@
1
+ module Quandl::Cassandra::Base::Schema
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ def initialize_class_once
8
+ return if defined?(@initialize_class_once)
9
+ define_schema_attributes
10
+ @initialize_class_once = true
11
+ end
12
+
13
+ def column_type(type)
14
+ column_types[type.to_sym]
15
+ end
16
+
17
+ def column_types
18
+ return @column_types if @column_types
19
+ @column_types = {}
20
+ columns.each do |c|
21
+ @column_types[c.column_name.to_sym] = Quandl::Cassandra::Types.type( c.type )
22
+ end
23
+ @column_types
24
+ end
25
+
26
+ def column_names
27
+ @column_names ||= columns.collect(&:column_name)
28
+ end
29
+
30
+ def columns
31
+ @columns ||= execute("SELECT * FROM #{table_name} LIMIT 1").metadata
32
+ end
33
+
34
+ def primary_key
35
+ @primary_key ||= key_aliases + column_aliases
36
+ end
37
+
38
+ def column_aliases
39
+ @column_aliases ||= JSON.parse(system_schema['column_aliases']).collect(&:to_sym)
40
+ rescue
41
+ []
42
+ end
43
+
44
+ def key_aliases
45
+ @key_aliases ||= JSON.parse(system_schema['key_aliases']).collect(&:to_sym)
46
+ rescue
47
+ []
48
+ end
49
+
50
+ def table_exists?
51
+ system_schema.present?
52
+ end
53
+
54
+ def system_schema
55
+ return @system_schema if defined?(@system_schema)
56
+ @system_schema = execute(%Q{
57
+ SELECT * FROM system.schema_columnfamilies WHERE
58
+ keyspace_name='#{Quandl::Cassandra.configuration.keyspace}'
59
+ AND columnfamily_name = '#{table_name}'
60
+ }).first
61
+ end
62
+
63
+ private
64
+
65
+ def define_schema_attributes
66
+ self.class_eval do
67
+ define_attributes *column_names
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ def initialize(*args, &block)
74
+ self.class.initialize_class_once
75
+ super if defined?(super)
76
+ end
77
+
78
+ end
79
+