chrono_model 0.11.1 → 0.12.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d582aa6350f8fac1d88f06a216447a309215479b
4
- data.tar.gz: aaabf96f89bb5aad1af0e6f2425978ac484b855d
3
+ metadata.gz: 514bcdaa49d7f8ca35bb422ea3fb47b5f11bfbd4
4
+ data.tar.gz: af83cb212905b691d0c0ab43e9bf38306a089819
5
5
  SHA512:
6
- metadata.gz: 0c5b541b0e8dfed9958e4ecab0b49adafeee077f7e8aca27f3d85e356cfa282f8247d890e0b06751d18da1d83c02570ff1dc6492e7fe404dd49d3c35d7a3eb74
7
- data.tar.gz: df5f7d097d783efe86bc8b05d4d9736a81cab3222fd1f291e7e7f3101224b9f2a4d47c6b5789f222b7bbfbd97929ac6b386b7b33a9f17227c6d425ff2de9735c
6
+ metadata.gz: 96b7a8b00ca96174c66499824b801f9ec50f4644ee0a65adc37fc8a3e0fc57188172cb0e72563800c94b0e82c860af6d1137eb24948f169ce99191f476f5257b
7
+ data.tar.gz: 1078c39fdab5c0af049df0eddbe7832055e72b872cec07d87d43d205ac1ccca44a3c8c8cb5cf5f9876f9a025a20109060b36541ef5354ed0410961c583ba586e
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ .byebug_history
6
7
  Gemfile.lock
7
8
  InstalledFiles
8
9
  _yardoc
data/.travis.yml CHANGED
@@ -27,6 +27,7 @@ addons:
27
27
 
28
28
  before_script:
29
29
  - psql -c "CREATE DATABASE chronomodel;" -U postgres
30
+ - psql -c "CREATE DATABASE chronomodel_railsapp;" -U postgres
30
31
 
31
32
  script:
32
33
  - bundle exec rake TEST_CONFIG=./spec/config.travis.yml
data/Rakefile CHANGED
@@ -4,4 +4,20 @@ require "bundler/gem_tasks"
4
4
  # RSpec
5
5
  require 'rspec/core/rake_task'
6
6
  RSpec::Core::RakeTask.new
7
- task :default => :spec
7
+ task :default => ['testapp:create', :spec]
8
+
9
+ # Create a test Rails app in tmp/railsapp for testing the rake
10
+ # tasks and overall Rails integration with Aruba.
11
+ #
12
+ namespace :testapp do
13
+ desc 'Create a dummy rails application for testing in /tmp'
14
+ task :create do
15
+ FileUtils.mkdir_p('tmp/aruba')
16
+ Dir.chdir('tmp') do
17
+ FileUtils.rm_rf('railsapp')
18
+ sh 'rails new railsapp --skip-bundle'
19
+ end
20
+ FileUtils.cp_r('spec/aruba/fixtures/railsapp/.', 'tmp/railsapp/')
21
+ FileUtils.rm('tmp/railsapp/Gemfile')
22
+ end
23
+ end
data/chrono_model.gemspec CHANGED
@@ -19,6 +19,8 @@ Gem::Specification.new do |gem|
19
19
  gem.add_dependency "pg"
20
20
  gem.add_dependency "multi_json"
21
21
 
22
+ gem.add_development_dependency 'rails'
23
+ gem.add_development_dependency 'aruba'
22
24
  gem.add_development_dependency 'pry'
23
25
  gem.add_development_dependency 'hirb'
24
26
  gem.add_development_dependency 'byebug'
@@ -1,5 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "activerecord", "~> 4.2.0"
4
+ gem "rails", "~> 4.2.0"
4
5
 
5
6
  gemspec :path => "../"
@@ -1,5 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "activerecord", "~> 5.0.0"
4
+ gem "rails", "~> 5.0.0"
4
5
 
5
6
  gemspec :path => "../"
@@ -1,5 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "activerecord", "~> 5.1.0"
4
+ gem "rails", "~> 5.1.0"
4
5
 
5
6
  gemspec :path => "../"
@@ -0,0 +1,86 @@
1
+ module ActiveRecord
2
+ module Tasks
3
+ class ChronomodelDatabaseTasks < PostgreSQLDatabaseTasks
4
+
5
+ def structure_dump(*arguments)
6
+
7
+ with_chronomodel_schema_search_path do
8
+ super(*arguments)
9
+ end
10
+
11
+ # The structure.sql includes CREATE SCHEMA statements, but as these are executed
12
+ # when the connection to the database is established, a db:structure:load fails.
13
+ #
14
+ # This code adds the IF NOT EXISTS clause to CREATE SCHEMA statements as long as
15
+ # it is not already present.
16
+ #
17
+ filename = arguments.first
18
+ sql = File.read(filename).gsub(/CREATE SCHEMA (?!IF NOT EXISTS)/, '\&IF NOT EXISTS ')
19
+ File.open(filename, 'w') { |file| file << sql }
20
+
21
+ remove_sql_header_comments(filename)
22
+ end
23
+
24
+ def data_dump(target)
25
+ set_psql_env
26
+
27
+ args = ['-c', '-f', target]
28
+ args << configuration['database']
29
+
30
+ run_cmd "pg_dump", args, 'dumping data'
31
+ end
32
+
33
+ def data_load(source)
34
+ set_psql_env
35
+
36
+ args = ['-f', source]
37
+ args << configuration['database']
38
+
39
+ run_cmd "psql", args, 'loading data'
40
+ end
41
+
42
+ private
43
+
44
+ # If a schema search path is defined in the configuration file, it will
45
+ # be used by the database tasks class to dump only the specified search
46
+ # path. Here we add also ChronoModel's temporal and history schemas to
47
+ # the search path and yield.
48
+ #
49
+ def with_chronomodel_schema_search_path
50
+ original_schema_search_path = configuration['schema_search_path']
51
+
52
+ if original_schema_search_path.present?
53
+ configuration['schema_search_path'] = original_schema_search_path.split(',').concat([
54
+ ChronoModel::Adapter::TEMPORAL_SCHEMA,
55
+ ChronoModel::Adapter::HISTORY_SCHEMA
56
+ ]).join(',')
57
+ end
58
+
59
+ yield
60
+
61
+ ensure
62
+ configuration['schema_search_path'] = original_schema_search_path
63
+ end
64
+
65
+ unless method_defined? :remove_sql_header_comments
66
+ def remove_sql_header_comments(filename)
67
+ sql_comment_begin = '--'
68
+ removing_comments = true
69
+ tempfile = Tempfile.open("uncommented_structure.sql")
70
+ begin
71
+ File.foreach(filename) do |line|
72
+ unless removing_comments && (line.start_with?(sql_comment_begin) || line.blank?)
73
+ tempfile << line
74
+ removing_comments = false
75
+ end
76
+ end
77
+ ensure
78
+ tempfile.close
79
+ end
80
+ FileUtils.mv(tempfile.path, filename)
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -1,9 +1,45 @@
1
+ require 'active_record/tasks/chronomodel_database_tasks'
2
+
1
3
  module ChronoModel
2
4
  class Railtie < ::Rails::Railtie
3
- ActiveRecord::Tasks::DatabaseTasks.register_task /chronomodel/, ActiveRecord::Tasks::PostgreSQLDatabaseTasks
4
5
 
5
6
  rake_tasks do
6
- load 'chrono_model/schema_format.rake'
7
+ if Rails.application.config.active_record.schema_format != :sql
8
+ raise 'In order to use ChronoModel, config.active_record.schema_format must be :sql!'
9
+ end
10
+
11
+ tasks_class = ActiveRecord::Tasks::ChronomodelDatabaseTasks
12
+
13
+ # Register our database tasks under our adapter name
14
+ #
15
+ ActiveRecord::Tasks::DatabaseTasks.register_task(/chronomodel/, tasks_class)
16
+
17
+ # Make schema:dump and schema:load invoke structure:dump and structure:load
18
+ Rake::Task['db:schema:dump'].clear.enhance(['environment']) do
19
+ Rake::Task['db:structure:dump'].invoke
20
+ end
21
+
22
+ Rake::Task['db:schema:load'].clear.enhance(['environment']) do
23
+ Rake::Task['db:structure:load'].invoke
24
+ end
25
+
26
+ desc "Dumps database into db/data.NOW.sql or file specified via DUMP="
27
+ task 'db:data:dump' => :environment do
28
+ config = ActiveRecord::Tasks::DatabaseTasks.current_config
29
+ target = ENV['DUMP'] || Rails.root.join('db', "data.#{Time.now.to_f}.sql")
30
+
31
+ tasks_class.new(config).data_dump(target)
32
+ end
33
+
34
+ desc "Loads database dump from file specified via DUMP="
35
+ task 'db:data:load' => :environment do
36
+ config = ActiveRecord::Tasks::DatabaseTasks.current_config
37
+ source = ENV['DUMP'].presence or
38
+ raise ArgumentError, "Invoke as rake db:data:load DUMP=/path/to/data.sql"
39
+
40
+ tasks_class.new(config).data_load(source)
41
+ end
7
42
  end
43
+
8
44
  end
9
45
  end
@@ -1,3 +1,3 @@
1
1
  module ChronoModel
2
- VERSION = "0.11.1"
2
+ VERSION = "0.12.0"
3
3
  end
@@ -0,0 +1,14 @@
1
+ default: &default
2
+ username: postgres
3
+ password: ""
4
+ adapter: chronomodel
5
+ encoding: unicode
6
+ pool: 20
7
+ database: chronomodel_railsapp
8
+
9
+ development:
10
+ <<: *default
11
+
12
+ test:
13
+ <<: *default
14
+
@@ -0,0 +1,11 @@
1
+ default: &default
2
+ adapter: chronomodel
3
+ encoding: unicode
4
+ pool: 20
5
+ database: chronomodel_railsapp
6
+
7
+ development:
8
+ <<: *default
9
+
10
+ test:
11
+ <<: *default
@@ -0,0 +1,27 @@
1
+ SET statement_timeout = 0;
2
+ SET lock_timeout = 0;
3
+ SET client_encoding = 'UTF8';
4
+ SET standard_conforming_strings = on;
5
+ SET check_function_bodies = false;
6
+ SET client_min_messages = warning;
7
+
8
+ --
9
+ -- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
10
+ --
11
+
12
+ CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
13
+
14
+
15
+ --
16
+ -- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: -
17
+ --
18
+
19
+ COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
20
+
21
+
22
+ --
23
+ -- PostgreSQL database dump complete
24
+ --
25
+
26
+ SET search_path TO "$user", public;
27
+
@@ -0,0 +1,17 @@
1
+ require_relative 'boot'
2
+
3
+ require 'rails/all'
4
+
5
+ # Require the gems listed in Gemfile, including any gems
6
+ # you've limited to :test, :development, or :production.
7
+ Bundler.require(*Rails.groups)
8
+
9
+ module Railsapp
10
+ class Application < Rails::Application
11
+ # Initialize configuration defaults for originally generated Rails version.
12
+ config.active_record.schema_format = :sql
13
+ # Settings in config/environments/* take precedence over those specified here.
14
+ # Application configuration should go into files in config/initializers
15
+ # -- all .rb files in that directory are automatically loaded.
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
@@ -0,0 +1,54 @@
1
+ Rails.application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
+
4
+ # In the development environment your application's code is reloaded on
5
+ # every request. This slows down response time but is perfect for development
6
+ # since you don't have to restart the web server when you make code changes.
7
+ config.cache_classes = false
8
+
9
+ # Do not eager load code on boot.
10
+ config.eager_load = false
11
+
12
+ # Show full error reports.
13
+ config.consider_all_requests_local = true
14
+
15
+ # Enable/disable caching. By default caching is disabled.
16
+ if Rails.root.join('tmp/caching-dev.txt').exist?
17
+ config.action_controller.perform_caching = true
18
+
19
+ config.cache_store = :memory_store
20
+ config.public_file_server.headers = {
21
+ 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}"
22
+ }
23
+ else
24
+ config.action_controller.perform_caching = false
25
+
26
+ config.cache_store = :null_store
27
+ end
28
+
29
+ # Don't care if the mailer can't send.
30
+ config.action_mailer.raise_delivery_errors = false
31
+
32
+ config.action_mailer.perform_caching = false
33
+
34
+ # Print deprecation notices to the Rails logger.
35
+ config.active_support.deprecation = :log
36
+
37
+ # Raise an error on page load if there are pending migrations.
38
+ config.active_record.migration_error = :page_load
39
+
40
+ # Debug mode disables concatenation and preprocessing of assets.
41
+ # This option may cause significant delays in view rendering with a large
42
+ # number of complex assets.
43
+ config.assets.debug = true
44
+
45
+ # Suppress logger output for asset requests.
46
+ config.assets.quiet = true
47
+
48
+ # Raises error for missing translations
49
+ # config.action_view.raise_on_missing_translations = true
50
+
51
+ # Use an evented file watcher to asynchronously detect changes in source code,
52
+ # routes, locales, etc. This feature depends on the listen gem.
53
+ # config.file_watcher = ActiveSupport::EventedFileUpdateChecker
54
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'database migrations' do
4
+ context 'after a migration was generated' do
5
+ before { write_file('config/database.yml',
6
+ File.read(File.expand_path('fixtures/database_without_username_and_password.yml', __dir__))) }
7
+
8
+ before { run_simple('bundle exec rails g migration CreateModels name:string') }
9
+
10
+ describe 'bundle exec rake db:migrate', type: :aruba do
11
+ let(:action) { run('bundle exec rake db:migrate') }
12
+ let(:last_command) { action && last_command_started }
13
+
14
+ specify { expect(last_command).to be_successfully_executed }
15
+ specify { expect(last_command).to have_output(/CreateModels: migrated/) }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ # add :announce_stdout, :announce_stderr, before the type: aruba tag in order
4
+ # to see the commmands' stdout and stderr output.
5
+ #
6
+ describe 'rake tasks', type: :aruba do
7
+ describe 'bundle exec rake -T' do
8
+ before { run_simple('bundle exec rake -T') }
9
+ subject { last_command_started }
10
+
11
+ it { is_expected.to have_output(/db:structure:load/) }
12
+ end
13
+
14
+ describe 'db:structure:load' do
15
+ let(:action) { run('bundle exec rake db:structure:load') }
16
+ let(:last_command) { action && last_command_started }
17
+
18
+ context 'given a file db/structure.sql' do
19
+ let(:structure_sql) { 'fixtures/empty_structure.sql' }
20
+ before { write_file('db/structure.sql', File.read(File.expand_path(structure_sql, __dir__))) }
21
+ before { write_file('config/database.yml', File.read(File.expand_path(database_yml, __dir__))) }
22
+
23
+ subject { expect(last_command).to be_successfully_executed }
24
+
25
+ context 'with default username and password', issue: 55 do
26
+ let(:database_yml) { 'fixtures/database_with_default_username_and_password.yml' }
27
+
28
+ # Handle Homebrew on MacOS, whose database superuser name is
29
+ # equal to the name of the current user.
30
+ #
31
+ before do
32
+ if which 'brew'
33
+ database_config = read('config/database.yml').join("\n").
34
+ sub('username: postgres', "username: #{Etc.getlogin}")
35
+
36
+ write_file 'config/database.yml', database_config
37
+ end
38
+ end
39
+
40
+ specify { subject }
41
+ end
42
+
43
+ context 'without a specified username and password', issue: 55 do
44
+ let(:database_yml) { 'fixtures/database_without_username_and_password.yml' }
45
+
46
+ specify { subject }
47
+ end
48
+ end
49
+ end
50
+
51
+ describe 'db:data:dump' do
52
+ let(:database_yml) { 'fixtures/database_without_username_and_password.yml' }
53
+ before { write_file('config/database.yml', File.read(File.expand_path(database_yml, __dir__))) }
54
+
55
+ before { run_simple('bundle exec rake db:data:dump DUMP=db/test.sql') }
56
+
57
+ it { expect(last_command_started).to be_successfully_executed }
58
+ it { expect('db/test.sql').to be_an_existing_file }
59
+ end
60
+
61
+ describe 'db:data:load' do
62
+ let(:database_yml) { 'fixtures/database_without_username_and_password.yml' }
63
+ before { write_file('config/database.yml', File.read(File.expand_path(database_yml, __dir__))) }
64
+
65
+ let(:structure_sql) { 'fixtures/empty_structure.sql' }
66
+ before { write_file('db/test.sql', File.read(File.expand_path(structure_sql, __dir__))) }
67
+
68
+ before { run_simple('bundle exec rake db:data:load DUMP=db/test.sql') }
69
+
70
+ it { expect(last_command_started).to be_successfully_executed }
71
+ end
72
+ end
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,7 @@ require 'support/matchers/schema'
10
10
  require 'support/matchers/table'
11
11
  require 'support/matchers/column'
12
12
  require 'support/matchers/index'
13
+ require 'support/aruba'
13
14
 
14
15
  # Rails 5 returns a True/FalseClass
15
16
  AR_TRUE, AR_FALSE = ActiveRecord::VERSION::MAJOR == 4 ? ['t', 'f'] : [true, false]
@@ -19,6 +20,12 @@ RSpec.configure do |config|
19
20
  config.include(ChronoTest::Matchers::Table)
20
21
  config.include(ChronoTest::Matchers::Column)
21
22
  config.include(ChronoTest::Matchers::Index)
23
+ config.include(ChronoTest::Aruba, type: :aruba)
22
24
 
23
25
  ChronoTest.recreate_database!
26
+
27
+ config.before(:example, type: :aruba) do
28
+ copy_dummy_app_into_aruba_working_directory
29
+ recreate_railsapp_database
30
+ end
24
31
  end
@@ -0,0 +1,33 @@
1
+ require 'aruba/rspec'
2
+ require 'arel'
3
+
4
+ module ChronoTest
5
+
6
+ module Aruba
7
+ def aruba_working_directory
8
+ File.expand_path("../../#{::Aruba.config.working_directory}", __dir__)
9
+ end
10
+
11
+ def dummy_app_directory
12
+ File.expand_path("../../tmp/railsapp/", __dir__)
13
+ end
14
+
15
+ def copy_dummy_app_into_aruba_working_directory
16
+ unless File.file?(Pathname.new(dummy_app_directory).join('Rakefile'))
17
+ raise %q(
18
+ The dummy application does not exist
19
+ Run `bundle exec rake testapp:create`
20
+ )
21
+ end
22
+ FileUtils.rm_rf(Dir.glob("#{aruba_working_directory}/*"))
23
+ FileUtils.cp_r(Dir.glob("#{dummy_app_directory}/*"), aruba_working_directory)
24
+ end
25
+
26
+ def recreate_railsapp_database
27
+ connection = AR.connection # we're still the 'chronomodel' user
28
+ database = 'chronomodel_railsapp'
29
+ connection.drop_database database
30
+ connection.create_database database
31
+ end
32
+ end
33
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chrono_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcello Barnaba
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-09-11 00:00:00.000000000 Z
12
+ date: 2017-11-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -59,6 +59,34 @@ dependencies:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rails
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: aruba
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
62
90
  - !ruby/object:Gem::Dependency
63
91
  name: pry
64
92
  requirement: !ruby/object:Gem::Requirement
@@ -193,21 +221,29 @@ files:
193
221
  - gemfiles/rails_5.0.gemfile
194
222
  - gemfiles/rails_5.1.gemfile
195
223
  - lib/active_record/connection_adapters/chronomodel_adapter.rb
224
+ - lib/active_record/tasks/chronomodel_database_tasks.rb
196
225
  - lib/chrono_model.rb
197
226
  - lib/chrono_model/adapter.rb
198
227
  - lib/chrono_model/patches.rb
199
228
  - lib/chrono_model/railtie.rb
200
- - lib/chrono_model/schema_format.rake
201
- - lib/chrono_model/schema_format.rb
202
229
  - lib/chrono_model/time_gate.rb
203
230
  - lib/chrono_model/time_machine.rb
204
231
  - lib/chrono_model/utils.rb
205
232
  - lib/chrono_model/version.rb
206
233
  - spec/adapter_spec.rb
234
+ - spec/aruba/fixtures/database_with_default_username_and_password.yml
235
+ - spec/aruba/fixtures/database_without_username_and_password.yml
236
+ - spec/aruba/fixtures/empty_structure.sql
237
+ - spec/aruba/fixtures/railsapp/config/application.rb
238
+ - spec/aruba/fixtures/railsapp/config/boot.rb
239
+ - spec/aruba/fixtures/railsapp/config/environments/development.rb
240
+ - spec/aruba/migrations_spec.rb
241
+ - spec/aruba/rake_task_spec.rb
207
242
  - spec/config.travis.yml
208
243
  - spec/config.yml.example
209
244
  - spec/json_ops_spec.rb
210
245
  - spec/spec_helper.rb
246
+ - spec/support/aruba.rb
211
247
  - spec/support/connection.rb
212
248
  - spec/support/helpers.rb
213
249
  - spec/support/matchers/base.rb
@@ -239,16 +275,25 @@ required_rubygems_version: !ruby/object:Gem::Requirement
239
275
  version: '0'
240
276
  requirements: []
241
277
  rubyforge_project:
242
- rubygems_version: 2.4.5.1
278
+ rubygems_version: 2.5.2.1
243
279
  signing_key:
244
280
  specification_version: 4
245
281
  summary: Temporal extensions (SCD Type II) for Active Record
246
282
  test_files:
247
283
  - spec/adapter_spec.rb
284
+ - spec/aruba/fixtures/database_with_default_username_and_password.yml
285
+ - spec/aruba/fixtures/database_without_username_and_password.yml
286
+ - spec/aruba/fixtures/empty_structure.sql
287
+ - spec/aruba/fixtures/railsapp/config/application.rb
288
+ - spec/aruba/fixtures/railsapp/config/boot.rb
289
+ - spec/aruba/fixtures/railsapp/config/environments/development.rb
290
+ - spec/aruba/migrations_spec.rb
291
+ - spec/aruba/rake_task_spec.rb
248
292
  - spec/config.travis.yml
249
293
  - spec/config.yml.example
250
294
  - spec/json_ops_spec.rb
251
295
  - spec/spec_helper.rb
296
+ - spec/support/aruba.rb
252
297
  - spec/support/connection.rb
253
298
  - spec/support/helpers.rb
254
299
  - spec/support/matchers/base.rb
