declare_schema 0.8.0.pre.6 → 0.10.1
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/.github/workflows/declare_schema_build.yml +1 -1
- data/CHANGELOG.md +28 -1
- data/Gemfile.lock +1 -1
- data/README.md +91 -13
- data/lib/declare_schema.rb +46 -0
- data/lib/declare_schema/dsl.rb +39 -0
- data/lib/declare_schema/extensions/active_record/fields_declaration.rb +23 -4
- data/lib/declare_schema/model.rb +51 -59
- data/lib/declare_schema/model/field_spec.rb +11 -8
- data/lib/declare_schema/model/foreign_key_definition.rb +4 -8
- data/lib/declare_schema/model/habtm_model_shim.rb +1 -1
- data/lib/declare_schema/model/index_definition.rb +0 -19
- data/lib/declare_schema/schema_change/all.rb +22 -0
- data/lib/declare_schema/schema_change/base.rb +45 -0
- data/lib/declare_schema/schema_change/column_add.rb +27 -0
- data/lib/declare_schema/schema_change/column_change.rb +32 -0
- data/lib/declare_schema/schema_change/column_remove.rb +20 -0
- data/lib/declare_schema/schema_change/column_rename.rb +23 -0
- data/lib/declare_schema/schema_change/foreign_key_add.rb +25 -0
- data/lib/declare_schema/schema_change/foreign_key_remove.rb +20 -0
- data/lib/declare_schema/schema_change/index_add.rb +33 -0
- data/lib/declare_schema/schema_change/index_remove.rb +20 -0
- data/lib/declare_schema/schema_change/primary_key_change.rb +33 -0
- data/lib/declare_schema/schema_change/table_add.rb +37 -0
- data/lib/declare_schema/schema_change/table_change.rb +36 -0
- data/lib/declare_schema/schema_change/table_remove.rb +22 -0
- data/lib/declare_schema/schema_change/table_rename.rb +22 -0
- data/lib/declare_schema/version.rb +1 -1
- data/lib/generators/declare_schema/migration/migrator.rb +189 -202
- data/lib/generators/declare_schema/support/model.rb +4 -4
- data/spec/lib/declare_schema/api_spec.rb +7 -7
- data/spec/lib/declare_schema/field_declaration_dsl_spec.rb +41 -15
- data/spec/lib/declare_schema/field_spec_spec.rb +50 -6
- data/spec/lib/declare_schema/generator_spec.rb +3 -3
- data/spec/lib/declare_schema/interactive_primary_key_spec.rb +116 -26
- data/spec/lib/declare_schema/migration_generator_spec.rb +1891 -845
- data/spec/lib/declare_schema/model/column_spec.rb +47 -17
- data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +134 -57
- data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +3 -3
- data/spec/lib/declare_schema/model/index_definition_spec.rb +188 -77
- data/spec/lib/declare_schema/model/table_options_definition_spec.rb +75 -11
- data/spec/lib/declare_schema/schema_change/base_spec.rb +75 -0
- data/spec/lib/declare_schema/schema_change/column_add_spec.rb +30 -0
- data/spec/lib/declare_schema/schema_change/column_change_spec.rb +33 -0
- data/spec/lib/declare_schema/schema_change/column_remove_spec.rb +30 -0
- data/spec/lib/declare_schema/schema_change/column_rename_spec.rb +28 -0
- data/spec/lib/declare_schema/schema_change/foreign_key_add_spec.rb +29 -0
- data/spec/lib/declare_schema/schema_change/foreign_key_remove_spec.rb +29 -0
- data/spec/lib/declare_schema/schema_change/index_add_spec.rb +56 -0
- data/spec/lib/declare_schema/schema_change/index_remove_spec.rb +29 -0
- data/spec/lib/declare_schema/schema_change/primary_key_change_spec.rb +69 -0
- data/spec/lib/declare_schema/schema_change/table_add_spec.rb +50 -0
- data/spec/lib/declare_schema/schema_change/table_change_spec.rb +30 -0
- data/spec/lib/declare_schema/schema_change/table_remove_spec.rb +27 -0
- data/spec/lib/declare_schema/schema_change/table_rename_spec.rb +27 -0
- data/spec/lib/declare_schema_spec.rb +101 -0
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +71 -13
- data/spec/support/acceptance_spec_helpers.rb +2 -2
- metadata +33 -3
- data/test_responses.txt +0 -2
@@ -85,14 +85,6 @@ RSpec.describe DeclareSchema::Model::Column do
|
|
85
85
|
end
|
86
86
|
|
87
87
|
describe 'instance methods' do
|
88
|
-
before do
|
89
|
-
class ColumnTestModel < ActiveRecord::Base
|
90
|
-
fields do
|
91
|
-
title :string, limit: 127, null: false
|
92
|
-
count :integer, null: false
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
88
|
let(:model) { ColumnTestModel }
|
97
89
|
let(:type) { :integer }
|
98
90
|
let(:current_table_name) { model.table_name }
|
@@ -108,18 +100,56 @@ RSpec.describe DeclareSchema::Model::Column do
|
|
108
100
|
sql_type_metadata: {}) }
|
109
101
|
subject { described_class.new(model, current_table_name, column) }
|
110
102
|
|
111
|
-
|
112
|
-
|
113
|
-
|
103
|
+
context 'Using fields' do
|
104
|
+
before do
|
105
|
+
class ColumnTestModel < ActiveRecord::Base
|
106
|
+
fields do
|
107
|
+
title :string, limit: 127, null: false
|
108
|
+
count :integer, null: false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#type' do
|
114
|
+
it 'returns type' do
|
115
|
+
expect(subject.type).to eq(type)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '#schema_attributes' do
|
120
|
+
it 'returns a hash with relevant key/values' do
|
121
|
+
if defined?(Mysql2)
|
122
|
+
expect(subject.schema_attributes).to eq(type: :integer, null: false, limit: 4)
|
123
|
+
else
|
124
|
+
expect(subject.schema_attributes).to eq(type: :integer, null: false)
|
125
|
+
end
|
126
|
+
end
|
114
127
|
end
|
115
128
|
end
|
116
129
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
130
|
+
context 'Using declare_schema' do
|
131
|
+
before do
|
132
|
+
class ColumnTestModel < ActiveRecord::Base
|
133
|
+
declare_schema do
|
134
|
+
string :title, limit: 127, null: false
|
135
|
+
integer :count, null: false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#type' do
|
141
|
+
it 'returns type' do
|
142
|
+
expect(subject.type).to eq(type)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '#schema_attributes' do
|
147
|
+
it 'returns a hash with relevant key/values' do
|
148
|
+
if defined?(Mysql2)
|
149
|
+
expect(subject.schema_attributes).to eq(type: :integer, null: false, limit: 4)
|
150
|
+
else
|
151
|
+
expect(subject.schema_attributes).to eq(type: :integer, null: false)
|
152
|
+
end
|
123
153
|
end
|
124
154
|
end
|
125
155
|
end
|
@@ -3,89 +3,166 @@
|
|
3
3
|
require_relative '../../../../lib/declare_schema/model/foreign_key_definition'
|
4
4
|
|
5
5
|
RSpec.describe DeclareSchema::Model::ForeignKeyDefinition do
|
6
|
-
|
7
|
-
|
6
|
+
let(:model_class) { Network }
|
7
|
+
|
8
|
+
context 'Using fields' do
|
9
|
+
before do
|
10
|
+
load File.expand_path('../prepare_testapp.rb', __dir__)
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
+
class Network < ActiveRecord::Base
|
13
|
+
fields do
|
14
|
+
name :string, limit: 127, index: true
|
12
15
|
|
13
|
-
|
16
|
+
timestamps
|
17
|
+
end
|
14
18
|
end
|
15
19
|
end
|
16
|
-
end
|
17
20
|
|
18
|
-
|
21
|
+
describe 'instance methods' do
|
22
|
+
let(:connection) { instance_double(ActiveRecord::Base.connection.class) }
|
23
|
+
let(:model) { instance_double('Model', table_name: 'models', connection: connection) }
|
24
|
+
let(:foreign_key) { :network_id }
|
25
|
+
let(:options) { {} }
|
26
|
+
subject { described_class.new(model, foreign_key, options)}
|
19
27
|
|
20
|
-
|
21
|
-
|
22
|
-
let(:model) { instance_double('Model', table_name: 'models', connection: connection) }
|
23
|
-
let(:foreign_key) { :network_id }
|
24
|
-
let(:options) { {} }
|
25
|
-
subject { described_class.new(model, foreign_key, options)}
|
26
|
-
|
27
|
-
before do
|
28
|
-
allow(connection).to receive(:index_name).with('models', column: 'network_id') { 'on_network_id' }
|
29
|
-
end
|
30
|
-
|
31
|
-
describe '#initialize' do
|
32
|
-
it 'normalizes symbols to strings' do
|
33
|
-
expect(subject.foreign_key).to eq('network_id')
|
34
|
-
expect(subject.parent_table_name).to eq('networks')
|
28
|
+
before do
|
29
|
+
allow(connection).to receive(:index_name).with('models', column: 'network_id') { 'on_network_id' }
|
35
30
|
end
|
36
31
|
|
37
|
-
|
38
|
-
let(:options) { { parent_table: :networks, foreign_key: :the_network_id, index_name: :index_on_network_id } }
|
39
|
-
|
32
|
+
describe '#initialize' do
|
40
33
|
it 'normalizes symbols to strings' do
|
41
34
|
expect(subject.foreign_key).to eq('network_id')
|
42
|
-
expect(subject.foreign_key_name).to eq('the_network_id')
|
43
35
|
expect(subject.parent_table_name).to eq('networks')
|
44
|
-
expect(subject.foreign_key).to eq('network_id')
|
45
|
-
expect(subject.constraint_name).to eq('index_on_network_id')
|
46
|
-
expect(subject.on_delete_cascade).to be_falsey
|
47
36
|
end
|
48
|
-
end
|
49
37
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
38
|
+
context 'when most options passed' do
|
39
|
+
let(:options) { { parent_table: :networks, foreign_key: :the_network_id, index_name: :index_on_network_id } }
|
40
|
+
|
41
|
+
it 'normalizes symbols to strings' do
|
42
|
+
expect(subject.foreign_key).to eq('network_id')
|
43
|
+
expect(subject.foreign_key_name).to eq('the_network_id')
|
44
|
+
expect(subject.parent_table_name).to eq('networks')
|
45
|
+
expect(subject.foreign_key).to eq('network_id')
|
46
|
+
expect(subject.constraint_name).to eq('index_on_network_id')
|
47
|
+
expect(subject.on_delete_cascade).to be_falsey
|
48
|
+
end
|
49
|
+
end
|
54
50
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
51
|
+
context 'when all options passed' do
|
52
|
+
let(:foreign_key) { nil }
|
53
|
+
let(:options) { { parent_table: :networks, foreign_key: :the_network_id, index_name: :index_on_network_id,
|
54
|
+
constraint_name: :constraint_1, dependent: :delete } }
|
55
|
+
|
56
|
+
it 'normalizes symbols to strings' do
|
57
|
+
expect(subject.foreign_key).to be_nil
|
58
|
+
expect(subject.foreign_key_name).to eq('the_network_id')
|
59
|
+
expect(subject.parent_table_name).to eq('networks')
|
60
|
+
expect(subject.constraint_name).to eq('constraint_1')
|
61
|
+
expect(subject.on_delete_cascade).to be_truthy
|
62
|
+
end
|
61
63
|
end
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
65
|
-
describe '
|
66
|
-
|
67
|
-
|
67
|
+
describe 'class << self' do
|
68
|
+
let(:connection) { instance_double(ActiveRecord::Base.connection.class) }
|
69
|
+
let(:model) { instance_double('Model', table_name: 'models', connection: connection) }
|
70
|
+
let(:old_table_name) { 'networks' }
|
71
|
+
before do
|
72
|
+
allow(connection).to receive(:quote_table_name).with('networks') { 'networks' }
|
73
|
+
allow(connection).to receive(:select_rows) { [['CONSTRAINT `constraint` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`)']] }
|
74
|
+
allow(connection).to receive(:index_name).with('models', column: 'network_id') { }
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '.for_model' do
|
78
|
+
subject { described_class.for_model(model, old_table_name) }
|
79
|
+
|
80
|
+
it 'returns new object' do
|
81
|
+
expect(subject.size).to eq(1), subject.inspect
|
82
|
+
expect(subject.first).to be_kind_of(described_class)
|
83
|
+
expect(subject.first.foreign_key).to eq('network_id')
|
84
|
+
end
|
68
85
|
end
|
69
86
|
end
|
70
87
|
end
|
71
88
|
|
72
|
-
|
73
|
-
let(:connection) { instance_double(ActiveRecord::Base.connection.class) }
|
74
|
-
let(:model) { instance_double('Model', table_name: 'models', connection: connection) }
|
75
|
-
let(:old_table_name) { 'networks' }
|
89
|
+
context 'Using declare_schema' do
|
76
90
|
before do
|
77
|
-
|
78
|
-
|
79
|
-
|
91
|
+
load File.expand_path('../prepare_testapp.rb', __dir__)
|
92
|
+
|
93
|
+
class Network < ActiveRecord::Base
|
94
|
+
declare_schema do
|
95
|
+
string :name, limit: 127, index: true
|
96
|
+
|
97
|
+
timestamps
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'instance methods' do
|
103
|
+
let(:connection) { instance_double(ActiveRecord::Base.connection.class) }
|
104
|
+
let(:model) { instance_double('Model', table_name: 'models', connection: connection) }
|
105
|
+
let(:foreign_key) { :network_id }
|
106
|
+
let(:options) { {} }
|
107
|
+
subject { described_class.new(model, foreign_key, options)}
|
108
|
+
|
109
|
+
before do
|
110
|
+
allow(connection).to receive(:index_name).with('models', column: 'network_id') { 'on_network_id' }
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#initialize' do
|
114
|
+
it 'normalizes symbols to strings' do
|
115
|
+
expect(subject.foreign_key).to eq('network_id')
|
116
|
+
expect(subject.parent_table_name).to eq('networks')
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'when most options passed' do
|
120
|
+
let(:options) { { parent_table: :networks, foreign_key: :the_network_id, index_name: :index_on_network_id } }
|
121
|
+
|
122
|
+
it 'normalizes symbols to strings' do
|
123
|
+
expect(subject.foreign_key).to eq('network_id')
|
124
|
+
expect(subject.foreign_key_name).to eq('the_network_id')
|
125
|
+
expect(subject.parent_table_name).to eq('networks')
|
126
|
+
expect(subject.foreign_key).to eq('network_id')
|
127
|
+
expect(subject.constraint_name).to eq('index_on_network_id')
|
128
|
+
expect(subject.on_delete_cascade).to be_falsey
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when all options passed' do
|
133
|
+
let(:foreign_key) { nil }
|
134
|
+
let(:options) { { parent_table: :networks, foreign_key: :the_network_id, index_name: :index_on_network_id,
|
135
|
+
constraint_name: :constraint_1, dependent: :delete } }
|
136
|
+
|
137
|
+
it 'normalizes symbols to strings' do
|
138
|
+
expect(subject.foreign_key).to be_nil
|
139
|
+
expect(subject.foreign_key_name).to eq('the_network_id')
|
140
|
+
expect(subject.parent_table_name).to eq('networks')
|
141
|
+
expect(subject.constraint_name).to eq('constraint_1')
|
142
|
+
expect(subject.on_delete_cascade).to be_truthy
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
80
146
|
end
|
81
147
|
|
82
|
-
describe '
|
83
|
-
|
148
|
+
describe 'class << self' do
|
149
|
+
let(:connection) { instance_double(ActiveRecord::Base.connection.class) }
|
150
|
+
let(:model) { instance_double('Model', table_name: 'models', connection: connection) }
|
151
|
+
let(:old_table_name) { 'networks' }
|
152
|
+
before do
|
153
|
+
allow(connection).to receive(:quote_table_name).with('networks') { 'networks' }
|
154
|
+
allow(connection).to receive(:select_rows) { [['CONSTRAINT `constraint` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`)']] }
|
155
|
+
allow(connection).to receive(:index_name).with('models', column: 'network_id') { }
|
156
|
+
end
|
84
157
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
158
|
+
describe '.for_model' do
|
159
|
+
subject { described_class.for_model(model, old_table_name) }
|
160
|
+
|
161
|
+
it 'returns new object' do
|
162
|
+
expect(subject.size).to eq(1), subject.inspect
|
163
|
+
expect(subject.first).to be_kind_of(described_class)
|
164
|
+
expect(subject.first.foreign_key).to eq('network_id')
|
165
|
+
end
|
89
166
|
end
|
90
167
|
end
|
91
168
|
end
|
@@ -88,13 +88,13 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
88
88
|
|
89
89
|
describe '#primary_key' do
|
90
90
|
it 'returns false' do
|
91
|
-
expect(subject.
|
91
|
+
expect(subject._defined_primary_key).to eq(false)
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
describe '#
|
95
|
+
describe '#_defined_primary_key' do
|
96
96
|
it 'returns false' do
|
97
|
-
expect(subject.
|
97
|
+
expect(subject._defined_primary_key).to eq(false)
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
@@ -10,119 +10,230 @@ require_relative '../../../../lib/declare_schema/model/index_definition'
|
|
10
10
|
# unless you manually create any Sqlite tables with UNIQUE constraints.
|
11
11
|
|
12
12
|
RSpec.describe DeclareSchema::Model::IndexDefinition do
|
13
|
-
|
14
|
-
|
13
|
+
let(:model_class) { IndexDefinitionTestModel }
|
14
|
+
|
15
|
+
context 'Using fields' do
|
16
|
+
before do
|
17
|
+
load File.expand_path('../prepare_testapp.rb', __dir__)
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
class IndexDefinitionTestModel < ActiveRecord::Base
|
20
|
+
fields do
|
21
|
+
name :string, limit: 127, index: true
|
19
22
|
|
20
|
-
|
23
|
+
timestamps
|
24
|
+
end
|
21
25
|
end
|
22
|
-
end
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
class IndexDefinitionCompoundIndexModel < ActiveRecord::Base
|
28
|
+
fields do
|
29
|
+
fk1_id :integer
|
30
|
+
fk2_id :integer
|
28
31
|
|
29
|
-
|
32
|
+
timestamps
|
33
|
+
end
|
30
34
|
end
|
31
35
|
end
|
32
|
-
end
|
33
36
|
|
34
|
-
|
37
|
+
describe 'instance methods' do
|
38
|
+
let(:model) { model_class.new }
|
39
|
+
subject { declared_class.new(model_class) }
|
35
40
|
|
36
|
-
|
37
|
-
|
38
|
-
|
41
|
+
it 'has index_definitions' do
|
42
|
+
expect(model_class.index_definitions).to be_kind_of(Array)
|
43
|
+
expect(model_class.index_definitions.map(&:name)).to eq(['on_name'])
|
44
|
+
expect([:name, :fields, :unique].map { |attr| model_class.index_definitions[0].send(attr)}).to eq(
|
45
|
+
['on_name', ['name'], false]
|
46
|
+
)
|
47
|
+
end
|
39
48
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
[
|
45
|
-
|
49
|
+
it 'has index_definitions_with_primary_key' do
|
50
|
+
expect(model_class.index_definitions_with_primary_key).to be_kind_of(Array)
|
51
|
+
result = model_class.index_definitions_with_primary_key.sort_by(&:name)
|
52
|
+
expect(result.map(&:name)).to eq(['PRIMARY', 'on_name'])
|
53
|
+
expect([:name, :fields, :unique].map { |attr| result[0].send(attr)}).to eq(
|
54
|
+
['PRIMARY', ['id'], true]
|
55
|
+
)
|
56
|
+
expect([:name, :fields, :unique].map { |attr| result[1].send(attr)}).to eq(
|
57
|
+
['on_name', ['name'], false]
|
58
|
+
)
|
59
|
+
end
|
46
60
|
end
|
47
61
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
62
|
+
describe 'class methods' do
|
63
|
+
describe 'index_name' do
|
64
|
+
it 'works with a single column' do
|
65
|
+
expect(described_class.index_name('parent_id')).to eq('on_parent_id')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'works with many columns' do
|
69
|
+
expect(described_class.index_name(['a', 'b', 'c'])).to eq('on_a_and_b_and_c')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with a migrated database' do
|
74
|
+
before do
|
75
|
+
ActiveRecord::Base.connection.execute <<~EOS
|
76
|
+
CREATE TABLE index_definition_test_models (
|
77
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
78
|
+
name #{if defined?(Sqlite3) then 'TEXT' else 'VARCHAR(255)' end} NOT NULL
|
79
|
+
)
|
80
|
+
EOS
|
81
|
+
ActiveRecord::Base.connection.execute <<~EOS
|
82
|
+
CREATE UNIQUE INDEX index_definition_test_models_on_name ON index_definition_test_models(name)
|
83
|
+
EOS
|
84
|
+
ActiveRecord::Base.connection.execute <<~EOS
|
85
|
+
CREATE TABLE index_definition_compound_index_models (
|
86
|
+
fk1_id INTEGER NOT NULL,
|
87
|
+
fk2_id INTEGER NOT NULL,
|
88
|
+
PRIMARY KEY (fk1_id, fk2_id)
|
89
|
+
)
|
90
|
+
EOS
|
91
|
+
ActiveRecord::Base.connection.schema_cache.clear!
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'for_model' do
|
95
|
+
subject { described_class.for_model(model_class) }
|
96
|
+
|
97
|
+
context 'with single-column PK' do
|
98
|
+
it 'returns the indexes for the model' do
|
99
|
+
expect(subject.size).to eq(2), subject.inspect
|
100
|
+
expect([:name, :columns, :unique].map { |attr| subject[0].send(attr) }).to eq(
|
101
|
+
['index_definition_test_models_on_name', ['name'], true]
|
102
|
+
)
|
103
|
+
expect([:name, :columns, :unique].map { |attr| subject[1].send(attr) }).to eq(
|
104
|
+
['PRIMARY', ['id'], true]
|
105
|
+
)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'with compound-column PK' do
|
110
|
+
let(:model_class) { IndexDefinitionCompoundIndexModel }
|
111
|
+
|
112
|
+
it 'returns the indexes for the model' do
|
113
|
+
if Rails::VERSION::MAJOR < 5
|
114
|
+
expect(model_class.connection).to receive(:primary_key).with('index_definition_compound_index_models').and_return(nil)
|
115
|
+
connection_stub = instance_double(ActiveRecord::Base.connection.class, "connection")
|
116
|
+
expect(connection_stub).to receive(:indexes).
|
117
|
+
with('index_definition_compound_index_models').
|
118
|
+
and_return([DeclareSchema::Model::IndexDefinition.new(model_class, ['fk1_id', 'fk2_id'], name: 'PRIMARY')])
|
119
|
+
|
120
|
+
expect(model_class.connection).to receive(:dup).and_return(connection_stub)
|
121
|
+
end
|
122
|
+
|
123
|
+
expect(subject.size).to eq(1), subject.inspect
|
124
|
+
expect([:name, :columns, :unique].map { |attr| subject[0].send(attr) }).to eq(
|
125
|
+
['PRIMARY', ['fk1_id', 'fk2_id'], true]
|
126
|
+
)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
58
131
|
end
|
59
132
|
end
|
60
133
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
134
|
+
context 'Using declare_schema' do
|
135
|
+
before do
|
136
|
+
load File.expand_path('../prepare_testapp.rb', __dir__)
|
137
|
+
|
138
|
+
class IndexDefinitionTestModel < ActiveRecord::Base
|
139
|
+
declare_schema do
|
140
|
+
string :name, limit: 127, index: true
|
141
|
+
|
142
|
+
timestamps
|
143
|
+
end
|
65
144
|
end
|
66
145
|
|
67
|
-
|
68
|
-
|
146
|
+
class IndexDefinitionCompoundIndexModel < ActiveRecord::Base
|
147
|
+
declare_schema do
|
148
|
+
integer :fk1_id
|
149
|
+
integer :fk2_id
|
150
|
+
|
151
|
+
timestamps
|
152
|
+
end
|
69
153
|
end
|
70
154
|
end
|
71
155
|
|
72
|
-
|
73
|
-
|
74
|
-
|
156
|
+
describe 'instance methods' do
|
157
|
+
let(:model) { model_class.new }
|
158
|
+
subject { declared_class.new(model_class) }
|
159
|
+
|
160
|
+
it 'has index_definitions' do
|
161
|
+
expect(model_class.index_definitions).to be_kind_of(Array)
|
162
|
+
expect(model_class.index_definitions.map(&:name)).to eq(['on_name'])
|
163
|
+
expect([:name, :fields, :unique].map { |attr| model_class.index_definitions[0].send(attr)}).to eq(
|
164
|
+
['on_name', ['name'], false]
|
165
|
+
)
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'has index_definitions_with_primary_key' do
|
169
|
+
expect(model_class.index_definitions_with_primary_key).to be_kind_of(Array)
|
170
|
+
result = model_class.index_definitions_with_primary_key.sort_by(&:name)
|
171
|
+
expect(result.map(&:name)).to eq(['PRIMARY', 'on_name'])
|
172
|
+
expect([:name, :fields, :unique].map { |attr| result[0].send(attr)}).to eq(
|
173
|
+
['PRIMARY', ['id'], true]
|
174
|
+
)
|
175
|
+
expect([:name, :fields, :unique].map { |attr| result[1].send(attr)}).to eq(
|
176
|
+
['on_name', ['name'], false]
|
177
|
+
)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe 'class << self' do
|
182
|
+
context 'with a migrated database' do
|
183
|
+
before do
|
184
|
+
ActiveRecord::Base.connection.execute <<~EOS
|
75
185
|
CREATE TABLE index_definition_test_models (
|
76
186
|
id INTEGER NOT NULL PRIMARY KEY,
|
77
187
|
name #{if defined?(Sqlite3) then 'TEXT' else 'VARCHAR(255)' end} NOT NULL
|
78
188
|
)
|
79
|
-
|
80
|
-
|
189
|
+
EOS
|
190
|
+
ActiveRecord::Base.connection.execute <<~EOS
|
81
191
|
CREATE UNIQUE INDEX index_definition_test_models_on_name ON index_definition_test_models(name)
|
82
|
-
|
83
|
-
|
192
|
+
EOS
|
193
|
+
ActiveRecord::Base.connection.execute <<~EOS
|
84
194
|
CREATE TABLE index_definition_compound_index_models (
|
85
195
|
fk1_id INTEGER NOT NULL,
|
86
196
|
fk2_id INTEGER NOT NULL,
|
87
197
|
PRIMARY KEY (fk1_id, fk2_id)
|
88
198
|
)
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
describe 'for_model' do
|
94
|
-
subject { described_class.for_model(model_class) }
|
199
|
+
EOS
|
200
|
+
ActiveRecord::Base.connection.schema_cache.clear!
|
201
|
+
end
|
95
202
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
203
|
+
describe 'for_model' do
|
204
|
+
subject { described_class.for_model(model_class) }
|
205
|
+
|
206
|
+
context 'with single-column PK' do
|
207
|
+
it 'returns the indexes for the model' do
|
208
|
+
expect(subject.size).to eq(2), subject.inspect
|
209
|
+
expect([:name, :columns, :unique].map { |attr| subject[0].send(attr) }).to eq(
|
210
|
+
['index_definition_test_models_on_name', ['name'], true]
|
211
|
+
)
|
212
|
+
expect([:name, :columns, :unique].map { |attr| subject[1].send(attr) }).to eq(
|
213
|
+
['PRIMARY', ['id'], true]
|
214
|
+
)
|
215
|
+
end
|
105
216
|
end
|
106
|
-
end
|
107
217
|
|
108
|
-
|
109
|
-
|
218
|
+
context 'with compound-column PK' do
|
219
|
+
let(:model_class) { IndexDefinitionCompoundIndexModel }
|
110
220
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
221
|
+
it 'returns the indexes for the model' do
|
222
|
+
if Rails::VERSION::MAJOR < 5
|
223
|
+
expect(model_class.connection).to receive(:primary_key).with('index_definition_compound_index_models').and_return(nil)
|
224
|
+
connection_stub = instance_double(ActiveRecord::Base.connection.class, "connection")
|
225
|
+
expect(connection_stub).to receive(:indexes).
|
226
|
+
with('index_definition_compound_index_models').
|
227
|
+
and_return([DeclareSchema::Model::IndexDefinition.new(model_class, ['fk1_id', 'fk2_id'], name: 'PRIMARY')])
|
118
228
|
|
119
|
-
|
120
|
-
|
229
|
+
expect(model_class.connection).to receive(:dup).and_return(connection_stub)
|
230
|
+
end
|
121
231
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
232
|
+
expect(subject.size).to eq(1), subject.inspect
|
233
|
+
expect([:name, :columns, :unique].map { |attr| subject[0].send(attr) }).to eq(
|
234
|
+
['PRIMARY', ['fk1_id', 'fk2_id'], true]
|
235
|
+
)
|
236
|
+
end
|
126
237
|
end
|
127
238
|
end
|
128
239
|
end
|