declare_schema 0.12.0.pre.1 → 0.13.0.pre.2

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: e1353d236bb050d93155e56eab2bf5e5d31da06338970b13278c07ed86ac3180
4
- data.tar.gz: f70054b7f56fd18264abe2e719167a2d83ebaa143279dc784dfcaf16b4cb4514
3
+ metadata.gz: 6a0a46f7400412223cb7e7bab356450fa5d0a58cf05ee2c70c1bc6b5d9c91ed1
4
+ data.tar.gz: a3f0ce02021eab5d27dc338634d07d6ac942eae493f868c0ba68850bbb5c0ff9
5
5
  SHA512:
6
- metadata.gz: 7e541c39b62bf7228842f20830ae52d1b49dca66a6a834f38478cc3320aa65dea1c7b85becbcc75edf7382470e7bdf0bc9949a3665e72ff778a26aaae65ae15a
7
- data.tar.gz: f3bdcaad7b1aa8341d168c5d10461737b54e7781dfadce2da26e289f2ca3192b6dd9775bdb8c99a040b17ba415be2725fcbd3451c518c96e901227f2572cf95c
6
+ metadata.gz: d9cc9136bcadb5bd2426ada4419e08e772a6976e98a0c96a6fe2129d79da4917819f4126966c4b1d0056b2b94e948433cfbc4370c7f6b85cab3f0ab9fd0b3c82
7
+ data.tar.gz: e5b96f7e05837c4a142651282381dbc7ad7647b8122946b221befcf858992a755ce0a15bf4f893f6d920353393145b305774f6fb38cab922641fc4f8ebda0f75
data/CHANGELOG.md CHANGED
@@ -4,7 +4,16 @@ 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.12.0] - Unreleased
7
+ ## [0.13.0] - Unreleased
8
+ ### Added
9
+ - Added support for `default_schema` block to apply a default schema to every model, unless disabled for that model with `default_schema: false`.
10
+
11
+ ## [0.12.1] - 2021-05-10
12
+ ### Fixed
13
+ - When an `enum` type field is declared, there is now enforcement that its `limit:` must be an array of 1 or more Symbols,
14
+ and its `default:`--if given--must be a Symbol or `nil`.
15
+
16
+ ## [0.12.0] - 2021-04-28
8
17
  ### Added
9
18
  - `belongs_to` now always infers the `limit:` of the foreign key to match that of the primary key it points to.
10
19
  Note: this isn't possible for polymorphic foreign keys, so it assumes `limit: 8` there...unless the schema
@@ -174,6 +183,8 @@ using the appropriate Rails configuration attributes.
174
183
  ### Added
175
184
  - Initial version from https://github.com/Invoca/hobo_fields v4.1.0.
176
185
 
186
+ [0.13.0]: https://github.com/Invoca/declare_schema/compare/v0.12.1...v0.13.0
187
+ [0.12.1]: https://github.com/Invoca/declare_schema/compare/v0.12.0...v0.12.1
177
188
  [0.12.0]: https://github.com/Invoca/declare_schema/compare/v0.11.1...v0.12.0
178
189
  [0.11.1]: https://github.com/Invoca/declare_schema/compare/v0.11.0...v0.11.1
179
190
  [0.11.0]: https://github.com/Invoca/declare_schema/compare/v0.10.1...v0.11.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- declare_schema (0.12.0.pre.1)
4
+ declare_schema (0.13.0.pre.2)
5
5
  rails (>= 4.2)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -62,7 +62,7 @@ trigger the `eager_load!` on the `Rails` application and all `Rails::Engine`s lo
62
62
  into scope. If you need to generate migrations for models that aren't automatically loaded by `eager_load!`,
63
63
  load them in the `before_generating_migration` block.
64
64
 
65
- **Example Configuration**
65
+ For example:
66
66
 
67
67
  ```ruby
68
68
  DeclareSchema::Migration::Migrator.before_generating_migration do
@@ -70,6 +70,32 @@ DeclareSchema::Migration::Migrator.before_generating_migration do
70
70
  end
71
71
  ```
72
72
 
73
+ ### default_schema
74
+ If there are default columns you would like in the schema for every model, you can define them in a block that is registered with
75
+ `DeclareSchema.default_schema`. For example:
76
+
77
+ ```ruby
78
+ DeclareSchema.default_schema do
79
+ timestamps
80
+ optimistic_lock
81
+ end
82
+ ```
83
+ This will add these fields to the schema of each model (if not already there).
84
+ If you have a model where you don't want the defaults applied, that can be set with the `default_schema:` boolean option to `declare_schema` (the default value is true). For example:
85
+ ```ruby
86
+ class User < ActiveRecord::Base
87
+ declare_schema default_schema: false do
88
+ ...
89
+ end
90
+ end
91
+ ```
92
+
93
+ ### clear_default_schema
94
+ This method clears out any previously declared `default_schema`.
95
+ ```ruby
96
+ DeclareSchema.clear_default_schema
97
+ ```
98
+
73
99
  ### Global Configuration
74
100
  Configurations can be set at the global level to customize default declaration for the following values:
75
101
 
@@ -85,6 +85,19 @@ module DeclareSchema
85
85
  @default_generate_indexing = generate_indexing
86
86
  end
87
87
 
88
+ def default_schema(&block)
89
+ if block.nil?
90
+ @default_schema # equivalent to attr_reader :default_schema
91
+ else
92
+ block.respond_to?(:call) or raise "default_schema must be passed a block that responds to call"
93
+ @default_schema = block
94
+ end
95
+ end
96
+
97
+ def clear_default_schema
98
+ @default_schema = nil
99
+ end
100
+
88
101
  def db_migrate_command=(db_migrate_command)
89
102
  db_migrate_command.is_a?(String) or raise ArgumentError, "db_migrate_command must be a string (got #{db_migrate_command.inspect})"
90
103
  @db_migrate_command = db_migrate_command
@@ -7,7 +7,7 @@ module DeclareSchema
7
7
  include ::Kernel # but we need the basic class methods
8
8
 
9
9
  instance_methods.each do |m|
10
- unless m.to_s.starts_with?('__') || m.in?([:object_id, :instance_eval])
10
+ unless m.to_s.starts_with?('__') || m.in?([:object_id, :instance_eval, :instance_exec])
11
11
  undef_method(m)
12
12
  end
13
13
  end
@@ -32,8 +32,11 @@ module DeclareSchema
32
32
  @model.declare_field(name, type, *(args + [@options.merge(options)]))
33
33
  end
34
34
 
35
- def method_missing(type, name, *args)
36
- field(name, type, *args)
35
+ # TODO: make [:required] just another option. Either 'required: true] or 'optional: false'?
36
+ def method_missing(*args, **options)
37
+ args.count(&:itself) >= 2 or raise ::ArgumentError, "fields in declare_schema block must be declared as: type name, [:required], options (got #{args.inspect}, #{options.inspect})"
38
+ type, name, *required = args
39
+ field(name, type, *required, options)
37
40
  end
38
41
  end
39
42
  end
@@ -27,7 +27,7 @@ module DeclareSchema
27
27
  end
28
28
  deprecate :fields, deprecator: ActiveSupport::Deprecation.new('1.0', 'DeclareSchema')
29
29
 
30
- def declare_schema(table_options = {}, &block)
30
+ def declare_schema(default_schema: true, **table_options, &block)
31
31
  # Any model that calls 'fields' gets DeclareSchema::Model behavior
32
32
  DeclareSchema::Model.mix_in(self)
33
33
 
@@ -37,10 +37,9 @@ module DeclareSchema
37
37
 
38
38
  if block
39
39
  dsl = DeclareSchema::Dsl.new(self, null: false)
40
- if block.arity == 1
41
- yield dsl
42
- else
43
- dsl.instance_eval(&block)
40
+ dsl.instance_eval(&block)
41
+ if default_schema && DeclareSchema.default_schema
42
+ dsl.instance_exec(&DeclareSchema.default_schema)
44
43
  end
45
44
  end
46
45
  end
@@ -34,19 +34,16 @@ module DeclareSchema
34
34
  # supported options include :charset and :collation
35
35
  inheriting_cattr_reader table_options: HashWithIndifferentAccess.new
36
36
 
37
- # eval avoids the ruby 1.9.2 "super from singleton method ..." error
38
-
39
- eval <<~EOS
40
- def self.inherited(klass)
41
- unless klass.field_specs.has_key?(inheritance_column)
42
- declare_schema do |f|
43
- f.field(inheritance_column, :string, limit: 255, null: true)
44
- end
45
- index(inheritance_column)
37
+ def self.inherited(klass)
38
+ unless klass.field_specs.has_key?(inheritance_column)
39
+ ic = inheritance_column
40
+ declare_schema do
41
+ field(ic, :string, limit: 255, null: true)
46
42
  end
47
- super
43
+ index(ic)
48
44
  end
49
- EOS
45
+ super
46
+ end
50
47
  end
51
48
  end
52
49
  end
@@ -76,12 +76,19 @@ module DeclareSchema
76
76
  when :bigint
