munson 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +234 -246
- data/bin/console +2 -10
- data/lib/munson/agent.rb +35 -69
- data/lib/munson/attribute.rb +76 -0
- data/lib/munson/client.rb +43 -0
- data/lib/munson/collection.rb +19 -1
- data/lib/munson/connection.rb +61 -14
- data/lib/munson/document.rb +140 -0
- data/lib/munson/key_formatter.rb +87 -0
- data/lib/munson/middleware/encode_json_api.rb +10 -2
- data/lib/munson/middleware/json_parser.rb +11 -5
- data/lib/munson/query.rb +218 -0
- data/lib/munson/resource.rb +174 -20
- data/lib/munson/response_mapper.rb +92 -32
- data/lib/munson/version.rb +1 -1
- data/lib/munson.rb +30 -22
- metadata +7 -7
- data/lib/munson/model.rb +0 -15
- data/lib/munson/paginator/offset_paginator.rb +0 -45
- data/lib/munson/paginator/paged_paginator.rb +0 -47
- data/lib/munson/paginator.rb +0 -6
- data/lib/munson/query_builder.rb +0 -226
data/lib/munson.rb
CHANGED
@@ -2,25 +2,46 @@ require 'json'
|
|
2
2
|
require 'cgi'
|
3
3
|
require 'faraday'
|
4
4
|
require 'faraday_middleware'
|
5
|
+
require 'bigdecimal'
|
5
6
|
|
6
7
|
require "munson/version"
|
7
|
-
|
8
|
-
require
|
9
|
-
require "munson/
|
10
|
-
|
8
|
+
require 'munson/agent'
|
9
|
+
require 'munson/attribute'
|
10
|
+
require "munson/client"
|
11
11
|
require 'munson/collection'
|
12
|
-
require 'munson/paginator'
|
13
|
-
require 'munson/response_mapper'
|
14
|
-
require 'munson/query_builder'
|
15
12
|
require 'munson/connection'
|
16
|
-
require 'munson/
|
13
|
+
require 'munson/document'
|
14
|
+
require 'munson/key_formatter'
|
15
|
+
require "munson/middleware/encode_json_api"
|
16
|
+
require "munson/middleware/json_parser"
|
17
17
|
require 'munson/resource'
|
18
|
+
require 'munson/response_mapper'
|
19
|
+
require 'munson/query'
|
18
20
|
|
19
21
|
module Munson
|
22
|
+
class Error < StandardError; end;
|
23
|
+
class UnsupportedSortDirectionError < Munson::Error; end;
|
24
|
+
class UnrecognizedKeyFormatter < Munson::Error; end;
|
25
|
+
class RelationshipNotIncludedError < Munson::Error; end;
|
26
|
+
class RelationshipNotFound < Munson::Error; end;
|
27
|
+
class ClientNotSet < Munson::Error; end;
|
20
28
|
@registered_types = {}
|
21
|
-
@registered_paginators = {}
|
22
29
|
|
23
30
|
class << self
|
31
|
+
# Transforms a JSONAPI hash into a Munson::Document, Munson::Resource, or arbitrary class
|
32
|
+
# @param [Munson::Document,Hash] document to transform
|
33
|
+
# @return [Munson::Document,~Munson::Resource]
|
34
|
+
def factory(document)
|
35
|
+
document = Munson::Document.new(document) if document.is_a?(Hash)
|
36
|
+
klass = Munson.lookup_type(document.type)
|
37
|
+
|
38
|
+
if klass && klass.respond_to?(:munson_initializer)
|
39
|
+
klass.munson_initializer(document)
|
40
|
+
else
|
41
|
+
document
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
24
45
|
# Configure the default connection.
|
25
46
|
#
|
26
47
|
# @param [Hash] opts {Munson::Connection} configuration options
|
@@ -52,14 +73,6 @@ module Munson
|
|
52
73
|
@registered_types[type.to_sym] = klass
|
53
74
|
end
|
54
75
|
|
55
|
-
def register_paginator(name, klass)
|
56
|
-
@registered_paginators[name.to_sym] = klass
|
57
|
-
end
|
58
|
-
|
59
|
-
def lookup_paginator(name)
|
60
|
-
@registered_paginators[name.to_sym]
|
61
|
-
end
|
62
|
-
|
63
76
|
# Lookup a class by JSON Spec type name
|
64
77
|
#
|
65
78
|
# @param [#to_sym] type JSON Spec type
|
@@ -67,10 +80,5 @@ module Munson
|
|
67
80
|
def lookup_type(type)
|
68
81
|
@registered_types[type.to_sym]
|
69
82
|
end
|
70
|
-
|
71
|
-
# @private
|
72
|
-
def flush_types!
|
73
|
-
@registered_types = {}
|
74
|
-
end
|
75
83
|
end
|
76
84
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: munson
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cory O'Daniel
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-07-
|
11
|
+
date: 2016-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -182,15 +182,15 @@ files:
|
|
182
182
|
- bin/setup
|
183
183
|
- lib/munson.rb
|
184
184
|
- lib/munson/agent.rb
|
185
|
+
- lib/munson/attribute.rb
|
186
|
+
- lib/munson/client.rb
|
185
187
|
- lib/munson/collection.rb
|
186
188
|
- lib/munson/connection.rb
|
189
|
+
- lib/munson/document.rb
|
190
|
+
- lib/munson/key_formatter.rb
|
187
191
|
- lib/munson/middleware/encode_json_api.rb
|
188
192
|
- lib/munson/middleware/json_parser.rb
|
189
|
-
- lib/munson/
|
190
|
-
- lib/munson/paginator.rb
|
191
|
-
- lib/munson/paginator/offset_paginator.rb
|
192
|
-
- lib/munson/paginator/paged_paginator.rb
|
193
|
-
- lib/munson/query_builder.rb
|
193
|
+
- lib/munson/query.rb
|
194
194
|
- lib/munson/resource.rb
|
195
195
|
- lib/munson/response_mapper.rb
|
196
196
|
- lib/munson/version.rb
|
data/lib/munson/model.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
# module Munson
|
2
|
-
# module Model
|
3
|
-
# extend ActiveSupport::Concern
|
4
|
-
#
|
5
|
-
# included do
|
6
|
-
# self.include Munson::Resource
|
7
|
-
# end
|
8
|
-
#
|
9
|
-
# class_methods do
|
10
|
-
# def has_many(*);end;
|
11
|
-
# def has_one(*);end;
|
12
|
-
# def belongs_to(*);end;
|
13
|
-
# end
|
14
|
-
# end
|
15
|
-
# end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module Munson
|
2
|
-
module Paginator
|
3
|
-
class OffsetPaginator
|
4
|
-
def initialize(options={})
|
5
|
-
@max_limit = options[:max]
|
6
|
-
@default_limit = options[:default]
|
7
|
-
end
|
8
|
-
|
9
|
-
def set(opts={})
|
10
|
-
limit(opts[:limit]) if opts[:limit]
|
11
|
-
offset(opts[:offset]) if opts[:offset]
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_params
|
15
|
-
{
|
16
|
-
page: {
|
17
|
-
limit: @limit || @default_limit || 10,
|
18
|
-
offset: @offset
|
19
|
-
}.select { |_, value| !value.nil? }
|
20
|
-
}
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
# Set limit of resources per page
|
26
|
-
#
|
27
|
-
# @param [Fixnum] num number of resources per page
|
28
|
-
def limit(num)
|
29
|
-
if @max_limit && num > @max_limit
|
30
|
-
@limit = @max_limit
|
31
|
-
else
|
32
|
-
@limit = num
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Set offset
|
37
|
-
#
|
38
|
-
# @param [Fixnum] num pages to offset
|
39
|
-
def offset(num)
|
40
|
-
@offset = num
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
Munson.register_paginator(:offset, Munson::Paginator::OffsetPaginator)
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module Munson
|
2
|
-
module Paginator
|
3
|
-
class PagedPaginator
|
4
|
-
def initialize(options={})
|
5
|
-
@max_size = options[:max]
|
6
|
-
@default_size = options[:default]
|
7
|
-
end
|
8
|
-
|
9
|
-
def set(opts={})
|
10
|
-
number(opts[:number]) if opts[:number]
|
11
|
-
size(opts[:size]) if opts[:size]
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_params
|
15
|
-
{
|
16
|
-
page: {
|
17
|
-
size: @size || @default_size || 10,
|
18
|
-
number: @number
|
19
|
-
}.select { |_, value| !value.nil? }
|
20
|
-
}
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
# Set number of resources per page
|
26
|
-
#
|
27
|
-
# @param [Fixnum] num number of resources per page
|
28
|
-
def size(num)
|
29
|
-
if @max_size && num > @max_size
|
30
|
-
@size = @max_size
|
31
|
-
else
|
32
|
-
@size = num
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Set page number
|
37
|
-
#
|
38
|
-
# @param [Fixnum] num page number
|
39
|
-
def number(num)
|
40
|
-
@number = num
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
Munson.register_paginator(:paged, Munson::Paginator::PagedPaginator)
|
data/lib/munson/paginator.rb
DELETED
data/lib/munson/query_builder.rb
DELETED
@@ -1,226 +0,0 @@
|
|
1
|
-
module Munson
|
2
|
-
class QueryBuilder
|
3
|
-
attr_reader :query
|
4
|
-
attr_reader :paginator
|
5
|
-
attr_reader :agent
|
6
|
-
class UnsupportedSortDirectionError < StandardError; end;
|
7
|
-
class PaginatorNotSet < StandardError; end;
|
8
|
-
class AgentNotSet < StandardError; end;
|
9
|
-
|
10
|
-
# Description of method
|
11
|
-
#
|
12
|
-
# @param [Class] paginator: nil instantiated paginator
|
13
|
-
# @param [Class] agent: nil instantiated agent to use for fetching results
|
14
|
-
# @return [Type] description of returned object
|
15
|
-
def initialize(paginator: nil, agent: nil)
|
16
|
-
@paginator = paginator
|
17
|
-
@agent = agent
|
18
|
-
|
19
|
-
@query = {
|
20
|
-
include: [],
|
21
|
-
fields: [],
|
22
|
-
filter: [],
|
23
|
-
sort: []
|
24
|
-
}
|
25
|
-
end
|
26
|
-
|
27
|
-
# @return [String] query as a query string
|
28
|
-
def to_query_string
|
29
|
-
Faraday::Utils.build_nested_query(to_params)
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_s
|
33
|
-
to_query_string
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_params
|
37
|
-
str = {}
|
38
|
-
str[:filter] = filter_to_query_value unless @query[:filter].empty?
|
39
|
-
str[:fields] = fields_to_query_value unless @query[:fields].empty?
|
40
|
-
str[:include] = includes_to_query_value unless @query[:include].empty?
|
41
|
-
str[:sort] = sort_to_query_value unless @query[:sort].empty?
|
42
|
-
|
43
|
-
str.merge!(paginator.to_params) if paginator
|
44
|
-
|
45
|
-
str
|
46
|
-
end
|
47
|
-
|
48
|
-
# Fetches resources using {Munson::Agent}
|
49
|
-
#
|
50
|
-
# @return [Array] Array of resources
|
51
|
-
def fetch
|
52
|
-
if @agent
|
53
|
-
response = @agent.get(params: to_params)
|
54
|
-
resources = ResponseMapper.new(response).resources
|
55
|
-
Collection.new(resources)
|
56
|
-
else
|
57
|
-
raise AgentNotSet, "Agent was not set. QueryBuilder#new(agent:)"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def paging?
|
62
|
-
!!paginator
|
63
|
-
end
|
64
|
-
|
65
|
-
# Paginator proxy
|
66
|
-
#
|
67
|
-
# @return [Class,nil] paginator if set
|
68
|
-
def page(opts={})
|
69
|
-
if paging?
|
70
|
-
paginator.set(opts)
|
71
|
-
self
|
72
|
-
else
|
73
|
-
raise PaginatorNotSet, "Paginator was not set. QueryBuilder#new(paginator:)"
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Chainably include related resources.
|
78
|
-
#
|
79
|
-
# @example including a resource
|
80
|
-
# Munson::QueryBuilder.new.includes(:user)
|
81
|
-
#
|
82
|
-
# @example including a related resource
|
83
|
-
# Munson::QueryBuilder.new.includes("user.addresses")
|
84
|
-
#
|
85
|
-
# @example including multiple resources
|
86
|
-
# Munson::QueryBuilder.new.includes("user.addresses", "user.images")
|
87
|
-
#
|
88
|
-
# @param [Array<String,Symbol>] *args relationships to include
|
89
|
-
# @return [Munson::QueryBuilder] self for chaining queries
|
90
|
-
#
|
91
|
-
# @see http://jsonapi.org/format/#fetching-includes JSON API Including Relationships
|
92
|
-
def includes(*args)
|
93
|
-
@query[:include] += args
|
94
|
-
self
|
95
|
-
end
|
96
|
-
|
97
|
-
# Chainably sort results
|
98
|
-
# @note Default order is ascending
|
99
|
-
#
|
100
|
-
# @example sorting by a single field
|
101
|
-
# Munsun::QueryBuilder.new.sort(:created_at)
|
102
|
-
#
|
103
|
-
# @example sorting by a multiple fields
|
104
|
-
# Munsun::QueryBuilder.new.sort(:created_at, :age)
|
105
|
-
#
|
106
|
-
# @example specifying sort direction
|
107
|
-
# Munsun::QueryBuilder.new.sort(:created_at, age: :desc)
|
108
|
-
#
|
109
|
-
# @example specifying sort direction
|
110
|
-
# Munsun::QueryBuilder.new.sort(score: :desc, :created_at)
|
111
|
-
#
|
112
|
-
# @param [Hash<Symbol,Symbol>, Symbol] *args fields to sort by
|
113
|
-
# @return [Munson::QueryBuilder] self for chaining queries
|
114
|
-
#
|
115
|
-
# @see http://jsonapi.org/format/#fetching-sorting JSON API Sorting Spec
|
116
|
-
def sort(*args)
|
117
|
-
validate_sort_args(args.select{|arg| arg.is_a?(Hash)})
|
118
|
-
@query[:sort] += args
|
119
|
-
self
|
120
|
-
end
|
121
|
-
|
122
|
-
# Hash resouce_name: [array of attribs]
|
123
|
-
def fields(*args)
|
124
|
-
@query[:fields] += args
|
125
|
-
self
|
126
|
-
end
|
127
|
-
|
128
|
-
def filter(*args)
|
129
|
-
@query[:filter] += args
|
130
|
-
self
|
131
|
-
end
|
132
|
-
|
133
|
-
def self.includes(*args)
|
134
|
-
new.includes(*args)
|
135
|
-
end
|
136
|
-
|
137
|
-
def self.sort(*args)
|
138
|
-
new.sort(*args)
|
139
|
-
end
|
140
|
-
|
141
|
-
def self.fields(*args)
|
142
|
-
new.fields(*args)
|
143
|
-
end
|
144
|
-
|
145
|
-
def self.filter(*args)
|
146
|
-
new.filter(*args)
|
147
|
-
end
|
148
|
-
|
149
|
-
protected
|
150
|
-
|
151
|
-
def sort_to_query_value
|
152
|
-
@query[:sort].map{|item|
|
153
|
-
if item.is_a?(Hash)
|
154
|
-
item.to_a.map{|name,dir|
|
155
|
-
dir.to_sym == :desc ? "-#{name}" : name.to_s
|
156
|
-
}
|
157
|
-
else
|
158
|
-
item.to_s
|
159
|
-
end
|
160
|
-
}.join(',')
|
161
|
-
end
|
162
|
-
|
163
|
-
def fields_to_query_value
|
164
|
-
@query[:fields].inject({}) do |acc, hash_arg|
|
165
|
-
hash_arg.each do |k,v|
|
166
|
-
acc[k] ||= []
|
167
|
-
v.is_a?(Array) ?
|
168
|
-
acc[k] += v :
|
169
|
-
acc[k] << v
|
170
|
-
|
171
|
-
acc[k].map(&:to_s).uniq!
|
172
|
-
end
|
173
|
-
|
174
|
-
acc
|
175
|
-
end.map { |k, v| [k, v.join(',')] }.to_h
|
176
|
-
end
|
177
|
-
|
178
|
-
def includes_to_query_value
|
179
|
-
@query[:include].map(&:to_s).sort.join(',')
|
180
|
-
end
|
181
|
-
|
182
|
-
# Since the filter query param's format isn't specified in the [spec](http://jsonapi.org/format/#fetching-filtering)
|
183
|
-
# this implemenation uses (JSONAPI::Resource's implementation](https://github.com/cerebris/jsonapi-resources#filters)
|
184
|
-
#
|
185
|
-
# To override, implement your own CustomQueryBuilder inheriting from {Munson::QueryBuilder}
|
186
|
-
# {Munson::Agent} takes a QueryBuilder class to use. This method could be overriden in your custom class
|
187
|
-
#
|
188
|
-
# @example Custom Query Builder
|
189
|
-
# class MyBuilder < Munson::QueryBuilder
|
190
|
-
# def filter_to_query_value
|
191
|
-
# # ... your fancier logic
|
192
|
-
# end
|
193
|
-
# end
|
194
|
-
#
|
195
|
-
# class Article
|
196
|
-
# def self.munson
|
197
|
-
# return @munson if @munson
|
198
|
-
# @munson = Munson::Agent.new(
|
199
|
-
# query_builder: MyBuilder
|
200
|
-
# path: 'products'
|
201
|
-
# )
|
202
|
-
# end
|
203
|
-
# end
|
204
|
-
#
|
205
|
-
def filter_to_query_value
|
206
|
-
@query[:filter].reduce({}) do |acc, hash_arg|
|
207
|
-
hash_arg.each do |k,v|
|
208
|
-
acc[k] ||= []
|
209
|
-
v.is_a?(Array) ? acc[k] += v : acc[k] << v
|
210
|
-
acc[k].uniq!
|
211
|
-
end
|
212
|
-
acc
|
213
|
-
end.map { |k, v| [k, v.join(',')] }.to_h
|
214
|
-
end
|
215
|
-
|
216
|
-
def validate_sort_args(hashes)
|
217
|
-
hashes.each do |hash|
|
218
|
-
hash.each do |k,v|
|
219
|
-
if !%i(desc asc).include?(v.to_sym)
|
220
|
-
raise UnsupportedSortDirectionError, "Unknown direction '#{v}'. Use :asc or :desc"
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|