quandl_cassandra 0.0.1 → 0.1.0

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.
Files changed (43) hide show
  1. data/lib/quandl/cassandra/base/attributes.rb +4 -4
  2. data/lib/quandl/cassandra/base/persistence.rb +24 -1
  3. data/lib/quandl/cassandra/base/sanitization.rb +4 -1
  4. data/lib/quandl/cassandra/base/schema.rb +8 -0
  5. data/lib/quandl/cassandra/base/scoping.rb +47 -3
  6. data/lib/quandl/cassandra/types/boolean_type.rb +1 -1
  7. data/lib/quandl/cassandra/types/decimal_type.rb +1 -1
  8. data/lib/quandl/cassandra/types/double_type.rb +1 -1
  9. data/lib/quandl/cassandra/types/float_type.rb +1 -1
  10. data/lib/quandl/cassandra/types/integer_type.rb +1 -1
  11. data/lib/quandl/cassandra/types/long_type.rb +1 -1
  12. data/lib/quandl/cassandra/types/timestamp_type.rb +1 -1
  13. data/lib/quandl/cassandra/types/utf8_type.rb +1 -1
  14. data/lib/quandl/cassandra/types/uuid_type.rb +1 -1
  15. data/lib/quandl/cassandra/version.rb +1 -1
  16. data/lib/quandl/cassandra_models/column/read/collapse.rb +2 -1
  17. data/lib/quandl/cassandra_models/column/read/column.rb +3 -2
  18. data/lib/quandl/cassandra_models/column/read/{data_table.rb → data.rb} +6 -4
  19. data/lib/quandl/cassandra_models/column/read/offset.rb +4 -0
  20. data/lib/quandl/cassandra_models/column/read/{query.rb → select_columns.rb} +21 -4
  21. data/lib/quandl/cassandra_models/column/read.rb +9 -5
  22. data/lib/quandl/cassandra_models/column/write/insert_column_attributes.rb +22 -0
  23. data/lib/quandl/cassandra_models/column/write/insert_columns.rb +29 -12
  24. data/lib/quandl/cassandra_models/column/write.rb +2 -2
  25. data/lib/quandl/cassandra_models/data/search.rb +104 -0
  26. data/lib/quandl/cassandra_models/data.rb +12 -46
  27. data/lib/quandl/cassandra_models/dataset.rb +17 -8
  28. data/lib/quandl/cassandra_models/multiset.rb +3 -3
  29. data/quandl_cassandra.gemspec +1 -1
  30. data/spec/lib/quandl/cassandra/base/sanitization_spec.rb +7 -0
  31. data/spec/lib/quandl/cassandra/base/scoping_spec.rb +11 -0
  32. data/spec/lib/quandl/cassandra_models/column_spec.rb +1 -1
  33. data/spec/lib/quandl/cassandra_models/data_spec.rb +51 -1
  34. data/spec/lib/quandl/cassandra_models/dataset/collapse_spec.rb +3 -0
  35. data/spec/lib/quandl/cassandra_models/dataset/column_spec.rb +3 -4
  36. data/spec/lib/quandl/cassandra_models/dataset/persistence_spec.rb +2 -2
  37. data/spec/lib/quandl/cassandra_models/dataset/row_spec.rb +8 -8
  38. data/spec/lib/quandl/cassandra_models/dataset/trim_spec.rb +6 -6
  39. data/spec/lib/quandl/cassandra_models/dataset/update_spec.rb +4 -4
  40. data/spec/lib/quandl/cassandra_models/dataset_spec.rb +42 -3
  41. data/spec/lib/quandl/cassandra_models/multiset/transform_spec.rb +2 -1
  42. metadata +10 -7
  43. data/lib/quandl/cassandra_models/column/write/insert_data.rb +0 -39
@@ -42,6 +42,7 @@ module Attributes
42
42
  end
43
43
 
44
44
  def initialize(*args)
45
+ @attributes = {}
45
46
  self.assign_attributes(args.extract_options!)
46
47
  end
47
48
 
@@ -63,12 +64,11 @@ module Attributes
63
64
  @attributes = value.symbolize_keys! if value.is_a?(Hash)
64
65
  end
65
66
 
66
- def save
67
- cycle_changes!
68
- end
69
-
70
67
  def reload
68
+ return false unless primary_key?
71
69
  clear_changes!
