declare_schema 0.9.0 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/declare_schema_build.yml +1 -1
  3. data/CHANGELOG.md +32 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +12 -2
  6. data/lib/declare_schema.rb +12 -1
  7. data/lib/declare_schema/dsl.rb +39 -0
  8. data/lib/declare_schema/extensions/active_record/fields_declaration.rb +22 -3
  9. data/lib/declare_schema/model.rb +4 -6
  10. data/lib/declare_schema/model/column.rb +1 -1
  11. data/lib/declare_schema/model/foreign_key_definition.rb +6 -11
  12. data/lib/declare_schema/model/index_definition.rb +1 -20
  13. data/lib/declare_schema/schema_change/all.rb +22 -0
  14. data/lib/declare_schema/schema_change/base.rb +45 -0
  15. data/lib/declare_schema/schema_change/column_add.rb +27 -0
  16. data/lib/declare_schema/schema_change/column_change.rb +32 -0
  17. data/lib/declare_schema/schema_change/column_remove.rb +20 -0
  18. data/lib/declare_schema/schema_change/column_rename.rb +23 -0
  19. data/lib/declare_schema/schema_change/foreign_key_add.rb +25 -0
  20. data/lib/declare_schema/schema_change/foreign_key_remove.rb +20 -0
  21. data/lib/declare_schema/schema_change/index_add.rb +33 -0
  22. data/lib/declare_schema/schema_change/index_remove.rb +20 -0
  23. data/lib/declare_schema/schema_change/primary_key_change.rb +33 -0
  24. data/lib/declare_schema/schema_change/table_add.rb +37 -0
  25. data/lib/declare_schema/schema_change/table_change.rb +36 -0
  26. data/lib/declare_schema/schema_change/table_remove.rb +22 -0
  27. data/lib/declare_schema/schema_change/table_rename.rb +22 -0
  28. data/lib/declare_schema/version.rb +1 -1
  29. data/lib/generators/declare_schema/migration/USAGE +14 -24
  30. data/lib/generators/declare_schema/migration/migration_generator.rb +40 -38
  31. data/lib/generators/declare_schema/migration/migrator.rb +175 -177
  32. data/lib/generators/declare_schema/migration/templates/migration.rb.erb +3 -3
  33. data/lib/generators/declare_schema/support/model.rb +4 -4
  34. data/spec/lib/declare_schema/api_spec.rb +8 -8
  35. data/spec/lib/declare_schema/field_declaration_dsl_spec.rb +41 -15
  36. data/spec/lib/declare_schema/field_spec_spec.rb +2 -2
  37. data/spec/lib/declare_schema/generator_spec.rb +5 -5
  38. data/spec/lib/declare_schema/interactive_primary_key_spec.rb +117 -28
  39. data/spec/lib/declare_schema/migration_generator_spec.rb +1990 -843
  40. data/spec/lib/declare_schema/model/column_spec.rb +49 -23
  41. data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +158 -57
  42. data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +0 -2
  43. data/spec/lib/declare_schema/model/index_definition_spec.rb +189 -78
  44. data/spec/lib/declare_schema/model/table_options_definition_spec.rb +75 -11
  45. data/spec/lib/declare_schema/schema_change/base_spec.rb +75 -0
  46. data/spec/lib/declare_schema/schema_change/column_add_spec.rb +30 -0
  47. data/spec/lib/declare_schema/schema_change/column_change_spec.rb +33 -0
  48. data/spec/lib/declare_schema/schema_change/column_remove_spec.rb +30 -0
  49. data/spec/lib/declare_schema/schema_change/column_rename_spec.rb +28 -0
  50. data/spec/lib/declare_schema/schema_change/foreign_key_add_spec.rb +29 -0
  51. data/spec/lib/declare_schema/schema_change/foreign_key_remove_spec.rb +29 -0
  52. data/spec/lib/declare_schema/schema_change/index_add_spec.rb +56 -0
  53. data/spec/lib/declare_schema/schema_change/index_remove_spec.rb +29 -0
  54. data/spec/lib/declare_schema/schema_change/primary_key_change_spec.rb +69 -0
  55. data/spec/lib/declare_schema/schema_change/table_add_spec.rb +50 -0
  56. data/spec/lib/declare_schema/schema_change/table_change_spec.rb +30 -0
  57. data/spec/lib/declare_schema/schema_change/table_remove_spec.rb +27 -0
  58. data/spec/lib/declare_schema/schema_change/table_rename_spec.rb +27 -0
  59. data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +59 -11
  60. data/spec/spec_helper.rb +1 -1
  61. data/spec/support/acceptance_spec_helpers.rb +2 -2
  62. metadata +35 -6
  63. data/test_responses.txt +0 -2
@@ -8,19 +8,20 @@ end
8
8
  require_relative '../../../../lib/declare_schema/model/table_options_definition'
9
9
 
10
10
  RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
11
- before do
12
- load File.expand_path('../prepare_testapp.rb', __dir__)
11
+ let(:model_class) { TableOptionsDefinitionTestModel }
12
+
13
+ context 'Using fields' do
14
+ before do
15
+ load File.expand_path('../prepare_testapp.rb', __dir__)
13
16
 
14
- class TableOptionsDefinitionTestModel < ActiveRecord::Base
15
- fields do
16
- name :string, limit: 127, index: true
17
+ class TableOptionsDefinitionTestModel < ActiveRecord::Base
18
+ fields do
19
+ name :string, limit: 127, index: true
20
+ end
17
21
  end
18
22
  end
19
- end
20
23
 
21
- let(:model_class) { TableOptionsDefinitionTestModel }
22
-
23
- context 'instance methods' do
24
+ context 'instance methods' do
24
25
  let(:table_options) { { charset: "utf8", collation: "utf8_general"} }
25
26
  let(:model) { described_class.new('table_options_definition_test_models', table_options) }
26
27
 
@@ -50,8 +51,7 @@ RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
50
51
  end
51
52
  end
52
53
 
53
-
54
- context 'class << self' do
54
+ context 'class << self' do
55
55
  describe '#for_model' do
56
56
  context 'when database migrated' do
57
57
  let(:options) do
@@ -70,5 +70,69 @@ RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
70
70
  it { should eq(described_class.new(model_class.table_name, options)) }
71
71
  end
72
72
  end
73
+ end
74
+ end
75
+
76
+ context 'Using declare_schema' do
77
+ before do
78
+ load File.expand_path('../prepare_testapp.rb', __dir__)
79
+
80
+ class TableOptionsDefinitionTestModel < ActiveRecord::Base
81
+ declare_schema do
82
+ string :name, limit: 127, index: true
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'instance methods' do
88
+ let(:table_options) { { charset: "utf8", collation: "utf8_general"} }
89
+ let(:model) { described_class.new('table_options_definition_test_models', table_options) }
90
+
91
+ describe '#to_key' do
92
+ subject { model.to_key }
93
+ it { should eq(['table_options_definition_test_models', '{:charset=>"utf8", :collation=>"utf8_general"}']) }
94
+ end
95
+
96
+ describe '#settings' do
97
+ subject { model.settings }
98
+ it { should eq("CHARACTER SET utf8 COLLATE utf8_general") }
99
+ end
100
+
101
+ describe '#hash' do
102
+ subject { model.hash }
103
+ it { should eq(['table_options_definition_test_models', '{:charset=>"utf8", :collation=>"utf8_general"}'].hash) }
104
+ end
105
+
106
+ describe '#to_s' do
107
+ subject { model.to_s }
108
+ it { should eq("CHARACTER SET utf8 COLLATE utf8_general") }
109
+ end
110
+
111
+ describe '#alter_table_statement' do
112
+ subject { model.alter_table_statement }
113
+ it { should match(/execute "ALTER TABLE .*table_options_definition_test_models.* CHARACTER SET utf8 COLLATE utf8_general"/) }
114
+ end
115
+ end
116
+
117
+ context 'class << self' do
118
+ describe '#for_model' do
119
+ context 'when database migrated' do
120
+ let(:options) do
121
+ if defined?(Mysql2)
122
+ { charset: "utf8mb4", collation: "utf8mb4_bin" }
123
+ else
124
+ { }
125
+ end
126
+ end
127
+ subject { described_class.for_model(model_class) }
128
+
129
+ before do
130
+ generate_migrations '-n', '-m'
131
+ end
132
+
133
+ it { should eq(described_class.new(model_class.table_name, options)) }
134
+ end
135
+ end
136
+ end
73
137
  end
74
138
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/declare_schema/schema_change/base'
4
+
5
+ RSpec.describe DeclareSchema::SchemaChange::Base do
6
+ before do
7
+ load File.expand_path('../prepare_testapp.rb', __dir__)
8
+ end
9
+
10
+ before :all do
11
+ class ChangeDefault < described_class
12
+ attr_reader :up_command, :down_command
13
+
14
+ def initialize(up:, down:)
15
+ @up_command = up
16
+ @down_command = down
17
+ end
18
+ end
19
+
20
+ class ChangeOverride < described_class
21
+ attr_reader :up_command, :down_command
22
+
23
+ def initialize(up:, down:)
24
+ @up_command = up
25
+ @down_command = down
26
+ end
27
+ end
28
+ end
29
+
30
+ describe 'class methods' do
31
+ describe 'format_options' do
32
+ subject { { limit: 8, 'key' => 'value', subhash: { subkey: :subvalue } } }
33
+
34
+ it 'formats using Ruby 2.0 symbol notation' do
35
+ expect(described_class.format_options(subject)).to eq(['limit: 8', '"key" => "value"', 'subhash: { subkey: :subvalue }'])
36
+ end
37
+ end
38
+ end
39
+
40
+ describe 'instance methods' do
41
+ describe '#up/#down' do
42
+ context 'with single-line commands' do
43
+ subject { ChangeDefault.new(up: "up_command", down: "down_command" )}
44
+
45
+ describe '#up' do
46
+ it 'responds with command and single spacing' do
47
+ expect(subject.up).to eq("up_command\n")
48
+ end
49
+ end
50
+
51
+ describe '#down' do
52
+ it 'responds with command and single spacing' do
53
+ expect(subject.down).to eq("down_command\n")
54
+ end
55
+ end
56
+ end
57
+
58
+ context 'with multi-line commands' do
59
+ subject { ChangeDefault.new(up: "up_command 1\nup_command 2", down: "down_command 1\ndown_command 2" )}
60
+
61
+ describe '#up' do
62
+ it 'responds with command and double spacing' do
63
+ expect(subject.up).to eq("up_command 1\nup_command 2\n\n")
64
+ end
65
+ end
66
+
67
+ describe '#down' do
68
+ it 'responds with command and spacing' do
69
+ expect(subject.down).to eq("down_command 1\ndown_command 2\n\n")
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/declare_schema/schema_change/column_add'
4
+
5
+ RSpec.describe DeclareSchema::SchemaChange::ColumnAdd do
6
+ before do
7
+ load File.expand_path('../prepare_testapp.rb', __dir__)
8
+ end
9
+
10
+ let(:table_name) { 'networks' }
11
+ let(:column_name) { 'title' }
12
+ let(:column_type) { :integer }
13
+ let(:column_options) { { limit: 8 } }
14
+ let(:column_options_string) { "limit: 8" }
15
+ subject { described_class.new(table_name, column_name, column_type, column_options) }
16
+
17
+ describe '#up/down' do
18
+ describe '#up' do
19
+ it 'responds with command' do
20
+ expect(subject.up).to eq("add_column :#{table_name}, :#{column_name}, :#{column_type}, #{column_options_string}\n")
21
+ end
22
+ end
23
+
24
+ describe '#down' do
25
+ it 'responds with command' do
26
+ expect(subject.down).to eq("remove_column :#{table_name}, :#{column_name}\n")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/declare_schema/schema_change/column_change'
4
+
5
+ RSpec.describe DeclareSchema::SchemaChange::ColumnChange do
6
+ before do
7
+ load File.expand_path('../prepare_testapp.rb', __dir__)
8
+ end
9
+
10
+ let(:table_name) { 'networks' }
11
+ let(:column_name) { 'title' }
12
+ let(:old_type) { :string }
13
+ let(:old_options) { { limit: 255, null: false } }
14
+ let(:old_options_string) { "limit: 255, null: false" }
15
+ let(:new_type) { :text }
16
+ let(:new_options) { { limit: 0xffff, null: true } }
17
+ let(:new_options_string) { "limit: 65535, null: true" }
18
+ subject { described_class.new(table_name, column_name, old_type: old_type, old_options: old_options, new_type: new_type, new_options: new_options) }
19
+
20
+ describe '#up/down' do
21
+ describe '#up' do
22
+ it 'responds with command' do
23
+ expect(subject.up).to eq("change_column :#{table_name}, :#{column_name}, :#{new_type}, #{new_options_string}\n")
24
+ end
25
+ end
26
+
27
+ describe '#down' do
28
+ it 'responds with command' do
29
+ expect(subject.down).to eq("change_column :#{table_name}, :#{column_name}, :#{old_type}, #{old_options_string}\n")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/declare_schema/schema_change/column_remove'
4
+
5
+ RSpec.describe DeclareSchema::SchemaChange::ColumnRemove do
6
+ before do
7
+ load File.expand_path('../prepare_testapp.rb', __dir__)
8
+ end
9
+
10
+ let(:table_name) { 'networks' }
11
+ let(:column_name) { 'title' }
12
+ let(:column_type) { :integer }
13
+ let(:column_options) { { limit: 8 } }
14
+ let(:column_options_string) { "limit: 8" }
15
+ subject { described_class.new(table_name, column_name, column_type, column_options) }
16
+
17
+ describe '#up/down' do
18
+ describe '#up' do
19
+ it 'responds with command' do
20
+ expect(subject.up).to eq("remove_column :#{table_name}, :#{column_name}\n")
21
+ end
22
+ end
23
+
24
+ describe '#down' do
25
+ it 'responds with command' do
26
+ expect(subject.down).to eq("add_column :#{table_name}, :#{column_name}, :#{column_type}, #{column_options_string}\n")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/declare_schema/schema_change/column_rename'
4
+
5
+ RSpec.describe DeclareSchema::SchemaChange::ColumnRename do
6
+ before do
7
+ load File.expand_path('../prepare_testapp.rb', __dir__)
8
+ end
9
+
10
+ let(:table_name) { 'networks' }
11
+ let(:old_name) { 'title' }
12
+ let(:new_name) { 'summary' }
13
+ subject { described_class.new(table_name, old_name, new_name) }
14
+
15
+ describe '#up/down' do
16
+ describe '#up' do
17
+ it 'responds with command' do
18
+ expect(subject.up).to eq("rename_column :#{table_name}, :#{old_name}, :#{new_name}\n")
19
+ end
20
+ end
21
+
22
+ describe '#down' do
23
+ it 'responds with command' do
24
+ expect(subject.down).to eq("rename_column :#{table_name}, :#{new_name}, :#{old_name}\n")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/declare_schema/schema_change/foreign_key_add'
4
+
5
+ RSpec.describe DeclareSchema::SchemaChange::ForeignKeyAdd do
6
+ before do
7
+ load File.expand_path('../prepare_testapp.rb', __dir__)
8
+ end
9
+
10
+ let(:table_name) { 'users' }
11
+ let(:parent_table_name) { 'organization' }
12
+ let(:column_name) { :organization_id }
13
+ let(:name) { 'on_organization_id' }
14
+ subject { described_class.new(table_name, parent_table_name, column_name: column_name, name: name) }
15
+
16
+ describe '#up/down' do
17
+ describe '#up' do
18
+ it 'responds with command' do
19
+ expect(subject.up).to eq("add_foreign_key :#{table_name}, :#{parent_table_name}, column: #{column_name.to_sym.inspect}, name: #{name.to_sym.inspect}\n")
20
+ end
21
+ end
22
+
23
+ describe '#down' do
24
+ it 'responds with command' do
25
+ expect(subject.down).to eq("remove_foreign_key :#{table_name}, name: #{name.to_sym.inspect}\n")
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/declare_schema/schema_change/foreign_key_remove'
4
+
5
+ RSpec.describe DeclareSchema::SchemaChange::ForeignKeyRemove do
6
+ before do
7
+ load File.expand_path('../prepare_testapp.rb', __dir__)
8
+ end
9
+
10
+ let(:table_name) { 'users' }
11
+ let(:parent_table_name) { 'organization' }
12
+ let(:column_name) { :organization_id }
13
+ let(:name) { 'on_organization_id' }
14
+ subject { described_class.new(table_name, parent_table_name, column_name: column_name, name: name) }
15
+
16
+ describe '#up/down' do
17
+ describe '#up' do
18
+ it 'responds with command' do
19
+ expect(subject.up).to eq("remove_foreign_key :#{table_name}, name: #{name.to_sym.inspect}\n")
20
+ end
21
+ end
22
+
23
+ describe '#down' do
24
+ it 'responds with command' do
25
+ expect(subject.down).to eq("add_foreign_key :#{table_name}, :#{parent_table_name}, column: #{column_name.to_sym.inspect}, name: #{name.to_sym.inspect}\n")
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/declare_schema/schema_change/index_add'
4
+
5
+ RSpec.describe DeclareSchema::SchemaChange::IndexAdd do
6
+ before do
7
+ load File.expand_path('../prepare_testapp.rb', __dir__)
8
+ end
9
+
10
+ let(:table_name) { 'users' }
11
+ let(:column_names) { [:last_name, 'first_name'] }
12
+ let(:name) { 'on_last_name_and_first_name' }
13
+ let(:unique) { false }
14
+ subject { described_class.new(table_name, column_names, name: name, unique: unique) }
15
+
16
+ describe '#up/down' do
17
+ describe '#up' do
18
+ context 'without where:' do
19
+ it 'responds with command' do
20
+ expect(subject.up).to eq("add_index :#{table_name}, #{column_names.map(&:to_sym).inspect}, name: #{name.to_sym.inspect}\n")
21
+ end
22
+ end
23
+
24
+ context 'with empty where:' do
25
+ subject { described_class.new(table_name, column_names, name: name, unique: unique, where: nil) }
26
+
27
+ it 'responds with command' do
28
+ expect(subject.up).to eq("add_index :#{table_name}, #{column_names.map(&:to_sym).inspect}, name: #{name.to_sym.inspect}\n")
29
+ end
30
+ end
31
+
32
+ context 'with where:' do
33
+ let(:where) { "'last_name like 'A%'"}
34
+ subject { described_class.new(table_name, column_names, name: name, unique: unique, where: where) }
35
+
36
+ it 'responds with command' do
37
+ expect(subject.up).to eq("add_index :#{table_name}, #{column_names.map(&:to_sym).inspect}, name: #{name.to_sym.inspect}, where: #{where.inspect}\n")
38
+ end
39
+ end
40
+
41
+ context 'with unique: true' do
42
+ let(:unique) { true }
43
+
44
+ it 'responds with command' do
45
+ expect(subject.up).to eq("add_index :#{table_name}, #{column_names.map(&:to_sym).inspect}, name: #{name.to_sym.inspect}, unique: true\n")
46
+ end
47
+ end
48
+ end
49
+
50
+ describe '#down' do
51
+ it 'responds with command' do
52
+ expect(subject.down).to eq("remove_index :#{table_name}, name: #{name.to_sym.inspect}\n")
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../lib/declare_schema/schema_change/index_remove'
4
+
5
+ RSpec.describe DeclareSchema::SchemaChange::IndexRemove do
6
+ before do
7
+ load File.expand_path('../prepare_testapp.rb', __dir__)
8
+ end
9
+
10
+ let(:table_name) { 'users' }
11
+ let(:column_names) { [:last_name, 'first_name'] }
12
+ let(:name) { 'on_last_name_and_first_name' }
13
+ let(:unique) { true }
14
+ subject { described_class.new(table_name, column_names, name: name, unique: unique) }
15
+
16
+ describe '#up/down' do
17
+ describe '#up' do
18
+ it 'responds with command' do
19
+ expect(subject.up).to eq("remove_index :#{table_name}, name: #{name.to_sym.inspect}\n")
20
+ end
21
+ end
22
+
23
+ describe '#down' do
24
+ it 'responds with command' do
25
+ expect(subject.down).to eq("add_index :#{table_name}, #{column_names.map(&:to_sym).inspect}, name: #{name.to_sym.inspect}, unique: #{unique}\n")
26
+ end
27
+ end
28
+ end
29
+ end