declare_schema 0.8.0.pre.6 → 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 +50 -58
- data/lib/declare_schema/model/field_spec.rb +2 -2
- data/lib/declare_schema/model/habtm_model_shim.rb +1 -1
- data/lib/declare_schema/version.rb +1 -1
- data/lib/generators/declare_schema/migration/migrator.rb +9 -8
- data/spec/lib/declare_schema/field_spec_spec.rb +8 -6
- data/spec/lib/declare_schema/interactive_primary_key_spec.rb +3 -3
- data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +3 -3
- metadata +2 -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
@@ -38,7 +38,7 @@ module DeclareSchema
|
|
38
38
|
|
39
39
|
# eval avoids the ruby 1.9.2 "super from singleton method ..." error
|
40
40
|
|
41
|
-
eval
|
41
|
+
eval <<~EOS
|
42
42
|
def self.inherited(klass)
|
43
43
|
unless klass.field_specs.has_key?(inheritance_column)
|
44
44
|
fields do |f|
|
@@ -48,14 +48,14 @@ module DeclareSchema
|
|
48
48
|
end
|
49
49
|
super
|
50
50
|
end
|
51
|
-
|
51
|
+
EOS
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
56
|
module ClassMethods
|
57
57
|
def index(fields, options = {})
|
58
|
-
#
|
58
|
+
# make index idempotent
|
59
59
|
index_fields_s = Array.wrap(fields).map(&:to_s)
|
60
60
|
unless index_definitions.any? { |index_spec| index_spec.fields == index_fields_s }
|
61
61
|
index_definitions << ::DeclareSchema::Model::IndexDefinition.new(self, fields, options)
|
@@ -74,7 +74,7 @@ module DeclareSchema
|
|
74
74
|
end
|
75
75
|
|
76
76
|
# tell the migration generator to ignore the named index. Useful for existing indexes, or for indexes
|
77
|
-
# that can't be automatically generated (for example:
|
77
|
+
# that can't be automatically generated (for example: a prefix index in MySQL)
|
78
78
|
def ignore_index(index_name)
|
79
79
|
ignore_indexes << index_name.to_s
|
80
80
|
end
|
@@ -85,10 +85,10 @@ module DeclareSchema
|
|
85
85
|
# declarations.
|
86
86
|
def declare_field(name, type, *args, **options)
|
87
87
|
try(:field_added, name, type, args, options)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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)
|
92
92
|
field_specs[name] = ::DeclareSchema::Model::FieldSpec.new(self, name, type, position: field_specs.size, **options)
|
93
93
|
attr_order << name unless attr_order.include?(name)
|
94
94
|
end
|
@@ -97,41 +97,10 @@ module DeclareSchema
|
|
97
97
|
if index_definitions.any?(&:primary_key?)
|
98
98
|
index_definitions
|
99
99
|
else
|
100
|
-
index_definitions + [
|
100
|
+
index_definitions + [_rails_default_primary_key]
|
101
101
|
end
|
102
102
|
end
|
103
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
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
def rails_default_primary_key
|
132
|
-
::DeclareSchema::Model::IndexDefinition.new(self, [primary_key.to_sym], unique: true, name: DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME)
|
133
|
-
end
|
134
|
-
|
135
104
|
# Extend belongs_to so that it creates a FieldSpec for the foreign key
|
136
105
|
def belongs_to(name, scope = nil, **options)
|
137
106
|
column_options = {}
|
@@ -172,7 +141,7 @@ module DeclareSchema
|
|
172
141
|
declare_field(fkey.to_sym, :integer, column_options)
|
173
142
|
if refl.options[:polymorphic]
|
174
143
|
foreign_type = options[:foreign_type] || "#{name}_type"
|
175
|
-
|
144
|
+
_declare_polymorphic_type_field(foreign_type, column_options)
|
176
145
|
index([foreign_type, fkey], index_options) if index_options[:name] != false
|
177
146
|
else
|
178
147
|
index(fkey, index_options) if index_options[:name] != false
|
@@ -180,26 +149,49 @@ module DeclareSchema
|
|
180
149
|
end
|
181
150
|
end
|
182
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
|
+
|
183
183
|
# Declares the "foo_type" field that accompanies the "foo_id"
|
184
184
|
# field for a polymorphic belongs_to
|
185
|
-
def
|
185
|
+
def _declare_polymorphic_type_field(foreign_type, column_options)
|
186
186
|
declare_field(foreign_type, :string, column_options.merge(limit: 255))
|
187
187
|
# FIXME: Before declare_schema was extracted, this used to now do:
|
188
188
|
# never_show(type_col)
|
189
189
|
# That needs doing somewhere
|
190
190
|
end
|
191
191
|
|
192
|
-
# Declare a rich-type for any attribute (i.e. getter method). This
|
193
|
-
# does not effect the attribute in any way - it just records the
|
194
|
-
# metadata.
|
195
|
-
def declare_attr_type(name, type, options = {})
|
196
|
-
attr_types[name] = klass = DeclareSchema.to_class(type)
|
197
|
-
klass.try(:declared, self, name, options)
|
198
|
-
end
|
199
|
-
|
200
192
|
# Add field validations according to arguments in the
|
201
193
|
# field declaration
|
202
|
-
def
|
194
|
+
def _add_validations_for_field(name, type, args, options)
|
203
195
|
validates_presence_of name if :required.in?(args)
|
204
196
|
validates_uniqueness_of name, allow_nil: !:required.in?(args) if :unique.in?(args)
|
205
197
|
|
@@ -218,18 +210,18 @@ module DeclareSchema
|
|
218
210
|
end
|
219
211
|
end
|
220
212
|
|
221
|
-
def
|
213
|
+
def _add_serialize_for_field(name, type, options)
|
222
214
|
if (serialize_class = options.delete(:serialize))
|
223
215
|
type == :string || type == :text or raise ArgumentError, "serialize field type must be :string or :text"
|
224
216
|
serialize_args = Array((serialize_class unless serialize_class == true))
|
225
217
|
serialize(name, *serialize_args)
|
226
218
|
if options.has_key?(:default)
|
227
|
-
options[:default] =
|
219
|
+
options[:default] = _serialized_default(name, serialize_class == true ? Object : serialize_class, options[:default])
|
228
220
|
end
|
229
221
|
end
|
230
222
|
end
|
231
223
|
|
232
|
-
def
|
224
|
+
def _serialized_default(attr_name, class_name_or_coder, default)
|
233
225
|
# copied from https://github.com/rails/rails/blob/7d6cb950e7c0e31c2faaed08c81743439156c9f5/activerecord/lib/active_record/attribute_methods/serialization.rb#L70-L76
|
234
226
|
coder = if class_name_or_coder == ::JSON
|
235
227
|
ActiveRecord::Coders::JSON
|
@@ -248,7 +240,7 @@ module DeclareSchema
|
|
248
240
|
end
|
249
241
|
end
|
250
242
|
|
251
|
-
def
|
243
|
+
def _add_formatting_for_field(name, type)
|
252
244
|
if (type_class = DeclareSchema.to_class(type))
|
253
245
|
if "format".in?(type_class.instance_methods)
|
254
246
|
before_validation do |record|
|
@@ -258,7 +250,7 @@ module DeclareSchema
|
|
258
250
|
end
|
259
251
|
end
|
260
252
|
|
261
|
-
def
|
253
|
+
def _add_index_for_field(name, args, options)
|
262
254
|
if (to_name = options.delete(:index))
|
263
255
|
index_opts =
|
264
256
|
{
|
@@ -287,13 +279,13 @@ module DeclareSchema
|
|
287
279
|
refl
|
288
280
|
end
|
289
281
|
end ||
|
290
|
-
if (col =
|
282
|
+
if (col = _column(name.to_s))
|
291
283
|
DeclareSchema::PLAIN_TYPES[col.type] || col.klass
|
292
284
|
end
|
293
285
|
end
|
294
286
|
|
295
287
|
# Return the entry from #columns for the named column
|
296
|
-
def
|
288
|
+
def _column(name)
|
297
289
|
defined?(@table_exists) or @table_exists = table_exists?
|
298
290
|
if @table_exists
|
299
291
|
columns_hash[name.to_s]
|
@@ -47,9 +47,9 @@ module DeclareSchema
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def initialize(model, name, type, position: 0, **options)
|
50
|
-
|
50
|
+
_defined_primary_key = model._defined_primary_key
|
51
51
|
|
52
|
-
name.to_s ==
|
52
|
+
name.to_s == _defined_primary_key and raise ArgumentError, "you may not provide a field spec for the primary key #{name.inspect}"
|
53
53
|
|
54
54
|
@model = model
|
55
55
|
@name = name.to_sym
|
@@ -285,12 +285,13 @@ module Generators
|
|
285
285
|
end
|
286
286
|
|
287
287
|
def create_table_options(model, disable_auto_increment)
|
288
|
-
|
288
|
+
primary_key = model._defined_primary_key
|
289
|
+
if primary_key.blank? || disable_auto_increment
|
289
290
|
"id: false"
|
290
|
-
elsif
|
291
|
+
elsif primary_key == "id"
|
291
292
|
"id: :bigint"
|
292
293
|
else
|
293
|
-
"primary_key: :#{
|
294
|
+
"primary_key: :#{primary_key}"
|
294
295
|
end
|
295
296
|
end
|
296
297
|
|
@@ -323,18 +324,18 @@ module Generators
|
|
323
324
|
new_table_name = model.table_name
|
324
325
|
|
325
326
|
db_columns = model.connection.columns(current_table_name).index_by(&:name)
|
326
|
-
key_missing = db_columns[model.
|
327
|
-
if model.
|
328
|
-
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)
|
329
330
|
end
|
330
331
|
|
331
332
|
model_column_names = model.field_specs.keys.map(&:to_s)
|
332
333
|
db_column_names = db_columns.keys.map(&:to_s)
|
333
334
|
|
334
335
|
to_add = model_column_names - db_column_names
|
335
|
-
to_add += [model.
|
336
|
+
to_add += [model._defined_primary_key] if key_missing && model._defined_primary_key.present?
|
336
337
|
to_remove = db_column_names - model_column_names
|
337
|
-
to_remove -= [model.
|
338
|
+
to_remove -= [model._defined_primary_key.to_sym] if model._defined_primary_key.present?
|
338
339
|
|
339
340
|
to_rename = extract_column_renames!(to_add, to_remove, new_table_name)
|
340
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
|
@@ -85,10 +85,12 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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)
|
93
|
+
end
|
92
94
|
end
|
93
95
|
end
|
94
96
|
|
@@ -109,7 +111,7 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
112
|
-
[:integer, :bigint, :string, :text, :binary, :
|
114
|
+
[:integer, :bigint, :string, :text, :binary, :datetime, :date, :time, (:varbinary if defined?(Mysql2))].compact.each do |t|
|
113
115
|
describe t.to_s do
|
114
116
|
let(:extra) { t == :string ? { limit: 100 } : {} }
|
115
117
|
|
@@ -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
|
|
@@ -88,13 +88,13 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
88
88
|
|
89
89
|
describe '#primary_key' do
|
90
90
|
it 'returns false' do
|
91
|
-
expect(subject.
|
91
|
+
expect(subject._defined_primary_key).to eq(false)
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
describe '#
|
95
|
+
describe '#_defined_primary_key' do
|
96
96
|
it 'returns false' do
|
97
|
-
expect(subject.
|
97
|
+
expect(subject._defined_primary_key).to eq(false)
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
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
|