@@ -1,67 +0,0 @@
1
- load File.expand_path(File.dirname(__FILE__) + '/schema_format.rb')
2
-
3
- namespace :db do
4
- namespace :structure do
5
- desc "desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql"
6
- task :dump => :environment do
7
- config = PG.config!
8
- target = ENV['DB_STRUCTURE'] || Rails.root.join('db', 'structure.sql')
9
- schema = config[:schema_search_path]
10
-
11
- if schema.present?
12
- # If a schema search path is configured, add also the ChronoModel schemas to the dump.
13
- #
14
- schema = schema.split /\s*,\s*/
15
- schema = schema.concat [ ChronoModel::Adapter::TEMPORAL_SCHEMA, ChronoModel::Adapter::HISTORY_SCHEMA ]
16
- schema = schema.map {|name| "--schema=#{name}" }
17
- else
18
- schema = [ ]
19
- end
20
-
21
- PG.make_dump target,
22
- *config.values_at(:username, :database),
23
- '-x', '-s', '-O', *schema
24
-
25
- # Add migration information, after resetting the schema to the default one
26
- File.open(target, 'a') do |f|
27
- f.puts "SET search_path TO #{ActiveRecord::Base.connection.schema_search_path};\n\n"
28
- f.puts ActiveRecord::Base.connection.dump_schema_information
29
- end
30
-
31
- # The structure.sql includes CREATE SCHEMA statements, but as these are executed
32
- # when the connection to the database is established, a db:structure:load fails.
33
- # This code adds the IF NOT EXISTS clause to CREATE SCHEMA statements as long as
34
- # it is not already present.
35
- #
36
- sql = File.read(target)
37
- sql.gsub!(/CREATE SCHEMA (?!IF NOT EXISTS)/, '\&IF NOT EXISTS ')
38
- File.open(target, "w") { |file| file << sql }
39
- end
40
-
41
- desc "Load structure.sql file into the current environment's database"
42
- task :load => :environment do
43
- # Loads the db/structure.sql file into current environment's database.
44
- #
45
- source = ENV['DB_STRUCTURE'] || Rails.root.join('db', 'structure.sql')
46
-
47
- PG.load_dump source, *PG.config!.values_at(:username, :database, :template)
48
- end
49
- end
50
-
51
- namespace :data do
52
- desc "Save a dump of the database in ENV['DUMP'] or db/data.NOW.sql"
53
- task :dump => :environment do
54
- target = ENV['DUMP'] || Rails.root.join('db', "data.#{Time.now.to_f}.sql")
55
-
56
- PG.make_dump target, *PG.config!.values_at(:username, :database), '-c'
57
- end
58
-
59
- desc "Load a dump of the database from ENV['DUMP']"
60
- task :load => :environment do
61
- source = ENV['DUMP'].presence or
62
- raise ArgumentError, "Invoke as rake db:data:load DUMP=/path/to/data.sql"
63
-
64
- PG.load_dump source, *PG.config!.values_at(:username, :database)
65
- end
66
- end
67
- end
@@ -1,98 +0,0 @@
1
- # h/t http://stackoverflow.com/questions/4698467
2
- #
3
- Rails.application.config.active_record.schema_format = :sql
4
-
5
- # Clear Rails' ones
6
- %w( db:structure:dump db:structure:load ).each {|t| Rake::Task[t].clear }
7
-
8
- # Make schema:dump and schema:load invoke structure:dump and structure:load
9
- Rake::Task['db:schema:dump'].clear.enhance(['environment']) do
10
- Rake::Task['db:structure:dump'].invoke
11
- end
12
-
13
- Rake::Task['db:schema:load'].clear.enhance(['environment']) do
14
- Rake::Task['db:structure:load'].invoke
15
- end
16
-
17
- # PG utilities
18
- #
19
- module PG
20
- SQL_COMMENT_BEGIN = "--".freeze
21
-
22
- extend self
23
-
24
- def config!
25
- ActiveRecord::Base.connection_pool.spec.config.tap do |config|
26
- ENV['PGHOST'] = config[:host].to_s if config.key?(:host)
27
- ENV['PGPORT'] = config[:port].to_s if config.key?(:port)
28
- ENV['PGPASSWORD'] = config[:password].to_s if config.key?(:password)
29
- ENV['PGUSER'] = config[:username].to_s if config.key?(:username)
30
- end
31
- end
32
-
33
- def make_dump(target, username, database, *options)
34
- exec 'pg_dump', '-f', target, '-U', username, '-d', database, *options
35
- remove_sql_header_comments(target)
36
- end
37
-
38
- def load_dump(source, username, database, *options)
39
- exec 'psql', '-U', username, '-f', source, database, *options
40
- end
41
-
42
- def exec(*argv)
43
- argv = argv.compact.map(&:to_s)
44
-
45
- print "> \033[1m#{argv.join(' ')}\033[0m... "
46
- logger.info "PG: exec #{argv.join(' ')}"
47
-
48
- stdout, stdout_w = IO.pipe
49
- stderr, stderr_w = IO.pipe
50
- pid = fork {
51
- stdout.close; STDOUT.reopen(stdout_w)
52
- stderr.close; STDERR.reopen(stderr_w)
53
-
54
- Kernel.exec *argv
55
- }
56
- stdout_w.close; stderr_w.close
57
- pid, status = Process.wait2
58
-
59
- puts "exit #{status.exitstatus}"
60
- logger.info "PG: exit #{status.exitstatus}"
61
-
62
- out, err = stdout.read.chomp, stderr.read.chomp
63
- stdout.close; stderr.close
64
-
65
- if out.present?
66
- logger.info "PG: -----8<----- stdout ----->8-----"
67
- logger.info out
68
- logger.info "PG: ----8<---- end stdout ---->8----"
69
- end
70
-
71
- if err.present?
72
- logger.info "PG: -----8<----- stderr ----->8-----"
73
- logger.info err
74
- logger.info "PG: ----8<---- end stderr ---->8----"
75
- end
76
- end
77
-
78
- def logger
79
- ActiveRecord::Base.logger
80
- end
81
-
82
- private
83
-
84
- def remove_sql_header_comments(filename)
85
- tempfile = Tempfile.open("uncommented_structure.sql")
86
- begin
87
- File.foreach(filename) do |line|
88
- unless line.start_with?(SQL_COMMENT_BEGIN)
89
- tempfile << line
90
- end
91
- end
92
- ensure
93
- tempfile.close
94
- end
95
- FileUtils.mv(tempfile.path, filename)
96
- end
97
-
98
- end