db_to_file 1.2.4

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.
@@ -0,0 +1,46 @@
1
+ module DbToFile
2
+ module ValuesNormalizer
3
+ class ObjectToHash
4
+ def initialize(object)
5
+ @object = object
6
+ end
7
+
8
+ def normalize
9
+ @hash = {}
10
+ @object.attributes.each do |field, value|
11
+ @current_field = field
12
+ @hash[field] = normalize_field_value(value)
13
+ end
14
+ @hash
15
+ end
16
+
17
+ private
18
+ def normalize_field_value(value)
19
+ value = convert_yaml(value)
20
+ value = convert_nil_value(value)
21
+ value = convert_integer_to_string(value)
22
+ value = add_trailing_newline(value)
23
+ end
24
+
25
+ def convert_yaml(value)
26
+ (!value.nil? && serialized_attribute?(@current_field)) ? value.to_yaml : value
27
+ end
28
+
29
+ def serialized_attribute?(field)
30
+ @object.class.serialized_attributes.keys.include?(field.to_s)
31
+ end
32
+
33
+ def convert_nil_value(value)
34
+ (value.nil?) ? '<NULL>' : value
35
+ end
36
+
37
+ def convert_integer_to_string(integer)
38
+ "#{integer}"
39
+ end
40
+
41
+ def add_trailing_newline(string)
42
+ (string[-1] == "\n") ? string : "#{string}\n"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,40 @@
1
+ module DbToFile
2
+ module ValuesNormalizer
3
+ class ValueIntoObject
4
+ def initialize(object)
5
+ @object = object
6
+ end
7
+
8
+ def normalize(fieldname, value)
9
+ if @object.respond_to?(fieldname.to_sym)
10
+ normalized_value = normalize_field_value(fieldname, value)
11
+ @object.send("#{fieldname}=", normalized_value)
12
+ end
13
+ end
14
+
15
+ private
16
+ def normalize_field_value(fieldname, value)
17
+ @current_field = fieldname
18
+ value = strip_trailing_newline(value)
19
+ value = convert_nil_value(value)
20
+ value = convert_yaml(value)
21
+ end
22
+
23
+ def strip_trailing_newline(text)
24
+ (text[-1] == "\n") ? text[0..-2] : text
25
+ end
26
+
27
+ def convert_nil_value(value)
28
+ (value == '<NULL>') ? nil : value
29
+ end
30
+
31
+ def convert_yaml(value)
32
+ (!value.nil? && serialized_attribute?(@current_field)) ? YAML.load(value) : value
33
+ end
34
+
35
+ def serialized_attribute?(field)
36
+ @object.class.serialized_attributes.keys.include?(field.to_s)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module DbToFile
2
+ VERSION = "1.2.4"
3
+ end
@@ -0,0 +1,78 @@
1
+ module DbToFile
2
+ class VersionController
3
+ def prepare_code_version
4
+ SystemExecuter.new("git stash save 'db-to-file'").execute
5
+ SystemExecuter.new('git pull').execute
6
+ FileUtils.rm_rf('db/db_to_file')
7
+ end
8
+
9
+ def update_code_version(commit_message = nil)
10
+ update_commit_stash
11
+ commit_changes(commit_message) if commitable_files_present?
12
+ end
13
+
14
+ def restore_local_stash
15
+ restore_stash
16
+ end
17
+
18
+ def merge_conflicts_present?
19
+ out = SystemExecuter.new('git status --porcelain').execute.split("\n")
20
+ out.any?{|line| line[0..0] == 'U'}
21
+ end
22
+
23
+ def get_modified_file_list
24
+ modified_files
25
+ end
26
+
27
+ private
28
+ DEFAULT_COMMIT_MESSAGE = 'DbToFile: changes by customer'
29
+
30
+ def update_commit_stash
31
+ SystemExecuter.new('git status --porcelain').execute
32
+ new_files.each do |file|
33
+ SystemExecuter.new("git add #{file}").execute if table_file?(file)
34
+ end
35
+ modified_files.each do |file|
36
+ SystemExecuter.new("git add #{file}").execute if table_file?(file)
37
+ end
38
+ deleted_files.each do |file|
39
+ SystemExecuter.new("git rm #{file}").execute if table_file?(file)
40
+ end
41
+ end
42
+
43
+ def commitable_files_present?
44
+ out = SystemExecuter.new('git status --porcelain').execute
45
+ out.split("\n").reject{|line| [' ', '?'].include?(line[0])}.any?
46
+ end
47
+
48
+ def commit_changes(commit_message)
49
+ puts 'Commit changes'
50
+ message = commit_message || DEFAULT_COMMIT_MESSAGE
51
+ git.commit(message)
52
+ end
53
+
54
+ def restore_stash
55
+ SystemExecuter.new('git stash pop').execute
56
+ end
57
+
58
+ def new_files
59
+ git.status.untracked.map{|file, git_object| file}
60
+ end
61
+
62
+ def modified_files
63
+ git.status.changed.map{|file, git_object| file}
64
+ end
65
+
66
+ def deleted_files
67
+ git.status.deleted.map{|file, git_object| file}
68
+ end
69
+
70
+ def table_file?(file)
71
+ file.index('db/db_to_file') === 0
72
+ end
73
+
74
+ def git
75
+ @git ||= Git.open(Dir.pwd)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,18 @@
1
+ namespace :db_to_file do
2
+ class WrongEnvironmentGiven < Exception; end
3
+
4
+ desc 'Unload tables to file system'
5
+ task :unload => :environment do |args|
6
+ # wrong_environment(:environment) unless Rails.env.production?
7
+ unload_tables
8
+ end
9
+
10
+ private
11
+ def unload_tables
12
+ DbToFile::Unloader.new.unload
13
+ end
14
+
15
+ def wrong_environment(environment)
16
+ raise WrongEnvironmentGiven, "Environment should be 'production'. '#{Rails.env}' is used"
17
+ end
18
+ end
@@ -0,0 +1,37 @@
1
+ namespace :db_to_file do
2
+ class NoCommitMessage < Exception; end
3
+
4
+ desc "Upload files to the database (set commit message via command 'rake db_to_file:unload['<commit message>'])"
5
+ task :upload, [:commit_message] => :environment do |t, args|
6
+ no_commit_message_error if args[:commit_message].blank?
7
+
8
+ upload_files(args[:commit_message])
9
+ end
10
+
11
+ desc "Force uploading to the database, without checks"
12
+ task :force_upload => :environment do |t, args|
13
+ force_upload_files
14
+ end
15
+
16
+ desc 'Force uploading only changed files in database, without checks'
17
+ task :force_changed => :environment do |t, args|
18
+ force_upload_changed_files
19
+ end
20
+
21
+ private
22
+ def upload_files(commit_message)
23
+ DbToFile::Uploader.new.upload(commit_message)
24
+ end
25
+
26
+ def force_upload_files
27
+ DbToFile::Uploader.new.force_upload
28
+ end
29
+
30
+ def force_upload_changed_files
31
+ DbToFile::Uploader.new.force_upload
32
+ end
33
+
34
+ def no_commit_message_error
35
+ raise NoCommitMessage, "invoke via 'rake db_to_file:unload['<commit message>']'"
36
+ end
37
+ end
@@ -0,0 +1,6 @@
1
+ tables:
2
+ users:
3
+ directory_prefix: name
4
+ field_extensions:
5
+ name: 'txt'
6
+ settings:
@@ -0,0 +1,137 @@
1
+ require_relative '../../test_helper'
2
+ require 'fileutils'
3
+
4
+ describe DbToFile::Unloader do
5
+ let(:unloader) { DbToFile::Unloader.new }
6
+
7
+ before do
8
+ DbToFile::Config.any_instance.stubs(:config_file).returns('test/fixtures/config.yml')
9
+ end
10
+
11
+ describe 'configuration-file' do
12
+ it 'can be parsed' do
13
+ unloader.send(:tables).must_equal(['users', 'settings'])
14
+ end
15
+
16
+ it 'can read directory prefix' do
17
+ @table = DbToFile::Unloader::Table.new('users', @unloader)
18
+ @record = DbToFile::Unloader::Table::Record.new(User.first, @table)
19
+
20
+ @record.send(:config_directory_prefix).must_equal('name')
21
+
22
+ @table = DbToFile::Unloader::Table.new('settings', @unloader)
23
+ @record = DbToFile::Unloader::Table::Record.new(Setting.first, @table)
24
+
25
+ @record.send(:config_directory_prefix).must_equal(nil)
26
+ end
27
+
28
+ it 'can read file-extensions' do
29
+ @table = DbToFile::Unloader::Table.new('users', @unloader)
30
+ @record = DbToFile::Unloader::Table::Record.new(User.first, @table)
31
+ @field_name = DbToFile::Unloader::Table::Record::Field.new('name', @record)
32
+ @field_id = DbToFile::Unloader::Table::Record::Field.new('id', @record)
33
+
34
+ DbToFile::Config.instance.stub(:config_file, 'test/fixtures/config.yml') do
35
+ @field_name.send(:config_field_extension).must_equal('txt')
36
+ @field_id.send(:config_field_extension).must_equal(nil)
37
+ end
38
+ end
39
+ end
40
+
41
+ describe 'unloading' do
42
+ it 'calls the functions' do
43
+ unloader.expects(:prepare_code_version)
44
+ unloader.expects(:unload_tables)
45
+ unloader.expects(:update_code_version)
46
+ unloader.expects(:restore_local_stash)
47
+
48
+ unloader.unload
49
+ end
50
+ end
51
+
52
+ describe 'build directory for users with prefix' do
53
+ before do
54
+ unloader.stubs(:config_directory_prefix).returns('name')
55
+ DbToFile::Config.instance.stub(:config_file, 'test/fixtures/config.yml') do
56
+ unloader.stub(:tables, ['users']) do
57
+ unloader.send(:unload_tables)
58
+ end
59
+ end
60
+ end
61
+
62
+ after do
63
+ FileUtils.rm_rf('db/db_to_file')
64
+ end
65
+
66
+ it 'for the users' do
67
+ File.directory?('db/db_to_file/users').must_equal true
68
+ end
69
+
70
+ it 'builds the directory for the records' do
71
+ File.directory?('db/db_to_file/users/ewout-quax_1').must_equal true
72
+ File.directory?('db/db_to_file/users/test-example_2').must_equal true
73
+ File.directory?('db/db_to_file/users/3').must_equal true
74
+ end
75
+
76
+ it 'builds the files for the record-files' do
77
+ File.file?('db/db_to_file/users/ewout-quax_1/id').must_equal true
78
+ File.file?('db/db_to_file/users/ewout-quax_1/name.txt').must_equal true
79
+
80
+ File.read('db/db_to_file/users/ewout-quax_1/name.txt').must_equal "Ewout Quax\n"
81
+ end
82
+ end
83
+
84
+ describe 'build directory for users without prefix' do
85
+ before do
86
+ unloader.stubs(:config_directory_prefix).returns(nil)
87
+ unloader.stubs(:config_ignore_columns).returns(nil)
88
+ unloader.stubs(:config_field_extension).returns(nil)
89
+ unloader.stub(:tables, ['settings']) do
90
+ unloader.send(:unload_tables)
91
+ end
92
+ end
93
+
94
+ after do
95
+ FileUtils.rm_rf('db/db_to_file')
96
+ end
97
+
98
+ it 'for the settings' do
99
+ File.directory?('db/db_to_file/settings').must_equal true
100
+ end
101
+
102
+ it 'builds the directory for the records' do
103
+ File.directory?('db/db_to_file/settings/1').must_equal true
104
+ File.directory?('db/db_to_file/settings/2').must_equal true
105
+ end
106
+
107
+ it 'builds the files for the record-files' do
108
+ File.file?('db/db_to_file/settings/2/key').must_equal true
109
+ File.file?('db/db_to_file/settings/2/value').must_equal true
110
+
111
+ File.read('db/db_to_file/settings/2/value').must_equal "<NULL>\n"
112
+ end
113
+ end
114
+
115
+ describe 'prepare code-versioning' do
116
+ it 'invokes the version-controller' do
117
+ controller = Minitest::Mock.new
118
+ DbToFile::VersionController.expects(:new).returns(controller)
119
+
120
+ controller.expect(:prepare_code_version, nil)
121
+ unloader.send(:prepare_code_version)
122
+ controller.verify
123
+ end
124
+ end
125
+
126
+ describe 'update_code_version' do
127
+ it 'invokes all the functions' do
128
+ controller = Minitest::Mock.new
129
+
130
+ unloader.expects(:version_controller).returns(controller)
131
+
132
+ controller.expect(:update_code_version, nil)
133
+ unloader.send(:update_code_version)
134
+ controller.verify
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,145 @@
1
+ require_relative '../../test_helper'
2
+ require 'fileutils'
3
+
4
+ describe DbToFile::Uploader do
5
+ it 'invokes all the functions' do
6
+ uploader = DbToFile::Uploader.new
7
+
8
+ uploader.expects(:can_continue?).returns(true).times(2)
9
+ uploader.expects(:invoke_unloader)
10
+ uploader.expects(:write_objects_to_db)
11
+ uploader.expects(:update_code_version)
12
+
13
+ uploader.upload('uploader_test')
14
+ end
15
+
16
+ describe 'can_continue' do
17
+ let(:uploader) { DbToFile::Uploader.new }
18
+
19
+ it 'return false, if merge conflicts are found' do
20
+ uploader.stub(:merge_conflicts_present?, true) do
21
+ uploader.send(:can_continue?).must_equal(false)
22
+ end
23
+ end
24
+
25
+ it 'return true, if no merge conflicts are found' do
26
+ uploader.stub(:merge_conflicts_present?, false) do
27
+ uploader.send(:can_continue?).must_equal(true)
28
+ end
29
+ end
30
+ end
31
+
32
+ describe 'merge_conflicts_present' do
33
+ let(:uploader) { DbToFile::Uploader.new }
34
+ let(:controller) { Minitest::Mock.new }
35
+
36
+ it 'invokes the version controller' do
37
+ controller.expect(:merge_conflicts_present?, true)
38
+ uploader.stub(:version_controller, controller) do
39
+ uploader.send(:merge_conflicts_present?).must_equal(true)
40
+ end
41
+ controller.verify
42
+ end
43
+ end
44
+
45
+ describe 'objects' do
46
+ after do
47
+ User.last.delete
48
+ end
49
+
50
+ it 'are saved to the db' do
51
+ user_1 = User.new(name: 'Test UserName')
52
+ uploader = DbToFile::Uploader.new
53
+ uploader.expects(:build_objects).returns([user_1])
54
+
55
+ uploader.send(:write_objects_to_db)
56
+
57
+ User.last.must_equal(user_1)
58
+ end
59
+ end
60
+
61
+ describe 'unloaded files' do
62
+ before do
63
+ write_file('db/db_to_file/users/ewout-quax_1', 'id', '1')
64
+ write_file('db/db_to_file/users/ewout-quax_1', 'name.txt', 'Ewout Quax')
65
+ write_file('db/db_to_file/users/test-example_2', 'id', '2')
66
+ write_file('db/db_to_file/users/test-example_2', 'name.txt', 'Test Example')
67
+ end
68
+
69
+ after do
70
+ FileUtils.rm_rf('db/db_to_file')
71
+ end
72
+
73
+ it 'can be read' do
74
+ files = DbToFile::Uploader.new.send(:read_files)
75
+ files.include?('db/db_to_file/users/ewout-quax_1/id').must_equal true
76
+ files.include?('db/db_to_file/users/ewout-quax_1/name.txt').must_equal true
77
+ files.include?('db/db_to_file/users/test-example_2/id').must_equal true
78
+ files.include?('db/db_to_file/users/test-example_2/name.txt').must_equal true
79
+ end
80
+
81
+ it 'can be builded into models' do
82
+ models = DbToFile::Uploader.new.send(:build_objects)
83
+ models.size.must_equal 2
84
+ models.first.class.must_equal(User)
85
+ models.last.class.must_equal(User)
86
+
87
+ user_1 = models.detect{|m| m.id == 1}
88
+ user_2 = models.detect{|m| m.id == 2}
89
+ user_1.name.must_equal 'Ewout Quax'
90
+ user_2.name.must_equal 'Test Example'
91
+ end
92
+ end
93
+
94
+ describe 'update_code_version' do
95
+ let(:uploader) { DbToFile::Uploader.new }
96
+ let(:controller) { Minitest::Mock.new }
97
+
98
+ it 'invokes the version-controller, with a commit message' do
99
+ uploader.expects(:version_controller).returns(controller)
100
+
101
+ controller.expect(:update_code_version, true, ['commit via test'])
102
+ uploader.send(:update_code_version, 'commit via test')
103
+ controller.verify
104
+ end
105
+ end
106
+
107
+ describe 'update_object_with_field_value' do
108
+ let(:uploader) { DbToFile::Uploader.new }
109
+
110
+ it 'with field value' do
111
+ uploader.expects(:file_value).with('db/db_to_file/users/1/name').returns('Bruce Wayne')
112
+
113
+ object = User.new
114
+ uploader.send(:update_object_with_field_value, object, 'name', 'db/db_to_file/users/1/name')
115
+ object.name.must_equal('Bruce Wayne')
116
+ end
117
+
118
+ it 'strips newline at end of field-value' do
119
+ uploader.expects(:file_value).with('db/db_to_file/users/1/name').returns("Bruce Wayne\n")
120
+
121
+ object = User.new
122
+ uploader.send(:update_object_with_field_value, object, 'name', 'db/db_to_file/users/1/name')
123
+ object.name.must_equal('Bruce Wayne')
124
+ end
125
+
126
+ it 'converts <NULL> to nil-value' do
127
+ uploader.expects(:file_value).with('db/db_to_file/users/1/name').returns("<NULL>\n")
128
+
129
+ object = User.new
130
+ uploader.send(:update_object_with_field_value, object, 'name', 'db/db_to_file/users/1/name')
131
+ object.name.must_equal(nil)
132
+ end
133
+ end
134
+
135
+ describe 'extract_data_segments' do
136
+ it 'splits the full-file-path into segments' do
137
+ uploader = DbToFile::Uploader.new
138
+ segments = uploader.send(:extract_data_segments, '/db/db_to_files/users/ewout-quax_1/name.txt')
139
+
140
+ segments[:model].must_equal User
141
+ segments[:id].must_equal 1
142
+ segments[:field].must_equal 'name'
143
+ end
144
+ end
145
+ end