declare_schema 1.4.0.colin.7 → 1.4.0.colin.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +4 -1
- data/lib/declare_schema/model/field_spec.rb +2 -0
- data/lib/declare_schema/model/foreign_key_definition.rb +39 -43
- data/lib/declare_schema/model/habtm_model_shim.rb +18 -25
- data/lib/declare_schema/model/index_definition.rb +43 -30
- data/lib/declare_schema/model/table_options_definition.rb +11 -1
- data/lib/declare_schema/model.rb +48 -36
- data/lib/declare_schema/version.rb +1 -1
- data/lib/declare_schema.rb +34 -2
- data/lib/generators/declare_schema/migration/migrator.rb +16 -10
- data/spec/lib/declare_schema/field_spec_spec.rb +22 -2
- data/spec/lib/declare_schema/migration_generator_spec.rb +17 -35
- data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +28 -27
- data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +54 -57
- data/spec/lib/declare_schema/model/index_definition_spec.rb +60 -53
- data/spec/lib/declare_schema/model/table_options_definition_spec.rb +26 -6
- data/spec/lib/declare_schema_spec.rb +62 -8
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +3 -1
- data/spec/spec_helper.rb +4 -3
- metadata +2 -2
data/lib/declare_schema.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'active_support'
|
4
4
|
require 'active_support/all'
|
5
5
|
require_relative 'declare_schema/version'
|
6
|
+
require 'rubygems/version'
|
6
7
|
|
7
8
|
ActiveSupport::Dependencies.autoload_paths |= [__dir__]
|
8
9
|
|
@@ -21,6 +22,8 @@ module DeclareSchema
|
|
21
22
|
text: String
|
22
23
|
}.freeze
|
23
24
|
|
25
|
+
SEMVER_8 = Gem::Version.new('8.0.0').freeze
|
26
|
+
|
24
27
|
@default_charset = "utf8mb4"
|
25
28
|
@default_collation = "utf8mb4_bin"
|
26
29
|
@default_text_limit = 0xffff_ffff
|
@@ -32,6 +35,7 @@ module DeclareSchema
|
|
32
35
|
@max_index_and_constraint_name_length = 64 # limit for MySQL
|
33
36
|
|
34
37
|
class << self
|
38
|
+
attr_writer :mysql_version
|
35
39
|
attr_reader :default_charset, :default_collation, :default_text_limit, :default_string_limit, :default_null,
|
36
40
|
:default_generate_foreign_keys, :default_generate_indexing, :db_migrate_command,
|
37
41
|
:max_index_and_constraint_name_length
|
@@ -47,14 +51,42 @@ module DeclareSchema
|
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
54
|
+
def mysql_version
|
55
|
+
if defined?(@mysql_version)
|
56
|
+
@mysql_version
|
57
|
+
else
|
58
|
+
@mysql_version =
|
59
|
+
if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
|
60
|
+
version_string = ActiveRecord::Base.connection.select_value('SELECT VERSION()')
|
61
|
+
Gem::Version.new(version_string)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def normalize_charset(charset)
|
67
|
+
if mysql_version && mysql_version >= SEMVER_8 && charset == 'utf8'
|
68
|
+
'utf8mb3'
|
69
|
+
else
|
70
|
+
charset
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def normalize_collation(collation)
|
75
|
+
if mysql_version && mysql_version >= SEMVER_8
|
76
|
+
collation.sub(/\Autf8_/, 'utf8mb3_')
|
77
|
+
else
|
78
|
+
collation
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
50
82
|
def default_charset=(charset)
|
51
83
|
charset.is_a?(String) or raise ArgumentError, "charset must be a string (got #{charset.inspect})"
|
52
|
-
@default_charset = charset
|
84
|
+
@default_charset = normalize_charset(charset)
|
53
85
|
end
|
54
86
|
|
55
87
|
def default_collation=(collation)
|
56
88
|
collation.is_a?(String) or raise ArgumentError, "collation must be a string (got #{collation.inspect})"
|
57
|
-
@default_collation = collation
|
89
|
+
@default_collation = normalize_collation(collation)
|
58
90
|
end
|
59
91
|
|
60
92
|
def default_text_limit=(text_limit)
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'active_record'
|
4
4
|
require 'active_record/connection_adapters/abstract_adapter'
|
5
5
|
require 'declare_schema/schema_change/all'
|
6
|
+
require_relative '../../../declare_schema/model/habtm_model_shim'
|
6
7
|
|
7
8
|
module Generators
|
8
9
|
module DeclareSchema
|
@@ -335,9 +336,9 @@ module Generators
|
|
335
336
|
end
|
336
337
|
|
337
338
|
def create_constraints(model)
|
338
|
-
model.
|
339
|
+
model.constraint_definitions.map do |fk|
|
339
340
|
::DeclareSchema::SchemaChange::ForeignKeyAdd.new(fk.child_table_name, fk.parent_table_name,
|
340
|
-
column_name: fk.
|
341
|
+
column_name: fk.foreign_key_column, name: fk.constraint_name)
|
341
342
|
end
|
342
343
|
end
|
343
344
|
|
@@ -425,7 +426,7 @@ module Generators
|
|
425
426
|
::DeclareSchema.default_generate_indexing or return []
|
426
427
|
|
427
428
|
new_table_name = model.table_name
|
428
|
-
existing_indexes = ::DeclareSchema::Model::IndexDefinition.
|
429
|
+
existing_indexes = ::DeclareSchema::Model::IndexDefinition.for_table(old_table_name || new_table_name, model.ignore_indexes, model.connection)
|
429
430
|
model_indexes_with_equivalents = model.index_definitions_with_primary_key.to_a
|
430
431
|
model_indexes = model_indexes_with_equivalents.map do |i|
|
431
432
|
if i.explicit_name.nil?
|
@@ -485,8 +486,12 @@ module Generators
|
|
485
486
|
ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/) and raise ArgumentError, 'SQLite does not support foreign keys'
|
486
487
|
::DeclareSchema.default_generate_foreign_keys or return []
|
487
488
|
|
488
|
-
|
489
|
-
|
489
|
+
if model.is_a?(::DeclareSchema::Model::HabtmModelShim)
|
490
|
+
force_dependent_delete = :delete
|
491
|
+
end
|
492
|
+
|
493
|
+
existing_fks = ::DeclareSchema::Model::ForeignKeyDefinition.for_table(old_table_name || model.table_name, model.connection, dependent: force_dependent_delete)
|
494
|
+
model_fks = model.constraint_definitions.to_a
|
490
495
|
|
491
496
|
fks_to_drop = existing_fks - model_fks
|
492
497
|
fks_to_add = model_fks - existing_fks
|
@@ -495,13 +500,13 @@ module Generators
|
|
495
500
|
|
496
501
|
drop_fks = (fks_to_drop - renamed_fks_to_drop).map do |fk|
|
497
502
|
::DeclareSchema::SchemaChange::ForeignKeyRemove.new(fk.child_table_name, fk.parent_table_name,
|
498
|
-
column_name: fk.
|
503
|
+
column_name: fk.foreign_key_column, name: fk.constraint_name)
|
499
504
|
end
|
500
505
|
|
501
506
|
add_fks = (fks_to_add - renamed_fks_to_add).map do |fk|
|
502
507
|
# next if fk.parent.constantize.abstract_class || fk.parent == fk.model.class_name
|
503
508
|
::DeclareSchema::SchemaChange::ForeignKeyAdd.new(fk.child_table_name, fk.parent_table_name,
|
504
|
-
column_name: fk.
|
509
|
+
column_name: fk.foreign_key_column, name: fk.constraint_name)
|
505
510
|
end
|
506
511
|
|
507
512
|
[drop_fks + add_fks]
|
@@ -523,9 +528,8 @@ module Generators
|
|
523
528
|
end
|
524
529
|
|
525
530
|
def fk_field_options(model, field_name)
|
526
|
-
foreign_key = model.
|
527
|
-
|
528
|
-
parent_columns = connection.columns(parent_table) rescue []
|
531
|
+
if (foreign_key = model.constraint_definitions.find { |fk| field_name == fk.foreign_key_column })
|
532
|
+
parent_columns = connection.columns(foreign_key.parent_table_name) rescue []
|
529
533
|
pk_limit =
|
530
534
|
if (pk_column = parent_columns.find { |column| column.name.to_s == "id" }) # right now foreign keys assume id is the target
|
531
535
|
pk_column.limit
|
@@ -585,6 +589,8 @@ module Generators
|
|
585
589
|
case charset
|
586
590
|
when "utf8"
|
587
591
|
"utf8_general_ci"
|
592
|
+
when "utf8mb3"
|
593
|
+
"utf8mb3_general_ci"
|
588
594
|
when "utf8mb4"
|
589
595
|
"utf8mb4_general_ci"
|
590
596
|
end
|
@@ -5,6 +5,11 @@ begin
|
|
5
5
|
rescue LoadError
|
6
6
|
end
|
7
7
|
|
8
|
+
begin
|
9
|
+
require 'sqlite3'
|
10
|
+
rescue LoadError
|
11
|
+
end
|
12
|
+
|
8
13
|
RSpec.describe DeclareSchema::Model::FieldSpec do
|
9
14
|
let(:model) { double('model', _table_options: {}, _declared_primary_key: 'id') }
|
10
15
|
let(:col_spec) { double('col_spec', type: :string) }
|
@@ -58,8 +63,23 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
58
63
|
end
|
59
64
|
end
|
60
65
|
|
61
|
-
|
62
|
-
|
66
|
+
if defined?(Mysql2)
|
67
|
+
context 'when running on MySQL 8.0' do
|
68
|
+
around do |spec|
|
69
|
+
DeclareSchema.mysql_version = Gem::Version.new('8.0.21')
|
70
|
+
spec.run
|
71
|
+
ensure
|
72
|
+
DeclareSchema.remove_instance_variable('@mysql_version') rescue nil
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'normalizes charset and collation' do
|
76
|
+
subject = described_class.new(model, :title, :string, limit: 100, null: true, charset: 'utf8', collation: 'utf8_general', position: 0)
|
77
|
+
|
78
|
+
expect(subject.schema_attributes(col_spec)).to eq(type: :string, limit: 100, null: true, charset: 'utf8mb3', collation: 'utf8mb3_general')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'raises error when default_string_limit option is nil when not explicitly set in field spec' do
|
63
83
|
expect(::DeclareSchema).to receive(:default_string_limit) { nil }
|
64
84
|
expect do
|
65
85
|
described_class.new(model, :title, :string, null: true, charset: 'utf8mb4', position: 0)
|
@@ -391,6 +391,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
391
391
|
|
392
392
|
Advert.field_specs.delete(:c_id)
|
393
393
|
Advert.index_definitions.delete_if { |spec| spec.fields == ["c_id"] }
|
394
|
+
Advert.constraint_definitions.delete_if { |spec| spec.foreign_key_column == "c_id" }
|
394
395
|
|
395
396
|
# You can avoid generating the index by specifying `index: false`
|
396
397
|
|
@@ -403,13 +404,13 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
403
404
|
expect(Generators::DeclareSchema::Migration::Migrator.run).to(
|
404
405
|
migrate_up(<<~EOS.strip)
|
405
406
|
add_column :adverts, :category_id, :integer, limit: 8, null: false
|
406
|
-
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :index_adverts_on_category_id
|
407
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id" if defined?(Mysql2)}
|
407
|
+
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :index_adverts_on_category_id" if defined?(Mysql2)}
|
408
408
|
EOS
|
409
409
|
)
|
410
410
|
|
411
411
|
Advert.field_specs.delete(:category_id)
|
412
412
|
Advert.index_definitions.delete_if { |spec| spec.fields == ["category_id"] }
|
413
|
+
Advert.constraint_definitions.delete_if { |spec| spec.foreign_key_column == "category_id" }
|
413
414
|
|
414
415
|
# You can specify the index name with index: 'name' [deprecated]
|
415
416
|
|
@@ -425,13 +426,13 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
425
426
|
migrate_up(<<~EOS.strip)
|
426
427
|
add_column :adverts, :category_id, :integer, limit: 8, null: false
|
427
428
|
add_index :adverts, [:category_id], name: :my_index
|
428
|
-
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :
|
429
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id" if defined?(Mysql2)}
|
429
|
+
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :my_index" if defined?(Mysql2)}
|
430
430
|
EOS
|
431
431
|
)
|
432
432
|
|
433
433
|
Advert.field_specs.delete(:category_id)
|
434
434
|
Advert.index_definitions.delete_if { |spec| spec.fields == ["category_id"] }
|
435
|
+
Advert.constraint_definitions.delete_if { |spec| spec.foreign_key_column == "category_id" }
|
435
436
|
|
436
437
|
# You can specify the index name with index: { name: }'name', unique: true|false }
|
437
438
|
|
@@ -443,15 +444,15 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
443
444
|
|
444
445
|
expect(Generators::DeclareSchema::Migration::Migrator.run).to(
|
445
446
|
migrate_up(<<~EOS.strip)
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
EOS
|
447
|
+
add_column :adverts, :category_id, :integer, limit: 8, null: false
|
448
|
+
add_index :adverts, [:category_id], name: :my_index
|
449
|
+
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :my_index" if defined?(Mysql2)}
|
450
|
+
EOS
|
451
451
|
)
|
452
452
|
|
453
453
|
Advert.field_specs.delete(:category_id)
|
454
454
|
Advert.index_definitions.delete_if { |spec| spec.fields == ["category_id"] }
|
455
|
+
Advert.constraint_definitions.delete_if { |spec| spec.foreign_key_column == "category_id" }
|
455
456
|
|
456
457
|
### Timestamps and Optimimistic Locking
|
457
458
|
|
@@ -470,12 +471,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
470
471
|
add_column :adverts, :created_at, :datetime, null: true
|
471
472
|
add_column :adverts, :updated_at, :datetime, null: true
|
472
473
|
add_column :adverts, :lock_version, :integer#{lock_version_limit}, null: false, default: 1
|
473
|
-
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :index_adverts_on_category_id\n" +
|
474
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id" if defined?(Mysql2)}
|
475
474
|
EOS
|
476
475
|
.and migrate_down(<<~EOS.strip)
|
477
|
-
#{"remove_foreign_key :adverts, name: :index_adverts_on_c_id\n" +
|
478
|
-
"remove_foreign_key :adverts, name: :index_adverts_on_category_id" if defined?(Mysql2)}
|
479
476
|
remove_column :adverts, :lock_version
|
480
477
|
remove_column :adverts, :updated_at
|
481
478
|
remove_column :adverts, :created_at
|
@@ -506,15 +503,15 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
506
503
|
add_column :adverts, :category_id, :integer, limit: 8, null: false
|
507
504
|
add_index :adverts, [:title], name: :index_adverts_on_title
|
508
505
|
add_index :adverts, [:category_id], name: :my_index
|
509
|
-
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :
|
510
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id" if defined?(Mysql2)}
|
506
|
+
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :my_index" if defined?(Mysql2)}
|
511
507
|
EOS
|
512
508
|
)
|
513
509
|
|
514
510
|
Advert.field_specs.delete(:category_id)
|
515
511
|
Advert.index_definitions.delete_if { |spec| spec.fields == ["title"] || spec.fields == ["category_id"] }
|
512
|
+
Advert.constraint_definitions.delete_if { |spec| spec.foreign_key_column == "category_id" }
|
516
513
|
|
517
|
-
# You can ask for a unique index
|
514
|
+
# You can ask for a unique index (deprecated syntax; use index: { unique: true } instead).
|
518
515
|
|
519
516
|
class Advert < ActiveRecord::Base
|
520
517
|
declare_schema do
|
@@ -526,8 +523,6 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
526
523
|
migrate_up(<<~EOS.strip)
|
527
524
|
add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
|
528
525
|
add_index :adverts, [:title], name: :index_adverts_on_title, unique: true
|
529
|
-
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :index_adverts_on_category_id\n" +
|
530
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id" if defined?(Mysql2)}
|
531
526
|
EOS
|
532
527
|
)
|
533
528
|
|
@@ -545,8 +540,6 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
545
540
|
migrate_up(<<~EOS.strip)
|
546
541
|
add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
|
547
542
|
add_index :adverts, [:title], name: :my_index
|
548
|
-
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :index_adverts_on_category_id\n" +
|
549
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id" if defined?(Mysql2)}
|
550
543
|
EOS
|
551
544
|
)
|
552
545
|
|
@@ -555,6 +548,9 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
555
548
|
# You can ask for an index outside of the fields block
|
556
549
|
|
557
550
|
class Advert < ActiveRecord::Base
|
551
|
+
declare_schema do
|
552
|
+
string :title, limit: 250, null: true
|
553
|
+
end
|
558
554
|
index :title
|
559
555
|
end
|
560
556
|
|
@@ -562,8 +558,6 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
562
558
|
migrate_up(<<~EOS.strip)
|
563
559
|
add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
|
564
560
|
add_index :adverts, [:title], name: :index_adverts_on_title
|
565
|
-
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :index_adverts_on_category_id\n" +
|
566
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id" if defined?(Mysql2)}
|
567
561
|
EOS
|
568
562
|
)
|
569
563
|
|
@@ -579,8 +573,6 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
579
573
|
migrate_up(<<~EOS.strip)
|
580
574
|
add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
|
581
575
|
add_index :adverts, [:title], name: :my_index, length: 10
|
582
|
-
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :index_adverts_on_category_id\n" +
|
583
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id" if defined?(Mysql2)}
|
584
576
|
EOS
|
585
577
|
)
|
586
578
|
|
@@ -596,8 +588,6 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
596
588
|
migrate_up(<<~EOS.strip)
|
597
589
|
add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
|
598
590
|
add_index :adverts, [:title, :category_id], name: :index_adverts_on_title_and_category_id
|
599
|
-
#{"add_foreign_key :adverts, :categories, column: :category_id, name: :index_adverts_on_category_id\n" +
|
600
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id" if defined?(Mysql2)}
|
601
591
|
EOS
|
602
592
|
)
|
603
593
|
|
@@ -627,16 +617,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
627
617
|
rename_table :adverts, :ads
|
628
618
|
add_column :ads, :title, :string, limit: 250, null: true#{charset_and_collation}
|
629
619
|
add_column :ads, :body, :text#{', limit: 4294967295' if defined?(Mysql2)}, null: true#{charset_and_collation}
|
630
|
-
|
631
|
-
"add_foreign_key :adverts, :categories, column: :category_id, name: :index_adverts_on_category_id\n" +
|
632
|
-
"add_foreign_key :adverts, :categories, column: :c_id, name: :index_adverts_on_c_id"
|
633
|
-
end}
|
634
|
-
EOS
|
620
|
+
EOS
|
635
621
|
.and migrate_down(<<~EOS.strip)
|
636
|
-
#{if defined?(Mysql2)
|
637
|
-
"remove_foreign_key :adverts, name: :index_adverts_on_c_id\n" +
|
638
|
-
"remove_foreign_key :adverts, name: :index_adverts_on_category_id"
|
639
|
-
end}
|
640
622
|
remove_column :ads, :body
|
641
623
|
remove_column :ads, :title
|
642
624
|
rename_table :ads, :adverts
|
@@ -21,9 +21,9 @@ RSpec.describe DeclareSchema::Model::ForeignKeyDefinition do
|
|
21
21
|
describe 'instance methods' do
|
22
22
|
let(:connection) { instance_double(ActiveRecord::Base.connection.class) }
|
23
23
|
let(:model) { instance_double('Model', table_name: 'models', connection: connection) }
|
24
|
-
let(:
|
25
|
-
let(:options) { {} }
|
26
|
-
subject { described_class.new(
|
24
|
+
let(:foreign_key_column) { :network_id }
|
25
|
+
let(:options) { { child_table_name: 'advertisers' } }
|
26
|
+
subject { described_class.new(foreign_key_column, **options)}
|
27
27
|
|
28
28
|
before do
|
29
29
|
allow(model.connection).to receive(:index_name).with(any_args) { 'index_on_network_id' }
|
@@ -31,63 +31,64 @@ RSpec.describe DeclareSchema::Model::ForeignKeyDefinition do
|
|
31
31
|
|
32
32
|
describe '#initialize' do
|
33
33
|
it 'normalizes symbols to strings' do
|
34
|
-
expect(subject.
|
34
|
+
expect(subject.foreign_key_column).to eq('network_id')
|
35
35
|
expect(subject.parent_table_name).to eq('networks')
|
36
36
|
end
|
37
37
|
|
38
38
|
context 'when most options passed' do
|
39
|
-
let(:options) { {
|
39
|
+
let(:options) { { child_table_name: 'advertisers', parent_class_name: 'Network' } }
|
40
40
|
|
41
41
|
it 'normalizes symbols to strings' do
|
42
|
-
expect(subject.
|
43
|
-
expect(subject.foreign_key_name).to eq('the_network_id')
|
42
|
+
expect(subject.foreign_key_column).to eq('network_id')
|
44
43
|
expect(subject.parent_table_name).to eq('networks')
|
45
|
-
expect(subject.
|
46
|
-
expect(subject.constraint_name).to eq('
|
47
|
-
expect(subject.
|
44
|
+
expect(subject.foreign_key_column).to eq('network_id')
|
45
|
+
expect(subject.constraint_name).to eq('index_advertisers_on_network_id')
|
46
|
+
expect(subject.dependent).to be_nil
|
48
47
|
end
|
49
48
|
end
|
50
49
|
|
51
50
|
context 'when all options passed' do
|
52
|
-
let(:options) { {
|
51
|
+
let(:options) { { child_table_name: 'advertisers', parent_class_name: 'Network', constraint_name: :constraint_1, dependent: :delete } }
|
53
52
|
|
54
53
|
it 'normalizes symbols to strings' do
|
55
|
-
expect(subject.
|
56
|
-
expect(subject.foreign_key_name).to eq('the_network_id')
|
54
|
+
expect(subject.foreign_key_column).to eq('network_id')
|
57
55
|
expect(subject.parent_table_name).to eq('networks')
|
58
56
|
expect(subject.constraint_name).to eq('constraint_1')
|
59
|
-
expect(subject.
|
57
|
+
expect(subject.dependent).to eq(:delete)
|
60
58
|
end
|
61
59
|
end
|
62
60
|
|
63
61
|
describe `#<=>` do
|
62
|
+
let(:foreign_key_column) { :the_network_id }
|
63
|
+
|
64
64
|
context 'when class name not passed' do
|
65
|
-
let(:options) { {
|
65
|
+
let(:options) { { child_table_name: 'advertisers', constraint_name: :constraint_1, dependent: :delete } }
|
66
66
|
|
67
|
-
it 'compares equal without
|
67
|
+
it 'compares equal without requiring the parent class' do
|
68
68
|
expect(subject <=> subject).to eq(0)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
72
|
context 'when class name passed' do
|
73
|
-
let(:options) { {
|
73
|
+
let(:options) { { child_table_name: 'advertisers', parent_class_name: 'TheNetwork', constraint_name: :constraint_1 } }
|
74
74
|
|
75
|
-
it 'compares equal without
|
75
|
+
it 'compares equal without requiring the parent class' do
|
76
76
|
expect(subject <=> subject).to eq(0)
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
context 'when constraint name passed as empty string' do
|
82
|
-
let(:options) { { constraint_name: "" } }
|
82
|
+
let(:options) { { child_table_name: 'advertisers', constraint_name: "" } }
|
83
|
+
|
83
84
|
it 'defaults to rails constraint name' do
|
84
|
-
expect(subject.constraint_name).to eq("
|
85
|
+
expect(subject.constraint_name).to eq("index_advertisers_on_network_id")
|
85
86
|
end
|
86
87
|
end
|
87
88
|
|
88
89
|
context 'when no constraint name passed' do
|
89
90
|
it 'defaults to rails constraint name' do
|
90
|
-
expect(subject.constraint_name).to eq("
|
91
|
+
expect(subject.constraint_name).to eq("index_advertisers_on_network_id")
|
91
92
|
end
|
92
93
|
end
|
93
94
|
end
|
@@ -103,13 +104,13 @@ RSpec.describe DeclareSchema::Model::ForeignKeyDefinition do
|
|
103
104
|
allow(connection).to receive(:index_name).with('models', column: 'network_id') { }
|
104
105
|
end
|
105
106
|
|
106
|
-
describe '.
|
107
|
-
subject { described_class.
|
107
|
+
describe '.for_table' do
|
108
|
+
subject { described_class.for_table(old_table_name, model.connection) }
|
108
109
|
|
109
|
-
it 'returns
|
110
|
-
expect(subject.
|
111
|
-
|
112
|
-
|
110
|
+
it 'returns definitions' do
|
111
|
+
expect(subject.map(&:key)).to eq([
|
112
|
+
["networks", "network_id", nil]
|
113
|
+
])
|
113
114
|
end
|
114
115
|
end
|
115
116
|
end
|
@@ -8,19 +8,19 @@ end
|
|
8
8
|
require_relative '../../../../lib/declare_schema/model/habtm_model_shim'
|
9
9
|
|
10
10
|
RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
11
|
-
let(:join_table) { "
|
12
|
-
let(:foreign_keys) { ["
|
13
|
-
let(:
|
11
|
+
let(:join_table) { "customers_users" }
|
12
|
+
let(:foreign_keys) { ["user_id", "customer_id"] }
|
13
|
+
let(:parent_table_names) { ["users", "customers"] }
|
14
14
|
|
15
15
|
before do
|
16
16
|
load File.expand_path('../prepare_testapp.rb', __dir__)
|
17
17
|
|
18
|
-
class
|
19
|
-
self.table_name = "
|
18
|
+
class User < ActiveRecord::Base
|
19
|
+
self.table_name = "users"
|
20
20
|
end
|
21
21
|
|
22
|
-
class
|
23
|
-
self.table_name = "
|
22
|
+
class Customer < ActiveRecord::Base
|
23
|
+
self.table_name = "customers"
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -29,12 +29,14 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
29
29
|
let(:reflection) { double("reflection", join_table: join_table,
|
30
30
|
foreign_key: foreign_keys.first,
|
31
31
|
association_foreign_key: foreign_keys.last,
|
32
|
-
active_record:
|
33
|
-
class_name: '
|
32
|
+
active_record: User,
|
33
|
+
class_name: 'Customer') }
|
34
34
|
it 'returns a new object' do
|
35
35
|
result = described_class.from_reflection(reflection)
|
36
36
|
|
37
37
|
expect(result).to be_a(described_class)
|
38
|
+
expect(result.foreign_keys).to eq(foreign_keys.reverse)
|
39
|
+
expect(result.parent_table_names).to eq(parent_table_names.reverse)
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
@@ -42,14 +44,12 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
42
44
|
describe 'instance methods' do
|
43
45
|
let(:connection) { instance_double(ActiveRecord::Base.connection.class, "connection") }
|
44
46
|
|
45
|
-
subject { described_class.new(join_table, foreign_keys,
|
47
|
+
subject { described_class.new(join_table, foreign_keys, parent_table_names) }
|
46
48
|
|
47
49
|
describe '#initialize' do
|
48
50
|
it 'stores initialization attributes' do
|
49
51
|
expect(subject.join_table).to eq(join_table)
|
50
|
-
expect(subject.foreign_keys).to eq(foreign_keys)
|
51
|
-
expect(subject.foreign_key_classes).to be(foreign_key_classes)
|
52
|
-
expect(subject.connection).to be(connection)
|
52
|
+
expect(subject.foreign_keys).to eq(foreign_keys.reverse)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -67,20 +67,20 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
67
67
|
|
68
68
|
describe '#field_specs' do
|
69
69
|
it 'returns 2 field specs' do
|
70
|
-
|
71
|
-
expect(
|
72
|
-
|
73
|
-
expect(
|
74
|
-
expect(
|
75
|
-
expect(
|
76
|
-
expect(
|
77
|
-
expect(
|
78
|
-
|
79
|
-
expect(
|
80
|
-
expect(
|
81
|
-
expect(
|
82
|
-
expect(
|
83
|
-
expect(
|
70
|
+
field_specs = subject.field_specs
|
71
|
+
expect(field_specs.size).to eq(2), field_specs.inspect
|
72
|
+
|
73
|
+
expect(field_specs[foreign_keys.first]).to be_a(::DeclareSchema::Model::FieldSpec)
|
74
|
+
expect(field_specs[foreign_keys.first].model).to eq(subject)
|
75
|
+
expect(field_specs[foreign_keys.first].name.to_s).to eq(foreign_keys.first)
|
76
|
+
expect(field_specs[foreign_keys.first].type).to eq(:integer)
|
77
|
+
expect(field_specs[foreign_keys.first].position).to eq(1)
|
78
|
+
|
79
|
+
expect(field_specs[foreign_keys.last]).to be_a(::DeclareSchema::Model::FieldSpec)
|
80
|
+
expect(field_specs[foreign_keys.last].model).to eq(subject)
|
81
|
+
expect(field_specs[foreign_keys.last].name.to_s).to eq(foreign_keys.last)
|
82
|
+
expect(field_specs[foreign_keys.last].type).to eq(:integer)
|
83
|
+
expect(field_specs[foreign_keys.last].position).to eq(0)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -98,20 +98,21 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
98
98
|
|
99
99
|
describe '#index_definitions_with_primary_key' do
|
100
100
|
it 'returns 2 index definitions' do
|
101
|
-
|
102
|
-
expect(
|
101
|
+
index_definitions = subject.index_definitions_with_primary_key
|
102
|
+
expect(index_definitions.size).to eq(2), index_definitions.inspect
|
103
103
|
|
104
|
-
expect(
|
105
|
-
expect(
|
106
|
-
expect(
|
107
|
-
expect(
|
104
|
+
expect(index_definitions.first).to be_a(::DeclareSchema::Model::IndexDefinition)
|
105
|
+
expect(index_definitions.first.name).to eq('PRIMARY')
|
106
|
+
expect(index_definitions.first.fields).to eq(foreign_keys.reverse)
|
107
|
+
expect(index_definitions.first.unique).to be_truthy
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
111
|
context 'when table and foreign key names are long' do
|
112
112
|
let(:join_table) { "advertiser_campaigns_tracking_pixels" }
|
113
|
-
let(:
|
114
|
-
let(:
|
113
|
+
let(:foreign_keys_and_table_names) { [["advertiser_id", "advertisers"], ["campaign_id", "campaigns"]] }
|
114
|
+
let(:foreign_keys) { foreign_keys_and_table_names.map(&:first) }
|
115
|
+
let(:parent_table_names) { foreign_keys_and_table_names.map(&:last) }
|
115
116
|
|
116
117
|
before do
|
117
118
|
class Table1 < ActiveRecord::Base
|
@@ -124,19 +125,23 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
124
125
|
end
|
125
126
|
|
126
127
|
it 'returns two index definitions and does not raise a IndexNameTooLongError' do
|
127
|
-
|
128
|
-
expect(
|
129
|
-
expect(
|
130
|
-
expect(
|
131
|
-
expect(
|
132
|
-
expect(
|
128
|
+
indexes = subject.index_definitions_with_primary_key.to_a
|
129
|
+
expect(indexes.size).to eq(2), indexes.inspect
|
130
|
+
expect(indexes.first).to be_a(::DeclareSchema::Model::IndexDefinition)
|
131
|
+
expect(indexes.first.name).to eq('PRIMARY')
|
132
|
+
expect(indexes.first.fields).to eq(foreign_keys)
|
133
|
+
expect(indexes.first.unique).to be_truthy
|
134
|
+
expect(indexes.last).to be_a(::DeclareSchema::Model::IndexDefinition)
|
135
|
+
expect(indexes.last.name).to eq('index_advertiser_campaigns_tracking_pixels_on_campaign_id')
|
136
|
+
expect(indexes.last.fields).to eq([foreign_keys.last])
|
137
|
+
expect(indexes.last.unique).to be_falsey
|
133
138
|
end
|
134
139
|
end
|
135
140
|
|
136
141
|
describe '#index_definitions' do
|
137
142
|
it 'returns index_definitions_with_primary_key' do
|
138
|
-
|
139
|
-
expect(
|
143
|
+
indexes = subject.index_definitions
|
144
|
+
expect(indexes.size).to eq(2), indexes.inspect
|
140
145
|
end
|
141
146
|
end
|
142
147
|
|
@@ -146,21 +151,13 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
146
151
|
end
|
147
152
|
end
|
148
153
|
|
149
|
-
describe '#
|
154
|
+
describe '#constraint_definitions' do
|
150
155
|
it 'returns 2 foreign keys' do
|
151
|
-
|
152
|
-
expect(
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
expect(result.first.parent_table_name).to be(Parent1.table_name)
|
157
|
-
expect(result.first.on_delete_cascade).to be_truthy
|
158
|
-
|
159
|
-
sample = result.to_a.last
|
160
|
-
expect(sample).to be_a(::DeclareSchema::Model::ForeignKeyDefinition)
|
161
|
-
expect(sample.foreign_key).to eq(foreign_keys.last)
|
162
|
-
expect(sample.parent_table_name).to be(Parent2.table_name)
|
163
|
-
expect(sample.on_delete_cascade).to be_truthy
|
156
|
+
constraints = subject.constraint_definitions
|
157
|
+
expect(constraints.map(&:key)).to eq([
|
158
|
+
["customers_users", "customer_id", :delete],
|
159
|
+
["customers_users", "user_id", :delete]
|
160
|
+
])
|
164
161
|
end
|
165
162
|
end
|
166
163
|
end
|