declare_schema 0.8.0.pre.2 → 0.8.0
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 +2 -1
- data/Gemfile.lock +1 -1
- data/lib/declare_schema/model.rb +52 -37
- data/lib/declare_schema/model/column.rb +3 -1
- data/lib/declare_schema/model/field_spec.rb +4 -6
- 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 +10 -72
- data/spec/lib/declare_schema/field_spec_spec.rb +33 -24
- data/spec/lib/declare_schema/interactive_primary_key_spec.rb +3 -3
- 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: ae6f3f47d3ad4fa0b1d2e30d8f34b7ac5825b690838492ac57846dcd53396e9a
|
4
|
+
data.tar.gz: 129d77729c08d2fb41e506571ead2a82dd76c0c1675c18556bc3811e0adf3362
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b145fdd60646c467772034afa2a29e30d29a4d35445c7e769bab731c043cb38c8e0b365ac7f6dc416e93fafdc1edd6e77724085054a6a442934cc191e335fdf
|
7
|
+
data.tar.gz: 1356d29f00f1eb4a72b567c48c57c6683bcc56852dfb68a3252b521a74c6c0afcfdf5765d94a31d3322ee297465c3ca60ec611090cf3ad5dd935e2bc343285ed
|
data/CHANGELOG.md
CHANGED
@@ -4,8 +4,9 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
4
4
|
|
5
5
|
Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
-
## [0.8.0] -
|
7
|
+
## [0.8.0] - 2021-02-22
|
8
8
|
### Removed
|
9
|
+
- Removed assumption that primary key is named 'id'.
|
9
10
|
- Removed `sql_type` that was confusing because it was actually the same as `type` (ex: :string) and not
|
10
11
|
in fact the SQL type (ex: ``varchar(255)'`).
|
11
12
|
|
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
|
@@ -36,7 +38,7 @@ module DeclareSchema
|
|
36
38
|
|
37
39
|
# eval avoids the ruby 1.9.2 "super from singleton method ..." error
|
38
40
|
|
39
|
-
eval
|
41
|
+
eval <<~EOS
|
40
42
|
def self.inherited(klass)
|
41
43
|
unless klass.field_specs.has_key?(inheritance_column)
|
42
44
|
fields do |f|
|
@@ -46,14 +48,14 @@ module DeclareSchema
|
|
46
48
|
end
|
47
49
|
super
|
48
50
|
end
|
49
|
-
|
51
|
+
EOS
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
54
56
|
module ClassMethods
|
55
57
|
def index(fields, options = {})
|
56
|
-
#
|
58
|
+
# make index idempotent
|
57
59
|
index_fields_s = Array.wrap(fields).map(&:to_s)
|
58
60
|
unless index_definitions.any? { |index_spec| index_spec.fields == index_fields_s }
|
59
61
|
index_definitions << ::DeclareSchema::Model::IndexDefinition.new(self, fields, options)
|
@@ -72,7 +74,7 @@ module DeclareSchema
|
|
72
74
|
end
|
73
75
|
|
74
76
|
# tell the migration generator to ignore the named index. Useful for existing indexes, or for indexes
|
75
|
-
# that can't be automatically generated (for example:
|
77
|
+
# that can't be automatically generated (for example: a prefix index in MySQL)
|
76
78
|
def ignore_index(index_name)
|
77
79
|
ignore_indexes << index_name.to_s
|
78
80
|
end
|
@@ -83,10 +85,10 @@ module DeclareSchema
|
|
83
85
|
# declarations.
|
84
86
|
def declare_field(name, type, *args, **options)
|
85
87
|
try(:field_added, name, type, args, options)
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
88
|
+
_add_serialize_for_field(name, type, options)
|
89
|
+
_add_formatting_for_field(name, type)
|
90
|
+
_add_validations_for_field(name, type, args, options)
|
91
|
+
_add_index_for_field(name, args, options)
|
90
92
|
field_specs[name] = ::DeclareSchema::Model::FieldSpec.new(self, name, type, position: field_specs.size, **options)
|
91
93
|
attr_order << name unless attr_order.include?(name)
|
92
94
|
end
|
@@ -95,20 +97,10 @@ module DeclareSchema
|
|
95
97
|
if index_definitions.any?(&:primary_key?)
|
96
98
|
index_definitions
|
97
99
|
else
|
98
|
-
index_definitions + [
|
100
|
+
index_definitions + [_rails_default_primary_key]
|
99
101
|
end
|
100
102
|
end
|
101
103
|
|
102
|
-
def primary_key
|
103
|
-
super || 'id'
|
104
|
-
end
|
105
|
-
|
106
|
-
private
|
107
|
-
|
108
|
-
def rails_default_primary_key
|
109
|
-
::DeclareSchema::Model::IndexDefinition.new(self, [primary_key.to_sym], unique: true, name: DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME)
|
110
|
-
end
|
111
|
-
|
112
104
|
# Extend belongs_to so that it creates a FieldSpec for the foreign key
|
113
105
|
def belongs_to(name, scope = nil, **options)
|
114
106
|
column_options = {}
|
@@ -149,7 +141,7 @@ module DeclareSchema
|
|
149
141
|
declare_field(fkey.to_sym, :integer, column_options)
|
150
142
|
if refl.options[:polymorphic]
|
151
143
|
foreign_type = options[:foreign_type] || "#{name}_type"
|
152
|
-
|
144
|
+
_declare_polymorphic_type_field(foreign_type, column_options)
|
153
145
|
index([foreign_type, fkey], index_options) if index_options[:name] != false
|
154
146
|
else
|
155
147
|
index(fkey, index_options) if index_options[:name] != false
|
@@ -157,26 +149,49 @@ module DeclareSchema
|
|
157
149
|
end
|
158
150
|
end
|
159
151
|
|
152
|
+
if ::Rails::VERSION::MAJOR < 5
|
153
|
+
def primary_key
|
154
|
+
super || 'id'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# returns the primary key (String) as declared with primary_key =
|
159
|
+
# unlike the `primary_key` method, DOES NOT query the database to find the actual primary key in use right now
|
160
|
+
# if no explicit primary key set, returns the default_defined_primary_key
|
161
|
+
def _defined_primary_key
|
162
|
+
if defined?(@primary_key)
|
163
|
+
@primary_key&.to_s
|
164
|
+
end || _default_defined_primary_key
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
# if this is a derived class, returns the base class's _defined_primary_key
|
170
|
+
# otherwise, returns 'id'
|
171
|
+
def _default_defined_primary_key
|
172
|
+
if self == base_class
|
173
|
+
'id'
|
174
|
+
else
|
175
|
+
base_class._defined_primary_key
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def _rails_default_primary_key
|
180
|
+
::DeclareSchema::Model::IndexDefinition.new(self, [_defined_primary_key.to_sym], unique: true, name: DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME)
|
181
|
+
end
|
182
|
+
|
160
183
|
# Declares the "foo_type" field that accompanies the "foo_id"
|
161
184
|
# field for a polymorphic belongs_to
|
162
|
-
def
|
185
|
+
def _declare_polymorphic_type_field(foreign_type, column_options)
|
163
186
|
declare_field(foreign_type, :string, column_options.merge(limit: 255))
|
164
187
|
# FIXME: Before declare_schema was extracted, this used to now do:
|
165
188
|
# never_show(type_col)
|
166
189
|
# That needs doing somewhere
|
167
190
|
end
|
168
191
|
|
169
|
-
# Declare a rich-type for any attribute (i.e. getter method). This
|
170
|
-
# does not effect the attribute in any way - it just records the
|
171
|
-
# metadata.
|
172
|
-
def declare_attr_type(name, type, options = {})
|
173
|
-
attr_types[name] = klass = DeclareSchema.to_class(type)
|
174
|
-
klass.try(:declared, self, name, options)
|
175
|
-
end
|
176
|
-
|
177
192
|
# Add field validations according to arguments in the
|
178
193
|
# field declaration
|
179
|
-
def
|
194
|
+
def _add_validations_for_field(name, type, args, options)
|
180
195
|
validates_presence_of name if :required.in?(args)
|
181
196
|
validates_uniqueness_of name, allow_nil: !:required.in?(args) if :unique.in?(args)
|
182
197
|
|
@@ -195,18 +210,18 @@ module DeclareSchema
|
|
195
210
|
end
|
196
211
|
end
|
197
212
|
|
198
|
-
def
|
213
|
+
def _add_serialize_for_field(name, type, options)
|
199
214
|
if (serialize_class = options.delete(:serialize))
|
200
215
|
type == :string || type == :text or raise ArgumentError, "serialize field type must be :string or :text"
|
201
216
|
serialize_args = Array((serialize_class unless serialize_class == true))
|
202
217
|
serialize(name, *serialize_args)
|
203
218
|
if options.has_key?(:default)
|
204
|
-
options[:default] =
|
219
|
+
options[:default] = _serialized_default(name, serialize_class == true ? Object : serialize_class, options[:default])
|
205
220
|
end
|
206
221
|
end
|
207
222
|
end
|
208
223
|
|
209
|
-
def
|
224
|
+
def _serialized_default(attr_name, class_name_or_coder, default)
|
210
225
|
# copied from https://github.com/rails/rails/blob/7d6cb950e7c0e31c2faaed08c81743439156c9f5/activerecord/lib/active_record/attribute_methods/serialization.rb#L70-L76
|
211
226
|
coder = if class_name_or_coder == ::JSON
|
212
227
|
ActiveRecord::Coders::JSON
|
@@ -225,7 +240,7 @@ module DeclareSchema
|
|
225
240
|
end
|
226
241
|
end
|
227
242
|
|
228
|
-
def
|
243
|
+
def _add_formatting_for_field(name, type)
|
229
244
|
if (type_class = DeclareSchema.to_class(type))
|
230
245
|
if "format".in?(type_class.instance_methods)
|
231
246
|
before_validation do |record|
|
@@ -235,7 +250,7 @@ module DeclareSchema
|
|
235
250
|
end
|
236
251
|
end
|
237
252
|
|
238
|
-
def
|
253
|
+
def _add_index_for_field(name, args, options)
|
239
254
|
if (to_name = options.delete(:index))
|
240
255
|
index_opts =
|
241
256
|
{
|
@@ -264,13 +279,13 @@ module DeclareSchema
|
|
264
279
|
refl
|
265
280
|
end
|
266
281
|
end ||
|
267
|
-
if (col =
|
282
|
+
if (col = _column(name.to_s))
|
268
283
|
DeclareSchema::PLAIN_TYPES[col.type] || col.klass
|
269
284
|
end
|
270
285
|
end
|
271
286
|
|
272
287
|
# Return the entry from #columns for the named column
|
273
|
-
def
|
288
|
+
def _column(name)
|
274
289
|
defined?(@table_exists) or @table_exists = table_exists?
|
275
290
|
if @table_exists
|
276
291
|
columns_hash[name.to_s]
|
@@ -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
|
@@ -80,7 +78,7 @@ module DeclareSchema
|
|
80
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
|
|
@@ -348,12 +285,13 @@ module Generators
|
|
348
285
|
end
|
349
286
|
|
350
287
|
def create_table_options(model, disable_auto_increment)
|
351
|
-
|
288
|
+
primary_key = model._defined_primary_key
|
289
|
+
if primary_key.blank? || disable_auto_increment
|
352
290
|
"id: false"
|
353
|
-
elsif
|
291
|
+
elsif primary_key == "id"
|
354
292
|
"id: :bigint"
|
355
293
|
else
|
356
|
-
"primary_key: :#{
|
294
|
+
"primary_key: :#{primary_key}"
|
357
295
|
end
|
358
296
|
end
|
359
297
|
|
@@ -386,18 +324,18 @@ module Generators
|
|
386
324
|
new_table_name = model.table_name
|
387
325
|
|
388
326
|
db_columns = model.connection.columns(current_table_name).index_by(&:name)
|
389
|
-
key_missing = db_columns[model.
|
390
|
-
if model.
|
391
|
-
db_columns.delete(model.
|
327
|
+
key_missing = db_columns[model._defined_primary_key].nil? && model._defined_primary_key.present?
|
328
|
+
if model._defined_primary_key.present?
|
329
|
+
db_columns.delete(model._defined_primary_key)
|
392
330
|
end
|
393
331
|
|
394
332
|
model_column_names = model.field_specs.keys.map(&:to_s)
|
395
333
|
db_column_names = db_columns.keys.map(&:to_s)
|
396
334
|
|
397
335
|
to_add = model_column_names - db_column_names
|
398
|
-
to_add += [model.
|
336
|
+
to_add += [model._defined_primary_key] if key_missing && model._defined_primary_key.present?
|
399
337
|
to_remove = db_column_names - model_column_names
|
400
|
-
to_remove -= [model.
|
338
|
+
to_remove -= [model._defined_primary_key.to_sym] if model._defined_primary_key.present?
|
401
339
|
|
402
340
|
to_rename = extract_column_renames!(to_add, to_remove, new_table_name)
|
403
341
|
|
@@ -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
|
@@ -83,37 +83,46 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
83
83
|
expect(subject.schema_attributes(col_spec)).to eq(type: :text, null: true, default: 'none')
|
84
84
|
end
|
85
85
|
end
|
86
|
+
end
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
if defined?(Mysql2)
|
89
|
+
describe 'varbinary' do # TODO: :varbinary is an Invoca addition to Rails; make it a configurable option
|
90
|
+
it 'is supported' do
|
91
|
+
subject = described_class.new(model, :binary_dump, :varbinary, limit: 200, null: false, position: 2)
|
92
|
+
expect(subject.schema_attributes(col_spec)).to eq(type: :varbinary, limit: 200, null: false)
|
91
93
|
end
|
94
|
+
end
|
95
|
+
end
|
92
96
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
+
describe 'decimal' do
|
98
|
+
it 'allows precision: and scale:' do
|
99
|
+
subject = described_class.new(model, :quantity, :decimal, precision: 8, scale: 10, null: true, position: 3)
|
100
|
+
expect(subject.schema_attributes(col_spec)).to eq(type: :decimal, precision: 8, scale: 10, null: true)
|
101
|
+
end
|
97
102
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
103
|
+
it 'requires precision:' do
|
104
|
+
expect_any_instance_of(described_class).to receive(:warn).with(/precision: required for :decimal type/)
|
105
|
+
described_class.new(model, :quantity, :decimal, scale: 10, null: true, position: 3)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'requires scale:' do
|
109
|
+
expect_any_instance_of(described_class).to receive(:warn).with(/scale: required for :decimal type/)
|
110
|
+
described_class.new(model, :quantity, :decimal, precision: 8, null: true, position: 3)
|
102
111
|
end
|
112
|
+
end
|
103
113
|
|
104
|
-
|
105
|
-
|
106
|
-
|
114
|
+
[:integer, :bigint, :string, :text, :binary, :datetime, :date, :time, (:varbinary if defined?(Mysql2))].compact.each do |t|
|
115
|
+
describe t.to_s do
|
116
|
+
let(:extra) { t == :string ? { limit: 100 } : {} }
|
107
117
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
118
|
+
it 'does not allow precision:' do
|
119
|
+
expect_any_instance_of(described_class).to receive(:warn).with(/precision: only allowed for :decimal type/)
|
120
|
+
described_class.new(model, :quantity, t, { precision: 8, null: true, position: 3 }.merge(extra))
|
121
|
+
end unless t == :datetime
|
112
122
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
123
|
+
it 'does not allow scale:' do
|
124
|
+
expect_any_instance_of(described_class).to receive(:warn).with(/scale: only allowed for :decimal type/)
|
125
|
+
described_class.new(model, :quantity, t, { scale: 10, null: true, position: 3 }.merge(extra))
|
117
126
|
end
|
118
127
|
end
|
119
128
|
end
|
@@ -19,7 +19,7 @@ RSpec.describe 'DeclareSchema Migration Generator interactive primary key' do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
generate_migrations '-n', '-m'
|
22
|
-
expect(Foo.
|
22
|
+
expect(Foo._defined_primary_key).to eq('foo_id')
|
23
23
|
|
24
24
|
### migrate from
|
25
25
|
# rename from custom primary_key
|
@@ -31,7 +31,7 @@ RSpec.describe 'DeclareSchema Migration Generator interactive primary key' do
|
|
31
31
|
|
32
32
|
puts "\n\e[45m Please enter 'id' (no quotes) at the next prompt \e[0m"
|
33
33
|
generate_migrations '-n', '-m'
|
34
|
-
expect(Foo.
|
34
|
+
expect(Foo._defined_primary_key).to eq('id')
|
35
35
|
|
36
36
|
nuke_model_class(Foo)
|
37
37
|
|
@@ -47,7 +47,7 @@ RSpec.describe 'DeclareSchema Migration Generator interactive primary key' do
|
|
47
47
|
|
48
48
|
puts "\n\e[45m Please enter 'drop id' (no quotes) at the next prompt \e[0m"
|
49
49
|
generate_migrations '-n', '-m'
|
50
|
-
expect(Foo.
|
50
|
+
expect(Foo._defined_primary_key).to eq('foo_id')
|
51
51
|
|
52
52
|
### ensure it doesn't cause further migrations
|
53
53
|
|
@@ -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._defined_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
|
4
|
+
version: 0.8.0
|
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-22 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
|