updateable_views_inheritance 1.2.1 → 1.2.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.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 1.2.2 (18 August 2015)
2
+
3
+ Bugfixes:
4
+
5
+ - fixed compatibility with Rails 3.2.19+ and ActiveRecord's prepared statements
6
+
1
7
  ## 1.2.1 (27 August 2014)
2
8
 
3
9
  Bugfixes:
data/Gemfile CHANGED
@@ -3,4 +3,9 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in updateable_views_inheritance.gemspec
4
4
  gemspec
5
5
 
6
- gem 'debugger'
6
+ if RUBY_VERSION > "2"
7
+ gem 'byebug'
8
+ else
9
+ gem 'debugger'
10
+ end
11
+
data/README.rdoc CHANGED
@@ -25,11 +25,6 @@ Run
25
25
 
26
26
  * In <tt>Gemfile</tt> add <tt>gem 'updateable_views_inheritance'</tt>
27
27
  * Run <tt>rails generate updateable_views_inheritance:install && rake db:migrate</tt>
28
- * In <tt>config/database.yml</tt> аdd to every environment
29
-
30
- prepared_statements: false
31
-
32
- ActiveRecord's postgresql adapter has subtle problems with prepared statements that cause strange errors every now and then.
33
28
  * In <tt>config/environment.rb</tt> set <tt>config.active_record.schema_format = :sql</tt>
34
29
  * In case you're using fixtures, don't forget to run
35
30
 
@@ -118,4 +113,9 @@ may fail when there are foreign key constraints on tables. To fix this, explicit
118
113
 
119
114
  fixtures :roots, :trunks, :leafs, ...
120
115
 
121
- for all fixtures you want to load.
116
+ for all fixtures you want to load.
117
+
118
+ ==Gem Development & Testing
119
+
120
+ The gem has a comprehensive test suite. In order to run it, your user must be a superuser in PostgreSQL.
121
+ If this is not the case, run <tt>createuser -s pesho</tt> (assuming your Unix account is <tt>pesho</tt>).
data/Rakefile CHANGED
@@ -24,12 +24,12 @@ end
24
24
  namespace :test do
25
25
  desc 'Build the test database'
26
26
  task :create_database do
27
- %x( createdb -U postgres updateable_views_inheritance_test )
27
+ %x( createdb updateable_views_inheritance_test )
28
28
  end
29
29
 
30
30
  desc 'Drop the test database'
31
- task :drop_database do
32
- %x( dropdb -U postgres updateable_views_inheritance_test )
31
+ task :drop_database do
32
+ %x( dropdb updateable_views_inheritance_test )
33
33
  end
34
34
 
35
35
  desc 'Rebuild the test database'
@@ -111,7 +111,7 @@ module ActiveRecord #:nodoc:
111
111
  parent = parent_table(relation)
112
112
  pk_and_sequence_for(parent) if parent
113
113
  else
114
- # log(result[0], "PK for #{relation}")
114
+ # log(result[0], "PK for #{relation}") {}
115
115
  [result[0], query("SELECT pg_get_serial_sequence('#{relation}', '#{result[0]}') ")[0][0]]
116
116
  end
117
117
  rescue
@@ -295,14 +295,13 @@ module ActiveRecord #:nodoc:
295
295
  execute <<-end_sql
296
296
  CREATE OR REPLACE RULE #{quote_column_name("#{child_view}_insert")} AS
297
297
  ON INSERT TO #{child_view} DO INSTEAD (
298
- SELECT setval('#{parent_pk_seq}', NEW.#{parent_pk});
299
298
  INSERT INTO #{parent_table}
300
299
  ( #{ [parent_pk, parent_columns].flatten.join(", ") } )
301
- VALUES( currval('#{parent_pk_seq}') #{ parent_columns.empty? ? '' : ',' + parent_columns.collect{ |col| "NEW." + col}.join(",") } )
302
- #{insert_returning_clause(child_view, parent_columns.unshift(parent_pk)) if supports_insert_with_returning?};
300
+ VALUES( DEFAULT #{ parent_columns.empty? ? '' : ' ,' + parent_columns.collect{ |col| "NEW." + col}.join(", ") } ) ;
303
301
  INSERT INTO #{child_table}
304
302
  ( #{ [child_pk, child_columns].flatten.join(",")} )
305
- VALUES( currval('#{parent_pk_seq}') #{ child_columns.empty? ? '' : ',' + child_columns.collect{ |col| "NEW." + col}.join(",") } )
303
+ VALUES( currval('#{parent_pk_seq}') #{ child_columns.empty? ? '' : ' ,' + child_columns.collect{ |col| "NEW." + col}.join(", ") } )
304
+ #{insert_returning_clause(parent_pk, child_pk, child_view) if supports_insert_with_returning?}
306
305
  )
307
306
  end_sql
308
307
 
@@ -330,15 +329,12 @@ module ActiveRecord #:nodoc:
330
329
  end_sql
331
330
  end
332
331
 
333
- def insert_returning_clause(child_view,parent_columns)
334
- "RETURNING "+
335
- columns(child_view).map do |c|
336
- if parent_columns.include?(c.name)
337
- c.name
338
- else
339
- "CAST (NULL AS #{c.sql_type})"
340
- end
341
- end.join(",")
332
+ def insert_returning_clause(parent_pk, child_pk, child_view)
333
+ columns_cast_to_null = columns(child_view)
334
+ .reject { |c| c.name == parent_pk}
335
+ .map { |c| "CAST (NULL AS #{c.sql_type})" }
336
+ .join(", ")
337
+ "RETURNING #{child_pk}, #{columns_cast_to_null}"
342
338
  end
343
339
 
344
340
  # Set default values from the table columns for a view
@@ -1,3 +1,3 @@
1
1
  module UpdateableViewsInheritance
2
- VERSION = "1.2.1"
2
+ VERSION = "1.2.2"
3
3
  end
data/test/content_test.rb CHANGED
@@ -3,9 +3,6 @@ require File.join(File.dirname(__FILE__), 'test_helper')
3
3
  class UpdateableViewsInheritanceContentTest < ActiveSupport::TestCase
4
4
  def setup
5
5
  ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 5)
6
- # order of fixtures is important for the test - last loaded should not be with max(id)
7
- ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :electric_locomotives)
8
- ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :steam_locomotives)
9
6
  end
10
7
 
11
8
  def teardown
@@ -13,6 +10,7 @@ class UpdateableViewsInheritanceContentTest < ActiveSupport::TestCase
13
10
  end
14
11
 
15
12
  def test_find
13
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :steam_locomotives)
16
14
  locomotive = Locomotive.find(1)
17
15
  assert locomotive.kind_of?(SteamLocomotive)
18
16
  assert_equal %w(coal_consumption id max_speed name type water_consumption),
@@ -20,8 +18,31 @@ class UpdateableViewsInheritanceContentTest < ActiveSupport::TestCase
20
18
  end
21
19
 
22
20
  def test_exec_query
23
- res = ActiveRecord::Base.connection.exec_query(%q{INSERT INTO electric_locomotives (electricity_consumption, max_speed, name, type) VALUES (40, 120, 'test', 'ElectricLocomotive') RETURNING id})
24
- assert !res.rows.empty?
21
+ # order of fixtures is important for the test - last loaded should not be with max(id)
22
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :electric_locomotives)
23
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :steam_locomotives)
24
+
25
+ res = ActiveRecord::Base.connection.exec_query(<<-SQL)
26
+ INSERT INTO electric_locomotives (electricity_consumption, max_speed, name, type)
27
+ VALUES (40, 120, 'BoBo', 'ElectricLocomotive') RETURNING id
28
+ SQL
29
+ assert !res.rows.empty?, 'No id returned on INSERT in database view'
30
+ assert_equal 3, res.rows.first.first.to_i
31
+ end
32
+
33
+ def test_exec_query_with_prepared_statement
34
+ # order of fixtures is important for the test - last loaded should not be with max(id)
35
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :electric_locomotives)
36
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :steam_locomotives)
37
+
38
+ binds = [[ElectricLocomotive.columns.find { |c| c.name == 'electricity_consumption'}, 40],
39
+ [ElectricLocomotive.columns.find { |c| c.name == 'max_speed'}, 120],
40
+ [ElectricLocomotive.columns.find { |c| c.name == 'name'}, 'BoBo'],
41
+ [ElectricLocomotive.columns.find { |c| c.name == 'type'}, 'ElectricLocomotive']]
42
+ res = ActiveRecord::Base.connection.exec_query(<<-SQL, 'Test prepared statement', binds)
43
+ INSERT INTO electric_locomotives (electricity_consumption, max_speed, name, type) VALUES ($1, $2, $3, $4) RETURNING id
44
+ SQL
45
+ assert !res.rows.empty?, 'Empty result on INSERT in database view through a prepared statement'
25
46
  assert_equal 3, res.rows.first.first.to_i
26
47
  end
27
48
 
@@ -32,6 +53,9 @@ class UpdateableViewsInheritanceContentTest < ActiveSupport::TestCase
32
53
  end
33
54
 
34
55
  def test_reset_sequence_after_loading_fixture
56
+ # order of fixtures is important for the test - last loaded should not be with max(id)
57
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :electric_locomotives)
58
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :steam_locomotives)
35
59
  steam_locomotive = SteamLocomotive.new(:name => 'Mogul', :max_speed => 120, :water_consumption => 12.3, :coal_consumption => 54.6)
36
60
  assert steam_locomotive.save
37
61
  mogul = Locomotive.find(steam_locomotive.id)
@@ -39,6 +63,7 @@ class UpdateableViewsInheritanceContentTest < ActiveSupport::TestCase
39
63
  end
40
64
 
41
65
  def test_update
66
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :steam_locomotives)
42
67
  steam_locomotive = Locomotive.find(1)
43
68
  steam_locomotive.update_attributes( :name => 'Rocket')
44
69
  steam_locomotive.reload
@@ -46,6 +71,7 @@ class UpdateableViewsInheritanceContentTest < ActiveSupport::TestCase
46
71
  end
47
72
 
48
73
  def test_delete_from_parent_relation
74
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :steam_locomotives)
49
75
  num_locomotives = Locomotive.count
50
76
  num_steam_locomotives = SteamLocomotive.count
51
77
  Locomotive.find(1).destroy
@@ -54,13 +80,11 @@ class UpdateableViewsInheritanceContentTest < ActiveSupport::TestCase
54
80
  end
55
81
 
56
82
  def test_delete_from_child_relation
83
+ ActiveRecord::Fixtures.create_fixtures(File.dirname(__FILE__) + '/fixtures/', :steam_locomotives)
57
84
  num_locomotives = Locomotive.count
58
85
  num_steam_locomotives = SteamLocomotive.count
59
86
  SteamLocomotive.find(1).destroy
60
87
  assert_equal num_locomotives - 1, Locomotive.count
61
88
  assert_equal num_steam_locomotives - 1, SteamLocomotive.count
62
89
  end
63
-
64
-
65
-
66
90
  end
@@ -1,7 +1,4 @@
1
1
  test:
2
2
  adapter: postgresql
3
- username: postgres
4
- password: postgres
5
3
  database: updateable_views_inheritance_test
6
4
  min_messages: ERROR
7
- prepared_statements: false
@@ -0,0 +1,58 @@
1
+ gem "pg", "0.18.2"
2
+
3
+ require "pg"
4
+ require "rspec"
5
+
6
+ describe "Insert returning on view with rules and default value" do
7
+ before(:each) do
8
+ @conn = PG.connect(dbname: 'updateable_views_inheritance_test')
9
+ @conn.exec(%q{ SET client_min_messages TO 'ERROR' })
10
+
11
+ @conn.exec(%q{ CREATE TABLE parent ( id SERIAL PRIMARY KEY,
12
+ name TEXT) })
13
+ @conn.exec(%q{ CREATE TABLE child ( parent_id INTEGER PRIMARY KEY REFERENCES parent(id),
14
+ surname TEXT) })
15
+
16
+ @conn.exec(%q{ CREATE VIEW v AS (SELECT id, name, surname FROM parent JOIN child ON parent.id=child.parent_id) })
17
+ @conn.exec(%q{ ALTER VIEW v ALTER id SET DEFAULT nextval('parent_id_seq'::regclass) })
18
+ #
19
+ # The old way that didn't return anything when binds are empty
20
+ #
21
+ # @conn.exec(%q{ CREATE RULE v_on_insert AS ON INSERT TO v DO INSTEAD
22
+ # (
23
+ # SELECT setval('parent_id_seq', NEW.id);
24
+ # INSERT INTO parent (id, name)
25
+ # VALUES( currval('parent_id_seq'), NEW.name ) RETURNING id, name, NULL::text;
26
+ # INSERT INTO child (parent_id, surname)
27
+ # VALUES( currval('parent_id_seq'), NEW.surname );
28
+ #
29
+ # )
30
+ # })
31
+ @conn.exec(%q{ CREATE RULE v_on_insert AS ON INSERT TO v DO INSTEAD
32
+ (
33
+ INSERT INTO parent (id, name)
34
+ VALUES( DEFAULT, NEW.name );
35
+ INSERT INTO child (parent_id, surname)
36
+ VALUES( currval('parent_id_seq'), NEW.surname ) RETURNING parent_id, NULL::text, NULL::te;
37
+ )
38
+ })
39
+
40
+ @sql = %q{ INSERT INTO v (name, surname) VALUES ('parent', 'child') RETURNING id}
41
+ end
42
+
43
+ after(:each) do
44
+ @conn.exec(%q{ DROP VIEW IF EXISTS v })
45
+ @conn.exec(%q{ DROP TABLE IF EXISTS parent CASCADE})
46
+ @conn.exec(%q{ DROP TABLE IF EXISTS child CASCADE})
47
+ end
48
+
49
+ it 'async exec with empty binds' do
50
+ res = @conn.async_exec(@sql, [])
51
+ expect(res.values).to eq([["1"]])
52
+ end
53
+
54
+ it 'async exec with no binds' do
55
+ res = @conn.async_exec(@sql)
56
+ expect(res.values).to eq([["1"]])
57
+ end
58
+ end
data/test/test_helper.rb CHANGED
@@ -6,7 +6,11 @@ require 'rails/test_help'
6
6
  require 'updateable_views_inheritance'
7
7
 
8
8
  begin
9
- require 'ruby-debug'
9
+ if RUBY_VERSION > "2"
10
+ require 'byebug'
11
+ else
12
+ require 'debugger'
13
+ end
10
14
  rescue LoadError
11
15
  # no debugger available
12
16
  end
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: updateable_views_inheritance
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.2
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Sava Chankov
@@ -9,11 +10,12 @@ authors:
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2014-08-27 00:00:00.000000000 Z
13
+ date: 2015-08-18 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: activerecord
16
17
  requirement: !ruby/object:Gem::Requirement
18
+ none: false
17
19
  requirements:
18
20
  - - ~>
19
21
  - !ruby/object:Gem::Version
@@ -21,6 +23,7 @@ dependencies:
21
23
  type: :runtime
22
24
  prerelease: false
23
25
  version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
24
27
  requirements:
25
28
  - - ~>
26
29
  - !ruby/object:Gem::Version
@@ -28,6 +31,7 @@ dependencies:
28
31
  - !ruby/object:Gem::Dependency
29
32
  name: pg
30
33
  requirement: !ruby/object:Gem::Requirement
34
+ none: false
31
35
  requirements:
32
36
  - - ! '>='
33
37
  - !ruby/object:Gem::Version
@@ -35,6 +39,7 @@ dependencies:
35
39
  type: :runtime
36
40
  prerelease: false
37
41
  version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
38
43
  requirements:
39
44
  - - ! '>='
40
45
  - !ruby/object:Gem::Version
@@ -42,6 +47,7 @@ dependencies:
42
47
  - !ruby/object:Gem::Dependency
43
48
  name: rails
44
49
  requirement: !ruby/object:Gem::Requirement
50
+ none: false
45
51
  requirements:
46
52
  - - ~>
47
53
  - !ruby/object:Gem::Version
@@ -49,6 +55,7 @@ dependencies:
49
55
  type: :development
50
56
  prerelease: false
51
57
  version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
52
59
  requirements:
53
60
  - - ~>
54
61
  - !ruby/object:Gem::Version
@@ -56,6 +63,7 @@ dependencies:
56
63
  - !ruby/object:Gem::Dependency
57
64
  name: bundler
58
65
  requirement: !ruby/object:Gem::Requirement
66
+ none: false
59
67
  requirements:
60
68
  - - ~>
61
69
  - !ruby/object:Gem::Version
@@ -63,6 +71,7 @@ dependencies:
63
71
  type: :development
64
72
  prerelease: false
65
73
  version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
66
75
  requirements:
67
76
  - - ~>
68
77
  - !ruby/object:Gem::Version
@@ -70,6 +79,7 @@ dependencies:
70
79
  - !ruby/object:Gem::Dependency
71
80
  name: rake
72
81
  requirement: !ruby/object:Gem::Requirement
82
+ none: false
73
83
  requirements:
74
84
  - - ! '>='
75
85
  - !ruby/object:Gem::Version
@@ -77,6 +87,7 @@ dependencies:
77
87
  type: :development
78
88
  prerelease: false
79
89
  version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
80
91
  requirements:
81
92
  - - ! '>='
82
93
  - !ruby/object:Gem::Version
@@ -104,10 +115,6 @@ files:
104
115
  - lib/updateable_views_inheritance/postgresql_adapter.rb
105
116
  - lib/updateable_views_inheritance/version.rb
106
117
  - tasks/updateable_views_inheritance_tasks.rake
107
- - test/config/database.yml
108
- - test/config/environment.rb
109
- - test/config/routes.rb
110
- - test/config/schema.rb
111
118
  - test/content_test.rb
112
119
  - test/deep_hierarchy_test.rb
113
120
  - test/dummy/Rakefile
@@ -176,6 +183,7 @@ files:
176
183
  - test/fixtures/steam_trains.yml
177
184
  - test/install_generator_test.rb
178
185
  - test/migration_test.rb
186
+ - test/pg_insert_returning_with_rules_spec.rb
179
187
  - test/schema_test.rb
180
188
  - test/single_table_inheritance.rb
181
189
  - test/test_helper.rb
@@ -183,32 +191,29 @@ files:
183
191
  homepage: http://github.com/tutuf/updateable_views_inheritance
184
192
  licenses:
185
193
  - MIT
186
- metadata: {}
187
194
  post_install_message:
188
195
  rdoc_options: []
189
196
  require_paths:
190
197
  - lib
191
198
  required_ruby_version: !ruby/object:Gem::Requirement
199
+ none: false
192
200
  requirements:
193
201
  - - ! '>='
194
202
  - !ruby/object:Gem::Version
195
203
  version: '0'
196
204
  required_rubygems_version: !ruby/object:Gem::Requirement
205
+ none: false
197
206
  requirements:
198
207
  - - ! '>='
199
208
  - !ruby/object:Gem::Version
200
209
  version: '0'
201
210
  requirements: []
202
211
  rubyforge_project:
203
- rubygems_version: 2.4.1
212
+ rubygems_version: 1.8.23
204
213
  signing_key:
205
- specification_version: 4
214
+ specification_version: 3
206
215
  summary: Class table inheritance for ActiveRecord
207
216
  test_files:
208
- - test/config/database.yml
209
- - test/config/environment.rb
210
- - test/config/routes.rb
211
- - test/config/schema.rb
212
217
  - test/content_test.rb
213
218
  - test/deep_hierarchy_test.rb
214
219
  - test/dummy/Rakefile
@@ -277,6 +282,7 @@ test_files:
277
282
  - test/fixtures/steam_trains.yml
278
283
  - test/install_generator_test.rb
279
284
  - test/migration_test.rb
285
+ - test/pg_insert_returning_with_rules_spec.rb
280
286
  - test/schema_test.rb
281
287
  - test/single_table_inheritance.rb
282
288
  - test/test_helper.rb
checksums.yaml DELETED
@@ -1,15 +0,0 @@
1
- ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MDFhNTFiOTNiNDBhYjg4MzY5NTBmMWQ1MjYyMWU1MGQyMTE0OTJmYw==
5
- data.tar.gz: !binary |-
6
- Y2I1NDc5YTAwNzVlMTdkODNjNjYwMmFlMjAxZDQ5MDk2ZDI4MWJkNg==
7
- SHA512:
8
- metadata.gz: !binary |-
9
- YzMxMjM3Y2I5MGJmMzBiN2ZjNGNiMzllOGYwMjA2ZDg0MjFlM2YxYmEzMzc5
10
- OTU5M2Y5ZmUxMDJhOTUxN2NjNTlhZWNjNjU4NWUzOGM0YzgxMDg5NDRjN2Zj
11
- OGJjNjYzMzlmOTVlYjlmMTMwOTRiOTZmMTJkZmY1OWViODAzZTQ=
12
- data.tar.gz: !binary |-
13
- YmU5NzU4ODA5YjNiYmU3NjE1MzdjODc1NTllM2IyMDk5NDFhNDVlM2EwNDQz
14
- ZTdmZGUzMDkxZGU1OTEwNWFiMGNjOTE1NGM1NDcwNGIyOTJlNGRjZGZkMzg4
15
- ZmY1Njk1YmM4MDg1ODRiODNjOTY4NmJjZWZhMjVkMDdjODJiNGQ=
@@ -1,19 +0,0 @@
1
- test:
2
- adapter: sqlite3
3
- dbfile: test.sqlite3.db
4
-
5
- # adapter: sqlite
6
- # dbfile: test.sqlite.db
7
-
8
- # adapter: mysql
9
- # host: localhost
10
- # username:
11
- # password:
12
- # database: test
13
-
14
- # adapter: postgresql
15
- # host: localhost
16
- # username:
17
- # password:
18
- # database: test
19
-
@@ -1,14 +0,0 @@
1
-
2
- Rails::Initializer.run do |config|
3
-
4
- config.cache_classes = true
5
-
6
- config.whiny_nils = true
7
-
8
- config.action_controller.consider_all_requests_local = true
9
- config.action_controller.perform_caching = false
10
-
11
- config.action_mailer.delivery_method = :test
12
- config.action_mailer.perform_deliveries = true
13
-
14
- end
@@ -1,3 +0,0 @@
1
- ActionController::Routing::Routes.draw do |map|
2
-
3
- end
@@ -1,3 +0,0 @@
1
- ActiveRecord::Schema.define(:version => 2) do
2
-
3
- end