jsonapi_compliable 0.3.8 → 0.3.9

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
  SHA1:
3
- metadata.gz: ab0e2b34af698b690cd0d1f5fea26dcc427cb8c2
4
- data.tar.gz: e0e5a124231ae7e35fdaeb75365aa88537657ad8
3
+ metadata.gz: e0418e83aaae7d67b616dab559f7f5986430d022
4
+ data.tar.gz: da31edddd52610cd95b14868b797b4197b508a68
5
5
  SHA512:
6
- metadata.gz: f9f74ff51519f73a6e85cd3c1b0dac20dc4111b044d7c93e9218415cf647143a9b57bf76c23c8611e66f2d509df3779e08a46644d8696d6678284b7702120252
7
- data.tar.gz: 762dc586bda947c104cea4aec73ee89164608644dc10aa09f552dca22762307f9eff761a8b78256899242c1153ce24928d6fa72d9ac5af6d43eca113427a89a5
6
+ metadata.gz: cf21cdf1b18b9af6190d790214e24009ab48c679d18f4d12b40d97952053d0752e1363d59dc8921a77cf3b845de07327381e412fa600bebaaa1193d3b7fe40de
7
+ data.tar.gz: 999ba235c7156753d37c5f8a3a8a70dc5f980fde4598e37d4ca6c597cc92db8ce04dac4bc6a88daba63c789a9512083587e80da87e5bec3c60b57c88e8d76efc
@@ -7,7 +7,7 @@ module JsonapiCompliable
7
7
 
8
8
  included do
9
9
  class_attribute :_jsonapi_compliable
10
- attr_reader :_jsonapi_scoped
10
+ attr_reader :_jsonapi_scope
11
11
 
12
12
  before_action :parse_fieldsets!
13
13
  after_action :reset_scope_flag
@@ -36,13 +36,14 @@ module JsonapiCompliable
36
36
  scope = JsonapiCompliable::Scope::ExtraFields.new(self, scope).apply if extra_fields
37
37
  scope = JsonapiCompliable::Scope::Sideload.new(self, scope).apply if includes
38
38
  scope = JsonapiCompliable::Scope::Sort.new(self, scope).apply if sort
39
+ # This is set before pagination so it can be re-used for stats
40
+ @_jsonapi_scope = scope
39
41
  scope = JsonapiCompliable::Scope::Paginate.new(self, scope).apply if paginate
40
- @_jsonapi_scoped = true
41
42
  scope
42
43
  end
43
44
 
44
45
  def reset_scope_flag
45
- @_jsonapi_scoped = false
46
+ @_jsonapi_scope = nil
46
47
  end
47
48
 
48
49
  def parse_fieldsets!
@@ -51,14 +52,16 @@ module JsonapiCompliable
51
52
  end
52
53
 
53
54
  def render_ams(scope, opts = {})
54
- scope = jsonapi_scope(scope) if Util::Scoping.apply?(self, scope, opts.delete(:scope))
55
+ scoped = Util::Scoping.apply?(self, scope, opts.delete(:scope)) ? jsonapi_scope(scope) : scope
55
56
  options = default_ams_options
56
57
  options[:include] = forced_includes || Util::IncludeParams.scrub(self)
57
- options[:jsonapi] = scope
58
+ options[:jsonapi] = JsonapiCompliable::Util::Pagination.zero?(params) ? [] : scoped
58
59
  options[:fields] = Util::FieldParams.fieldset(params, :fields) if params[:fields]
59
60
  options[:extra_fields] = Util::FieldParams.fieldset(params, :extra_fields) if params[:extra_fields]
60
-
61
+ options[:meta] ||= {}
61
62
  options.merge!(opts)
63
+ options[:meta][:stats] = Stats::Payload.new(self, scoped).generate if params[:stats]
64
+
62
65
  render(options)
63
66
  end
64
67
 
@@ -5,6 +5,7 @@ module JsonapiCompliable
5
5
  :extra_fields,
6
6
  :filters,
7
7
  :sorting,
8
+ :stats,
8
9
  :pagination
9
10
 
10
11
  def initialize
@@ -19,6 +20,7 @@ module JsonapiCompliable
19
20
  instance.extra_fields = extra_fields.deep_dup
20
21
  instance.sorting = sorting.deep_dup
21
22
  instance.pagination = pagination.deep_dup
23
+ instance.stats = stats.deep_dup
22
24
  instance
23
25
  end
24
26
 
@@ -27,6 +29,7 @@ module JsonapiCompliable
27
29
  @filters = {}
28
30
  @default_filters = {}
29
31
  @extra_fields = {}
32
+ @stats = {}
30
33
  @sorting = nil
31
34
  @pagination = nil
32
35
  end
@@ -50,6 +53,12 @@ module JsonapiCompliable
50
53
  }
51
54
  end
52
55
 
56
+ def allow_stat(symbol_or_hash, &blk)
57
+ dsl = Stats::DSL.new(symbol_or_hash)
58
+ dsl.instance_eval(&blk) if blk
59
+ @stats[dsl.name] = dsl
60
+ end
61
+
53
62
  def default_filter(name, &blk)
54
63
  @default_filters[name.to_sym] = {
55
64
  filter: blk
@@ -71,5 +80,11 @@ module JsonapiCompliable
71
80
  proc: blk
72
81
  }
73
82
  end
83
+
84
+ def stat(attribute, calculation)
85
+ stats_dsl = @stats[attribute] || @stats[attribute.to_sym]
86
+ raise Errors::StatNotFound.new(attribute, calculation) unless stats_dsl
87
+ stats_dsl.calculation(calculation)
88
+ end
74
89
  end
75
90
  end
@@ -11,5 +11,26 @@ module JsonapiCompliable
11
11
  "Requested page size #{@size} is greater than max supported size #{@max}"
12
12
  end
13
13
  end
14
+
15
+ class StatNotFound < StandardError
16
+ def initialize(attribute, calculation)
17
+ @attribute = attribute
18
+ @calculation = calculation
19
+ end
20
+
21
+ def message
22
+ "No stat configured for calculation #{pretty(@calculation)} on attribute #{pretty(@attribute)}"
23
+ end
24
+
25
+ private
26
+
27
+ def pretty(input)
28
+ if input.is_a?(Symbol)
29
+ ":#{input}"
30
+ else
31
+ "'#{input}'"
32
+ end
33
+ end
34
+ end
14
35
  end
15
36
  end
@@ -0,0 +1,54 @@
1
+ module JsonapiCompliable
2
+ module Stats
3
+ class DSL
4
+ attr_reader :name, :calculations
5
+
6
+ def self.defaults
7
+ {
8
+ count: ->(scope, attr) { scope.count },
9
+ average: ->(scope, attr) { scope.average(attr).to_f },
10
+ sum: ->(scope, attr) { scope.sum(attr) },
11
+ maximum: ->(scope, attr) { scope.maximum(attr) },
12
+ minimum: ->(scope, attr) { scope.minimum(attr) }
13
+ }
14
+ end
15
+
16
+ def initialize(config)
17
+ config = { config => [] } if config.is_a?(Symbol)
18
+
19
+ @calculations = {}
20
+ @name = config.keys.first
21
+ Array(config.values.first).each { |c| send(:"#{c}!") }
22
+ end
23
+
24
+ def method_missing(meth, *args, &blk)
25
+ @calculations[meth] = blk
26
+ end
27
+
28
+ def calculation(name)
29
+ callable = @calculations[name] || @calculations[name.to_sym]
30
+ callable || raise(Errors::StatNotFound.new(@name, name))
31
+ end
32
+
33
+ def count!
34
+ @calculations[:count] = self.class.defaults[:count]
35
+ end
36
+
37
+ def sum!
38
+ @calculations[:sum] = self.class.defaults[:sum]
39
+ end
40
+
41
+ def average!
42
+ @calculations[:average] = self.class.defaults[:average]
43
+ end
44
+
45
+ def maximum!
46
+ @calculations[:maximum] = self.class.defaults[:maximum]
47
+ end
48
+
49
+ def minimum!
50
+ @calculations[:minimum] = self.class.defaults[:minimum]
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,34 @@
1
+ module JsonapiCompliable
2
+ module Stats
3
+ class Payload
4
+ def initialize(controller, scope)
5
+ @dsl = controller._jsonapi_compliable
6
+ @directive = controller.params[:stats]
7
+ @scope = controller._jsonapi_scope || scope
8
+ end
9
+
10
+ def generate
11
+ {}.tap do |stats|
12
+ @directive.each_pair do |name, calculation|
13
+ stats[name] = {}
14
+
15
+ each_calculation(name, calculation) do |calc, function|
16
+ stats[name][calc] = function.call(@scope, name)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def each_calculation(name, calculation_string)
25
+ calculations = calculation_string.split(',').map(&:to_sym)
26
+
27
+ calculations.each do |calc|
28
+ function = @dsl.stat(name, calc)
29
+ yield calc, function
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ module JsonapiCompliable
2
+ module Util
3
+ class Pagination
4
+ def self.zero?(params)
5
+ params = params[:page] || params['page'] || {}
6
+ size = params[:size] || params['size']
7
+ [0, '0'].include?(size)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -3,9 +3,9 @@ module JsonapiCompliable
3
3
  class Scoping
4
4
  def self.apply?(controller, object, force)
5
5
  return false if force == false
6
- return true if !controller._jsonapi_scoped && object.is_a?(ActiveRecord::Relation)
6
+ return true if controller._jsonapi_scope.nil? && object.is_a?(ActiveRecord::Relation)
7
7
 
8
- already_scoped = !!controller._jsonapi_scoped
8
+ already_scoped = !!controller._jsonapi_scope
9
9
  is_activerecord = object.is_a?(ActiveRecord::Base)
10
10
  is_activerecord_array = object.is_a?(Array) && object[0].is_a?(ActiveRecord::Base)
11
11
 
@@ -1,3 +1,3 @@
1
1
  module JsonapiCompliable
2
- VERSION = "0.3.8"
2
+ VERSION = "0.3.9"
3
3
  end
@@ -13,9 +13,12 @@ require "jsonapi_compliable/scope/extra_fields"
13
13
  require "jsonapi_compliable/scope/filterable"
14
14
  require "jsonapi_compliable/scope/default_filter"
15
15
  require "jsonapi_compliable/scope/filter"
16
+ require "jsonapi_compliable/stats/dsl"
17
+ require "jsonapi_compliable/stats/payload"
16
18
  require "jsonapi_compliable/util/include_params"
17
19
  require "jsonapi_compliable/util/field_params"
18
20
  require "jsonapi_compliable/util/scoping"
21
+ require "jsonapi_compliable/util/pagination"
19
22
 
20
23
  require 'jsonapi_compliable/railtie' if defined?(::Rails)
21
24
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi_compliable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.3.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-11-07 00:00:00.000000000 Z
12
+ date: 2016-11-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -228,8 +228,11 @@ files:
228
228
  - lib/jsonapi_compliable/scope/paginate.rb
229
229
  - lib/jsonapi_compliable/scope/sideload.rb
230
230
  - lib/jsonapi_compliable/scope/sort.rb
231
+ - lib/jsonapi_compliable/stats/dsl.rb
232
+ - lib/jsonapi_compliable/stats/payload.rb
231
233
  - lib/jsonapi_compliable/util/field_params.rb
232
234
  - lib/jsonapi_compliable/util/include_params.rb
235
+ - lib/jsonapi_compliable/util/pagination.rb
233
236
  - lib/jsonapi_compliable/util/scoping.rb
234
237
  - lib/jsonapi_compliable/version.rb
235
238
  homepage: