declare_schema 0.12.0.pre.2 → 0.13.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 +12 -1
- data/Gemfile.lock +1 -1
- data/README.md +27 -1
- data/lib/declare_schema.rb +13 -0
- data/lib/declare_schema/dsl.rb +6 -3
- data/lib/declare_schema/extensions/active_record/fields_declaration.rb +4 -5
- data/lib/declare_schema/model.rb +8 -11
- data/lib/declare_schema/model/field_spec.rb +8 -1
- data/lib/declare_schema/version.rb +1 -1
- data/lib/generators/declare_schema/migration/migrator.rb +2 -3
- data/spec/lib/declare_schema/api_spec.rb +0 -4
- data/spec/lib/declare_schema/field_spec_spec.rb +42 -0
- data/spec/lib/declare_schema/migration_generator_spec.rb +75 -0
- 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: dc0328d501bd76426598e121bc75283089a2a1b7c72781ce9b29ae4e60f8dff2
|
4
|
+
data.tar.gz: a734efaadde7dae50ee1cf512a52858eabc7c7315e6b5dbf3a8f6660eda32da4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 697da828c1b2fe88048a4c66cccda205adc809d449361294fc4e0e0c69d229bb97ed8b861979ab85eed6c8bd30d5dd942ed2791b8ded632eb371f084215e56c8
|
7
|
+
data.tar.gz: 5ff7eb9bc51daba2f0544e093baf38e2b181b2631683d3e2548d2054c4da70036ed98cdc7223658c93f5cb9423a79081c67e600629e0441dd505b09b82039bc1
|
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.
|
7
|
+
## [0.13.0] - 2020-06-11
|
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
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
|
-
|
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
|
|
data/lib/declare_schema.rb
CHANGED
@@ -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
|
data/lib/declare_schema/dsl.rb
CHANGED
@@ -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
|
-
|
36
|
-
|
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(
|
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
|
-
|
41
|
-
|
42
|
-
|
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
|
data/lib/declare_schema/model.rb
CHANGED
@@ -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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
43
|
+
index(ic)
|
48
44
|
end
|
49
|
-
|
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
|
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)
|
@@ -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
|
-
|
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 if pk && !
|
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.
|
4
|
+
version: 0.13.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-
|
11
|
+
date: 2021-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|