77
77
  @type = :integer
78
78
  @options[:limit] = 8
79
+ when :enum
80
+ @options[:default].nil? || @options[:default].is_a?(Symbol) or
81
+ raise ArgumentError, "enum default: must be nil or a Symbol; got #{@options[:default].inspect}"
82
+ @options[:limit].is_a?(Array) && @options[:limit].size >= 1 && @options[:limit].all? { |value| value.is_a?(Symbol) } or
83
+ raise ArgumentError, "enum limit: must be an array of 1 or more Symbols; got #{@options[:limit].inspect}"
79
84
  end
80
85
 
81
86
  Column.native_type?(@type) or raise UnknownTypeError, "#{@type.inspect} not found in #{Column.native_types.inspect} for adapter #{ActiveRecord::Base.connection.class.name}"
82
87
 
83
- if @type.in?([:string, :text, :binary, :varbinary, :integer, :enum])
88
+ if @type.in?([:string, :text, :binary, :varbinary, :integer])
84
89
  @options[:limit] ||= Column.native_types.dig(@type, :limit)
90
+ elsif @type.in?([:enum])
91
+ # nothing to do
85
92
  else
86
93
  @type != :decimal && @options.has_key?(:limit) and warn("unsupported limit: for SQL type #{@type} in field #{model}##{@name}")
87
94
  @options.delete(:limit)
@@ -6,9 +6,9 @@ module DeclareSchema
6
6
  module SchemaChange
7
7
  class ColumnAdd < Base
8
8
  def initialize(table_name, column_name, column_type, **column_options)
9
- @table_name = table_name
10
- @column_name = column_name
11
- @column_type = column_type
9
+ @table_name = table_name or raise ArgumentError, "must provide table_name"
10
+ @column_name = column_name or raise ArgumentError, "must provide column_name"
11
+ @column_type = column_type or raise ArgumentError, "must provide column_type"
12
12
  @column_options = column_options
13
13
  end
14
14
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeclareSchema
4
- VERSION = "0.12.0.pre.1"
4
+ VERSION = "0.13.0.pre.2"
5
5
  end
@@ -343,16 +343,15 @@ module Generators
343
343
 
344
344
  db_columns = model.connection.columns(current_table_name).index_by(&:name)
345
345
  if (pk = model._declared_primary_key.presence)
346
- key_was_in_db_columns = db_columns.delete(pk)
346
+ pk_was_in_db_columns = db_columns.delete(pk)
347
347
  end
348
348
 
349
349
  model_column_names = model.field_specs.keys.map(&:to_s)
350
350
  db_column_names = db_columns.keys.map(&:to_s)
351
351
 
352
352
  to_add = model_column_names - db_column_names
353
- to_add += [pk] unless key_was_in_db_columns
353
+ to_add << pk if pk && !pk_was_in_db_columns
354
354
  to_remove = db_column_names - model_column_names
355
- to_remove -= [pk.to_sym] if pk # TODO: The .to_sym here means this code is always a no-op, right? -Colin
356
355
 
357
356
  to_rename = extract_column_renames!(to_add, to_remove, new_table_name)
358
357
 
@@ -40,8 +40,6 @@ RSpec.describe 'DeclareSchema API' do
40
40
  load_models
41
41
 
42
42
  if ActiveSupport::VERSION::MAJOR == 5
43
- # TODO: get this to work on Travis for Rails 6
44
- # TODO: uncomment since we're not on Travis any more? -Colin
45
43
  generate_migrations '-n', '-m'
46
44
  end
47
45
 
@@ -50,8 +48,6 @@ RSpec.describe 'DeclareSchema API' do
50
48
 
51
49
  ## The Basics
52
50
 
53
- # The main feature of DeclareSchema, aside from the migration generator, is the ability to declare rich types for your fields. For example, you can declare that a field is an email address, and the field will be automatically validated for correct email address syntax.
54
-
55
51
  ### Field Types
56
52
 
57
53
  # Field values are returned as the type you specify.
@@ -115,6 +115,48 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
115
115
  end
116
116
  end
117
117
 
118
+ describe 'enum' do
119
+ before do
120
+ allow(::DeclareSchema::Model::Column).to receive(:native_types).and_wrap_original do |m, *_args|
121
+ result = m.call
122
+ if result.has_key?(:enum)
123
+ result
124
+ else
125
+ result.merge(enum: { name: "enum" })
126
+ end
127
+ end
128
+ end
129
+
130
+ describe 'default' do
131
+ it 'allows default of nil or a Symbol' do
132
+ [nil, :first].each do |default|
133
+ expect do
134
+ subject = described_class.new(model, :status, :enum, limit: [:first, :second, :third], default: default, null: false, position: 2)
135
+ expect(subject.default).to eq(default)
136
+ end.to_not raise_exception
137
+ end
138
+ end
139
+
140
+ it 'raises ArgumentError if default is not nil or a Symbol' do
141
+ ["first", 1].each do |default|
142
+ expect do
143
+ described_class.new(model, :status, :enum, limit: [:first, :second, :third], default: default, null: false, position: 2)
144
+ end.to raise_exception(ArgumentError, /enum default: must be nil or a Symbol; got #{Regexp.escape(default.inspect)}/)
145
+ end
146
+ end
147
+ end
148
+
149
+ describe 'limit' do
150
+ it 'raises ArgumentError if any of the limit values are not Symbols' do
151
+ [['first', 'second', 'third'], [1, 2, 3], nil, []].each do |limit|
152
+ expect do
153
+ described_class.new(model, :status, :enum, limit: limit, null: false, position: 2)
154
+ end.to raise_exception(ArgumentError, /enum limit: must be an array of 1 or more Symbols; got #{Regexp.escape(limit.inspect)}/)
155
+ end
156
+ end
157
+ end
158
+ end
159
+
118
160
  if defined?(Mysql2)
119
161
  describe 'varbinary' do # TODO: :varbinary is an Invoca addition to Rails; make it a configurable option
120
162
  it 'is supported' do
@@ -1860,6 +1860,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
1860
1860
  class SuperFancyAdvert < FancyAdvert
1861
1861
  end
1862
1862
 
1863
+ expect(Generators::DeclareSchema::Migration::Migrator.run.first).to be_present
1864
+
1863
1865
  up, _ = Generators::DeclareSchema::Migration::Migrator.run do |migrations|
1864
1866
  expect(migrations).to(
1865
1867
  migrate_up(<<~EOS.strip)
@@ -2491,5 +2493,78 @@ RSpec.describe 'DeclareSchema Migration Generator' do
2491
2493
  end
2492
2494
  end
2493
2495
  end
2496
+
2497
+ context 'default_schema' do
2498
+ let(:default_schema_block) { nil }
2499
+ let(:declare_model) do
2500
+ -> do
2501
+ class Advert < active_record_base_class.constantize
2502
+ declare_schema do
2503
+ integer :price, limit: 8
2504
+ end
2505
+ end
2506
+ end
2507
+ end
2508
+
2509
+ before do
2510
+ DeclareSchema.default_schema(&default_schema_block)
2511
+ end
2512
+
2513
+ after do
2514
+ DeclareSchema.clear_default_schema
2515
+ end
2516
+
2517
+ context 'when unset' do
2518
+ it 'adds nothing' do
2519
+ declare_model.call
2520
+
2521
+ expect(Advert.field_specs.keys).to eq(['price'])
2522
+ end
2523
+ end
2524
+
2525
+ context 'when set to a block' do
2526
+ let(:default_schema_block) do
2527
+ -> do
2528
+ timestamps
2529
+ field :lock_version, :integer, default: 1
2530
+ end
2531
+ end
2532
+
2533
+ it 'adds the fields in that block' do
2534
+ declare_model.call
2535
+
2536
+ expect(Advert.field_specs.keys).to eq(['price', 'created_at', 'updated_at', 'lock_version'])
2537
+ end
2538
+
2539
+ context 'and the model sets default_schema: false' do
2540
+ before do
2541
+ class Advert < active_record_base_class.constantize
2542
+ declare_schema default_schema: false do
2543
+ integer :price, limit: 8
2544
+ end
2545
+ end
2546
+ end
2547
+
2548
+ it 'does not add the default schema fields' do
2549
+ expect(Advert.field_specs.keys).to eq(['price'])
2550
+ end
2551
+ end
2552
+
2553
+ context 'and the block has redundant fields' do
2554
+ before do
2555
+ class Advert < active_record_base_class.constantize
2556
+ declare_schema do
2557
+ integer :price, limit: 8
2558
+ timestamps
2559
+ end
2560
+ end
2561
+ end
2562
+
2563
+ it 'is a no-op' do
2564
+ expect(Advert.field_specs.keys).to eq(['price', 'created_at', 'updated_at', 'lock_version'])
2565
+ end
2566
+ end
2567
+ end
2568
+ end
2494
2569
  end
2495
2570
  end
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.12.0.pre.1
4
+ version: 0.13.0.pre.2
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-04-27 00:00:00.000000000 Z
11
+ date: 2021-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails