praxis 2.0.pre.22 → 2.0.pre.24

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: fcf3359dc0ac9062c61efc934673d9bf5dfdda43e5abfbc9abc41d3030a7a00e
4
- data.tar.gz: 04ffe07b27222f714b8da5e756cc9e1733b76d066a9e1bf5a3d15358dc7e6662
3
+ metadata.gz: 7f399850436ae7099b3d2bcef4f1d0648b094af1d307f47498d92c3ce275379a
4
+ data.tar.gz: 5f1fa0dbad1f3cf54de9c1a398f93f72c994fe7e61e081ab0e4af3e90f1941b0
5
5
  SHA512:
6
- metadata.gz: f90af4ae85f4170a850d7d7637758c0c2d878271befa2fe437da8c994ac78657eebd28831bb0945a74ca48aa93a91d42e8b734fd70f3996984e427ad6850a7ae
7
- data.tar.gz: b8eaa60ce2ba599b94f4b844339df8501ca295f3e1efb9a0f5dd38b9c4551aa64f108ba3a28913d06a22748dab11fee5c4bd8f9cfb8d2e85b1c456fb3284a5b3
6
+ metadata.gz: a1bb3ad07b0376ea46601104c0c5539cf39c4027e787f5228366cc5d5d7ff2a0ec44b8bf516ae3692ddd4ce781e4695faf760cb46750ad052e66f0618b454b71
7
+ data.tar.gz: 0d9689af7ec169f05a39113c69deb470f70cb41425b0aca71102fd7bb32f877fb8dfca73737ec6935b3b6afcf43e79d670881344c56cffdf13ee9162126c2a05
data/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## next
4
4
 
5
+ ## 2.0.pre.24
6
+ Assorted set of fixes and cleanup:
7
+ * better forwarding signature for query methods
8
+ * Fix the way with which to decide how to wrap an association (based on Enumerable isn't right, as Hashes are Enumerable as well). Wrapping decision
9
+ is now made based on the association type, and not the shape of the resulting type.
10
+ * Built handling of some multivalue and/or fuzzy matching cases in filtering params
11
+ * unrestrict mustermann's dependent version
12
+ * Support options and even passing a full type (instead of a block) in signature definitions (TypedMethods for resources)
13
+
14
+ ## 2.0.pre.22
15
+ * Small fix in OpenAPI doc generation, which would detect and report more output types, even if they are only defined within the
16
+ children of anonymous types.
17
+
5
18
  ## 2.0.pre.22
6
19
  * Introduced Resource callbacks (an includeable concern). Callbacks allow you to define methods or blocks to be executed `before`, `after` or `around` any existing method in the resource. Class-level callbacks are defined with `self.xxxxx`. These methods will be executed within the instance of the resource (i.e., in the same context of the original) and must be defined with the same parameter signature. For around methods, only blocks can be used, and to call the original (inner) one, one needs to yield.
7
20
  * Introduced QueryMethods for resources (an includeable concern). QueryMethods expose handy querying methods (`.get`, `.get!`, `.all`, `.first` and `.last` ) which will reach into the underlying ORM (i.e., right now, only ActiveModelCompat is supported) to perform the desired loading of data (and subsequent wrapping of results in resource instances).
@@ -26,8 +26,19 @@ module Praxis
26
26
  # NOTE2: we should just create a $ref here unless it's an anon mediatype...
27
27
  return {} if type.is_a? SimpleMediaType # NOTE: skip if it's a SimpleMediaType?? ... is that correct?
28
28
 
29
- the_schema = if type.anonymous? || !(type < Praxis::MediaType) # Avoid referencing custom/simple Types? (i.e., just MTs)
30
- SchemaObject.new(info: type).dump_schema(shallow: false, allow_ref: false)
29
+ the_schema = if type.anonymous? || !(type < Praxis::MediaType)
30
+ # Avoid referencing custom/simple types (i.e. just MTs). As a corner case,
31
+ # dig into collections (which are anonymous) provided their member is not.
32
+ # This isn't germane to content attributes, but is necessary to ensure that we visit every
33
+ # non-anonymous type so that our emitted scheme covers the whole "surface area" of all
34
+ # actions.
35
+ underlying_type = type
36
+ underlying_type = underlying_type.member_type while underlying_type < Attributor::Collection
37
+
38
+ SchemaObject.new(info: type).dump_schema(
39
+ shallow: false,
40
+ allow_ref: type < Attributor::Collection && !underlying_type.anonymous?
41
+ )
31
42
  else
32
43
  SchemaObject.new(info: type).dump_schema(shallow: true, allow_ref: true)
33
44
  end
@@ -250,7 +250,8 @@ module Praxis
250
250
  next unless item[:value].presence
251
251
 
252
252
  fuzzy_match = attr_filters[:fuzzy_match]
253
- errors << "Fuzzy matching for #{attr_name} is not allowed (yet '*' was found in the value)" if item[:fuzzy] && !item[:fuzzy].empty? && !fuzzy_match
253
+ # If fuzzy matches aren't allowed, but there is one passed in (or in the case of a multimatch, any of the ones in it), we disallow it
254
+ errors << "Fuzzy matching for #{attr_name} is not allowed (yet '*' was found in the value)" if item[:fuzzy] && !fuzzy_match && !(item[:fuzzy].is_a?(Array) && item[:fuzzy].compact.empty?)
254
255
  end
255
256
  end
256
257
 
@@ -258,7 +259,29 @@ module Praxis
258
259
  def dump
259
260
  parsed_array.each_with_object([]) do |item, arr|
260
261
  field = item[:name]
261
- arr << "#{field}#{item[:op]}#{item[:value]}"
262
+ value = \
263
+ if item[:value].is_a?(Array)
264
+ item[:value].map.with_index do |i, idx|
265
+ case item[:fuzzy][idx]
266
+ when nil
267
+ i
268
+ when :start
269
+ "*#{i}"
270
+ when :end
271
+ "#{i}*"
272
+ end
273
+ end.join(',')
274
+ else
275
+ case item[:fuzzy]
276
+ when nil
277
+ item[:value]
278
+ when :start
279
+ "*#{item[:value]}"
280
+ when :end
281
+ "#{item[:value]}*"
282
+ end
283
+ end
284
+ arr << "#{field}#{item[:op]}#{value}"
262
285
  end.join('&')
263
286
  end
264
287
 
@@ -177,13 +177,24 @@ module Praxis
177
177
  return unless association_resource_class
178
178
 
179
179
  memoized_variables << name
180
+
181
+ # Add the call to wrap (for true collections) or simply for_record if it's a n:1 association
182
+ wrapping = \
183
+ case association_spec.fetch(:type)
184
+ when :one_to_many, :many_to_many
185
+ "@__#{name} ||= #{association_resource_class}.wrap(records)"
186
+ else
187
+ "@__#{name} ||= #{association_resource_class}.for_record(records)"
188
+ end
189
+
180
190
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
181
191
  def #{name}
182
192
  return @__#{name} if instance_variable_defined?("@__#{name}")
183
193
 
184
194
  records = record.#{name}
185
195
  return nil if records.nil?
186
- @__#{name} ||= #{association_resource_class}.wrap(records)
196
+
197
+ #{wrapping}
187
198
  end
188
199
  RUBY
189
200
  end
@@ -13,8 +13,8 @@ module Praxis
13
13
  QueryProxy.new(klass: self).including(args)
14
14
  end
15
15
 
16
- def all(args = {})
17
- QueryProxy.new(klass: self).all(args)
16
+ def all(...)
17
+ QueryProxy.new(klass: self).all(...)
18
18
  end
19
19
 
20
20
  def get(args)
@@ -22,7 +22,7 @@ module Praxis
22
22
  base = klass.model._add_includes(klass.model, @_includes) # includes(nil) seems to have no effect
23
23
  record = base._get(condition)
24
24
 
25
- record.nil? ? nil : klass.wrap(record)
25
+ record.nil? ? nil : klass.for_record(record)
26
26
  end
27
27
 
28
28
  def get!(condition)
@@ -40,17 +40,25 @@ module Praxis
40
40
  super
41
41
  end
42
42
 
43
- def signature(method_name, &block)
43
+ # It can take options to be passed to the attribute's block of the constructed struct
44
+ # It can take an already existing struct instead of a block/options
45
+ def signature(method_name, same_as_type = nil, **opts, &block)
44
46
  method = method_name.to_sym
45
47
  @signatures ||= {}
48
+ raise "signature definition for #{method_name}: need to pass either an existing type or a block, not both" if block_given? && same_as_type
49
+
46
50
  if block_given?
47
51
  type =
48
52
  Class.new(Attributor::Struct) do
49
- attributes do
53
+ attributes(**opts) do
50
54
  instance_eval(&block)
51
55
  end
52
56
  end
53
57
  @signatures[method] = type
58
+ elsif same_as_type
59
+ raise "Options for signature definition for #{method_name} are not supported when passing an already existing type" unless opts.empty?
60
+
61
+ @signatures[method] = same_as_type
54
62
  else
55
63
  @signatures[method]
56
64
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Praxis
4
- VERSION = '2.0.pre.22'
4
+ VERSION = '2.0.pre.24'
5
5
  end
data/praxis.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency 'activesupport', '>= 3'
26
26
  spec.add_dependency 'attributor', '>= 6.2'
27
27
  spec.add_dependency 'mime', '~> 0'
28
- spec.add_dependency 'mustermann', '>=1.1', '<=2'
28
+ spec.add_dependency 'mustermann', '>=1.1'
29
29
  spec.add_dependency 'rack', '>= 1'
30
30
  spec.add_dependency 'terminal-table', '~> 1.4'
31
31
  spec.add_dependency 'thor'
@@ -278,12 +278,46 @@ describe Praxis::Extensions::AttributeFiltering::FilteringParams do
278
278
  expect(subject.first).to match(/Fuzzy matching for content is not allowed/)
279
279
  end
280
280
  end
281
+ context 'given a fuzzy string in only one of the values' do
282
+ let(:filters_string) { 'content=IAmNotFuzzy,IAmAString*' }
283
+ it 'errors out' do
284
+ expect(subject).to_not be_empty
285
+ expect(subject.first).to match(/Fuzzy matching for content is not allowed/)
286
+ end
287
+ end
281
288
  context 'given a non-fuzzy string' do
282
289
  let(:filters_string) { 'content=IAmAString' }
283
290
  it 'validates properly' do
284
291
  expect(subject).to be_empty
285
292
  end
286
293
  end
294
+ context 'given a non-fuzzy string for a multivalue' do
295
+ let(:filters_string) { 'content=IAmAString,IAmAnotherString' }
296
+ it 'validates properly' do
297
+ expect(subject).to be_empty
298
+ end
299
+ end
300
+ end
301
+ end
302
+ end
303
+
304
+ context '.dump' do
305
+ context 'round trips for different types' do
306
+ it 'round trips for different types of values and operators' do
307
+ str = 'one=11&two!=22&three>=33&four<=4&five<5&six>6&seven!&eight!!'
308
+ expect(described_class.load(str).dump).to eq(str)
309
+ end
310
+ it 'round trips for multivalues' do
311
+ str = 'filtername=1,2,3'
312
+ expect(described_class.load(str).dump).to eq(str)
313
+ end
314
+ it 'round trips for fuzzies' do
315
+ str = 'filtername=file*'
316
+ expect(described_class.load(str).dump).to eq(str)
317
+ end
318
+ it 'round trips for fuzzies in multivalues' do
319
+ str = 'filtername=1,*2,3*'
320
+ expect(described_class.load(str).dump).to eq(str)
287
321
  end
288
322
  end
289
323
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: praxis
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.pre.22
4
+ version: 2.0.pre.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep M. Blanquer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-05-16 00:00:00.000000000 Z
12
+ date: 2022-10-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -60,9 +60,6 @@ dependencies:
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: '1.1'
63
- - - "<="
64
- - !ruby/object:Gem::Version
65
- version: '2'
66
63
  type: :runtime
67
64
  prerelease: false
68
65
  version_requirements: !ruby/object:Gem::Requirement
@@ -70,9 +67,6 @@ dependencies:
70
67
  - - ">="
71
68
  - !ruby/object:Gem::Version
72
69
  version: '1.1'
73
- - - "<="
74
- - !ruby/object:Gem::Version
75
- version: '2'
76
70
  - !ruby/object:Gem::Dependency
77
71
  name: rack
78
72
  requirement: !ruby/object:Gem::Requirement