chrono_model 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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