declare_schema 0.8.0.pre.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd8228bfafad807a853f8abea954459b3ac209b7041b27699fc5691184c86b80
4
- data.tar.gz: 01a278f8d7bbc83a9309a3c8908b546c509f5b2d14e28fe11bca2fa4fcc7bbed
3
+ metadata.gz: 531940d48f1fe38830944576136ff76e2b29dc69a323a2a8e3f60f431731f104
4
+ data.tar.gz: 3afe0ce91fa631f4fa07d10ef1039f788589d440e87245c859db9bbe0179972d
5
5
  SHA512:
6
- metadata.gz: 632350f71bb95b99fd7f25f0dd9a71c84d544e1e5d26cafcf3ae671e994c9719be3c7f4f297a096ffdca3ec63c5179aea1c159f600bbb061fa86b99a3d92fc6c
7
- data.tar.gz: 757876168af2c046c63332fadc22ce26b63e7697ae5d6c9091b46a4c5d7d349eefc2899052e6e0f2d7df13a200c18f029d881937436e95a17283f1ce709f19f5
6
+ metadata.gz: 67270e128e00f45b8ed8393b85ffe65ab4bc7ae197296adacf22c37629bdf5e768d6e204987b67e2d63b3ac0cc79aadb0b02c2c4f60e7e4b85e01f4d24ef55e2
7
+ data.tar.gz: c9763a6eacd9d1d1deef9e829072e974ea53a5575f0938a8b4202e4210aa704186022a12e8704c08edde24bc73c2da7f95b467b77f3c81e422df54eddaf2352a
data/CHANGELOG.md CHANGED
@@ -4,8 +4,18 @@ 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] - UNRELEASED
7
+ ## [0.9.0] - 2021-03-01
8
+ ### Added
9
+ - Added configurable default settings for `default_text_limit`, `default_string_limit`, `default_null`,
10
+ `default_generate_foreign_keys` and `default_generate_indexing` to allow developers to adhere to project conventions.
11
+
12
+ ### Changed
13
+ - Moved and deprecated default settings for `default_charset` and `default_collation` from
14
+ `Generators::DeclareSchema::Migration::Migrator` to `::DeclareSchema`
15
+
16
+ ## [0.8.0] - 2021-02-22
8
17
  ### Removed
18
+ - Removed assumption that primary key is named 'id'.
9
19
  - Removed `sql_type` that was confusing because it was actually the same as `type` (ex: :string) and not
