activerecord_views 0.0.1 → 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a3d25414ba7a2d31b49f8604f17f5c2d73824135
4
+ data.tar.gz: a68b23bae39199bfa2ae160dfc0bb0e091a2dc88
5
+ SHA512:
6
+ metadata.gz: e41efe797b61dc942ac41b595b39b0d3c651b2e2966132b313b58f0d342f06fbb170239fc7fe079b879a7a60ea60f02688ee861b6d96f620b745fd4e7bdf2efe
7
+ data.tar.gz: 090e0cef956babdaacb0fb71199aff94a5e38f04c8b68f1c8b885c99e18f09d80a31e9c145aa0cf2d0ac66e77fe95fc8d530136d7840f34a104b260721b91784
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  .bundle
2
2
  Gemfile.lock
3
+ gemfiles/*.gemfile.lock
3
4
  pkg
4
5
  spec/internal/log/*.log
data/Appraisals ADDED
@@ -0,0 +1,7 @@
1
+ appraise 'rails3_2' do
2
+ gem 'rails', '~> 3.2.0'
3
+ end
4
+
5
+ appraise 'rails4_0' do
6
+ gem 'rails', '~> 4.0.0'
7
+ end
data/README.markdown CHANGED
@@ -14,7 +14,7 @@ Advantages over creating views manually in migrations include:
14
14
 
15
15
  Add this line to your application's `Gemfile`:
16
16
 
17
- ```
17
+ ```ruby
18
18
  gem 'activerecord_views'
19
19
  ```
20
20
 
@@ -22,7 +22,7 @@ gem 'activerecord_views'
22
22
 
23
23
  app/models/account.rb:
24
24
 
25
- ``` ruby
25
+ ```ruby
26
26
  class Account < ActiveRecord::Base
27
27
  has_many :transactions
28
28
 
@@ -33,7 +33,7 @@ end
33
33
 
34
34
  app/models/transaction.rb:
35
35
 
36
- ``` ruby
36
+ ```ruby
37
37
  class Transaction < ActiveRecord::Base
38
38
  belongs_to :account
39
39
  end
@@ -41,7 +41,7 @@ end
41
41
 
42
42
  app/models/account_balance.rb:
43
43
 
44
- ``` ruby
44
+ ```ruby
45
45
  class AccountBalance < ActiveRecord::Base
46
46
  is_view
47
47
 
@@ -51,7 +51,7 @@ end
51
51
 
52
52
  app/models/account_balance.sql:
53
53
 
54
- ``` sql
54
+ ```sql
55
55
  SELECT accounts.id AS account_id, coalesce(sum(transactions.amount), 0) AS balance
56
56
  FROM accounts
57
57
  LEFT JOIN transactions ON accounts.id = transactions.account_id
@@ -60,7 +60,7 @@ GROUP BY accounts.id
60
60
 
61
61
  Example usage:
62
62
 
63
- ``` ruby
63
+ ```ruby
64
64
  p Account.first.balance
65
65
 
66
66
  Account.includes(:account_balance).find_each do |account|
@@ -70,7 +70,7 @@ end
70
70
 
71
71
  ### Usage outside of Rails
72
72
 
73
- ``` ruby
73
+ ```ruby
74
74
  require 'active_record'
75
75
  require 'active_record_views'
76
76
  ActiveRecordViews.load_path = ['.']
data/Rakefile CHANGED
@@ -1 +1,14 @@
1
+ require 'appraisal'
2
+ require 'bundler/setup'
1
3
  require 'bundler/gem_tasks'
4
+
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default do
9
+ if ENV['BUNDLE_GEMFILE'] == File.expand_path('Gemfile')
10
+ exec 'rake appraisal:all'
11
+ else
12
+ Rake::Task['spec'].invoke
13
+ end
14
+ end
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.add_dependency 'activerecord', ['>= 3.1', '< 4.1']
21
21
 
22
+ gem.add_development_dependency 'appraisal'
22
23
  gem.add_development_dependency 'rspec-rails', '>= 2.14'
23
24
  gem.add_development_dependency 'combustion', '>= 0.5.1'
24
25
  gem.add_development_dependency 'pg'
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 3.2.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 4.0.0"
6
+
7
+ gemspec :path=>"../"
@@ -1,12 +1,5 @@
1
- require 'active_record'
2
-
3
1
  module ActiveRecordViews
4
2
  class ChecksumCache
5
- class Model < ActiveRecord::Base
6
- self.table_name = 'active_record_views'
7
- self.primary_key = 'name'
8
- end
9
-
10
3
  def initialize(connection)
11
4
  @connection = connection
12
5
  init_state_table!
@@ -19,15 +12,16 @@ module ActiveRecordViews
19
12
  end
20
13
 
21
14
  def get(name)
22
- Model.where(:name => name).first_or_initialize.checksum
15
+ @connection.select_value("SELECT checksum FROM active_record_views WHERE name = #{@connection.quote name}")
23
16
  end
24
17
 
25
18
  def set(name, checksum)
26
- row = Model.where(:name => name).first_or_initialize
27
19
  if checksum
28
- row.update_attributes! :checksum => checksum
20
+ if @connection.update("UPDATE active_record_views SET checksum = #{@connection.quote checksum} WHERE name = #{@connection.quote name}") == 0
21
+ @connection.insert "INSERT INTO active_record_views (name, checksum) VALUES (#{@connection.quote name}, #{@connection.quote checksum})"
22
+ end
29
23
  else
30
- row.destroy
24
+ @connection.delete "DELETE FROM active_record_views WHERE name = #{@connection.quote name}"
31
25
  end
32
26
  end
33
27
  end
@@ -3,7 +3,7 @@ module ActiveRecordViews
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  def self.currently_migrating?
6
- if defined? Rake
6
+ if defined?(Rake) && Rake.method_defined?(:application)
7
7
  Rake.application.top_level_tasks.include?('db:migrate')
8
8
  end
9
9
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordViews
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
@@ -25,31 +25,54 @@ module ActiveRecordViews
25
25
  raise "could not find #{name}.sql"
26
26
  end
27
27
 
28
+ def self.without_transaction(connection)
29
+ in_transaction = if connection.respond_to? :transaction_open?
30
+ connection.transaction_open?
31
+ else
32
+ !connection.outside_transaction?
33
+ end
34
+
35
+ if in_transaction
36
+ begin
37
+ temp_connection = connection.pool.checkout
38
+ yield temp_connection
39
+ ensure
40
+ connection.pool.checkin temp_connection
41
+ end
42
+ else
43
+ yield connection
44
+ end
45
+ end
46
+
28
47
  def self.create_view(connection, name, sql)
29
- cache = ActiveRecordViews::ChecksumCache.new(connection)
30
- checksum = Digest::SHA1.hexdigest(sql)
31
- return if cache.get(name) == checksum
48
+ without_transaction connection do |connection|
49
+ cache = ActiveRecordViews::ChecksumCache.new(connection)
50
+ checksum = Digest::SHA1.hexdigest(sql)
51
+ return if cache.get(name) == checksum
32
52
 
33
- begin
34
- connection.execute "CREATE OR REPLACE VIEW #{connection.quote_table_name name} AS #{sql}"
35
- rescue ActiveRecord::StatementInvalid => original_exception
36
53
  begin
37
- connection.transaction :requires_new => true do
38
- connection.execute "DROP VIEW #{connection.quote_table_name name}"
39
- connection.execute "CREATE VIEW #{connection.quote_table_name name} AS #{sql}"
54
+ connection.execute "CREATE OR REPLACE VIEW #{connection.quote_table_name name} AS #{sql}"
55
+ rescue ActiveRecord::StatementInvalid => original_exception
56
+ begin
57
+ connection.transaction :requires_new => true do
58
+ connection.execute "DROP VIEW #{connection.quote_table_name name}"
59
+ connection.execute "CREATE VIEW #{connection.quote_table_name name} AS #{sql}"
60
+ end
61
+ rescue
62
+ raise original_exception
40
63
  end
41
- rescue
42
- raise original_exception
43
64
  end
44
- end
45
65
 
46
- cache.set name, checksum
66
+ cache.set name, checksum
67
+ end
47
68
  end
48
69
 
49
70
  def self.drop_view(connection, name)
50
- cache = ActiveRecordViews::ChecksumCache.new(connection)
51
- connection.execute "DROP VIEW IF EXISTS #{connection.quote_table_name name}"
52
- cache.set name, nil
71
+ without_transaction connection do |connection|
72
+ cache = ActiveRecordViews::ChecksumCache.new(connection)
73
+ connection.execute "DROP VIEW IF EXISTS #{connection.quote_table_name name}"
74
+ cache.set name, nil
75
+ end
53
76
  end
54
77
 
55
78
  def self.register_for_reload(sql_path, model_path)
@@ -12,6 +12,11 @@ describe ActiveRecordViews::Extension do
12
12
  expect(ExternalFileTestModel.first.name).to eq 'External SQL file'
13
13
  end
14
14
 
15
+ it 'creates database views from namespaced external SQL files' do
16
+ expect(ActiveRecordViews).to receive(:create_view).once.and_call_original
17
+ expect(Namespace::TestModel.first.name).to eq 'Namespaced SQL file'
18
+ end
19
+
15
20
  it 'errors if external SQL file is missing' do
16
21
  expect {
17
22
  MissingFileTestModel
@@ -61,7 +66,6 @@ describe ActiveRecordViews::Extension do
61
66
  File.unlink sql_file
62
67
 
63
68
  expect(ActiveRecord::Base.connection).to receive(:execute).with(/\ADROP/).once.and_call_original
64
- expect(ActiveRecord::Base.connection).to receive(:execute).with(/\A(?:RELEASE )?SAVEPOINT/).at_least(1).times.and_call_original
65
69
  test_request
66
70
  test_request # second request does not `drop_view` again
67
71
 
@@ -4,19 +4,13 @@ describe ActiveRecordViews do
4
4
  describe '.create_view' do
5
5
  let(:connection) { ActiveRecord::Base.connection }
6
6
 
7
- self.use_transactional_fixtures = false
8
- after do
9
- connection.execute 'DROP VIEW IF EXISTS test'
10
- connection.execute 'DROP TABLE IF EXISTS active_record_views'
11
- end
12
-
13
7
  def create_test_view(sql)
14
8
  ActiveRecordViews.create_view connection, 'test', sql
15
9
  end
16
10
 
17
11
  def test_view_sql
18
12
  connection.select_value <<-SQL
19
- SELECT view_definition
13
+ SELECT trim(view_definition)
20
14
  FROM information_schema.views
21
15
  WHERE table_name = 'test'
22
16
  SQL
@@ -28,6 +22,15 @@ describe ActiveRecordViews do
28
22
  expect(test_view_sql).to eq 'SELECT 1 AS id;'
29
23
  end
30
24
 
25
+ it 'persists views if transaction rolls back' do
26
+ expect(test_view_sql).to be_nil
27
+ connection.transaction :requires_new => true do
28
+ create_test_view 'select 1 as id'
29
+ raise ActiveRecord::Rollback
30
+ end
31
+ expect(test_view_sql).to eq 'SELECT 1 AS id;'
32
+ end
33
+
31
34
  context 'with existing view' do
32
35
  before do
33
36
  create_test_view 'select 1 as id'
@@ -0,0 +1,3 @@
1
+ class Namespace::TestModel < ActiveRecord::Base
2
+ is_view
3
+ end
@@ -0,0 +1 @@
1
+ SELECT 1 AS id, 'Namespaced SQL file'::text AS name;
@@ -1,3 +1,4 @@
1
1
  test:
2
2
  adapter: postgresql
3
3
  database: activerecord_views_test
4
+ min_messages: warning
data/spec/spec_helper.rb CHANGED
@@ -5,11 +5,28 @@ require 'combustion'
5
5
  require 'active_record_views'
6
6
  Combustion.initialize! :active_record, :action_controller do
7
7
  config.cache_classes = false
8
+ config.active_record.whitelist_attributes = true if Rails::VERSION::MAJOR < 4
8
9
  end
9
10
  require 'rspec/rails'
10
11
 
11
12
  RSpec.configure do |config|
12
- config.use_transactional_fixtures = true
13
+ config.use_transactional_fixtures = false
14
+
15
+ config.before do
16
+ connection = ActiveRecord::Base.connection
17
+
18
+ connection.execute 'DROP TABLE IF EXISTS active_record_views'
19
+
20
+ view_names = connection.select_values <<-SQL
21
+ SELECT table_name
22
+ FROM information_schema.views
23
+ WHERE table_schema = 'public';
24
+ SQL
25
+ view_names.each do |view_name|
26
+ connection.execute "DROP VIEW IF EXISTS #{connection.quote_table_name view_name}"
27
+ end
28
+ end
29
+
13
30
  end
14
31
 
15
32
  def test_request
metadata CHANGED
@@ -1,84 +1,89 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord_views
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- prerelease:
4
+ version: 0.0.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jason Weathered
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-11 00:00:00.000000000 Z
11
+ date: 2014-06-22 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activerecord
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '3.1'
22
- - - <
20
+ - - "<"
23
21
  - !ruby/object:Gem::Version
24
22
  version: '4.1'
25
23
  type: :runtime
26
24
  prerelease: false
27
25
  version_requirements: !ruby/object:Gem::Requirement
28
- none: false
29
26
  requirements:
30
- - - ! '>='
27
+ - - ">="
31
28
  - !ruby/object:Gem::Version
32
29
  version: '3.1'
33
- - - <
30
+ - - "<"
34
31
  - !ruby/object:Gem::Version
35
32
  version: '4.1'
33
+ - !ruby/object:Gem::Dependency
34
+ name: appraisal
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
36
47
  - !ruby/object:Gem::Dependency
37
48
  name: rspec-rails
38
49
  requirement: !ruby/object:Gem::Requirement
39
- none: false
40
50
  requirements:
41
- - - ! '>='
51
+ - - ">="
42
52
  - !ruby/object:Gem::Version
43
53
  version: '2.14'
44
54
  type: :development
45
55
  prerelease: false
46
56
  version_requirements: !ruby/object:Gem::Requirement
47
- none: false
48
57
  requirements:
49
- - - ! '>='
58
+ - - ">="
50
59
  - !ruby/object:Gem::Version
51
60
  version: '2.14'
52
61
  - !ruby/object:Gem::Dependency
53
62
  name: combustion
54
63
  requirement: !ruby/object:Gem::Requirement
55
- none: false
56
64
  requirements:
57
- - - ! '>='
65
+ - - ">="
58
66
  - !ruby/object:Gem::Version
59
67
  version: 0.5.1
60
68
  type: :development
61
69
  prerelease: false
62
70
  version_requirements: !ruby/object:Gem::Requirement
63
- none: false
64
71
  requirements:
65
- - - ! '>='
72
+ - - ">="
66
73
  - !ruby/object:Gem::Version
67
74
  version: 0.5.1
68
75
  - !ruby/object:Gem::Dependency
69
76
  name: pg
70
77
  requirement: !ruby/object:Gem::Requirement
71
- none: false
72
78
  requirements:
73
- - - ! '>='
79
+ - - ">="
74
80
  - !ruby/object:Gem::Version
75
81
  version: '0'
76
82
  type: :development
77
83
  prerelease: false
78
84
  version_requirements: !ruby/object:Gem::Requirement
79
- none: false
80
85
  requirements:
81
- - - ! '>='
86
+ - - ">="
82
87
  - !ruby/object:Gem::Version
83
88
  version: '0'
84
89
  description:
@@ -88,12 +93,15 @@ executables: []
88
93
  extensions: []
89
94
  extra_rdoc_files: []
90
95
  files:
91
- - .gitignore
96
+ - ".gitignore"
97
+ - Appraisals
92
98
  - Gemfile
93
99
  - LICENSE.txt
94
100
  - README.markdown
95
101
  - Rakefile
96
102
  - activerecord_views.gemspec
103
+ - gemfiles/rails3_2.gemfile
104
+ - gemfiles/rails4_0.gemfile
97
105
  - lib/active_record_views.rb
98
106
  - lib/active_record_views/checksum_cache.rb
99
107
  - lib/active_record_views/extension.rb
@@ -107,39 +115,34 @@ files:
107
115
  - spec/internal/app/models/external_file_test_model.sql
108
116
  - spec/internal/app/models/heredoc_test_model.rb
109
117
  - spec/internal/app/models/missing_file_test_model.rb
118
+ - spec/internal/app/models/namespace/test_model.rb
119
+ - spec/internal/app/models/namespace/test_model.sql
110
120
  - spec/internal/config/database.yml
111
121
  - spec/internal/db/schema.rb
112
122
  - spec/spec_helper.rb
113
123
  homepage: http://github.com/jasoncodes/activerecord_views
114
124
  licenses:
115
125
  - MIT
126
+ metadata: {}
116
127
  post_install_message:
117
128
  rdoc_options: []
118
129
  require_paths:
119
130
  - lib
120
131
  required_ruby_version: !ruby/object:Gem::Requirement
121
- none: false
122
132
  requirements:
123
- - - ! '>='
133
+ - - ">="
124
134
  - !ruby/object:Gem::Version
125
135
  version: '0'
126
- segments:
127
- - 0
128
- hash: -3691843505786316541
129
136
  required_rubygems_version: !ruby/object:Gem::Requirement
130
- none: false
131
137
  requirements:
132
- - - ! '>='
138
+ - - ">="
133
139
  - !ruby/object:Gem::Version
134
140
  version: '0'
135
- segments:
136
- - 0
137
- hash: -3691843505786316541
138
141
  requirements: []
139
142
  rubyforge_project:
140
- rubygems_version: 1.8.24
143
+ rubygems_version: 2.2.2
141
144
  signing_key:
142
- specification_version: 3
145
+ specification_version: 4
143
146
  summary: Automatic database view creation for ActiveRecord
144
147
  test_files:
145
148
  - spec/active_record_views_extension_spec.rb
@@ -148,6 +151,8 @@ test_files:
148
151
  - spec/internal/app/models/external_file_test_model.sql
149
152
  - spec/internal/app/models/heredoc_test_model.rb
150
153
  - spec/internal/app/models/missing_file_test_model.rb
154
+ - spec/internal/app/models/namespace/test_model.rb
155
+ - spec/internal/app/models/namespace/test_model.sql
151
156
  - spec/internal/config/database.yml
152
157
  - spec/internal/db/schema.rb
153
158
  - spec/spec_helper.rb