70
+ reload_attributes
71
+ true
72
72
  end
73
73
 
74
74
  protected
@@ -23,21 +23,27 @@ module Quandl::Cassandra::Base::Persistence
23
23
  def new_from_query_result(result)
24
24
  return nil if result.blank?
25
25
  r = self.new
26
+ r.new_record = false
26
27
  r.attributes = result
27
28
  r
28
29
  end
29
30
 
30
31
  end
31
32
 
33
+ attr_accessor :new_record
34
+
32
35
  def save!
33
36
  save
34
37
  end
35
38
 
36
39
  def save
40
+ return false if self.class.autosave_changes && !primary_key?
37
41
  run_callbacks :save do
38
42
  touch
39
43
  save_changes! if self.class.autosave_changes == true
40
- clear_changes!
44
+ cycle_changes!
45
+ new_record = false
46
+ true
41
47
  end
42
48
  end
43
49
 
@@ -56,8 +62,25 @@ module Quandl::Cassandra::Base::Persistence
56
62
  self.class.execute("INSERT INTO #{self.class.table_name} (#{values.keys.join(', ')}) VALUES (#{values.values.join(', ')})")
57
63
  end
58
64
 
65
+ def new_record?
66
+ new_record
67
+ end
68
+
69
+ def new_record
70
+ return @new_record if defined?(@new_record)
71
+ @new_record = true
72
+ end
73
+
74
+ def new_record=(value)
75
+ @new_record = (value == true)
76
+ end
77
+
59
78
  private
60
79
 
80
+ def reload_attributes
81
+ self.attributes = self.class.where(primary_key_attributes).limit(1).to_h.first
82
+ end
83
+
61
84
  def save_changes!
62
85
  attrs = {}
63
86
  changes.each{|k,v| attrs[k] = v[1] }
@@ -20,12 +20,15 @@ module Quandl::Cassandra::Base::Sanitization
20
20
  # exclude attributes that are not present in columns
21
21
  next unless column_type(attribute)
22
22
  # sanitize value for cql
23
- values[attribute] = sanitize_attribute(attribute, value)# unless value.nil?
23
+ values[attribute] = sanitize_attribute(attribute, value)
24
24
  end
25
25
  values
26
26
  end
27
27
 
28
28
  def sanitize_attribute(attribute, value)
29
+ # process each value
30
+ return value.collect{|val| column_type(attribute).sanitize_for_cql( val ) } if value.is_a?(Array)
31
+ # process value
29
32
  column_type(attribute).sanitize_for_cql( value )
30
33
  end
31
34
 
@@ -1,6 +1,14 @@
1
1
  module Quandl::Cassandra::Base::Schema
2
2
 
3
3
  extend ActiveSupport::Concern
4
+
5
+ def primary_key?
6
+ !primary_key_attributes.values.include?(nil)
7
+ end
8
+
9
+ def primary_key_attributes
10
+ self.class.primary_key.inject({}){|m,key| m[key] = self.send(key); m }
11
+ end
4
12
 
5
13
  module ClassMethods
6
14
 
@@ -4,6 +4,10 @@ module Quandl::Cassandra::Base::Scoping
4
4
 
5
5
  module ClassMethods
6
6
 
7
+ def scope_names
8
+ scope.scope_names
9
+ end
10
+
7
11
  def where(*args)
8
12
  scope.new.where(*args)
9
13
  end
@@ -16,10 +20,13 @@ module Quandl::Cassandra::Base::Scoping
16
20
 
17
21
  has_scope_composer
18
22
 
19
- scope :select, :limit, :order, :count, :find, :first, :all, :pluck, :exists?
23
+ scope :select, :delete_all, :limit,
24
+ :order, :count, :find, :first, :all, :pluck, :exists?, :to_h
20
25
 
21
26
  scope.class_eval do
22
27
 
28
+ attr_accessor :statement_type
29
+
23
30
  delegate :to_a, to: :execute
24
31
 
25
32
  delegate :primary_key, :table_name, :sanitize_attributes, to: :parent
@@ -41,18 +48,28 @@ module Quandl::Cassandra::Base::Scoping
41
48
  select(*columns).execute.present?
42
49
  end
43
50
 
51
+ def to_h
52
+ execute
53
+ end
54
+
44
55
  def pluck(*args)
45
56
  r = select(*args).values
46
57
  r = r.flatten if args.count <= 1
