active_data_frame 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ module ActiveDataFrame
2
+ class Point < Struct.new(:index, :offset, :position)
3
+ end
4
+ end
@@ -3,8 +3,8 @@ module ActiveDataFrame
3
3
 
4
4
  attr_accessor :instance
5
5
 
6
- def initialize(block_type, data_frame_type, instance)
7
- super(block_type, data_frame_type)
6
+ def initialize(block_type, data_frame_type, instance, value_map: nil, singular_df_name: '', plural_df_name: '')
7
+ super(block_type, data_frame_type, value_map: value_map, singular_df_name: singular_df_name, plural_df_name: plural_df_name)
8
8
  self.instance = instance
9
9
  end
10
10
 
@@ -16,25 +16,30 @@ module ActiveDataFrame
16
16
  to = (from + values.length) - 1
17
17
  bounds = get_bounds(from, to)
18
18
 
19
- self.class.suppress_logs do
20
- new_blocks = Hash.new do |h, k|
21
- h[k] = [[0] * block_type::BLOCK_SIZE]
22
- end
19
+ new_blocks = Hash.new do |h, k|
20
+ h[k] = [[0] * block_type::BLOCK_SIZE]
21
+ end
23
22
 
24
- existing = blocks_between([bounds]).pluck(:id, :period_index, *block_type::COLUMNS).map do |id, period_index, *block_values|
25
- [period_index, [block_values, id]]
26
- end.to_h
23
+ deleted_indices = []
27
24
 
28
- iterate_bounds([bounds]) do |index, left, right, cursor, size|
29
- chunk = values[cursor...cursor + size]
25
+ existing = blocks_between([bounds]).pluck(:data_frame_id, :period_index, *block_type::COLUMNS).map do |id, period_index, *block_values|
26
+ [period_index, [block_values, id]]
27
+ end.to_h
28
+
29
+ iterate_bounds([bounds]) do |index, left, right, cursor, size|
30
+ chunk = values[cursor...cursor + size]
31
+ if size == block_type::BLOCK_SIZE && chunk.all?(&:zero?)
32
+ deleted_indices << index
33
+ else
30
34
  block = existing[index] || new_blocks[index]
31
35
  block.first[left..right] = chunk.to_a
32
36
  end
33
-
34
- bulk_update(existing) unless existing.size.zero?
35
- bulk_insert(new_blocks) unless new_blocks.size.zero?
36
- values
37
37
  end
38
+
39
+ database.bulk_delete(self.id, deleted_indices) unless deleted_indices.size.zero?
40
+ database.bulk_update(existing) unless existing.size.zero?
41
+ database.bulk_insert(new_blocks, instance) unless new_blocks.size.zero?
42
+ values
38
43
  end
39
44
 
40
45
  def get(ranges)
@@ -60,9 +65,9 @@ module ActiveDataFrame
60
65
  [range.first, range.size, last_total]
61
66
  end
62
67
  index_of = ->(column){
63
- selected = range_sizes.find{|start, size, total| start <= column && start + size >= column}
68
+ selected = range_sizes.find{|start, size| start <= column && start + size >= column}
64
69
  if selected
65
- start, size, total = selected
70
+ start, _, total = selected
66
71
  (column - start) + total
67
72
  else
68
73
  nil
@@ -76,57 +81,6 @@ module ActiveDataFrame
76
81
  end
77
82
 
78
83
  private
79
- ##
80
- # Update block data for all blocks in a single call
81
- ##
82
- def bulk_update(existing)
83
- case ActiveRecord::Base.connection_config[:adapter]
84
- when 'postgresql'
85
- # Fast bulk update
86
- updates = ''
87
- existing.each do |period_index, (values, id)|
88
- updates << "(#{id}, #{values.map{|v| v.inspect.gsub('"',"'") }.join(',')}),"
89
- end
90
- perform_update(updates)
91
- else
92
- ids = existing.map {|_, (_, id)| id}
93
- updates = block_type::COLUMNS.map.with_index do |column, column_idx|
94
- [column, "CASE period_index\n#{existing.map{|period_index, (values, id)| "WHEN #{period_index} then #{values[column_idx]}"}.join("\n")} \nEND\n"]
95
- end.to_h
96
- update_statement = updates.map{|cl, up| "#{cl} = #{up}" }.join(', ')
97
- block_type.connection.execute("UPDATE #{block_type.table_name} SET #{update_statement} WHERE #{block_type.table_name}.id IN (#{ids.join(',')});")
98
- end
99
- end
100
-
101
- ##
102
- # Insert block data for all blocks in a single call
103
- ##
104
- def bulk_insert(new_blocks)
105
- inserts = ''
106
- new_blocks.each do |period_index, (values)|
107
- inserts << \
108
- case ActiveRecord::Base.connection_config[:adapter]
109
- when 'postgresql', 'mysql2' then "(#{values.map{|v| v.inspect.gsub('"',"'") }.join(',')}, #{instance.id}, #{period_index}, '#{data_frame_type.name}', now(), now()),"
110
- else "(#{values.map{|v| v.inspect.gsub('"',"'") }.join(',')}, #{instance.id}, #{period_index}, '#{data_frame_type.name}', datetime(), datetime()),"
111
- end
112
- end
113
- perform_insert(inserts)
114
- end
115
-
116
- def perform_update(updates)
117
- block_type.transaction do
118
- block_type.connection.execute(
119
- "UPDATE #{block_type.table_name} SET #{block_type::COLUMNS.map{|col| "#{col} = t.#{col}" }.join(", ")} FROM(VALUES #{updates[0..-2]}) as t(id, #{block_type::COLUMNS.join(',')}) WHERE #{block_type.table_name}.id = t.id"
120
- )
121
- end
122
- true
123
- end
124
-
125
- def perform_insert(inserts)
126
- sql = "INSERT INTO #{block_type.table_name} (#{block_type::COLUMNS.join(',')}, data_frame_id, period_index, data_frame_type, created_at, updated_at) VALUES #{inserts[0..-2]}"
127
- block_type.connection.execute sql
128
- end
129
-
130
84
  def scope
131
85
  @scope ||= block_type.where(data_frame_type: data_frame_type.name, data_frame_id: instance.id)
132
86
  end
@@ -2,8 +2,10 @@ module ActiveDataFrame
2
2
  class Table < DataFrameProxy
3
3
 
4
4
  def set(from, values)
5
- data_frame_type.find_each do |instance|
6
- Row.new(self.block_type, self.data_frame_type, instance).set(from, values)
5
+ ActiveDataFrame::Database.batch do
6
+ data_frame_type.each do |instance|
7
+ Row.new(self.block_type, self.data_frame_type, instance).set(from, values)
8
+ end
7
9
  end
8
10
  end
9
11
 
@@ -35,7 +37,7 @@ module ActiveDataFrame
35
37
  map
36
38
  end
37
39
 
38
- def column_cases(cases, agg=nil)
40
+ def column_cases(cases, aggregation_function=nil)
39
41
  block_type::COLUMNS.map do |col|
40
42
  col_cases = cases[col].sort_by(&:begin).reduce([]) do |agg, col_case|
41
43
  if agg.empty?
@@ -51,9 +53,9 @@ module ActiveDataFrame
51
53
  end
52
54
  end
53
55
 
54
- if agg
56
+ if aggregation_function
55
57
  case col_cases.length
56
- when 0 then "NULL as #{col}"
58
+ when 0 then "NULL::float as #{col}"
57
59
  else
58
60
  case_str = col_cases.map do |match|
59
61
  case
@@ -61,7 +63,7 @@ module ActiveDataFrame
61
63
  else "period_index BETWEEN #{match.begin} AND #{match.end}"
62
64
  end
63
65
  end.join(" OR ")
64
- "CASE WHEN #{case_str} THEN #{agg}(#{col}) ELSE NULL END"
66
+ "CASE WHEN #{case_str} THEN #{aggregation_function}(#{col}) ELSE NULL END"
65
67
  end
66
68
  else
67
69
  case col_cases.length
@@ -92,7 +94,6 @@ module ActiveDataFrame
92
94
  index_map = {}
93
95
  res = ActiveRecord::Base.transaction do
94
96
  ids = data_frame_type.pluck(:id)
95
-
96
97
  as_sql = blocks_between(
97
98
  all_bounds,
98
99
  block_scope: data_frame_type.unscoped
@@ -130,9 +131,9 @@ module ActiveDataFrame
130
131
  [range.first, range.size, last_total]
131
132
  end
132
133
  index_of = ->(column){
133
- selected = range_sizes.find{|start, size, total| start <= column && start + size >= column}
134
+ selected = range_sizes.find{|start, size| start <= column && start + size >= column}
134
135
  if selected
135
- start, size, total = selected
136
+ start, _, total = selected
136
137
  (column - start) + total
137
138
  else
138
139
  nil
@@ -156,11 +157,11 @@ module ActiveDataFrame
156
157
  end
157
158
 
158
159
  def idx_where_sum_gte(*ranges, max)
159
- select_agg_indices(extract_ranges(ranges), 'SUM', ->(x, y){ x <= y } , 'SUM(%) > :max', max: max)
160
+ select_agg_indices(extract_ranges(ranges), 'SUM', ->(x, y){ x <= y } , 'SUM(%) >= :max', max: max)
160
161
  end
161
162
 
162
163
  def idx_where_sum_lte(*ranges, min)
163
- select_agg_indices(extract_ranges(ranges), 'SUM', ->(x, y){ x >= y } , 'SUM(%) < :min', min: min)
164
+ select_agg_indices(extract_ranges(ranges), 'SUM', ->(x, y){ x >= y } , 'SUM(%) <= :min', min: min)
164
165
  end
165
166
 
166
167
  def AggregateProxy(agg)
@@ -234,9 +235,7 @@ module ActiveDataFrame
234
235
  end
235
236
 
236
237
  case_map = build_case_map(all_bounds)
237
- existing = blocks_between(all_bounds)
238
- .group(:period_index)
239
- .pluck(:period_index, *column_cases(case_map, agg))
238
+ existing = blocks_between(all_bounds).group(:period_index).pluck(:period_index, *column_cases(case_map, agg))
240
239
  .map{|pi, *values| [pi, values]}.to_h
241
240
  result = M.blank(columns: all_bounds.map(&:length).sum, typecode: block_type::TYPECODE)
242
241
 
@@ -1,3 +1,3 @@
1
1
  module ActiveDataFrame
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -4,7 +4,7 @@ module ActiveDataFrame
4
4
  class InstallGenerator < ActiveRecord::Generators::Base
5
5
  desc "Generates a new data_frame type"
6
6
 
7
- STREAM_TYPES = %w(bit byte int long float double)
7
+ STREAM_TYPES = %w(bit byte integer long float double)
8
8
  # Commandline options can be defined here using Thor-like options:
9
9
  argument :type, :type => :string, :default => 'float', :desc => "DataFrame type. One of(#{STREAM_TYPES*" ,"})"
10
10
  argument :columns, :type => :numeric, :default => 512, :desc => "Number of columns"
@@ -46,12 +46,20 @@ module ActiveDataFrame
46
46
  end
47
47
  end
48
48
 
49
+ def get_typecode
50
+ case type
51
+ when "float", "double" then M::Typecode::FLOAT
52
+ when "integer", "long" then M::Typecode::INT
53
+ when "bit", "byte" then M::Typecode::BYTE
54
+ end
55
+ end
56
+
49
57
  def inject_data_frame_helpers
50
58
  content = \
51
59
  <<RUBY
52
60
  BLOCK_SIZE = #{columns}
53
61
  COLUMNS = %w(#{columns.times.map{|i| "t#{i+1}" }.join(" ")})
54
- TYPECODE = M::Typecode::FLOAT
62
+ TYPECODE = #{get_typecode}
55
63
  self.table_name = '#{block_table_name}'
56
64
  RUBY
57
65
  class_name = "Blocks::#{singular_block_table_name.camelize}"
@@ -76,9 +84,9 @@ RUBY
76
84
 
77
85
  def migration_data
78
86
  <<RUBY
79
- t.integer :data_frame_id, index: true
80
- t.string :data_frame_type, index: true
81
- t.integer :period_index, index: true
87
+ t.integer :data_frame_id
88
+ t.string :data_frame_type
89
+ t.integer :period_index
82
90
  #{
83
91
  columns.times.map do |i|
84
92
  " t.#{type} :t#{i+1}"
@@ -1,6 +1,3 @@
1
- require 'active_support/concern'
2
-
3
1
  module <%= concern_name %>
4
- extend ActiveSupport::Concern
5
- include ActiveDataFrame::HasDataFrame('<%= singular_table_name %>', '<%= table_name %>',Blocks::<%= block_type %>)
2
+ include ActiveDataFrame::HasDataFrame('<%= singular_table_name %>', Blocks::<%= block_type %>)
6
3
  end
@@ -2,10 +2,8 @@ class ActiveDataFrameCreate<%= table_name.camelize %> < ActiveRecord::Migration<
2
2
  def change
3
3
  create_table :<%= block_table_name %> do |t|
4
4
  <%= migration_data -%>
5
- t.timestamps null: false
6
5
  end
7
6
 
8
-
9
- add_index :<%= block_table_name %>, [:data_frame_type, :data_frame_id , :period_index], :unique => true, name: 'index_<%= block_table_name %>_on_type_id_and_index'
7
+ add_index :<%= block_table_name %>, [:data_frame_id , :period_index, :data_frame_type], :unique => true, name: 'index_<%= block_table_name %>_id_index_and_type'
10
8
  end
11
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_data_frame
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter Coppieters
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-01 00:00:00.000000000 Z
11
+ date: 2018-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -78,20 +78,82 @@ dependencies:
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
80
  version: 0.10.0
81
+ - !ruby/object:Gem::Dependency
82
+ name: pg
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: minitest
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '5.11'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '5.11'
109
+ - !ruby/object:Gem::Dependency
110
+ name: minitest-reporters
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '1.1'
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: 1.1.0
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '1.1'
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: 1.1.0
129
+ - !ruby/object:Gem::Dependency
130
+ name: minitest-around
131
+ requirement: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - '='
134
+ - !ruby/object:Gem::Version
135
+ version: 0.4.1
136
+ type: :development
137
+ prerelease: false
138
+ version_requirements: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - '='
141
+ - !ruby/object:Gem::Version
142
+ version: 0.4.1
81
143
  - !ruby/object:Gem::Dependency
82
144
  name: activerecord
83
145
  requirement: !ruby/object:Gem::Requirement
84
146
  requirements:
85
147
  - - "~>"
86
148
  - !ruby/object:Gem::Version
87
- version: 5.0.0
149
+ version: '5.0'
88
150
  type: :runtime
89
151
  prerelease: false
90
152
  version_requirements: !ruby/object:Gem::Requirement
91
153
  requirements:
92
154
  - - "~>"
93
155
  - !ruby/object:Gem::Version
94
- version: 5.0.0
156
+ version: '5.0'
95
157
  - !ruby/object:Gem::Dependency
96
158
  name: rmatrix
97
159
  requirement: !ruby/object:Gem::Requirement
@@ -124,13 +186,19 @@ files:
124
186
  - Gemfile
125
187
  - README.md
126
188
  - Rakefile
189
+ - active_data_frame-0.1.1.gem
127
190
  - active_data_frame.gemspec
128
191
  - active_data_frame.todo
129
192
  - bin/console
130
193
  - bin/setup
194
+ - examples.rb
131
195
  - lib/active_data_frame.rb
196
+ - lib/active_data_frame/bounds.rb
132
197
  - lib/active_data_frame/data_frame_proxy.rb
198
+ - lib/active_data_frame/database.rb
199
+ - lib/active_data_frame/group_proxy.rb
133
200
  - lib/active_data_frame/has_data_frame.rb
201
+ - lib/active_data_frame/point.rb
134
202
  - lib/active_data_frame/row.rb
135
203
  - lib/active_data_frame/table.rb
136
204
  - lib/active_data_frame/version.rb