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.
- 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
|