47
58
  r
48
59
  end
49
60
 
61
+ def select=(*names)
62
+ self.statement_type = :select
63
+ write_scope_attribute(:select, names)
64
+ end
65
+
50
66
  def values
51
67
  to_a.collect(&:values)
52
68
  end
53
69
 
54
70
  def find(*args)
55
71
  primary_key = parent.bind_primary_key(*args)
72
+ return nil if primary_key.blank?
56
73
  where(primary_key).first
57
74
  end
58
75
 
@@ -69,17 +86,44 @@ module Quandl::Cassandra::Base::Scoping
69
86
  end
70
87
 
71
88
  def to_cql
72
- ["SELECT #{cql_select} FROM", table_name, cql_where, cql_order, cql_limit].compact.join(' ')
89
+ [cql_statement_type, table_name, cql_where, cql_order, cql_limit].compact.join(' ')
90
+ end
91
+
92
+ def delete_all
93
+ self.statement_type = :delete
94
+ execute
95
+ end
96
+
97
+ def insert
98
+ self.statement_type = :insert
99
+ self
73
100
  end
74
101
 
75
102
  protected
76
103
 
104
+ def cql_statement_type
105
+ case statement_type
106
+ when :insert then "INSERT INTO"
107
+ when :delete then "DELETE FROM"
108
+ else
109
+ "SELECT #{cql_select} FROM"
110
+ end
111
+ end
112
+
77
113
  def cql_where
78
114
  attrs = attributes.clone
79
115
  attrs = sanitize_attributes(attrs) if parent.table_exists?
80
- attrs = attrs.collect{|k,v| "#{k} = #{v}" }.join(' AND ')
116
+ attrs = attrs.collect{|key, value| cql_where_attribute(key, value) }.join(' AND ')
81
117
  cql = attrs.present? ? "WHERE #{attrs}" : nil
82
118
  end
119
+
120
+ def cql_where_attribute(key, value)
121
+ if value.is_a?(Array)
122
+ "#{key} IN (#{value.join(',')})"
123
+ else
124
+ "#{key} = #{value}"
125
+ end
126
+ end
83
127
 
84
128
  def cql_select
85
129
  columns = Array(select).join(',') if select.present?
@@ -4,7 +4,7 @@ class Quandl::Cassandra::Types::BooleanType < Quandl::Cassandra::Types::Abstract
4
4
  return true if value == true || value.to_s =~ (/(true|t|yes|y|1)$/i)
5
5
  return false if value == false || value.blank? || value.to_s =~ (/(false|f|no|n|0)$/i)
6
6
  rescue
7
- raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{self.class}", value)
7
+ raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{name} #{value}", value)
8
8
  end
9
9
 
10
10
  end
@@ -3,7 +3,7 @@ class Quandl::Cassandra::Types::DecimalType < Quandl::Cassandra::Types::Abstract
3
3
  def self.sanitize(value)
4
4
  Float(value)
5
5
  rescue
6
- raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{self.class}", value)
6
+ raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{name} #{value}", value)
7
7
  end
8
8
 
9
9
  end
@@ -3,7 +3,7 @@ class Quandl::Cassandra::Types::DoubleType < Quandl::Cassandra::Types::AbstractT
3
3
  def self.sanitize(value)
4
4
  Float(value)
5
5
  rescue
6
- raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{self.class}", value)
6
+ raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{name} #{value}", value)
7
7
  end
8
8
 
9
9
  end
@@ -3,7 +3,7 @@ class Quandl::Cassandra::Types::FloatType < Quandl::Cassandra::Types::AbstractTy
3
3
  def self.sanitize(value)
4
4
  Float(value)
5
5
  rescue
6
- raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{self.class}", value)
6
+ raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{self.name} #{value}", value)
7
7
  end
8
8
 
9
9
  end
@@ -3,7 +3,7 @@ class Quandl::Cassandra::Types::IntegerType < Quandl::Cassandra::Types::Abstract
3
3
  def self.sanitize(value)
4
4
  Integer(value)
5
5
  rescue
6
- raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{self.class}", value)
6
+ raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{self.name} #{value}", value)
7
7
  end
8
8
 
9
9
  end
@@ -3,7 +3,7 @@ class Quandl::Cassandra::Types::LongType < Quandl::Cassandra::Types::AbstractTyp
3
3
  def self.sanitize(value)
4
4
  Integer(value)
5
5
  rescue
6
- raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{self.class}", value)
6
+ raise Quandl::Cassandra::Error::CastException.new("Unable to convert value to #{self.name} #{value}", value)
7
7
  end
8
8
 
9
9
  end
@@ -9,7 +9,7 @@ class Quandl::Cassandra::Types::TimestampType < Quandl::Cassandra::Types::Abstra
9
9
  return Time.at(value.get_time / 1000.0) if value.respond_to?(:get_time)
10
10
  Time.at(value.to_f) if value.present?
11
11
  rescue => error
12
- raise Quandl::Cassandra::Error::CastException.new("Unable to convert to Timestamp #{value} #{error}", value)
12
+ raise Quandl::Cassandra::Error::CastException.new("Unable to convert to #{name} #{value}", value)
13
13
  end
14
14
 
15
15
  end
@@ -7,7 +7,7 @@ class Quandl::Cassandra::Types::UTF8Type < Quandl::Cassandra::Types::AbstractTyp
7
7
  def self.sanitize(value)
8
8
  RUBY_VERSION >= "1.9" ? value.to_s.dup.force_encoding('UTF-8') : value.to_s.dup
9
9
  rescue => e
10
- raise Quandl::Cassandra::Error::CastException.new("Unable to convert to UTF8", caller)
10
+ raise Quandl::Cassandra::Error::CastException.new("Unable to convert to #{name} #{value}", caller)
11
11
  end
12
12
 
13
13
  end
@@ -4,7 +4,7 @@ module Quandl::Cassandra::Types
4
4
 
5
5
  def self.sanitize(value)
6
6
  value = value.to_s
7
- raise Quandl::Cassandra::Error::CastException, "Unable to convert to UUID", caller unless value =~ regex_validator
7
+ raise Quandl::Cassandra::Error::CastException, "Unable to convert to #{name} #{value}", caller unless value =~ regex_validator
8
8
  value
9
9
  rescue => e
10
10
  raise
@@ -1,5 +1,5 @@
1
1
  module Quandl
2
2
  module Cassandra
3
- VERSION = '0.0.1'
3
+ VERSION = '0.1.0'
4
4
  end
5
5
  end
@@ -22,11 +22,12 @@ class Quandl::Cassandra::Column::Read::Collapse < Quandl::Cassandra::Column::Rea
22
22
  # frequency is the given frequency
23
23
  freq = attributes[:frequency]
24
24
  # grab from database
25
- freq = DatasetAttribute.where(id: id).pluck(:frequency).first if freq.blank? and id.present?
25
+ freq = Quandl::Cassandra::DatasetAttribute.where(id: id).pluck(:frequency).first if freq.blank? and id.present?
26
26
  # fallback to collapse
27
27
  freq = attributes[:collapse] if freq.blank?
28
28
  # if freq is source, daily is being requested
29
29
  freq = :daily if freq == :source
30
+ freq = freq.to_sym
30
31
  freq
31
32
  end
32
33
 
@@ -2,9 +2,10 @@ class Quandl::Cassandra::Column::Read::Column < Quandl::Cassandra::Column::Read
2
2
 
3
3
  def perform
4
4
  # given an id, this is a dataset
5
- attributes[:column_ids] ||= Quandl::Cassandra::Dataset.find(id).column_ids if id.present?
5
+ attributes[:column_ids] ||= Quandl::Cassandra::Dataset.find(id).try(:column_ids) if id.present?
6
+ attributes[:column_ids] = [] if attributes[:column_ids].blank?
6
7
  # given a column, this is requesting a specific column
7
- attributes[:column_ids] = pluck_column_id if column.present?
8
+ attributes[:column_ids] = pluck_column_id if column.present? && attributes[:column_ids].present?
8
9
  end
9
10
 
10
11
  def pluck_column_id
@@ -1,13 +1,15 @@
1
- class Quandl::Cassandra::Column::Read::DataTable < Quandl::Cassandra::Column::Read
1
+ class Quandl::Cassandra::Column::Read::Data < Quandl::Cassandra::Column::Read
2
2
 
3
3
  def perform
4
- attributes[:data] = quandl_data( attributes[:data] )
4
+ attributes[:data] = quandl_data( attributes[:data] ) unless count?
5
5
  end
6
6
 
7
-
8
7
  def quandl_data(data)
