blueprinter_schema 1.4.0 → 1.6.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: 820f85b8d22780549e1913cd8fa26f219c425c14746296b466b7966efc58bb2b
4
- data.tar.gz: c013ef3d11fe9c214a21e0400ba2f0c66aa2ca2be0fb62e9feafe0fed0b55e46
3
+ metadata.gz: 9cfb85c67fa7ef32587a53be7c9a0af7fac5d7073355c104ad4e5463949ba846
4
+ data.tar.gz: 07161f373f93501eb0a053800549ebc39ce7012d58706fd2fcd6d998b69f3b5e
5
5
  SHA512:
6
- metadata.gz: 6075da5a95d77f0f0c2142f7d1a9f94e067c863f4f1aa6c042945e5793367633147005824bbd12fff807e10568c653ebd734cebcb9b67d261710178053f61410
7
- data.tar.gz: 7b89616467a6d82202bc2b105f4e948392a4c1fd841c56a6dcb4c66130897ad49d94b2140362576297ca59d615cb37b1eaf2f340eabf01b2702a05790f3808a2
6
+ metadata.gz: 3378f86662ed59bfa7b929d618b42e6507c61b10520797b738e0f1a8b79488b815d26f0ba64f5a3cdc7ede9071c03a00f93e3d2d56588c47cee457d5b9446486
7
+ data.tar.gz: c36d3d50ccc702382c2bdc55b77b30c53e048e340384b0d75119ec8bc2ab097d940a475809355a7107fe59389b47b35c18900813586891d403544a709bd6318b
data/README.md CHANGED
@@ -177,6 +177,44 @@ BlueprinterSchema.generate(
177
177
  )
178
178
  ```
179
179
 
180
+ ### Active Model Support
181
+
182
+ ```rb
183
+ class Restrictions
184
+ include ActiveModel::Model
185
+ include ActiveModel::Attributes
186
+
187
+ attribute :min_units, :integer
188
+ attribute :max_units, :integer
189
+
190
+ validates :min_units, presence: true
191
+ end
192
+
193
+ class RestrictionsSerializer < Blueprinter::Base
194
+ field :min_units
195
+ field :max_units
196
+ end
197
+
198
+ BlueprinterSchema.generate(serializer: RestrictionsSerializer, model: Restrictions)
199
+ ```
200
+
201
+ ```rb
202
+ {
203
+ "type" => "object",
204
+ "title" => "Restrictions",
205
+ "properties" => {
206
+ "min_units" => {
207
+ "type" => "integer"
208
+ },
209
+ "max_units" => {
210
+ "type" => ["integer", "null"]
211
+ }
212
+ },
213
+ "required" => ["max_units", "min_units"],
214
+ "additionalProperties" => false
215
+ }
216
+ ```
217
+
180
218
  ## Development
181
219
 
182
220
  Devcontainer / Codespaces / Native
@@ -81,13 +81,20 @@ module BlueprinterSchema
81
81
  if field.options[:type]
82
82
  type_definition['type'] = ensure_valid_json_schema_types!(field)
83
83
  elsif @model
84
- column = @model.columns_hash[field.name.to_s]
85
- type_definition = ar_column_to_json_schema(column)
84
+ type_definition = model_attribute_to_json_schema(field.name.to_s)
86
85
  end
87
86
 
88
87
  merge_field_options(type_definition, field.options)
89
88
  end
90
89
 
90
+ def model_attribute_to_json_schema(name)
91
+ type_to_json_schema(model_attributes.type(name), model_attributes.nullable?(name))
92
+ end
93
+
94
+ def model_attributes
95
+ @model_attributes ||= ModelAttributes.new(@model)
96
+ end
97
+
91
98
  def merge_field_options(type_definition, options)
92
99
  type_definition['enum'] = options[:enum] if options[:enum]
93
100
  type_definition['items'] = options[:items].deep_stringify_keys if options[:items]
@@ -108,22 +115,24 @@ module BlueprinterSchema
108
115
 
109
116
  # rubocop:disable Metrics/MethodLength
110
117
  # rubocop:disable Metrics/CyclomaticComplexity
111
- def ar_column_to_json_schema(column)
112
- case column&.type
118
+ def type_to_json_schema(type, null)
119
+ case type
113
120
  when :string, :text
114
- build_json_schema_type('string', column.null)
121
+ build_json_schema_type('string', null)
115
122
  when :integer
116
- build_json_schema_type('integer', column.null)
123
+ build_json_schema_type('integer', null)
117
124
  when :float, :decimal
118
- build_json_schema_type('number', column.null)
125
+ build_json_schema_type('number', null)
119
126
  when :boolean
120
- build_json_schema_type('boolean', column.null)
127
+ build_json_schema_type('boolean', null)
121
128
  when :date
122
- build_json_schema_type('string', column.null, 'date')
129
+ build_json_schema_type('string', null, 'date')
123
130
  when :datetime, :timestamp
124
- build_json_schema_type('string', column.null, 'date-time')
131
+ build_json_schema_type('string', null, 'date-time')
125
132
  when :uuid
126
- build_json_schema_type('string', column.null, 'uuid')
133
+ build_json_schema_type('string', null, 'uuid')
134
+ else
135
+ @fallback_definition.dup
127
136
  end
128
137
  end
129
138
  # rubocop:enable Metrics/MethodLength
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlueprinterSchema
4
+ # Resolves an attribute's type and nullability from a model.
5
+ #
6
+ # ActiveRecord models (responding to +columns_hash+) infer both the type and
7
+ # nullability from the column. ActiveModel objects (responding to
8
+ # +type_for_attribute+) infer the type from the attribute; nullability is
9
+ # inferred from presence validations when available, otherwise assumed nullable.
10
+ class ModelAttributes
11
+ def initialize(model)
12
+ @model = model
13
+ end
14
+
15
+ def type(name)
16
+ if active_record?
17
+ @model.columns_hash[name]&.type
18
+ elsif active_model?
19
+ @model.type_for_attribute(name)&.type
20
+ end
21
+ end
22
+
23
+ def nullable?(name)
24
+ if active_record?
25
+ column = @model.columns_hash[name]
26
+ column ? column.null : false
27
+ elsif active_model?
28
+ active_model_nullable?(name)
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def active_record?
37
+ @model.respond_to?(:columns_hash)
38
+ end
39
+
40
+ def active_model?
41
+ @model.respond_to?(:type_for_attribute)
42
+ end
43
+
44
+ def active_model_nullable?(name)
45
+ return true unless @model.respond_to?(:validators_on)
46
+
47
+ !presence_validated?(name)
48
+ end
49
+
50
+ def presence_validated?(name)
51
+ @model.validators_on(name).any? { |validator| validator.kind == :presence }
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BlueprinterSchema
4
- VERSION = '1.4.0'
4
+ VERSION = '1.6.0'
5
5
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'blueprinter_schema/version'
4
+ require_relative 'blueprinter_schema/model_attributes'
4
5
  require_relative 'blueprinter_schema/generator'
5
6
 
6
7
  module BlueprinterSchema
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blueprinter_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thisismydesign
@@ -27,6 +27,7 @@ files:
27
27
  - compose.yml
28
28
  - lib/blueprinter_schema.rb
29
29
  - lib/blueprinter_schema/generator.rb
30
+ - lib/blueprinter_schema/model_attributes.rb
30
31
  - lib/blueprinter_schema/version.rb
31
32
  - sig/blueprinter_schema.rbs
32
33
  homepage: https://github.com/thisismydesign/blueprinter_schema