declare_schema 0.8.0.pre.3 → 0.9.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 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