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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/Rakefile +17 -1
- data/chrono_model.gemspec +2 -0
- data/gemfiles/rails_4.2.gemfile +1 -0
- data/gemfiles/rails_5.0.gemfile +1 -0
- data/gemfiles/rails_5.1.gemfile +1 -0
- data/lib/active_record/tasks/chronomodel_database_tasks.rb +86 -0
- data/lib/chrono_model/railtie.rb +38 -2
- data/lib/chrono_model/version.rb +1 -1
- data/spec/aruba/fixtures/database_with_default_username_and_password.yml +14 -0
- data/spec/aruba/fixtures/database_without_username_and_password.yml +11 -0
- data/spec/aruba/fixtures/empty_structure.sql +27 -0
- data/spec/aruba/fixtures/railsapp/config/application.rb +17 -0
- data/spec/aruba/fixtures/railsapp/config/boot.rb +5 -0
- data/spec/aruba/fixtures/railsapp/config/environments/development.rb +54 -0
- data/spec/aruba/migrations_spec.rb +18 -0
- data/spec/aruba/rake_task_spec.rb +72 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/aruba.rb +33 -0
- metadata +50 -5
- data/lib/chrono_model/schema_format.rake +0 -67
- data/lib/chrono_model/schema_format.rb +0 -98
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 514bcdaa49d7f8ca35bb422ea3fb47b5f11bfbd4
|
4
|
+
data.tar.gz: af83cb212905b691d0c0ab43e9bf38306a089819
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96b7a8b00ca96174c66499824b801f9ec50f4644ee0a65adc37fc8a3e0fc57188172cb0e72563800c94b0e82c860af6d1137eb24948f169ce99191f476f5257b
|
7
|
+
data.tar.gz: 1078c39fdab5c0af049df0eddbe7832055e72b872cec07d87d43d205ac1ccca44a3c8c8cb5cf5f9876f9a025a20109060b36541ef5354ed0410961c583ba586e
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
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'
|
data/gemfiles/rails_4.2.gemfile
CHANGED
data/gemfiles/rails_5.0.gemfile
CHANGED
data/gemfiles/rails_5.1.gemfile
CHANGED
@@ -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
|
data/lib/chrono_model/railtie.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/chrono_model/version.rb
CHANGED
@@ -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,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.
|
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-
|
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.
|
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
|