-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow stats to be nested_on resources
- Loading branch information
Showing
12 changed files
with
223 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
module Graphiti | ||
module Stats | ||
# Generate the nested stats payload so we can return it in the response for each record i.e. | ||
# | ||
# { | ||
# data: [ | ||
# { | ||
# id: "1", | ||
# type: "employee", | ||
# attributes: {}, | ||
# relationships: {}, | ||
# meta: { stats: { total: { count: 100 } } } | ||
# } | ||
# ], | ||
# meta: {} | ||
# } | ||
|
||
class NestedPayload | ||
def initialize(resource, query, scope, data) | ||
@resource = resource | ||
@query = query | ||
@scope = scope | ||
@data = data | ||
end | ||
|
||
# Generate the payload for +{ meta: { stats: { ... } } }+ | ||
# Loops over all calculations, computes then, and gives back | ||
# a hash of stats and their results. | ||
# @return [Hash] the generated payload | ||
def generate | ||
{}.tap do |stats| | ||
@query.stats.each_pair do |name, calculation| | ||
nested_on = @resource.stats[name].nested_on | ||
next if nested_on.blank? | ||
|
||
stats[nested_on] ||= {} | ||
|
||
each_calculation(name, calculation) do |calc, function| | ||
data_arr = (@data.is_a? Enumerable) ? @data : [@data] | ||
|
||
data_arr.each do |object| | ||
args = [@scope, name] | ||
args << @resource.context if function.arity >= 3 | ||
args << object if function.arity == 4 | ||
result = function.call(*args) | ||
|
||
stats[nested_on][object.id] ||= {} | ||
stats[nested_on][object.id][name] ||= {} | ||
stats[nested_on][object.id][name][calc] = result | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
def each_calculation(name, calculations) | ||
calculations.each do |calc| | ||
function = @resource.stat(name, calc) | ||
yield calc, function | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
require "spec_helper" | ||
|
||
RSpec.describe 'A resource with nested stats' do | ||
include_context "resource testing" | ||
|
||
let!(:employee1) { PORO::Employee.create first_name: 'Alice', age: 25 } | ||
let!(:employee2) { PORO::Employee.create first_name: 'Bob', age: 40 } | ||
|
||
let!(:position1) { PORO::Position.create employee_id: employee1.id, rank: 4 } | ||
let!(:position2) { PORO::Position.create employee_id: employee1.id, rank: 8 } | ||
let!(:position3) { PORO::Position.create employee_id: employee2.id, rank: 10 } | ||
let!(:position4) { PORO::Position.create employee_id: employee2.id, rank: 22 } | ||
|
||
let(:state_group_count) { [{ id: 10, count: 3 }, { id: 11, count: 0 }] } | ||
|
||
def jsonapi | ||
JSON.parse(proxy.to_jsonapi) | ||
end | ||
|
||
describe "has_many" do | ||
context "with include directive" do | ||
let(:resource) do | ||
Class.new(PORO::EmployeeResource) do | ||
def self.name | ||
"PORO::EmployeeResource" | ||
end | ||
|
||
has_many :positions | ||
|
||
stat age: [:squared], nested_on: :employees do | ||
squared do |scope, attr, context, employee| | ||
employee.age * employee.age | ||
end | ||
end | ||
end | ||
end | ||
|
||
before do | ||
allow_any_instance_of(PORO::Employee).to receive(:applications_by_state_group_count).and_return(state_group_count) | ||
|
||
params[:include] = "positions" | ||
params[:stats] = {age: 'squared'} | ||
render | ||
end | ||
|
||
it "includes the top-level stats" do | ||
expect(jsonapi['meta']['stats']).to be_nil | ||
end | ||
|
||
it "includes the stats nested on employees" do | ||
jsonapi['data'].each do |record| | ||
expect(record['meta']['stats']).to_not be_nil | ||
expect(record['meta']['stats']['age']).to_not be_nil | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
require "spec_helper" | ||
|
||
RSpec.describe 'A resource with nested stats' do | ||
include_context "resource testing" | ||
|
||
let!(:employee1) { PORO::Employee.create first_name: 'Alice', age: 25 } | ||
let!(:employee2) { PORO::Employee.create first_name: 'Bob', age: 40 } | ||
|
||
let!(:position1) { PORO::Position.create employee_id: employee1.id, rank: 4 } | ||
let!(:position2) { PORO::Position.create employee_id: employee1.id, rank: 8 } | ||
let!(:position3) { PORO::Position.create employee_id: employee2.id, rank: 10 } | ||
let!(:position4) { PORO::Position.create employee_id: employee2.id, rank: 22 } | ||
|
||
let(:state_group_count) { [{ id: 10, count: 3 }, { id: 11, count: 0 }] } | ||
|
||
def jsonapi | ||
JSON.parse(proxy.to_jsonapi) | ||
end | ||
|
||
describe "has_many" do | ||
context "with include directive" do | ||
let(:resource) do | ||
Class.new(PORO::EmployeeResource) do | ||
def self.name | ||
"PORO::EmployeeResource" | ||
end | ||
|
||
has_many :positions | ||
|
||
stat age: [:average] | ||
|
||
stat jobApplicationsByStateGroup: [:count], nested_on: :employees do | ||
count do |scope, attr, context, employee| | ||
employee.applications_by_state_group_count | ||
end | ||
end | ||
end | ||
end | ||
|
||
before do | ||
allow_any_instance_of(PORO::Employee).to receive(:applications_by_state_group_count).and_return(state_group_count) | ||
|
||
params[:include] = "positions" | ||
params[:stats] = {age: 'average', jobApplicationsByStateGroup: 'count' } | ||
render | ||
end | ||
|
||
it "includes the top-level stats" do | ||
expect(jsonapi['meta']['stats']).to_not be_nil | ||
end | ||
|
||
it "includes the stats nested on employees" do | ||
jsonapi['data'].each do |record| | ||
expect(record['meta']['stats']).to_not be_nil | ||
expect(record['meta']['stats']['jobApplicationsByStateGroup']).to_not be_nil | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters