declare_schema 1.4.0.colin.6 → 1.4.0.colin.8

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.
@@ -11,6 +11,7 @@ require_relative '../../../../lib/declare_schema/model/index_definition'
11
11
 
12
12
  RSpec.describe DeclareSchema::Model::IndexDefinition do
13
13
  let(:model_class) { IndexDefinitionTestModel }
14
+ let(:table_name) { model_class.table_name }
14
15
 
15
16
  context 'Using declare_schema' do
16
17
  before do
@@ -34,23 +35,19 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
34
35
  end
35
36
  end
36
37
 
38
+ # TODO: create model_spec.rb and move the Model specs below into it. -Colin
37
39
  describe 'instance methods' do
38
40
  let(:model) { model_class.new }
41
+ let(:table_name) { "index_definition_test_models" }
39
42
  let(:fields) { ['last_name', 'first_name'] }
40
- let(:options) { {} }
41
- subject(:instance) { described_class.new(model_class, fields, **options) }
43
+ let(:options) { { table_name: table_name } }
44
+ subject(:instance) { described_class.new(fields, **options) }
42
45
 
43
46
  describe 'attr_readers' do
44
- describe '#table' do
45
- subject { instance.table }
47
+ describe '#table_name' do
48
+ subject { instance.table_name }
46
49
 
47
- it { is_expected.to eq(model_class.table_name) }
48
-
49
- context 'with table_name option' do
50
- let(:options) { { table_name: 'auth_users' } }
51
-
52
- it { is_expected.to eq('auth_users') }
53
- end
50
+ it { is_expected.to eq(table_name) }
54
51
  end
55
52
 
56
53
  describe '#fields' do
@@ -62,18 +59,22 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
62
59
  describe '#explicit_name' do
63
60
  subject { instance.explicit_name }
64
61
 
65
- it { is_expected.to eq(nil) }
62
+ context 'with allow_equivalent' do
63
+ let(:options) { { table_name: table_name, allow_equivalent: true } }
64
+
65
+ it { is_expected.to eq(nil) }
66
+ end
66
67
 
67
68
  context 'with name option' do
68
- let(:options) { { name: 'index_auth_users_on_last_name_and_first_name' } }
69
+ let(:options) { { table_name: table_name, name: 'index_auth_users_on_names' } }
69
70
 
70
- it { is_expected.to eq('index_auth_users_on_last_name_and_first_name') }
71
+ it { is_expected.to eq('index_auth_users_on_names') }
71
72
  end
72
73
  end
73
74
 
74
75
  describe '#length' do
75
76
  subject { instance.length }
76
- let(:options) { { length: length } }
77
+ let(:options) { { table_name: table_name, length: length } }
77
78
 
78
79
  context 'with integer length' do
79
80
  let(:length) { 2 }
@@ -90,9 +91,9 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
90
91
 
91
92
  describe '#options' do
92
93
  subject { instance.options }
93
- let(:options) { { name: 'my_index', unique: false, where: "(name like 'a%')", length: 10 } }
94
+ let(:options) { { name: 'my_index', table_name: table_name, unique: false, where: "(name like 'a%')", length: 10 } }
94
95
 
95
- it { is_expected.to eq(options) }
96
+ it { is_expected.to eq(options.except(:table_name)) }
96
97
  end
97
98
 
98
99
  describe '#with_name' do
@@ -105,33 +106,25 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
105
106
  end
106
107
  end
107
108
 
108
- describe 'class methods' do
109
- let(:model) { model_class.new }
110
-
111
- describe 'index_definitions' do
112
- it do
113
- expect(model_class.index_definitions.size).to eq(1)
109
+ describe 'Model class methods' do
110
+ describe '.has index_definitions' do
111
+ subject { model_class.index_definitions }
114
112
 
115
- sample = model_class.index_definitions.to_a.first
116
- expect(sample.name).to eq('index_index_definition_test_models_on_name')
117
- expect(sample.fields).to eq(['name'])
118
- expect(sample.unique).to eq(false)
113
+ it 'returns indexes without primary key' do
114
+ expect(subject.map(&:to_key)).to eq([
115
+ ['index_index_definition_test_models_on_name', ['name'], { length: nil, unique: false, where: nil }],
116
+ ])
119
117
  end
120
118
  end
121
119
 
122
- describe 'has index_definitions_with_primary_key' do
123
- it do
124
- expect(model_class.index_definitions_with_primary_key).to be_kind_of(Set)
125
- result = model_class.index_definitions_with_primary_key.sort_by(&:name)
126
- expect(result.size).to eq(2)
120
+ describe '.has index_definitions_with_primary_key' do
121
+ subject { model_class.index_definitions_with_primary_key }
127
122
 
128
- expect(result[0].name).to eq('PRIMARY')
129
- expect(result[0].fields).to eq(['id'])
130
- expect(result[0].unique).to eq(true)
131
-
132
- expect(result[1].name).to eq('index_index_definition_test_models_on_name')
133
- expect(result[1].fields).to eq(['name'])
134
- expect(result[1].unique).to eq(false)
123
+ it 'returns indexes with primary key' do
124
+ expect(subject.map(&:to_key)).to eq([
125
+ ['index_index_definition_test_models_on_name', ['name'], { length: nil, unique: false, where: nil }],
126
+ ['PRIMARY', ['id'], { length: nil, unique: true, where: nil }],
127
+ ])
135
128
  end
136
129
  end
137
130
  end
@@ -147,6 +140,11 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
147
140
  ActiveRecord::Base.connection.execute <<~EOS
148
141
  CREATE UNIQUE INDEX index_definition_test_models_on_name ON index_definition_test_models(name)
149
142
  EOS
143
+ if defined?(Mysql2)
144
+ ActiveRecord::Base.connection.execute <<~EOS
145
+ CREATE INDEX index_definition_test_models_on_name_partial ON index_definition_test_models(name(10))
146
+ EOS
147
+ end
150
148
  ActiveRecord::Base.connection.execute <<~EOS
151
149
  CREATE TABLE index_definition_compound_index_models (
152
150
  fk1_id INTEGER NOT NULL,
@@ -157,29 +155,38 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
157
155
  ActiveRecord::Base.connection.schema_cache.clear!
158
156
  end
159
157
 
160
- describe 'for_model' do
161
- subject { described_class.for_model(model_class) }
158
+ describe 'for_table' do
159
+ let(:ignore_indexes) { model_class.ignore_indexes }
160
+ subject { described_class.for_table(model_class.table_name, ignore_indexes, model_class.connection) }
162
161
 
163
162
  context 'with single-column PK' do
164
163
  it 'returns the indexes for the model' do
165
- expect(subject.size).to eq(2), subject.inspect
166
- expect(subject[0].name).to eq('index_definition_test_models_on_name')
167
- expect(subject[0].columns).to eq(['name'])
168
- expect(subject[0].unique).to eq(true)
169
- expect(subject[1].name).to eq('PRIMARY')
170
- expect(subject[1].columns).to eq(['id'])
171
- expect(subject[1].unique).to eq(true)
164
+ expect(subject.map(&:to_key)).to eq([
165
+ ["index_definition_test_models_on_name", ["name"], { unique: true, where: nil, length: nil }],
166
+ (["index_definition_test_models_on_name_partial", ["name"], { unique: false, where: nil, length: 10 }] if defined?(Mysql2)),
167
+ ["PRIMARY", ["id"], { unique: true, where: nil, length: nil }]
168
+ ].compact)
172
169
  end
173
170
  end
174
171
 
175
- context 'with compound-column PK' do
172
+ context 'with composite (multi-column) PK' do
176
173
  let(:model_class) { IndexDefinitionCompoundIndexModel }
177
174
 
178
175
  it 'returns the indexes for the model' do
179
- expect(subject.size).to eq(1), subject.inspect
180
- expect(subject[0].name).to eq('PRIMARY')
181
- expect(subject[0].columns).to eq(['fk1_id', 'fk2_id'])
182
- expect(subject[0].unique).to eq(true)
176
+ expect(subject.map(&:to_key)).to eq([
177
+ ["PRIMARY", ["fk1_id", "fk2_id"], { length: nil, unique: true, where: nil }]
178
+ ])
179
+ end
180
+ end
181
+
182
+ context 'with ignored_indexes' do
183
+ let(:ignore_indexes) { ['index_definition_test_models_on_name'] }
184
+
185
+ it 'skips the ignored index' do
186
+ expect(subject.map(&:to_key)).to eq([
187
+ (["index_definition_test_models_on_name_partial", ["name"], { unique: false, where: nil, length: 10 }] if defined?(Mysql2)),
188
+ ["PRIMARY", ["id"], { length: nil, unique: true, where: nil }]
189
+ ].compact)
183
190
  end
184
191
  end
185
192
  end
@@ -9,6 +9,8 @@ require_relative '../../../../lib/declare_schema/model/table_options_definition'
9
9
 
10
10
  RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
11
11
  let(:model_class) { TableOptionsDefinitionTestModel }
12
+ let(:charset) { DeclareSchema.normalize_charset('utf8') }
13
+ let(:collation) { DeclareSchema.normalize_collation('utf8_general') } # adapt so that tests will pass on MySQL 5.7 or 8+
12
14
 
13
15
  context 'Using declare_schema' do
14
16
  before do
@@ -27,27 +29,45 @@ RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
27
29
 
28
30
  describe '#to_key' do
29
31
  subject { model.to_key }
30
- it { should eq(['table_options_definition_test_models', '{:charset=>"utf8", :collation=>"utf8_general"}']) }
32
+ it { is_expected.to eq(['table_options_definition_test_models', "{:charset=>#{charset.inspect}, :collation=>#{collation.inspect}}"]) }
31
33
  end
32
34
 
33
35
  describe '#settings' do
34
36
  subject { model.settings }
35
- it { should eq("CHARACTER SET utf8 COLLATE utf8_general") }
37
+ it { is_expected.to eq("CHARACTER SET #{charset} COLLATE #{collation}") }
38
+
39
+ if defined?(Mysql2)
40
+ context 'when running in MySQL 8' do
41
+ around do |spec|
42
+ DeclareSchema.mysql_version = Gem::Version.new('8.0.21')
43
+ spec.run
44
+ ensure
45
+ DeclareSchema.remove_instance_variable('@mysql_version') rescue nil
46
+ end
47
+
48
+ it { is_expected.to eq("CHARACTER SET utf8mb3 COLLATE utf8mb3_general") }
49
+
50
+ context 'when _ci collation' do
51
+ let(:table_options) { { charset: "utf8", collation: "utf8_general_ci"} }
52
+ it { is_expected.to eq("CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci") }
53
+ end
54
+ end
55
+ end
36
56
  end
37
57
 
38
58
  describe '#hash' do
39
59
  subject { model.hash }
40
- it { should eq(['table_options_definition_test_models', '{:charset=>"utf8", :collation=>"utf8_general"}'].hash) }
60
+ it { is_expected.to eq(['table_options_definition_test_models', "{:charset=>#{charset.inspect}, :collation=>#{collation.inspect}}"].hash) }
41
61
  end
42
62
 
43
63
  describe '#to_s' do
44
64
  subject { model.to_s }
45
- it { should eq("CHARACTER SET utf8 COLLATE utf8_general") }
65
+ it { is_expected.to eq("CHARACTER SET #{charset} COLLATE #{collation}") }
46
66
  end
47
67
 
48
68
  describe '#alter_table_statement' do
49
69
  subject { model.alter_table_statement }
50
- it { should match(/execute "ALTER TABLE .*table_options_definition_test_models.* CHARACTER SET utf8 COLLATE utf8_general"/) }
70
+ it { is_expected.to match(/execute "ALTER TABLE .*table_options_definition_test_models.* CHARACTER SET #{charset} COLLATE #{collation}"/) }
51
71
  end
52
72
  end
53
73
 
@@ -67,7 +87,7 @@ RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
67
87
  generate_migrations '-n', '-m'
68
88
  end
69
89
 
70
- it { should eq(described_class.new(model_class.table_name, **options)) }
90
+ it { is_expected.to eq(described_class.new(model_class.table_name, **options)) }
71
91
  end
72
92
  end
73
93
  end
@@ -8,10 +8,34 @@ RSpec.describe DeclareSchema do
8
8
  it { is_expected.to eq("utf8mb4") }
9
9
  end
10
10
 
11
- context 'when explicitly set' do
12
- before { described_class.default_charset = "utf8" }
13
- after { described_class.default_charset = "utf8mb4" }
14
- it { is_expected.to eq("utf8") }
11
+ context 'when running on MySQL 5.7' do
12
+ around do |spec|
13
+ described_class.mysql_version = Gem::Version.new('5.7.48')
14
+ spec.run
15
+ ensure
16
+ described_class.remove_instance_variable('@mysql_version') rescue nil
17
+ end
18
+
19
+ context 'when explicitly set' do
20
+ before { described_class.default_charset = "utf8" }
21
+ after { described_class.default_charset = "utf8mb4" }
22
+ it { is_expected.to eq("utf8") }
23
+ end
24
+ end
25
+
26
+ context 'when running on MySQL 8.0' do
27
+ around do |spec|
28
+ described_class.mysql_version = Gem::Version.new('8.0.21')
29
+ spec.run
30
+ ensure
31
+ described_class.remove_instance_variable('@mysql_version') rescue nil
32
+ end
33
+
34
+ context 'when explicitly set' do
35
+ before { described_class.default_charset = "utf8" }
36
+ after { described_class.default_charset = "utf8mb4" }
37
+ it { is_expected.to eq("utf8mb3") }
38
+ end
15
39
  end
16
40
  end
17
41
 
@@ -22,10 +46,40 @@ RSpec.describe DeclareSchema do
22
46
  it { is_expected.to eq("utf8mb4_bin") }
23
47
  end
24
48
 
25
- context 'when explicitly set' do
26
- before { described_class.default_collation = "utf8mb4_general_ci" }
27
- after { described_class.default_collation = "utf8mb4_bin" }
28
- it { is_expected.to eq("utf8mb4_general_ci") }
49
+ context 'when running on MySQL 5.7' do
50
+ around do |spec|
51
+ described_class.mysql_version = Gem::Version.new('5.7.48')
52
+ spec.run
53
+ ensure
54
+ described_class.remove_instance_variable('@mysql_version')
55
+ end
56
+
57
+ context 'when explicitly set' do
58
+ before { described_class.default_collation = "utf8_general_ci" }
59
+ after { described_class.default_collation = "utf8mb4_bin" }
60
+ it { is_expected.to eq("utf8_general_ci") }
61
+ end
62
+ end
63
+
64
+ context 'when running on MySQL 8.0' do
65
+ around do |spec|
66
+ described_class.mysql_version = Gem::Version.new('8.0.21')
67
+ spec.run
68
+ ensure
69
+ described_class.remove_instance_variable('@mysql_version')
70
+ end
71
+
72
+ context 'when explicitly set without _ci' do
73
+ before { described_class.default_collation = "utf8_general" }
74
+ after { described_class.default_collation = "utf8mb4_bin" }
75
+ it { is_expected.to eq("utf8mb3_general") }
76
+ end
77
+
78
+ context 'when explicitly set with _ci' do
79
+ before { described_class.default_collation = "utf8_general_ci" }
80
+ after { described_class.default_collation = "utf8mb4_bin" }
81
+ it { is_expected.to eq("utf8mb3_general_ci") }
82
+ end
29
83
  end
30
84
  end
31
85
 
@@ -12,6 +12,8 @@ module Generators
12
12
  module Migration
13
13
  RSpec.describe Migrator do
14
14
  subject { described_class.new }
15
+ let(:charset) { ::DeclareSchema.normalize_charset('utf8') }
16
+ let(:collation) { ::DeclareSchema.normalize_collation('utf8_general') } # adapt so that tests will pass on MySQL 5.7 or 8+
15
17
 
16
18
  describe '#before_generating_migration' do
17
19
  it 'requires a block be passed' do
@@ -29,7 +31,7 @@ module Generators
29
31
  context 'when explicitly set' do
30
32
  before { described_class.default_charset = "utf8" }
31
33
  after { described_class.default_charset = "utf8mb4" }
32
- it { should eq("utf8") }
34
+ it { should eq(charset) }
33
35
  end
34
36
 
35
37
  it 'should output deprecation warning' do
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/setup"
4
- require "declare_schema"
5
- require "climate_control"
3
+ require 'bundler/setup'
4
+ require 'declare_schema'
5
+ require 'climate_control'
6
+ require 'pry'
6
7
 
7
8
  require_relative "./support/acceptance_spec_helpers"
8
9
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: declare_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0.colin.6
4
+ version: 1.4.0.colin.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Invoca Development adapted from hobo_fields by Tom Locke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-16 00:00:00.000000000 Z
11
+ date: 2024-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails