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.
- 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 +57 -48
- data/lib/declare_schema/version.rb +1 -1
- data/lib/declare_schema.rb +34 -2
- data/lib/generators/declare_schema/migration/migrator.rb +17 -11
- 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,8 +426,8 @@ 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
|
-
model_indexes_with_equivalents = model.index_definitions_with_primary_key
|
429
|
+
existing_indexes = ::DeclareSchema::Model::IndexDefinition.for_table(old_table_name || new_table_name, model.ignore_indexes, model.connection)
|
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?
|
432
433
|
if (existing = existing_indexes.find { |e| i != e && e.equivalent?(i) })
|
@@ -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
|