apiwork 0.0.0.pre → 0.1.2

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.
Files changed (202) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +2 -2
  3. data/README.md +117 -1
  4. data/Rakefile +5 -3
  5. data/app/controllers/apiwork/errors_controller.rb +13 -0
  6. data/app/controllers/apiwork/exports_controller.rb +22 -0
  7. data/lib/apiwork/abstractable.rb +26 -0
  8. data/lib/apiwork/adapter/base.rb +369 -0
  9. data/lib/apiwork/adapter/builder/api/base.rb +66 -0
  10. data/lib/apiwork/adapter/builder/contract/base.rb +86 -0
  11. data/lib/apiwork/adapter/capability/api/base.rb +51 -0
  12. data/lib/apiwork/adapter/capability/api/scope.rb +64 -0
  13. data/lib/apiwork/adapter/capability/base.rb +291 -0
  14. data/lib/apiwork/adapter/capability/contract/base.rb +37 -0
  15. data/lib/apiwork/adapter/capability/contract/scope.rb +110 -0
  16. data/lib/apiwork/adapter/capability/operation/base.rb +172 -0
  17. data/lib/apiwork/adapter/capability/operation/metadata_shape.rb +165 -0
  18. data/lib/apiwork/adapter/capability/result.rb +21 -0
  19. data/lib/apiwork/adapter/capability/runner.rb +56 -0
  20. data/lib/apiwork/adapter/capability/transformer/request/base.rb +72 -0
  21. data/lib/apiwork/adapter/capability/transformer/response/base.rb +45 -0
  22. data/lib/apiwork/adapter/registry.rb +16 -0
  23. data/lib/apiwork/adapter/serializer/error/base.rb +72 -0
  24. data/lib/apiwork/adapter/serializer/error/default/api_builder.rb +32 -0
  25. data/lib/apiwork/adapter/serializer/error/default.rb +37 -0
  26. data/lib/apiwork/adapter/serializer/resource/base.rb +84 -0
  27. data/lib/apiwork/adapter/serializer/resource/default/contract_builder.rb +209 -0
  28. data/lib/apiwork/adapter/serializer/resource/default.rb +39 -0
  29. data/lib/apiwork/adapter/standard/capability/filtering/api_builder.rb +75 -0
  30. data/lib/apiwork/adapter/standard/capability/filtering/constants.rb +37 -0
  31. data/lib/apiwork/adapter/standard/capability/filtering/contract_builder.rb +193 -0
  32. data/lib/apiwork/adapter/standard/capability/filtering/operation/filter/builder.rb +47 -0
  33. data/lib/apiwork/adapter/standard/capability/filtering/operation/filter/operator_builder.rb +36 -0
  34. data/lib/apiwork/adapter/standard/capability/filtering/operation/filter.rb +462 -0
  35. data/lib/apiwork/adapter/standard/capability/filtering/operation.rb +22 -0
  36. data/lib/apiwork/adapter/standard/capability/filtering/request_transformer.rb +47 -0
  37. data/lib/apiwork/adapter/standard/capability/filtering.rb +18 -0
  38. data/lib/apiwork/adapter/standard/capability/including/contract_builder.rb +169 -0
  39. data/lib/apiwork/adapter/standard/capability/including/operation.rb +20 -0
  40. data/lib/apiwork/adapter/standard/capability/including.rb +16 -0
  41. data/lib/apiwork/adapter/standard/capability/pagination/api_builder.rb +34 -0
  42. data/lib/apiwork/adapter/standard/capability/pagination/contract_builder.rb +35 -0
  43. data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate/cursor.rb +84 -0
  44. data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate/offset.rb +66 -0
  45. data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate.rb +24 -0
  46. data/lib/apiwork/adapter/standard/capability/pagination/operation.rb +24 -0
  47. data/lib/apiwork/adapter/standard/capability/pagination.rb +21 -0
  48. data/lib/apiwork/adapter/standard/capability/sorting/api_builder.rb +19 -0
  49. data/lib/apiwork/adapter/standard/capability/sorting/contract_builder.rb +84 -0
  50. data/lib/apiwork/adapter/standard/capability/sorting/operation/sort.rb +83 -0
  51. data/lib/apiwork/adapter/standard/capability/sorting/operation.rb +22 -0
  52. data/lib/apiwork/adapter/standard/capability/sorting.rb +17 -0
  53. data/lib/apiwork/adapter/standard/capability/writing/constants.rb +15 -0
  54. data/lib/apiwork/adapter/standard/capability/writing/contract_builder.rb +253 -0
  55. data/lib/apiwork/adapter/standard/capability/writing/operation/issue_mapper.rb +210 -0
  56. data/lib/apiwork/adapter/standard/capability/writing/operation.rb +32 -0
  57. data/lib/apiwork/adapter/standard/capability/writing/request_transformer.rb +37 -0
  58. data/lib/apiwork/adapter/standard/capability/writing.rb +17 -0
  59. data/lib/apiwork/adapter/standard/includes_resolver.rb +106 -0
  60. data/lib/apiwork/adapter/standard.rb +22 -0
  61. data/lib/apiwork/adapter/wrapper/base.rb +70 -0
  62. data/lib/apiwork/adapter/wrapper/collection/base.rb +60 -0
  63. data/lib/apiwork/adapter/wrapper/collection/default.rb +47 -0
  64. data/lib/apiwork/adapter/wrapper/error/base.rb +30 -0
  65. data/lib/apiwork/adapter/wrapper/error/default.rb +34 -0
  66. data/lib/apiwork/adapter/wrapper/member/base.rb +58 -0
  67. data/lib/apiwork/adapter/wrapper/member/default.rb +40 -0
  68. data/lib/apiwork/adapter/wrapper/shape.rb +203 -0
  69. data/lib/apiwork/adapter.rb +50 -0
  70. data/lib/apiwork/api/base.rb +802 -0
  71. data/lib/apiwork/api/element.rb +110 -0
  72. data/lib/apiwork/api/enum_registry/definition.rb +51 -0
  73. data/lib/apiwork/api/enum_registry.rb +98 -0
  74. data/lib/apiwork/api/info/contact.rb +67 -0
  75. data/lib/apiwork/api/info/license.rb +50 -0
  76. data/lib/apiwork/api/info/server.rb +50 -0
  77. data/lib/apiwork/api/info.rb +221 -0
  78. data/lib/apiwork/api/object.rb +235 -0
  79. data/lib/apiwork/api/registry.rb +33 -0
  80. data/lib/apiwork/api/representation_registry.rb +76 -0
  81. data/lib/apiwork/api/resource/action.rb +41 -0
  82. data/lib/apiwork/api/resource.rb +648 -0
  83. data/lib/apiwork/api/router.rb +104 -0
  84. data/lib/apiwork/api/type_registry/definition.rb +117 -0
  85. data/lib/apiwork/api/type_registry.rb +99 -0
  86. data/lib/apiwork/api/union.rb +49 -0
  87. data/lib/apiwork/api.rb +85 -0
  88. data/lib/apiwork/configurable.rb +71 -0
  89. data/lib/apiwork/configuration/option.rb +125 -0
  90. data/lib/apiwork/configuration/validatable.rb +25 -0
  91. data/lib/apiwork/configuration.rb +95 -0
  92. data/lib/apiwork/configuration_error.rb +6 -0
  93. data/lib/apiwork/constraint_error.rb +20 -0
  94. data/lib/apiwork/contract/action/request.rb +79 -0
  95. data/lib/apiwork/contract/action/response.rb +87 -0
  96. data/lib/apiwork/contract/action.rb +258 -0
  97. data/lib/apiwork/contract/base.rb +714 -0
  98. data/lib/apiwork/contract/element.rb +130 -0
  99. data/lib/apiwork/contract/object/coercer.rb +194 -0
  100. data/lib/apiwork/contract/object/deserializer.rb +101 -0
  101. data/lib/apiwork/contract/object/transformer.rb +95 -0
  102. data/lib/apiwork/contract/object/validator/result.rb +27 -0
  103. data/lib/apiwork/contract/object/validator.rb +734 -0
  104. data/lib/apiwork/contract/object.rb +566 -0
  105. data/lib/apiwork/contract/request_parser/result.rb +25 -0
  106. data/lib/apiwork/contract/request_parser.rb +72 -0
  107. data/lib/apiwork/contract/response_parser/result.rb +25 -0
  108. data/lib/apiwork/contract/response_parser.rb +35 -0
  109. data/lib/apiwork/contract/union.rb +56 -0
  110. data/lib/apiwork/contract_error.rb +9 -0
  111. data/lib/apiwork/controller.rb +300 -0
  112. data/lib/apiwork/domain_error.rb +13 -0
  113. data/lib/apiwork/element.rb +386 -0
  114. data/lib/apiwork/engine.rb +20 -0
  115. data/lib/apiwork/error.rb +6 -0
  116. data/lib/apiwork/error_code/definition.rb +63 -0
  117. data/lib/apiwork/error_code/registry.rb +18 -0
  118. data/lib/apiwork/error_code.rb +132 -0
  119. data/lib/apiwork/export/base.rb +291 -0
  120. data/lib/apiwork/export/open_api.rb +600 -0
  121. data/lib/apiwork/export/pipeline/writer.rb +66 -0
  122. data/lib/apiwork/export/pipeline.rb +84 -0
  123. data/lib/apiwork/export/registry.rb +16 -0
  124. data/lib/apiwork/export/surface_resolver.rb +189 -0
  125. data/lib/apiwork/export/type_analysis.rb +170 -0
  126. data/lib/apiwork/export/type_script.rb +23 -0
  127. data/lib/apiwork/export/type_script_mapper.rb +349 -0
  128. data/lib/apiwork/export/zod.rb +39 -0
  129. data/lib/apiwork/export/zod_mapper.rb +421 -0
  130. data/lib/apiwork/export.rb +80 -0
  131. data/lib/apiwork/http_error.rb +16 -0
  132. data/lib/apiwork/introspection/action/request.rb +66 -0
  133. data/lib/apiwork/introspection/action/response.rb +57 -0
  134. data/lib/apiwork/introspection/action.rb +124 -0
  135. data/lib/apiwork/introspection/api/info/contact.rb +59 -0
  136. data/lib/apiwork/introspection/api/info/license.rb +49 -0
  137. data/lib/apiwork/introspection/api/info/server.rb +50 -0
  138. data/lib/apiwork/introspection/api/info.rb +107 -0
  139. data/lib/apiwork/introspection/api/resource.rb +83 -0
  140. data/lib/apiwork/introspection/api.rb +92 -0
  141. data/lib/apiwork/introspection/contract.rb +63 -0
  142. data/lib/apiwork/introspection/dump/action.rb +101 -0
  143. data/lib/apiwork/introspection/dump/api.rb +119 -0
  144. data/lib/apiwork/introspection/dump/contract.rb +129 -0
  145. data/lib/apiwork/introspection/dump/param.rb +486 -0
  146. data/lib/apiwork/introspection/dump/resource.rb +112 -0
  147. data/lib/apiwork/introspection/dump/type.rb +339 -0
  148. data/lib/apiwork/introspection/dump.rb +17 -0
  149. data/lib/apiwork/introspection/enum.rb +63 -0
  150. data/lib/apiwork/introspection/error_code.rb +44 -0
  151. data/lib/apiwork/introspection/param/array.rb +88 -0
  152. data/lib/apiwork/introspection/param/base.rb +285 -0
  153. data/lib/apiwork/introspection/param/binary.rb +73 -0
  154. data/lib/apiwork/introspection/param/boolean.rb +73 -0
  155. data/lib/apiwork/introspection/param/date.rb +73 -0
  156. data/lib/apiwork/introspection/param/date_time.rb +73 -0
  157. data/lib/apiwork/introspection/param/decimal.rb +121 -0
  158. data/lib/apiwork/introspection/param/integer.rb +131 -0
  159. data/lib/apiwork/introspection/param/literal.rb +45 -0
  160. data/lib/apiwork/introspection/param/number.rb +121 -0
  161. data/lib/apiwork/introspection/param/object.rb +59 -0
  162. data/lib/apiwork/introspection/param/reference.rb +45 -0
  163. data/lib/apiwork/introspection/param/string.rb +122 -0
  164. data/lib/apiwork/introspection/param/time.rb +73 -0
  165. data/lib/apiwork/introspection/param/union.rb +57 -0
  166. data/lib/apiwork/introspection/param/unknown.rb +26 -0
  167. data/lib/apiwork/introspection/param/uuid.rb +73 -0
  168. data/lib/apiwork/introspection/param.rb +31 -0
  169. data/lib/apiwork/introspection/type.rb +129 -0
  170. data/lib/apiwork/introspection.rb +28 -0
  171. data/lib/apiwork/issue.rb +80 -0
  172. data/lib/apiwork/json_pointer.rb +21 -0
  173. data/lib/apiwork/object.rb +1618 -0
  174. data/lib/apiwork/reference_generator.rb +638 -0
  175. data/lib/apiwork/registry.rb +56 -0
  176. data/lib/apiwork/representation/association.rb +391 -0
  177. data/lib/apiwork/representation/attribute.rb +335 -0
  178. data/lib/apiwork/representation/base.rb +819 -0
  179. data/lib/apiwork/representation/deserializer.rb +95 -0
  180. data/lib/apiwork/representation/element.rb +128 -0
  181. data/lib/apiwork/representation/inheritance.rb +78 -0
  182. data/lib/apiwork/representation/model_detector.rb +75 -0
  183. data/lib/apiwork/representation/root_key.rb +35 -0
  184. data/lib/apiwork/representation/serializer.rb +127 -0
  185. data/lib/apiwork/request.rb +79 -0
  186. data/lib/apiwork/response.rb +56 -0
  187. data/lib/apiwork/union.rb +102 -0
  188. data/lib/apiwork/version.rb +2 -2
  189. data/lib/apiwork.rb +61 -3
  190. data/lib/generators/apiwork/api_generator.rb +38 -0
  191. data/lib/generators/apiwork/contract_generator.rb +25 -0
  192. data/lib/generators/apiwork/install_generator.rb +27 -0
  193. data/lib/generators/apiwork/representation_generator.rb +25 -0
  194. data/lib/generators/apiwork/templates/api/api.rb.tt +4 -0
  195. data/lib/generators/apiwork/templates/contract/contract.rb.tt +6 -0
  196. data/lib/generators/apiwork/templates/install/application_contract.rb.tt +5 -0
  197. data/lib/generators/apiwork/templates/install/application_representation.rb.tt +5 -0
  198. data/lib/generators/apiwork/templates/representation/representation.rb.tt +6 -0
  199. data/lib/tasks/apiwork.rake +102 -0
  200. metadata +319 -19
  201. data/.rubocop.yml +0 -8
  202. data/sig/apiwork.rbs +0 -4
@@ -0,0 +1,235 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apiwork
4
+ module API
5
+ # @api public
6
+ # Block context for defining reusable object types.
7
+ #
8
+ # Accessed via `object :name do` in API or contract definitions.
9
+ # Use type methods to define params: {#string}, {#integer}, {#decimal},
10
+ # {#boolean}, {#array}, {#object}, {#union}, {#reference}.
11
+ #
12
+ # @see API::Element Block context for array/variant elements
13
+ # @see Contract::Object Block context for inline objects
14
+ #
15
+ # @example instance_eval style
16
+ # object :item do
17
+ # string :description
18
+ # decimal :amount
19
+ # end
20
+ #
21
+ # @example yield style
22
+ # object :item do |object|
23
+ # object.string :description
24
+ # object.decimal :amount
25
+ # end
26
+ class Object < Apiwork::Object
27
+ # @api public
28
+ # Defines a param with explicit type.
29
+ #
30
+ # This is the verbose form. Prefer sugar methods (string, integer, etc.)
31
+ # for static definitions. Use `param` for dynamic param generation.
32
+ #
33
+ # @param name [Symbol]
34
+ # The param name.
35
+ # @param type [Symbol, nil] (nil) [:array, :binary, :boolean, :date, :datetime, :decimal, :integer, :literal, :number, :object, :string, :time, :union, :uuid]
36
+ # The param type.
37
+ # @param as [Symbol, nil] (nil)
38
+ # The target attribute name.
39
+ # @param default [Object, nil] (nil)
40
+ # The default value.
41
+ # @param deprecated [Boolean] (false)
42
+ # Whether deprecated. Metadata included in exports.
43
+ # @param description [String, nil] (nil)
44
+ # The description. Metadata included in exports.
45
+ # @param discriminator [Symbol, nil] (nil)
46
+ # The discriminator field name. Unions only.
47
+ # @param enum [Array, nil] (nil)
48
+ # The allowed values.
49
+ # @param example [Object, nil] (nil)
50
+ # The example value. Metadata included in exports.
51
+ # @param format [Symbol, nil] (nil) [:date, :datetime, :double, :email, :float, :hostname, :int32, :int64, :ipv4, :ipv6, :password, :url, :uuid]
52
+ # Format hint for exports. Does not change the type, but exports may add validation or documentation based on it.
53
+ # Valid formats by type: `:decimal`/`:number` (`:double`, `:float`), `:integer` (`:int32`, `:int64`),
54
+ # `:string` (`:date`, `:datetime`, `:email`, `:hostname`, `:ipv4`, `:ipv6`, `:password`, `:url`, `:uuid`).
55
+ # @param max [Integer, nil] (nil)
56
+ # The maximum. For `:array`: size. For `:decimal`, `:integer`, `:number`: value. For `:string`: length.
57
+ # @param min [Integer, nil] (nil)
58
+ # The minimum. For `:array`: size. For `:decimal`, `:integer`, `:number`: value. For `:string`: length.
59
+ # @param nullable [Boolean] (false)
60
+ # Whether the value can be `null`.
61
+ # @param of [Symbol, Hash, nil] (nil)
62
+ # The element type. Arrays only.
63
+ # @param optional [Boolean] (false)
64
+ # Whether the param is optional.
65
+ # @param required [Boolean] (false)
66
+ # Whether the param is required.
67
+ # @param shape [API::Object, API::Union, nil] (nil)
68
+ # The pre-built shape.
69
+ # @param value [Object, nil] (nil)
70
+ # The literal value.
71
+ # @yield block for nested structure
72
+ # @yieldparam shape [API::Object, API::Union, API::Element]
73
+ # @return [void]
74
+ #
75
+ # @example Dynamic param generation
76
+ # param_type = :string
77
+ # param :title, type: param_type
78
+ #
79
+ # @example Object with block
80
+ # param :metadata, type: :object do
81
+ # string :key
82
+ # string :value
83
+ # end
84
+ def param(
85
+ name,
86
+ type: nil,
87
+ as: nil,
88
+ default: nil,
89
+ deprecated: false,
90
+ description: nil,
91
+ discriminator: nil,
92
+ enum: nil,
93
+ example: nil,
94
+ format: nil,
95
+ max: nil,
96
+ min: nil,
97
+ nullable: false,
98
+ of: nil,
99
+ optional: false,
100
+ required: false,
101
+ shape: nil,
102
+ value: nil,
103
+ &block
104
+ )
105
+ resolved_of = resolve_of(of, type, &block)
106
+ resolved_shape = type == :array ? nil : (shape || build_shape(type, discriminator, &block))
107
+ discriminator = resolved_of&.discriminator if type == :array
108
+
109
+ param_hash = {
110
+ as:,
111
+ default:,
112
+ deprecated:,
113
+ description:,
114
+ discriminator:,
115
+ enum:,
116
+ example:,
117
+ format:,
118
+ max:,
119
+ min:,
120
+ name:,
121
+ nullable:,
122
+ optional:,
123
+ required:,
124
+ type:,
125
+ value:,
126
+ of: resolved_of,
127
+ }
128
+ param_hash[:shape] = resolved_shape if resolved_shape
129
+
130
+ @params[name] = (@params[name] || {}).merge(param_hash.compact)
131
+ end
132
+
133
+ # @api public
134
+ # Defines an array param with element type.
135
+ #
136
+ # @param name [Symbol]
137
+ # The param name.
138
+ # @param as [Symbol, nil] (nil)
139
+ # The target attribute name.
140
+ # @param default [Object, nil] (nil)
141
+ # The default value.
142
+ # @param deprecated [Boolean] (false)
143
+ # Whether deprecated. Metadata included in exports.
144
+ # @param description [String, nil] (nil)
145
+ # The description. Metadata included in exports.
146
+ # @param nullable [Boolean] (false)
147
+ # Whether the value can be `null`.
148
+ # @param optional [Boolean] (false)
149
+ # Whether the param is optional.
150
+ # @param required [Boolean] (false)
151
+ # Whether the param is required.
152
+ # @yield block for defining element type
153
+ # @yieldparam element [API::Element]
154
+ # @return [void]
155
+ #
156
+ # @example instance_eval style
157
+ # array :tags do
158
+ # string
159
+ # end
160
+ #
161
+ # @example yield style
162
+ # array :tags do |element|
163
+ # element.string
164
+ # end
165
+ def array(
166
+ name,
167
+ as: nil,
168
+ default: nil,
169
+ deprecated: false,
170
+ description: nil,
171
+ nullable: false,
172
+ optional: false,
173
+ required: false,
174
+ &block
175
+ )
176
+ raise ArgumentError, 'array requires a block' unless block
177
+
178
+ element = Element.new
179
+ block.arity.positive? ? yield(element) : element.instance_eval(&block)
180
+ element.validate!
181
+
182
+ param(
183
+ name,
184
+ as:,
185
+ default:,
186
+ deprecated:,
187
+ description:,
188
+ nullable:,
189
+ optional:,
190
+ required:,
191
+ of: element,
192
+ type: :array,
193
+ )
194
+ end
195
+
196
+ private
197
+
198
+ def resolve_of(of, type, &block)
199
+ return nil unless type == :array
200
+
201
+ if block
202
+ element = Element.new
203
+ block.arity.positive? ? yield(element) : element.instance_eval(&block)
204
+ element.validate!
205
+ element
206
+ elsif of.is_a?(Symbol)
207
+ wrap_symbol_in_element(of)
208
+ else
209
+ of
210
+ end
211
+ end
212
+
213
+ def wrap_symbol_in_element(type_symbol)
214
+ element = Element.new
215
+ element.of(type_symbol)
216
+ element
217
+ end
218
+
219
+ def build_shape(type, discriminator, &block)
220
+ return nil unless block
221
+
222
+ case type
223
+ when :object
224
+ shape = Object.new
225
+ block.arity.positive? ? yield(shape) : shape.instance_eval(&block)
226
+ shape
227
+ when :union
228
+ shape = Union.new(discriminator:)
229
+ block.arity.positive? ? yield(shape) : shape.instance_eval(&block)
230
+ shape
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apiwork
4
+ module API
5
+ class Registry < Apiwork::Registry
6
+ class << self
7
+ def register(api_class)
8
+ return unless api_class.base_path
9
+
10
+ store[normalize_key(api_class.base_path)] = api_class
11
+ end
12
+
13
+ def find(base_path)
14
+ return nil unless base_path
15
+
16
+ super
17
+ end
18
+
19
+ def unregister(base_path)
20
+ delete(base_path) if base_path
21
+ end
22
+
23
+ private
24
+
25
+ def normalize_key(base_path)
26
+ return :root if base_path == '/'
27
+
28
+ base_path.delete_prefix('/').underscore.to_sym
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apiwork
4
+ module API
5
+ class RepresentationRegistry
6
+ def initialize
7
+ @store = Set.new
8
+ @roles = Hash.new { |hash, key| hash[key] = Set.new }
9
+ end
10
+
11
+ def register(representation_class)
12
+ @store.add(representation_class)
13
+ end
14
+
15
+ def mark(representation_class, role)
16
+ @roles[representation_class].add(role)
17
+ end
18
+
19
+ def nested_writable?(representation_class)
20
+ @roles[representation_class].include?(:nested_writable)
21
+ end
22
+
23
+ def each(&block)
24
+ @store.each(&block)
25
+ end
26
+
27
+ def include?(representation_class)
28
+ @store.include?(representation_class)
29
+ end
30
+
31
+ def clear!
32
+ @store.clear
33
+ @roles.clear
34
+ end
35
+
36
+ def filter_types
37
+ @filter_types ||= extract_filter_types(nullable: false)
38
+ end
39
+
40
+ def nullable_filter_types
41
+ @nullable_filter_types ||= extract_filter_types(nullable: true)
42
+ end
43
+
44
+ def sortable?
45
+ return @sortable if defined?(@sortable)
46
+
47
+ @sortable = @store.any? do |representation|
48
+ representation.attributes.values.any?(&:sortable?) ||
49
+ representation.associations.values.any?(&:sortable?)
50
+ end
51
+ end
52
+
53
+ def filterable?
54
+ filter_types.any?
55
+ end
56
+
57
+ def options_for(option, key = nil)
58
+ @store.filter_map { |representation| representation.adapter_config.dig(option, key) }.to_set
59
+ end
60
+
61
+ private
62
+
63
+ def extract_filter_types(nullable:)
64
+ filterable_attributes = @store
65
+ .flat_map { |representation| representation.attributes.values }
66
+ .select(&:filterable?)
67
+
68
+ if nullable
69
+ filterable_attributes.select(&:nullable?).map(&:type).to_set.to_a
70
+ else
71
+ filterable_attributes.map(&:type).to_set.to_a
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apiwork
4
+ module API
5
+ class Resource
6
+ class Action
7
+ CRUD = %i[index show create update destroy].freeze
8
+
9
+ METHODS = {
10
+ create: :post,
11
+ destroy: :delete,
12
+ index: :get,
13
+ show: :get,
14
+ update: :patch,
15
+ }.freeze
16
+
17
+ attr_reader :method,
18
+ :name,
19
+ :type
20
+
21
+ def initialize(name, method: nil, type: nil)
22
+ @name = name.to_sym
23
+ @type = type || (name == :index ? :collection : :member)
24
+ @method = method || METHODS[name] || :get
25
+ end
26
+
27
+ def member?
28
+ type == :member
29
+ end
30
+
31
+ def collection?
32
+ type == :collection
33
+ end
34
+
35
+ def crud?
36
+ CRUD.include?(name)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end