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.
- data/lib/quandl/cassandra/base/attributes.rb +4 -4
- data/lib/quandl/cassandra/base/persistence.rb +24 -1
- data/lib/quandl/cassandra/base/sanitization.rb +4 -1
- data/lib/quandl/cassandra/base/schema.rb +8 -0
- data/lib/quandl/cassandra/base/scoping.rb +47 -3
- data/lib/quandl/cassandra/types/boolean_type.rb +1 -1
- data/lib/quandl/cassandra/types/decimal_type.rb +1 -1
- data/lib/quandl/cassandra/types/double_type.rb +1 -1
- data/lib/quandl/cassandra/types/float_type.rb +1 -1
- data/lib/quandl/cassandra/types/integer_type.rb +1 -1
- data/lib/quandl/cassandra/types/long_type.rb +1 -1
- data/lib/quandl/cassandra/types/timestamp_type.rb +1 -1
- data/lib/quandl/cassandra/types/utf8_type.rb +1 -1
- data/lib/quandl/cassandra/types/uuid_type.rb +1 -1
- data/lib/quandl/cassandra/version.rb +1 -1
- data/lib/quandl/cassandra_models/column/read/collapse.rb +2 -1
- data/lib/quandl/cassandra_models/column/read/column.rb +3 -2
- data/lib/quandl/cassandra_models/column/read/{data_table.rb → data.rb} +6 -4
- data/lib/quandl/cassandra_models/column/read/offset.rb +4 -0
- data/lib/quandl/cassandra_models/column/read/{query.rb → select_columns.rb} +21 -4
- data/lib/quandl/cassandra_models/column/read.rb +9 -5
- data/lib/quandl/cassandra_models/column/write/insert_column_attributes.rb +22 -0
- data/lib/quandl/cassandra_models/column/write/insert_columns.rb +29 -12
- data/lib/quandl/cassandra_models/column/write.rb +2 -2
- data/lib/quandl/cassandra_models/data/search.rb +104 -0
- data/lib/quandl/cassandra_models/data.rb +12 -46
- data/lib/quandl/cassandra_models/dataset.rb +17 -8
- data/lib/quandl/cassandra_models/multiset.rb +3 -3
- data/quandl_cassandra.gemspec +1 -1
- data/spec/lib/quandl/cassandra/base/sanitization_spec.rb +7 -0
- data/spec/lib/quandl/cassandra/base/scoping_spec.rb +11 -0
- data/spec/lib/quandl/cassandra_models/column_spec.rb +1 -1
- data/spec/lib/quandl/cassandra_models/data_spec.rb +51 -1
- data/spec/lib/quandl/cassandra_models/dataset/collapse_spec.rb +3 -0
- data/spec/lib/quandl/cassandra_models/dataset/column_spec.rb +3 -4
- data/spec/lib/quandl/cassandra_models/dataset/persistence_spec.rb +2 -2
- data/spec/lib/quandl/cassandra_models/dataset/row_spec.rb +8 -8
- data/spec/lib/quandl/cassandra_models/dataset/trim_spec.rb +6 -6
- data/spec/lib/quandl/cassandra_models/dataset/update_spec.rb +4 -4
- data/spec/lib/quandl/cassandra_models/dataset_spec.rb +42 -3
- data/spec/lib/quandl/cassandra_models/multiset/transform_spec.rb +2 -1
- metadata +10 -7
- 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
|
-
|
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)
|
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, :
|
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
|
-
[
|
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{|
|
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 #{
|
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 #{
|
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 #{
|
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.
|
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.
|
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.
|
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
|
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
|
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
|
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
|
@@ -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::
|
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::
|
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
|
-
|
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 #{
|
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/
|
5
|
+
require_relative 'read/data'
|
6
6
|
require_relative 'read/offset'
|
7
|
-
require_relative 'read/
|
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::
|
23
|
-
c.use Quandl::Cassandra::Column::Read::
|
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
15
|
-
|
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
|
19
|
-
"INSERT INTO
|
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
|