jsonapi_compliable 0.3.8 → 0.3.9

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
  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: