Class: JsonapiCompliable::Query

Inherits:
Object
  • Object
show all
Defined in:
lib/jsonapi_compliable/query.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(resource, params) ⇒ Query

Returns a new instance of Query



24
25
26
27
# File 'lib/jsonapi_compliable/query.rb', line 24

def initialize(resource, params)
  @resource = resource
  @params = params
end

Instance Attribute Details

#paramsObject (readonly)

TODO: This class could use some refactoring love!



4
5
6
# File 'lib/jsonapi_compliable/query.rb', line 4

def params
  @params
end

#resourceObject (readonly)

TODO: This class could use some refactoring love!



4
5
6
# File 'lib/jsonapi_compliable/query.rb', line 4

def resource
  @resource
end

Class Method Details

.default_hashHash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This is the structure of Query#to_hash used elsewhere in the library

Returns:

  • (Hash)

    the default hash

See Also:



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/jsonapi_compliable/query.rb', line 12

def self.default_hash
  {
    filter: {},
    sort: [],
    page: {},
    include: {},
    stats: {},
    fields: {},
    extra_fields: {}
  }
end

Instance Method Details

#association_namesArray<Symbol>

All the keys of the #include_hash

For example, let's say we had

{ posts: { comments: {} }

#association_names would return

[:posts, :comments]

Returns:

  • (Array<Symbol>)

    all association names, recursive



71
72
73
# File 'lib/jsonapi_compliable/query.rb', line 71

def association_names
  @association_names ||= Util::Hash.keys(include_hash)
end

#include_directiveJSONAPI::IncludeDirective

The relevant include directive

Returns:

  • (JSONAPI::IncludeDirective)

See Also:



32
33
34
# File 'lib/jsonapi_compliable/query.rb', line 32

def include_directive
  @include_directive ||= JSONAPI::IncludeDirective.new(params[:include])
end

#include_hashHash

The include, directive, as a hash. For instance

{ posts: { comments: {} } }

This will only include relationships that are

  • Available on the Resource

  • Whitelisted (when specified)

So that users can't simply request your entire object graph.

Returns:

  • (Hash)

    the scrubbed include directive as a hash

See Also:



49
50
51
52
53
54
55
56
57
58
# File 'lib/jsonapi_compliable/query.rb', line 49

def include_hash
  @include_hash ||= begin
    requested     = include_directive.to_hash
    all_allowed   = resource.sideloading.to_hash[:base]
    whitelist     = resource.sideload_whitelist.values.reduce(:merge)
    allowed       = whitelist ? Util::IncludeParams.scrub(all_allowed, whitelist) : all_allowed

    Util::IncludeParams.scrub(requested, allowed)
  end
end

#to_hashHash

A flat hash of sanitized query parameters. All relationship names are top-level:

{
  posts: { filter, sort, ... }
  comments: { filter, sort, ... }
}

Examples:

sorting

# GET /posts?sort=-title
{ posts: { sort: { title: :desc } } }

pagination

# GET /posts?page[number]=2&page[size]=10
{ posts: { page: { number: 2, size: 10 } }

filtering

# GET /posts?filter[title]=Foo
{ posts: { filter: { title: 'Foo' } }

include

# GET /posts?include=comments.author
{ posts: { include: { comments: { author: {} } } } }

stats

# GET /posts?stats[likes]=count,average
{ posts: { stats: [:count, :average] } }

fields

# GET /posts?fields=foo,bar
{ posts: { fields: [:foo, :bar] } }

extra fields

# GET /posts?fields=foo,bar
{ posts: { extra_fields: [:foo, :bar] } }

nested parameters

# GET /posts?include=comments&sort=comments.created_at&page[comments][size]=3
{
  posts: { ... },
  comments: { page: { size: 3 }, sort: { created_at: :asc } }

Returns:

  • (Hash)

    the normalized query hash

See Also:



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/jsonapi_compliable/query.rb', line 120

def to_hash
  hash = { resource.type => self.class.default_hash }

  association_names.each do |name|
    hash[name] = self.class.default_hash
  end

  fields = parse_fields({}, :fields)
  extra_fields = parse_fields({}, :extra_fields)
  hash.each_pair do |type, query_hash|
    hash[type][:fields] = fields
    hash[type][:extra_fields] = extra_fields
  end

  parse_filter(hash)
  parse_sort(hash)
  parse_pagination(hash)

  parse_include(hash, include_hash, resource.type)
  parse_stats(hash)

  hash
end

#zero_results?Boolean

Check if the user has requested 0 actual results They may have done this to get, say, the total count without the overhead of fetching actual records.

Examples:

Total Count, 0 Results

# GET /posts?page[size]=0&stats[total]=count
# Response:
{
  data: [],
  meta: {
    stats: { total: { count: 100 } }
  }
}

Returns:

  • (Boolean)

    were 0 results requested?



159
160
161
162
163
# File 'lib/jsonapi_compliable/query.rb', line 159

def zero_results?
  !@params[:page].nil? &&
    !@params[:page][:size].nil? &&
    @params[:page][:size].to_i == 0
end