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 +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
|