10
20
  in fact the SQL type (ex: ``varchar(255)'`).
11
21
 
@@ -130,6 +140,7 @@ using the appropriate Rails configuration attributes.
130
140
  ### Added
131
141
  - Initial version from https://github.com/Invoca/hobo_fields v4.1.0.
132
142
 
143
+ [0.9.0]: https://github.com/Invoca/declare_schema/compare/v0.8.0...v0.9.0
133
144
  [0.8.0]: https://github.com/Invoca/declare_schema/compare/v0.7.1...v0.8.0
134
145
  [0.7.1]: https://github.com/Invoca/declare_schema/compare/v0.7.0...v0.7.1
135
146
  [0.7.0]: https://github.com/Invoca/declare_schema/compare/v0.6.3...v0.7.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- declare_schema (0.8.0.pre.3)
4
+ declare_schema (0.9.0)
5
5
  rails (>= 4.2)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -70,18 +70,85 @@ DeclareSchema::Migration::Migrator.before_generating_migration do
70
70
  end
71
71
  ```
72
72
 
73
- ## Declaring Character Set and Collation
74
- _Note: This feature currently only works for MySQL database configurations._
73
+ ### Global Configuration
74
+ Configurations can be set at the global level to customize default declaration for the following values:
75
75
 
76
- MySQL originally supported UTF-8 in the range of 1-3 bytes (`mb3` or "multi-byte 3")
77
- which covered the full set of Unicode code points at the time: U+0000 - U+FFFF.
78
- But later, Unicode was extended beyond U+FFFF to make room for emojis, and with that
79
- UTF-8 require 1-4 bytes (`mb4` or "multi-byte 4"). With this addition, there has
80
- come a need to dynamically define the character set and collation for individual
81
- tables and columns in the database. With `declare_schema` this can be configured
82
- at three separate levels
76
+ #### Text Limit
77
+ The default text limit can be set using the `DeclareSchema.default_text_limit=` method.
78
+ Note that a `nil` default means that there is no default-- so every declaration must be explicit.
79
+ This will `raise` a `limit: must be provided for field :text...` error when the default value is `nil` and there is no explicit
80
+ declaration.
83
81
 
84
- ### Global Configuration
82
+ For example, adding the following to your `config/initializers` directory will
83
+ set the default `text limit` value to `0xffff`:
84
+
85
+ **declare_schema.rb**
86
+ ```ruby
87
+ # frozen_string_literal: true
88
+
89
+ DeclareSchema.default_text_limit = 0xffff
90
+ ```
91
+
92
+ #### String Limit
93
+ The default string limit can be set using the `DeclareSchema.default_string_limit=` method.
94
+ Note that a `nil` default means that there is no default-- so every declaration must be explicit.
95
+ This will `raise` a `limit: must be provided for field :string...` error when the default value is `nil` and there is no explicit
96
+ declaration.
97
+
98
+ For example, adding the following to your `config/initializers` directory will
99
+ set the default `string limit` value to `255`:
100
+
101
+ **declare_schema.rb**
102
+ ```ruby
103
+ # frozen_string_literal: true
104
+
105
+ DeclareSchema.default_string_limit = 255
106
+ ```
107
+
108
+ #### Null
109
+ The default null value can be set using the `DeclareSchema.default_null=` method.
110
+ Note that a `nil` default means that there is no default-- so every declaration must be explicit.
111
+ This will `raise` a `null: must be provided for field...` error when the default value is `nil` and there is no explicit
112
+ declaration.
113
+
114
+ For example, adding the following to your `config/initializers` directory will
115
+ set the default `null` value to `true`:
116
+
117
+ **declare_schema.rb**
118
+ ```ruby
119
+ # frozen_string_literal: true
120
+
121
+ DeclareSchema.default_null = true
122
+ ```
123
+
124
+ #### Generate Foreign Keys
125
+ The default value for generate foreign keys can be set using the `DeclareSchema.default_generate_foreign_keys=` method.
126
+ This value defaults to `true` and can only be set at the global level.
127
+
128
+ For example, adding the following to your `config/initializers` directory will set
129
+ the default `generate foreign keys` value to `false`:
130
+
131
+ **declare_schema.rb**
132
+ ```ruby
133
+ # frozen_string_literal: true
134
+
135
+ DeclareSchema.default_generate_foreign_keys = false
136
+ ```
137
+
138
+ #### Generate Indexing
139
+ The default value for generate indexing can be set using the `DeclareSchema.default_generate_indexing=` method.
140
+ This value defaults to `true` and can only be set at the global level.
141
+
142
+ For example, adding the following to your `config/initializers` directory will
143
+ set the default `generate indexing` value to `false`:
144
+
145
+ **declare_schema.rb**
146
+ ```ruby
147
+ # frozen_string_literal: true
148
+
149
+ DeclareSchema.default_generate_indexing = false
150
+ ```
151
+ #### Character Set and Collation
85
152
  The character set and collation for all tables and fields can be set at the global level
86
153
  using the `Generators::DeclareSchema::Migrator.default_charset=` and
87
154
  `Generators::DeclareSchema::Migrator.default_collation=` configuration methods.
@@ -93,10 +160,21 @@ turn all tables into `utf8mb4` supporting tables:
93
160
  ```ruby
94
161
  # frozen_string_literal: true
95
162
 
96
- Generators::DeclareSchema::Migration::Migrator.default_charset = "utf8mb4"
97
- Generators::DeclareSchema::Migration::Migrator.default_collation = "utf8mb4_bin"
163
+ DeclareSchema.default_charset = "utf8mb4"
164
+ DeclareSchema.default_collation = "utf8mb4_bin"
98
165
  ```
99
166
 
167
+ ## Declaring Character Set and Collation
168
+ _Note: This feature currently only works for MySQL database configurations._
169
+
170
+ MySQL originally supported UTF-8 in the range of 1-3 bytes (`mb3` or "multi-byte 3")
171
+ which covered the full set of Unicode code points at the time: U+0000 - U+FFFF.
172
+ But later, Unicode was extended beyond U+FFFF to make room for emojis, and with that
173
+ UTF-8 require 1-4 bytes (`mb4` or "multi-byte 4"). With this addition, there has
174
+ come a need to dynamically define the character set and collation for individual
175
+ tables and columns in the database. With `declare_schema` this can be configured
176
+ at three separate levels
177
+
100
178
  ### Table Configuration
101
179
  In order to configure a table's default character set and collation, the `charset` and
102
180
  `collation` arguments can be added to the `fields` block.
@@ -21,7 +21,18 @@ module DeclareSchema
21
21
  text: String
22
22
  }.freeze
23
23
 
24
+ @default_charset = "utf8mb4"
25
+ @default_collation = "utf8mb4_bin"
26
+ @default_text_limit = 0xffff_ffff
27
+ @default_string_limit = nil
28
+ @default_null = false
29
+ @default_generate_foreign_keys = true
30
+ @default_generate_indexing = true
31
+
24
32
  class << self
33
+ attr_reader :default_charset, :default_collation, :default_text_limit, :default_string_limit, :default_null,
34
+ :default_generate_foreign_keys, :default_generate_indexing
35
+
25
36
  def to_class(type)
26
37
  case type
27
38
  when Class
@@ -32,6 +43,41 @@ module DeclareSchema
32
43
  raise ArgumentError, "expected Class or Symbol or String: got #{type.inspect}"
33
44
  end
34
45
  end
46
+
47
+ def default_charset=(charset)
48
+ charset.is_a?(String) or raise ArgumentError, "charset must be a string (got #{charset.inspect})"
49
+ @default_charset = charset
50
+ end
51
+
52
+ def default_collation=(collation)
53
+ collation.is_a?(String) or raise ArgumentError, "collation must be a string (got #{collation.inspect})"
54
+ @default_collation = collation
55
+ end
56
+
57
+ def default_text_limit=(text_limit)
58
+ text_limit.nil? or text_limit.is_a?(Integer) or raise ArgumentError, "text limit must be an integer or nil (got #{text_limit.inspect})"
59
+ @default_text_limit = text_limit
60
+ end
61
+
62
+ def default_string_limit=(string_limit)
63
+ string_limit.nil? or string_limit.is_a?(Integer) or raise ArgumentError, "string limit must be an integer or nil (got #{string_limit.inspect})"
64
+ @default_string_limit = string_limit
65
+ end
66
+
67
+ def default_null=(null)
68
+ null.in?([true, false, nil]) or raise ArgumentError, "null must be either true, false, or nil (got #{null.inspect})"
69
+ @default_null = null
70
+ end
71
+
72
+ def default_generate_foreign_keys=(generate_foreign_keys)
73
+ generate_foreign_keys.in?([true, false]) or raise ArgumentError, "generate_foreign_keys must be either true or false (got #{generate_foreign_keys.inspect})"
74
+ @default_generate_foreign_keys = generate_foreign_keys
75
+ end
76
+
77
+ def default_generate_indexing=(generate_indexing)
78
+ generate_indexing.in?([true, false]) or raise ArgumentError, "generate_indexing must be either true or false (got #{generate_indexing.inspect})"
79
+ @default_generate_indexing = generate_indexing
80
+ end
35
81
  end
36
82
  end
37
83
 
@@ -15,7 +15,7 @@ module DeclareSchema
15
15
  @table_options = table_options
16
16
 
17
17
  if block
18
- dsl = DeclareSchema::FieldDeclarationDsl.new(self, null: false)
18
+ dsl = DeclareSchema::FieldDeclarationDsl.new(self)
19
19
  if block.arity == 1
20
20
  yield dsl
21
21
  else
@@ -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
- # don't double-index fields
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: an prefix index in MySQL)
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
- add_serialize_for_field(name, type, options)
87
- add_formatting_for_field(name, type)
88
- add_validations_for_field(name, type, args, options)
89
- add_index_for_field(name, args, options)
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 + [rails_default_primary_key]
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
- declare_polymorphic_type_field(foreign_type, column_options)
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 declare_polymorphic_type_field(foreign_type, column_options)
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 add_validations_for_field(name, type, args, options)
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 add_serialize_for_field(name, type, options)
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] = serialized_default(name, serialize_class == true ? Object : serialize_class, 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 serialized_default(attr_name, class_name_or_coder, default)
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 add_formatting_for_field(name, type)
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 add_index_for_field(name, args, options)
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 = column(name.to_s))
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 column(name)
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]
@@ -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