active_data_frame 0.1.1 → 0.1.2

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