declare_schema 0.8.0.pre.1 → 0.8.0.pre.6
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/Gemfile.lock +1 -1
- data/lib/declare_schema/model.rb +25 -2
- data/lib/declare_schema/model/column.rb +3 -1
- data/lib/declare_schema/model/field_spec.rb +5 -7
- data/lib/declare_schema/model/foreign_key_definition.rb +5 -3
- data/lib/declare_schema/model/habtm_model_shim.rb +75 -0
- data/lib/declare_schema/model/index_definition.rb +5 -1
- data/lib/declare_schema/version.rb +1 -1
- data/lib/generators/declare_schema/migration/migrator.rb +1 -64
- data/spec/lib/declare_schema/field_spec_spec.rb +38 -25
- data/spec/lib/declare_schema/migration_generator_spec.rb +28 -28
- data/spec/lib/declare_schema/model/column_spec.rb +5 -0
- data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +148 -0
- data/spec/lib/declare_schema/model/index_definition_spec.rb +11 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d3ceea8167afc532a38353f4bdac36fc805762dd2c8f2bf5fdb7895e7fc9886
|
4
|
+
data.tar.gz: 766a96c62aad5a6360c12a74a2630d52d6ee4c08b44ceeb3dd7309251886ce14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9de9bb8b90e978d745b5832ce81553d1156e10810f30304a347dd5e591ccd55fa086982ea32f349634cc1a8ff34fad3798d94ccfcd1fe3351be1f9e5a1f9648
|
7
|
+
data.tar.gz: 7b569604b9dc7f0ca2b8a8c36ffaede21a85e5f0ca13e39291823cfdf41a7b2f3ee00dedb7dd93e4ddd589a266dee75909f9b33bcb084c1e8929086216dbdee9
|
data/Gemfile.lock
CHANGED
data/lib/declare_schema/model.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'rails'
|
4
|
+
|
3
5
|
require 'declare_schema/extensions/module'
|
4
6
|
|
5
7
|
module DeclareSchema
|
@@ -99,8 +101,29 @@ module DeclareSchema
|
|
99
101
|
end
|
100
102
|
end
|
101
103
|
|
102
|
-
|
103
|
-
|
104
|
+
if ::Rails::VERSION::MAJOR < 5
|
105
|
+
def primary_key
|
106
|
+
super || 'id'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# returns the primary key (String) as declared with primary_key =
|
111
|
+
# unlike the `primary_key` method, DOES NOT query the database to find the actual primary key in use right now
|
112
|
+
# if no explicit primary key set, returns the default_defined_primary_key
|
113
|
+
def defined_primary_key
|
114
|
+
if defined?(@primary_key)
|
115
|
+
@primary_key&.to_s
|
116
|
+
end || default_defined_primary_key
|
117
|
+
end
|
118
|
+
|
119
|
+
# if this is a derived class, returns the base class's defined_primary_key
|
120
|
+
# otherwise, returns 'id'
|
121
|
+
def default_defined_primary_key
|
122
|
+
if self == base_class
|
123
|
+
'id'
|
124
|
+
else
|
125
|
+
base_class.defined_primary_key
|
126
|
+
end
|
104
127
|
end
|
105
128
|
|
106
129
|
private
|
@@ -8,7 +8,7 @@ module DeclareSchema
|
|
8
8
|
class Column
|
9
9
|
class << self
|
10
10
|
def native_type?(type)
|
11
|
-
type != :primary_key && native_types[type]
|
11
|
+
type != :primary_key && (native_types.empty? || native_types[type]) # empty will happen with NullDBAdapter used in assets:precompile
|
12
12
|
end
|
13
13
|
|
14
14
|
# MySQL example:
|
@@ -44,6 +44,8 @@ module DeclareSchema
|
|
44
44
|
if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
|
45
45
|
types[:text][:limit] ||= 0xffff
|
46
46
|
types[:binary][:limit] ||= 0xffff
|
47
|
+
|
48
|
+
types[:varbinary] ||= { name: "varbinary" } # TODO: :varbinary is an Invoca addition to Rails; make it a configurable option
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
@@ -47,11 +47,9 @@ module DeclareSchema
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def initialize(model, name, type, position: 0, **options)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
# raise ArgumentError, "you cannot provide a field spec for the primary key" if name == model.primary_key
|
54
|
-
name == "id" and raise ArgumentError, "you cannot provide a field spec for the primary key"
|
50
|
+
defined_primary_key = model.defined_primary_key
|
51
|
+
|
52
|
+
name.to_s == defined_primary_key and raise ArgumentError, "you may not provide a field spec for the primary key #{name.inspect}"
|
55
53
|
|
56
54
|
@model = model
|
57
55
|
@name = name.to_sym
|
@@ -77,10 +75,10 @@ module DeclareSchema
|
|
77
75
|
@options[:limit] = 8
|
78
76
|
end
|
79
77
|
|
80
|
-
Column.native_type?(@type) or raise UnknownTypeError, "#{@type.inspect}"
|
78
|
+
Column.native_type?(@type) or raise UnknownTypeError, "#{@type.inspect} not found in #{Column.native_types.inspect} for adapter #{ActiveRecord::Base.connection.class.name}"
|
81
79
|
|
82
80
|
if @type.in?([:string, :text, :binary, :varbinary, :integer, :enum])
|
83
|
-
@options[:limit] ||= Column.native_types
|
81
|
+
@options[:limit] ||= Column.native_types.dig(@type, :limit)
|
84
82
|
else
|
85
83
|
@type != :decimal && @options.has_key?(:limit) and warn("unsupported limit: for SQL type #{@type} in field #{model}##{@name}")
|
86
84
|
@options.delete(:limit)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'index_definition'
|
4
|
+
|
3
5
|
module DeclareSchema
|
4
6
|
module Model
|
5
7
|
class ForeignKeyDefinition
|
@@ -15,10 +17,10 @@ module DeclareSchema
|
|
15
17
|
@child_table = model.table_name # unless a table rename, which would happen when a class is renamed??
|
16
18
|
@parent_table_name = options[:parent_table]&.to_s
|
17
19
|
@foreign_key_name = options[:foreign_key]&.to_s || @foreign_key
|
18
|
-
@index_name = options[:index_name]&.to_s || model.connection.index_name(model.table_name, column: @foreign_key_name)
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
@constraint_name = options[:constraint_name]&.to_s ||
|
22
|
+
options[:index_name]&.to_s ||
|
23
|
+
IndexDefinition.index_name(@foreign_key_name)
|
22
24
|
@on_delete_cascade = options[:dependent] == :delete
|
23
25
|
end
|
24
26
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeclareSchema
|
4
|
+
module Model
|
5
|
+
class HabtmModelShim
|
6
|
+
class << self
|
7
|
+
def from_reflection(refl)
|
8
|
+
join_table = refl.join_table
|
9
|
+
foreign_keys_and_classes = [
|
10
|
+
[refl.foreign_key.to_s, refl.active_record],
|
11
|
+
[refl.association_foreign_key.to_s, refl.class_name.constantize]
|
12
|
+
].sort { |a, b| a.first <=> b.first }
|
13
|
+
foreign_keys = foreign_keys_and_classes.map(&:first)
|
14
|
+
foreign_key_classes = foreign_keys_and_classes.map(&:last)
|
15
|
+
# this may fail in weird ways if HABTM is running across two DB connections (assuming that's even supported)
|
16
|
+
# figure that anybody who sets THAT up can deal with their own migrations...
|
17
|
+
connection = refl.active_record.connection
|
18
|
+
|
19
|
+
new(join_table, foreign_keys, foreign_key_classes, connection)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :join_table, :foreign_keys, :foreign_key_classes, :connection
|
24
|
+
|
25
|
+
def initialize(join_table, foreign_keys, foreign_key_classes, connection)
|
26
|
+
@join_table = join_table
|
27
|
+
@foreign_keys = foreign_keys
|
28
|
+
@foreign_key_classes = foreign_key_classes
|
29
|
+
@connection = connection
|
30
|
+
end
|
31
|
+
|
32
|
+
def table_options
|
33
|
+
{}
|
34
|
+
end
|
35
|
+
|
36
|
+
def table_name
|
37
|
+
join_table
|
38
|
+
end
|
39
|
+
|
40
|
+
def field_specs
|
41
|
+
foreign_keys.each_with_index.each_with_object({}) do |(v, position), result|
|
42
|
+
result[v] = ::DeclareSchema::Model::FieldSpec.new(self, v, :integer, position: position, null: false)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def primary_key
|
47
|
+
false # no single-column primary key in database
|
48
|
+
end
|
49
|
+
|
50
|
+
def defined_primary_key
|
51
|
+
false # no single-column primary key declared
|
52
|
+
end
|
53
|
+
|
54
|
+
def index_definitions_with_primary_key
|
55
|
+
[
|
56
|
+
IndexDefinition.new(self, foreign_keys, unique: true, name: ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME),
|
57
|
+
IndexDefinition.new(self, foreign_keys.last) # not unique by itself; combines with primary key to be unique
|
58
|
+
]
|
59
|
+
end
|
60
|
+
|
61
|
+
alias_method :index_definitions, :index_definitions_with_primary_key
|
62
|
+
|
63
|
+
def ignore_indexes
|
64
|
+
[]
|
65
|
+
end
|
66
|
+
|
67
|
+
def constraint_specs
|
68
|
+
[
|
69
|
+
ForeignKeyDefinition.new(self, foreign_keys.first, parent_table: foreign_key_classes.first.table_name, constraint_name: "#{join_table}_FK1", dependent: :delete),
|
70
|
+
ForeignKeyDefinition.new(self, foreign_keys.last, parent_table: foreign_key_classes.last.table_name, constraint_name: "#{join_table}_FK2", dependent: :delete)
|
71
|
+
]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -19,7 +19,7 @@ module DeclareSchema
|
|
19
19
|
@table = options.delete(:table_name) || model.table_name
|
20
20
|
@fields = Array.wrap(fields).map(&:to_s)
|
21
21
|
@explicit_name = options[:name] unless options.delete(:allow_equivalent)
|
22
|
-
@name = options.delete(:name) ||
|
22
|
+
@name = options.delete(:name) || self.class.index_name(@fields)
|
23
23
|
@unique = options.delete(:unique) || name == PRIMARY_KEY_NAME || false
|
24
24
|
|
25
25
|
if @name.length > MYSQL_INDEX_NAME_MAX_LENGTH
|
@@ -60,6 +60,10 @@ module DeclareSchema
|
|
60
60
|
index_definitions
|
61
61
|
end
|
62
62
|
|
63
|
+
def index_name(columns)
|
64
|
+
"on_#{Array(columns).join("_and_")}"
|
65
|
+
end
|
66
|
+
|
63
67
|
private
|
64
68
|
|
65
69
|
# This is the old approach which is still needed for MySQL in Rails 4 and SQLite
|
@@ -6,69 +6,6 @@ require 'active_record/connection_adapters/abstract_adapter'
|
|
6
6
|
module Generators
|
7
7
|
module DeclareSchema
|
8
8
|
module Migration
|
9
|
-
HabtmModelShim = Struct.new(:join_table, :foreign_keys, :foreign_key_classes, :connection) do
|
10
|
-
class << self
|
11
|
-
def from_reflection(refl)
|
12
|
-
join_table = refl.join_table
|
13
|
-
foreign_keys_and_classes = [
|
14
|
-
[refl.foreign_key.to_s, refl.active_record],
|
15
|
-
[refl.association_foreign_key.to_s, refl.class_name.constantize]
|
16
|
-
].sort { |a, b| a.first <=> b.first }
|
17
|
-
foreign_keys = foreign_keys_and_classes.map(&:first)
|
18
|
-
foreign_key_classes = foreign_keys_and_classes.map(&:last)
|
19
|
-
# this may fail in weird ways if HABTM is running across two DB connections (assuming that's even supported)
|
20
|
-
# figure that anybody who sets THAT up can deal with their own migrations...
|
21
|
-
connection = refl.active_record.connection
|
22
|
-
|
23
|
-
new(join_table, foreign_keys, foreign_key_classes, connection)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def table_options
|
28
|
-
{}
|
29
|
-
end
|
30
|
-
|
31
|
-
def table_name
|
32
|
-
join_table
|
33
|
-
end
|
34
|
-
|
35
|
-
def table_exists?
|
36
|
-
ActiveRecord::Migration.table_exists? table_name
|
37
|
-
end
|
38
|
-
|
39
|
-
def field_specs
|
40
|
-
i = 0
|
41
|
-
foreign_keys.each_with_object({}) do |v, result|
|
42
|
-
result[v] = ::DeclareSchema::Model::FieldSpec.new(self, v, :integer, position: i, null: false)
|
43
|
-
i += 1
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def primary_key
|
48
|
-
false # no single-column primary key
|
49
|
-
end
|
50
|
-
|
51
|
-
def index_definitions_with_primary_key
|
52
|
-
[
|
53
|
-
::DeclareSchema::Model::IndexDefinition.new(self, foreign_keys, unique: true, name: ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME),
|
54
|
-
::DeclareSchema::Model::IndexDefinition.new(self, foreign_keys.last) # not unique by itself; combines with primary key to be unique
|
55
|
-
]
|
56
|
-
end
|
57
|
-
|
58
|
-
alias_method :index_definitions, :index_definitions_with_primary_key
|
59
|
-
|
60
|
-
def ignore_indexes
|
61
|
-
[]
|
62
|
-
end
|
63
|
-
|
64
|
-
def constraint_specs
|
65
|
-
[
|
66
|
-
::DeclareSchema::Model::ForeignKeyDefinition.new(self, foreign_keys.first, parent_table: foreign_key_classes.first.table_name, constraint_name: "#{join_table}_FK1", dependent: :delete),
|
67
|
-
::DeclareSchema::Model::ForeignKeyDefinition.new(self, foreign_keys.last, parent_table: foreign_key_classes.last.table_name, constraint_name: "#{join_table}_FK2", dependent: :delete)
|
68
|
-
]
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
9
|
class Migrator
|
73
10
|
class Error < RuntimeError; end
|
74
11
|
|
@@ -266,7 +203,7 @@ module Generators
|
|
266
203
|
end
|
267
204
|
# generate shims for HABTM models
|
268
205
|
habtm_tables.each do |name, refls|
|
269
|
-
models_by_table_name[name] = HabtmModelShim.from_reflection(refls.first)
|
206
|
+
models_by_table_name[name] = ::DeclareSchema::Model::HabtmModelShim.from_reflection(refls.first)
|
270
207
|
end
|
271
208
|
model_table_names = models_by_table_name.keys
|
272
209
|
|
@@ -6,7 +6,7 @@ rescue LoadError
|
|
6
6
|
end
|
7
7
|
|
8
8
|
RSpec.describe DeclareSchema::Model::FieldSpec do
|
9
|
-
let(:model) { double('model', table_options: {}) }
|
9
|
+
let(:model) { double('model', table_options: {}, defined_primary_key: 'id') }
|
10
10
|
let(:col_spec) { double('col_spec', type: :string) }
|
11
11
|
|
12
12
|
before do
|
@@ -22,6 +22,12 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
22
22
|
subject = described_class.new(model, :price, :integer, anonymize_using: 'x', null: false, position: 0, limit: 4)
|
23
23
|
expect(subject.options.keys).to eq([:limit, :null, :anonymize_using])
|
24
24
|
end
|
25
|
+
|
26
|
+
it 'raises exception on unknown field type' do
|
27
|
+
expect do
|
28
|
+
described_class.new(model, :location, :lat_long, position: 0)
|
29
|
+
end.to raise_exception(::DeclareSchema::UnknownTypeError, /:lat_long not found in /)
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
33
|
describe '#schema_attributes' do
|
@@ -77,37 +83,44 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
77
83
|
expect(subject.schema_attributes(col_spec)).to eq(type: :text, null: true, default: 'none')
|
78
84
|
end
|
79
85
|
end
|
86
|
+
end
|
80
87
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
88
|
+
describe 'varbinary' do # TODO: :varbinary is an Invoca addition to Rails; make it a configurable option
|
89
|
+
it 'is supported' do
|
90
|
+
subject = described_class.new(model, :binary_dump, :varbinary, limit: 200, null: false, position: 2)
|
91
|
+
expect(subject.schema_attributes(col_spec)).to eq(type: :varbinary, limit: 200, null: false)
|
92
|
+
end
|
93
|
+
end
|
86
94
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
95
|
+
describe 'decimal' do
|
96
|
+
it 'allows precision: and scale:' do
|
97
|
+
subject = described_class.new(model, :quantity, :decimal, precision: 8, scale: 10, null: true, position: 3)
|
98
|
+
expect(subject.schema_attributes(col_spec)).to eq(type: :decimal, precision: 8, scale: 10, null: true)
|
99
|
+
end
|
91
100
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
101
|
+
it 'requires precision:' do
|
102
|
+
expect_any_instance_of(described_class).to receive(:warn).with(/precision: required for :decimal type/)
|
103
|
+
described_class.new(model, :quantity, :decimal, scale: 10, null: true, position: 3)
|
96
104
|
end
|
97
105
|
|
98
|
-
|
99
|
-
|
100
|
-
|
106
|
+
it 'requires scale:' do
|
107
|
+
expect_any_instance_of(described_class).to receive(:warn).with(/scale: required for :decimal type/)
|
108
|
+
described_class.new(model, :quantity, :decimal, precision: 8, null: true, position: 3)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
[:integer, :bigint, :string, :text, :binary, :varbinary, :datetime, :date, :time].each do |t|
|
113
|
+
describe t.to_s do
|
114
|
+
let(:extra) { t == :string ? { limit: 100 } : {} }
|
101
115
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
116
|
+
it 'does not allow precision:' do
|
117
|
+
expect_any_instance_of(described_class).to receive(:warn).with(/precision: only allowed for :decimal type/)
|
118
|
+
described_class.new(model, :quantity, t, { precision: 8, null: true, position: 3 }.merge(extra))
|
119
|
+
end unless t == :datetime
|
106
120
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
121
|
+
it 'does not allow scale:' do
|
122
|
+
expect_any_instance_of(described_class).to receive(:warn).with(/scale: only allowed for :decimal type/)
|
123
|
+
described_class.new(model, :quantity, t, { scale: 10, null: true, position: 3 }.merge(extra))
|
111
124
|
end
|
112
125
|
end
|
113
126
|
end
|
@@ -372,14 +372,14 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
372
372
|
|
373
373
|
add_index :adverts, [:category_id], name: 'on_category_id'
|
374
374
|
|
375
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
375
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" if defined?(Mysql2)}
|
376
376
|
EOS
|
377
377
|
.and migrate_down(<<~EOS.strip)
|
378
378
|
remove_column :adverts, :category_id
|
379
379
|
|
380
380
|
remove_index :adverts, name: :on_category_id rescue ActiveRecord::StatementInvalid
|
381
381
|
|
382
|
-
#{"remove_foreign_key(\"adverts\", name: \"
|
382
|
+
#{"remove_foreign_key(\"adverts\", name: \"on_category_id\")\n" if defined?(Mysql2)}
|
383
383
|
EOS
|
384
384
|
)
|
385
385
|
|
@@ -400,8 +400,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
400
400
|
|
401
401
|
add_index :adverts, [:c_id], name: 'on_c_id'
|
402
402
|
|
403
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
404
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
403
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
404
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
405
405
|
EOS
|
406
406
|
)
|
407
407
|
|
@@ -420,8 +420,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
420
420
|
migrate_up(<<~EOS.strip)
|
421
421
|
add_column :adverts, :category_id, :integer, limit: 8, null: false
|
422
422
|
|
423
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
424
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
423
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
424
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
425
425
|
EOS
|
426
426
|
)
|
427
427
|
|
@@ -442,8 +442,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
442
442
|
|
443
443
|
add_index :adverts, [:category_id], name: 'my_index'
|
444
444
|
|
445
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
446
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
445
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
446
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
447
447
|
EOS
|
448
448
|
)
|
449
449
|
|
@@ -468,16 +468,16 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
468
468
|
add_column :adverts, :updated_at, :datetime, null: true
|
469
469
|
add_column :adverts, :lock_version, :integer#{lock_version_limit}, null: false, default: 1
|
470
470
|
|
471
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
472
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
471
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
472
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
473
473
|
EOS
|
474
474
|
.and migrate_down(<<~EOS.strip)
|
475
475
|
remove_column :adverts, :created_at
|
476
476
|
remove_column :adverts, :updated_at
|
477
477
|
remove_column :adverts, :lock_version
|
478
478
|
|
479
|
-
#{"remove_foreign_key(\"adverts\", name: \"
|
480
|
-
"remove_foreign_key(\"adverts\", name: \"
|
479
|
+
#{"remove_foreign_key(\"adverts\", name: \"on_category_id\")\n" +
|
480
|
+
"remove_foreign_key(\"adverts\", name: \"on_c_id\")" if defined?(Mysql2)}
|
481
481
|
EOS
|
482
482
|
)
|
483
483
|
|
@@ -501,8 +501,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
501
501
|
|
502
502
|
add_index :adverts, [:title], name: 'on_title'
|
503
503
|
|
504
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
505
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
504
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
505
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
506
506
|
EOS
|
507
507
|
)
|
508
508
|
|
@@ -522,8 +522,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
522
522
|
|
523
523
|
add_index :adverts, [:title], unique: true, name: 'on_title'
|
524
524
|
|
525
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
526
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
525
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
526
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
527
527
|
EOS
|
528
528
|
)
|
529
529
|
|
@@ -543,8 +543,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
543
543
|
|
544
544
|
add_index :adverts, [:title], name: 'my_index'
|
545
545
|
|
546
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
547
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
546
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
547
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
548
548
|
EOS
|
549
549
|
)
|
550
550
|
|
@@ -562,8 +562,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
562
562
|
|
563
563
|
add_index :adverts, [:title], name: 'on_title'
|
564
564
|
|
565
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
566
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
565
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
566
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
567
567
|
EOS
|
568
568
|
)
|
569
569
|
|
@@ -581,8 +581,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
581
581
|
|
582
582
|
add_index :adverts, [:title], unique: true, name: 'my_index'
|
583
583
|
|
584
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
585
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
584
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
585
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
586
586
|
EOS
|
587
587
|
)
|
588
588
|
|
@@ -600,8 +600,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
600
600
|
|
601
601
|
add_index :adverts, [:title, :category_id], name: 'on_title_and_category_id'
|
602
602
|
|
603
|
-
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
604
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
603
|
+
#{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
604
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")" if defined?(Mysql2)}
|
605
605
|
EOS
|
606
606
|
)
|
607
607
|
|
@@ -637,8 +637,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
637
637
|
"add_index :ads, [:id], unique: true, name: 'PRIMARY'\n"
|
638
638
|
elsif defined?(Mysql2)
|
639
639
|
"execute \"ALTER TABLE ads DROP PRIMARY KEY, ADD PRIMARY KEY (id)\"\n\n" +
|
640
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"
|
641
|
-
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"
|
640
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"on_category_id\")\n" +
|
641
|
+
"add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"on_c_id\")"
|
642
642
|
end}
|
643
643
|
EOS
|
644
644
|
.and migrate_down(<<~EOS.strip)
|
@@ -651,8 +651,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
651
651
|
"add_index :adverts, [:id], unique: true, name: 'PRIMARY'\n"
|
652
652
|
elsif defined?(Mysql2)
|
653
653
|
"execute \"ALTER TABLE adverts DROP PRIMARY KEY, ADD PRIMARY KEY (id)\"\n\n" +
|
654
|
-
"remove_foreign_key(\"adverts\", name: \"
|
655
|
-
"remove_foreign_key(\"adverts\", name: \"
|
654
|
+
"remove_foreign_key(\"adverts\", name: \"on_category_id\")\n" +
|
655
|
+
"remove_foreign_key(\"adverts\", name: \"on_c_id\")"
|
656
656
|
end}
|
657
657
|
EOS
|
658
658
|
)
|
@@ -37,6 +37,11 @@ RSpec.describe DeclareSchema::Model::Column do
|
|
37
37
|
expect(described_class.native_type?(type)).to be_falsey
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
it "is truthy when there's a NullDbAdapter (like for assets:precompile) that doesn't have any native types" do
|
42
|
+
allow(described_class).to receive(:native_types).and_return({})
|
43
|
+
expect(described_class.native_type?(:integer)).to be_truthy
|
44
|
+
end
|
40
45
|
end
|
41
46
|
|
42
47
|
describe '.native_types' do
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'mysql2'
|
7
|
+
rescue LoadError
|
8
|
+
end
|
9
|
+
|
10
|
+
require_relative '../../../../lib/declare_schema/model/habtm_model_shim'
|
11
|
+
|
12
|
+
RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
13
|
+
let(:join_table) { "parent_1_parent_2" }
|
14
|
+
let(:foreign_keys) { ["parent_1_id", "parent_2_id"] }
|
15
|
+
let(:foreign_key_classes) { [Parent1, Parent2] }
|
16
|
+
|
17
|
+
before do
|
18
|
+
load File.expand_path('../prepare_testapp.rb', __dir__)
|
19
|
+
|
20
|
+
class Parent1 < ActiveRecord::Base
|
21
|
+
self.table_name = "parent_1s"
|
22
|
+
end
|
23
|
+
|
24
|
+
class Parent2 < ActiveRecord::Base
|
25
|
+
self.table_name = "parent_2s"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'class methods' do
|
30
|
+
describe '.from_reflection' do
|
31
|
+
let(:reflection) { double("reflection", join_table: join_table,
|
32
|
+
foreign_key: foreign_keys.first,
|
33
|
+
association_foreign_key: foreign_keys.last,
|
34
|
+
active_record: foreign_key_classes.first,
|
35
|
+
class_name: 'Parent1') }
|
36
|
+
it 'returns a new object' do
|
37
|
+
result = described_class.from_reflection(reflection)
|
38
|
+
|
39
|
+
expect(result).to be_a(described_class)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'instance methods' do
|
45
|
+
let(:connection) { instance_double(ActiveRecord::Base.connection.class, "connection") }
|
46
|
+
|
47
|
+
subject { described_class.new(join_table, foreign_keys, foreign_key_classes, connection) }
|
48
|
+
|
49
|
+
describe '#initialize' do
|
50
|
+
it 'stores initialization attributes' do
|
51
|
+
expect(subject.join_table).to eq(join_table)
|
52
|
+
expect(subject.foreign_keys).to eq(foreign_keys)
|
53
|
+
expect(subject.foreign_key_classes).to be(foreign_key_classes)
|
54
|
+
expect(subject.connection).to be(connection)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#table_options' do
|
59
|
+
it 'returns empty hash' do
|
60
|
+
expect(subject.table_options).to eq({})
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#table_name' do
|
65
|
+
it 'returns join_table' do
|
66
|
+
expect(subject.table_name).to eq(join_table)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#field_specs' do
|
71
|
+
it 'returns 2 field specs' do
|
72
|
+
result = subject.field_specs
|
73
|
+
expect(result.size).to eq(2), result.inspect
|
74
|
+
|
75
|
+
expect(result[foreign_keys.first]).to be_a(::DeclareSchema::Model::FieldSpec)
|
76
|
+
expect(result[foreign_keys.first].model).to eq(subject)
|
77
|
+
expect(result[foreign_keys.first].name.to_s).to eq(foreign_keys.first)
|
78
|
+
expect(result[foreign_keys.first].type).to eq(:integer)
|
79
|
+
expect(result[foreign_keys.first].position).to eq(0)
|
80
|
+
|
81
|
+
expect(result[foreign_keys.last]).to be_a(::DeclareSchema::Model::FieldSpec)
|
82
|
+
expect(result[foreign_keys.last].model).to eq(subject)
|
83
|
+
expect(result[foreign_keys.last].name.to_s).to eq(foreign_keys.last)
|
84
|
+
expect(result[foreign_keys.last].type).to eq(:integer)
|
85
|
+
expect(result[foreign_keys.last].position).to eq(1)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#primary_key' do
|
90
|
+
it 'returns false' do
|
91
|
+
expect(subject.primary_key).to eq(false)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#defined_primary_key' do
|
96
|
+
it 'returns false' do
|
97
|
+
expect(subject.defined_primary_key).to eq(false)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#index_definitions_with_primary_key' do
|
102
|
+
it 'returns 2 index definitions' do
|
103
|
+
result = subject.index_definitions_with_primary_key
|
104
|
+
expect(result.size).to eq(2), result.inspect
|
105
|
+
|
106
|
+
expect(result.first).to be_a(::DeclareSchema::Model::IndexDefinition)
|
107
|
+
expect(result.first.name).to eq('PRIMARY')
|
108
|
+
expect(result.first.fields).to eq(['parent_1_id', 'parent_2_id'])
|
109
|
+
expect(result.first.unique).to be_truthy
|
110
|
+
|
111
|
+
expect(result.last).to be_a(::DeclareSchema::Model::IndexDefinition)
|
112
|
+
expect(result.last.name).to eq('on_parent_2_id')
|
113
|
+
expect(result.last.unique).to be_falsey
|
114
|
+
expect(result.last.fields).to eq(['parent_2_id'])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#index_definitions' do
|
119
|
+
it 'returns index_definitions_with_primary_key' do
|
120
|
+
result = subject.index_definitions
|
121
|
+
expect(result.size).to eq(2), result.inspect
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe 'ignore_indexes' do
|
126
|
+
it 'returns empty array' do
|
127
|
+
expect(subject.ignore_indexes).to eq([])
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '#constraint_specs' do
|
132
|
+
it 'returns 2 foreign keys' do
|
133
|
+
result = subject.constraint_specs
|
134
|
+
expect(result.size).to eq(2), result.inspect
|
135
|
+
|
136
|
+
expect(result.first).to be_a(::DeclareSchema::Model::ForeignKeyDefinition)
|
137
|
+
expect(result.first.foreign_key).to eq(foreign_keys.first)
|
138
|
+
expect(result.first.parent_table_name).to be(Parent1.table_name)
|
139
|
+
expect(result.first.on_delete_cascade).to be_truthy
|
140
|
+
|
141
|
+
expect(result.last).to be_a(::DeclareSchema::Model::ForeignKeyDefinition)
|
142
|
+
expect(result.last.foreign_key).to eq(foreign_keys.last)
|
143
|
+
expect(result.last.parent_table_name).to be(Parent2.table_name)
|
144
|
+
expect(result.last.on_delete_cascade).to be_truthy
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -58,7 +58,17 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
describe 'class
|
61
|
+
describe 'class methods' do
|
62
|
+
describe 'index_name' do
|
63
|
+
it 'works with a single column' do
|
64
|
+
expect(described_class.index_name('parent_id')).to eq('on_parent_id')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'works with many columns' do
|
68
|
+
expect(described_class.index_name(['a', 'b', 'c'])).to eq('on_a_and_b_and_c')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
62
72
|
context 'with a migrated database' do
|
63
73
|
before do
|
64
74
|
ActiveRecord::Base.connection.execute <<~EOS
|
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: 0.8.0.pre.
|
4
|
+
version: 0.8.0.pre.6
|
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: 2021-02-
|
11
|
+
date: 2021-02-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- lib/declare_schema/model/column.rb
|
65
65
|
- lib/declare_schema/model/field_spec.rb
|
66
66
|
- lib/declare_schema/model/foreign_key_definition.rb
|
67
|
+
- lib/declare_schema/model/habtm_model_shim.rb
|
67
68
|
- lib/declare_schema/model/index_definition.rb
|
68
69
|
- lib/declare_schema/model/table_options_definition.rb
|
69
70
|
- lib/declare_schema/railtie.rb
|
@@ -85,6 +86,7 @@ files:
|
|
85
86
|
- spec/lib/declare_schema/migration_generator_spec.rb
|
86
87
|
- spec/lib/declare_schema/model/column_spec.rb
|
87
88
|
- spec/lib/declare_schema/model/foreign_key_definition_spec.rb
|
89
|
+
- spec/lib/declare_schema/model/habtm_model_shim_spec.rb
|
88
90
|
- spec/lib/declare_schema/model/index_definition_spec.rb
|
89
91
|
- spec/lib/declare_schema/model/table_options_definition_spec.rb
|
90
92
|
- spec/lib/declare_schema/prepare_testapp.rb
|