quandl_cassandra 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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