9
8
  # init
10
- data = Quandl::Data.new( data )
9
+ data = Quandl::Cassandra::Data.new( data )
10
+ data.dataset_id = attributes[:id]
11
+ data.column_ids = attributes[:column_ids] unless attributes[:column].present?
12
+ data.column_frequencies = attributes[:column_frequencies] unless attributes[:column].present?
11
13
  # post process
12
14
  data = collapse(data)
13
15
  data = transform(data)
@@ -2,6 +2,7 @@ class Quandl::Cassandra::Column::Read::Offset < Quandl::Cassandra::Column::Read
2
2
 
3
3
  def perform
4
4
  # apply offset
5
+ return unless column_ids.present?
5
6
  apply_offset_with_transform
6
7
  apply_offset
7
8
  end
@@ -60,6 +61,9 @@ class Quandl::Cassandra::Column::Read::Offset < Quandl::Cassandra::Column::Read
60
61
  end
61
62
 
62
63
  def accuracy_with_limit
64
+ # # short circuit for now
65
+ # return 0
66
+ # revist this at a later date:
63
67
  awl = accuracy
64
68
  awl = awl + limit - 1 if limit && limit > 0
65
69
  awl
@@ -1,8 +1,20 @@
1
- class Quandl::Cassandra::Column::Read::Query < Quandl::Cassandra::Column::Read
1
+ class Quandl::Cassandra::Column::Read::SelectColumns < Quandl::Cassandra::Column::Read
2
2
 
3
3
  def perform
4
4
  # attrs to result hash
5
- attributes[:data] = select_data
5
+ attributes[:data] = count? ? count_data : select_data
6
+ end
7
+
8
+ def count_data
9
+ prepared = Quandl::Cassandra::Base.prepare( statement )
10
+ rows = []
11
+ attributes[:column_ids].each_with_index do | id, index |
12
+ # pluck column type from collapses
13
+ type = attributes[:column_collapses][index].to_s
14
+ # bind and execute query
15
+ rows << prepared.execute( id, type, :one )
16
+ end
17
+ rows.collect{|r| r.first['count'] }.max
6
18
  end
7
19
 
8
20
  def select_data
@@ -42,14 +54,19 @@ class Quandl::Cassandra::Column::Read::Query < Quandl::Cassandra::Column::Read
42
54
  end
43
55
 
44
56
  def statement
45
- cql = "SELECT time,value FROM columns WHERE"
57
+ columns = count? ? "COUNT(*)" : "time,value"
58
+ cql = "SELECT #{columns} FROM columns WHERE"
46
59
  # cql += "ORDER"
47
60
  cql += " time >= #{attributes[:trim_start]} AND " if attributes[:trim_start]
48
61
  cql += " time <= #{attributes[:trim_end]} AND " if attributes[:trim_end]
49
62
  cql += " id = ? AND type = ?"
50
- cql += " ORDER BY type #{attributes[:order]}" if attributes[:order]
63
+ cql += " ORDER BY type #{order}"
51
64
  cql += " LIMIT #{attributes[:limit]}" if attributes[:limit]
52
65
  cql
53
66
  end
54
67
 
68
+ def order
69
+ @order ||= attributes[:order] == :asc ? :asc : :desc
70
+ end
71
+
55
72
  end
@@ -2,9 +2,9 @@ class Quandl::Cassandra::Column::Read < Quandl::Strategy::Strategize
2
2
 
3
3
  require_relative 'read/collapse'
4
4
  require_relative 'read/column'
5
- require_relative 'read/data_table'
5
+ require_relative 'read/data'
6
6
  require_relative 'read/offset'
7
- require_relative 'read/query'
7
+ require_relative 'read/select_columns'
8
8
  require_relative 'read/row'
9
9
  require_relative 'read/transform'
10
10
  require_relative 'read/type'
@@ -19,10 +19,14 @@ class Quandl::Cassandra::Column::Read < Quandl::Strategy::Strategize
19
19
  c.use Quandl::Cassandra::Column::Read::Collapse
20
20
  c.use Quandl::Cassandra::Column::Read::Transform
21
21
  c.use Quandl::Cassandra::Column::Read::Offset
22
- c.use Quandl::Cassandra::Column::Read::Query
23
- c.use Quandl::Cassandra::Column::Read::DataTable
22
+ c.use Quandl::Cassandra::Column::Read::SelectColumns
23
+ c.use Quandl::Cassandra::Column::Read::Data
24
24
  end
25
25
  strategy.perform
26
26
  end
27
-
27
+
28
+ def count?
29
+ attributes[:count] == true
30
+ end
31
+
28
32
  end
@@ -0,0 +1,22 @@
1
+ class Quandl::Cassandra::Column::Write::InsertColumnAttributes < Quandl::Cassandra::Column::Write
2
+
3
+ # INPUTS
4
+ # { source: { UUID: [[1,2], [2,4]], UUID: [[1,3],[2,8]] }}
5
+
6
+ def perform
7
+ return if column_ids.blank?
8
+ column_ids.each_with_index{|column_id, position|
9
+ Quandl::Cassandra::Base.execute( datasets_statement( column_id, position ) )
10
+ Quandl::Cassandra::Base.execute( column_attributes_statement( column_id ) )
11
+ }
12
+ end
13
+
14
+ def datasets_statement( column_id, position )
15
+ "INSERT INTO datasets (id, column_id, position) VALUES (#{id}, #{column_id}, #{position})"
16
+ end
17
+
18
+ def column_attributes_statement( column_id )
19
+ "INSERT INTO column_attributes ( id, frequency ) VALUES ( #{column_id}, '#{frequency}' )"
20
+ end
21
+
22
+ end
@@ -1,22 +1,39 @@
1
1
  class Quandl::Cassandra::Column::Write::InsertColumns < Quandl::Cassandra::Column::Write
2
2
 
3
- # INPUTS
4
- # { source: { UUID: [[1,2], [2,4]], UUID: [[1,3],[2,8]] }}
5
-
6
3
  def perform
7
- return if column_ids.blank?
8
- column_ids.each_with_index{|column_id, position|
9
- Quandl::Cassandra::Base.execute( datasets_statement( column_id, position ) )
10
- Quandl::Cassandra::Base.execute( column_attributes_statement( column_id ) )
11
- }
4
+ insert_data_in_batches.collect(&:value)
5
+ end
6
+
7
+ def insert_data_in_batches
8
+ futures = []
9
+ statements = []
10
+ frequency_column_data.each do |frequency, column_data|
11
+ column_data.each do |column_id, rows|
12
+ rows.each do |time_value|
13
+ # collect statements
14
+ statements << statement( column_id, frequency, time_value[0], time_value[1] )
15
+ # after 30 statements are collected, execute a batch insert
16
+ if statements.count >= Quandl::Cassandra.configuration.batch_size
17
+ # collect the futures
18
+ futures << execute_async_batch(statements)
19
+ # clear statements
20
+ statements = []
21
+ end
22
+ end
23
+ end
24
+ end
25
+ # execute any remaining statements
26
+ futures << execute_async_batch(statements) if statements.count > 0
27
+ futures
12
28
  end
13
29
 
14
- def datasets_statement( column_id, position )
15
- "INSERT INTO datasets (id, column_id, position) VALUES (#{id}, #{column_id}, #{position})"
30
+ def execute_async_batch(statements)
31
+ batch = %Q{BEGIN UNLOGGED BATCH\n#{statements.join("\n")}\nAPPLY BATCH;}
32
+ future = Quandl::Cassandra::Base.execute_async( batch )
16
33
  end
17
34
 
18
- def column_attributes_statement( column_id )
19
- "INSERT INTO column_attributes ( id, frequency ) VALUES ( #{column_id}, '#{frequency}' )"
35
+ def statement( id, type, time, value )
36
+ "INSERT INTO columns (id, type, time, value) VALUES (#{id}, '#{type}', #{time}, #{value})"
20
37
  end
21
38
 
22
39
  end
@@ -3,8 +3,8 @@ class Quandl::Cassandra::Column::Write < Quandl::Strategy::Strategize
3
3
  # strategy attributes
4
4
  define_attributes :id, :data, :frequency, :column_ids, :frequency_data, :frequency_column_data
5
5
 
6
- require_relative 'write/insert_data'
7
6
  require_relative 'write/insert_columns'
7
+ require_relative 'write/insert_column_attributes'
8
8
  require_relative 'write/group_data_by_column'
9
9
  require_relative 'write/group_data_by_frequency'
10
10
 
@@ -13,8 +13,8 @@ class Quandl::Cassandra::Column::Write < Quandl::Strategy::Strategize
13
13
  strategy = Quandl::Strategy.new( attributes ) do |c|
14
14
  c.use Quandl::Cassandra::Column::Write::GroupDataByFrequency
15
15
  c.use Quandl::Cassandra::Column::Write::GroupDataByColumn
16
- c.use Quandl::Cassandra::Column::Write::InsertData
17
16
  c.use Quandl::Cassandra::Column::Write::InsertColumns
17
+ c.use Quandl::Cassandra::Column::Write::InsertColumnAttributes
18
18
  end
19
19
  strategy.perform
20
20
  end
@@ -0,0 +1,104 @@
1
+ module Quandl::Cassandra::Data::Search
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+
7
+ include ScopeComposer::Model
8
+
9
+ def self.scope_names
10
+ scope.scope_names
11
+ end
12
+
13
+ has_scope_composer
14
+
15
+ delegate :where, to: :scope
16
+
17
+ scope :dataset, ->(d){
18
+ id(d.id)
19
+ column_ids(d.column_ids)
20
+ }
21
+
22
+ scope :row, :id, :limit, :offset, :column, :accuracy, :frequency, :count, :delete
23
+
24
+ scope :column_frequencies, ->(*freqs){ where( column_frequencies: Array(freqs).flatten ) }
25
+ scope :column_ids, ->(*ids){ cids = Array(ids).flatten.compact; where( column_ids: cids ) if cids.present? }
26
+
27
+ scope :collapse, ->(v){ where( collapse: v.to_sym ) if Quandl::Operation::Collapse.valid_collapse?(v) }
28
+ scope :transform, ->(v){ where( transform: v.to_sym ) if Quandl::Operation::Transform.valid_transformation?(v) }
29
+
30
+ scope :order, ->(v){
31
+ order = ( v.to_sym == :asc ) ? :asc : :desc
32
+ where( order: order )
33
+ }
34
+
35
+ scope :trim_start, ->(date){ date = parse_date(date); where( trim_start: date ) if date }
36
+ scope :trim_end, ->(date){ date = parse_date(date); where( trim_end: date ) if date }
37
+
38
+ scope_helper :find, ->(id){ id(id).to_table }
39
+ scope_helper :to_table, ->{ all }
40
+
41
+ scope_helper :parse_date, ->( value ){
42
+ begin
43
+ date = Date.jd(value.to_i) if value.kind_of?(String) && value.numeric?
44
+ date = Date.jd(value) if value.is_a?(Integer)
45
+ date = Date.parse(value) if value.is_a?(String) && value =~ /^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/
46
+ date.jd
47
+ rescue
48
+ nil
49
+ end
50
+ }
51
+
52
+ scope.class_eval do
53
+
54
+ delegate :to_a, :==, :inspect, :first, :flatten, :[], :collect, :<=>, :each, :each_with_index, :to_date, :to_h, to: :all, allow_nil: true
55
+
56
+ def delete_all(*args)
57
+ if attributes[:column_ids].present?
58
+ result = Quandl::Cassandra::Column.where( id: attributes[:column_ids] ).delete_all
59
+ return result.nil? ? true : result
60
+ end
61
+ false
62
+ end
63
+
64
+ def count(*args)
65
+ attributes[:count] = true
66
+ result = dataset? ? fetch.to_i : 0
67
+ attributes[:count] = false
68
+ result
69
+ end
70
+
71
+ def all
72
+ @all ||= fetch
73
+ end
74
+
75
+ def dataset?
76
+ self.id.present? || attributes[:column_ids].present?
77
+ end
78
+
79
+ def fetched?
80
+ @all.present?
81
+ end
82
+
83
+ def scoped
84
+ s = self.class.new
85
+ s.id( self.id ) if id.present?
86
+ s.column_ids( attributes[:column_ids] ) if attributes[:column_ids].present?
87
+ s.column_frequencies(attributes[:column_frequencies]) if attributes[:column_frequencies].present?
88
+ s
89
+ end
90
+
91
+ protected
92
+
93
+ def fetch
94
+ # without an id or columns there's nothing to be read
95
+ return Quandl::Cassandra::Data.new unless dataset?
96
+ # otherwise read the data
97
+ Quandl::Cassandra::Column.read( attributes.merge(scope_attributes) )
98
+ end
99
+
100
+
101
+ end
102
+
103
+ end
104
+ end