pureapi 0.3.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/pureapi.rb +1 -0
- data/lib/pureapi/controller.rb +140 -0
- data/lib/pureapi/model.rb +156 -0
- data/lib/pureapi/postgres_model.rb +75 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1785ebfc9a66dd582d162f50449a27eb66283a97
|
4
|
+
data.tar.gz: 76c8d1f5aaff7c60b576414e41f97a96da52c164
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 711367bd3e8cb79b9bd77d015a27a8d87de8bbedea5582c6616a9afee8a600dc13733a5e6d8886626cdc1b9143fcbf39db213a3c5adaa6cf7b4cf4cef69c9723
|
7
|
+
data.tar.gz: 4c3026a51a0ece1227c697d054abcc4cae1bd5eddb5d7be06ad33a336789d40e1ff1f61516464dab68e234ef3474bd33c71c4be6ed2887f28803c553d3c014b9
|
data/lib/pureapi.rb
CHANGED
@@ -3,6 +3,7 @@ module Pureapi
|
|
3
3
|
autoload :Controller, 'pureapi/controller'
|
4
4
|
# autoload :Model, 'pureapi/model'
|
5
5
|
# autoload :MongoidModel, 'pureapi/mongoid_model'
|
6
|
+
# autoload :PostgresModel, 'pureapi/postgres_model'
|
6
7
|
|
7
8
|
# Default way to set up Jwtauth.
|
8
9
|
# a fresh initializer with all configuration values.
|
data/lib/pureapi/controller.rb
CHANGED
@@ -16,6 +16,18 @@ module Pureapi::Controller
|
|
16
16
|
AFTER_REGEX = /\}/
|
17
17
|
|
18
18
|
### Begin 3 main API for GET data
|
19
|
+
# Filter list objects contain search, sort, paginate
|
20
|
+
def core_index_filter(objects)
|
21
|
+
# 1. search
|
22
|
+
objects = default_search_filter(objects)
|
23
|
+
# 2. sort and default sort is id.desc
|
24
|
+
objects = default_sort_filter(objects)
|
25
|
+
# 3. conditions (replace for +default_cond|incond_filter+)
|
26
|
+
objects = core_cond_filter(objects)
|
27
|
+
# 4. paginate
|
28
|
+
objects = paging_standard(objects)
|
29
|
+
end
|
30
|
+
|
19
31
|
# Filter list objects contain search, sort, paginate
|
20
32
|
def default_index_filter(objects)
|
21
33
|
# 1. search
|
@@ -105,6 +117,42 @@ module Pureapi::Controller
|
|
105
117
|
model.as_json(options)
|
106
118
|
end
|
107
119
|
|
120
|
+
# New version of return json for index action
|
121
|
+
def records_as_json(criterias, includes_deep_level = 2)
|
122
|
+
options = {}
|
123
|
+
includes = []
|
124
|
+
|
125
|
+
if params.permit(:fields)[:fields]
|
126
|
+
# Get fields from params
|
127
|
+
_fields = parse_fields(params.permit(:fields)[:fields], includes_deep_level)
|
128
|
+
# Merge with as_json_fields of entity
|
129
|
+
options = merge_as_json(_fields, criterias.as_json_fields)
|
130
|
+
# Get relations for includes
|
131
|
+
includes += include_relations(options)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Reflect options to params
|
135
|
+
params[:fields] = deparse_fields(options)
|
136
|
+
# Get relations for includes from methods
|
137
|
+
includes += criterias.json_method_includes.slice(*options[:methods]).values if !options[:methods].blank?
|
138
|
+
|
139
|
+
criterias.includes(includes).as_json(options)
|
140
|
+
end
|
141
|
+
|
142
|
+
# New version of return json for show action
|
143
|
+
def record_as_json(model, includes_deep_level = 2)
|
144
|
+
options = {}
|
145
|
+
|
146
|
+
if params.permit(:fields)[:fields]
|
147
|
+
# Get fields from params
|
148
|
+
_fields = parse_fields(params.permit(:fields)[:fields], includes_deep_level)
|
149
|
+
# Merge with as_json_fields of entity
|
150
|
+
options = merge_as_json(_fields, model.class.as_json_fields)
|
151
|
+
end
|
152
|
+
|
153
|
+
model.as_json(options)
|
154
|
+
end
|
155
|
+
|
108
156
|
# Define json filters for params in render json api
|
109
157
|
def filter_jsons
|
110
158
|
{
|
@@ -281,6 +329,71 @@ module Pureapi::Controller
|
|
281
329
|
end
|
282
330
|
### End setup of feature comparison conditions
|
283
331
|
|
332
|
+
### Begin setup new version of feature comparison conditions
|
333
|
+
# Filter conditions of object criteria
|
334
|
+
def core_cond_filter(objects)
|
335
|
+
# Default +compcond_params+ for query
|
336
|
+
compcond_params = {}
|
337
|
+
|
338
|
+
# Collaborate params, operators, model to get +compcond_params+
|
339
|
+
if params[:compconds].is_a?(ActionController::Parameters)
|
340
|
+
compcond_params = parse_compcond_fields(params[:compconds], objects)
|
341
|
+
end
|
342
|
+
|
343
|
+
# Assign params[:compconds] after parse
|
344
|
+
params[:compconds] = deparse_compcond_fields(compcond_params)
|
345
|
+
|
346
|
+
# Add conditions of +compcond_params+ to objects
|
347
|
+
objects.compcond_search(compcond_params)
|
348
|
+
end
|
349
|
+
|
350
|
+
def parse_compcond_fields params, model, limit = 10
|
351
|
+
# Default results
|
352
|
+
_results = {only: [], include: {}}
|
353
|
+
|
354
|
+
params.keys.each do |key|
|
355
|
+
# Get field and operator from +key+ of model
|
356
|
+
matchs = model.compcond_match(key)
|
357
|
+
|
358
|
+
if matchs
|
359
|
+
matchs[:v] = params.permit(permit_operator(key, matchs[:o]))[key]
|
360
|
+
|
361
|
+
_results[:only] << matchs
|
362
|
+
end
|
363
|
+
|
364
|
+
# Process for belongs_to relations
|
365
|
+
entity = model.of_entities[key.to_sym]
|
366
|
+
|
367
|
+
if limit > 1 && entity && params[key].is_a?(ActionController::Parameters)
|
368
|
+
_results[:include][key.to_sym] = parse_compcond_fields(params[key], entity, limit - 1)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
_results
|
373
|
+
end
|
374
|
+
|
375
|
+
def deparse_compcond_fields compcond_params
|
376
|
+
# Default results
|
377
|
+
_results = {}
|
378
|
+
|
379
|
+
# Assign from +compcond_params[:only]+
|
380
|
+
compcond_params[:only] && compcond_params[:only].each do |item|
|
381
|
+
_results["#{item[:f]}.#{item[:o]}"] = item[:v]
|
382
|
+
end
|
383
|
+
|
384
|
+
# Assign from +compcond_params[:include]+
|
385
|
+
compcond_params[:include] && compcond_params[:include].each do |key, item|
|
386
|
+
_results[key] = deparse_compcond_fields(item)
|
387
|
+
end
|
388
|
+
|
389
|
+
_results
|
390
|
+
end
|
391
|
+
|
392
|
+
def permit_operator key, operator
|
393
|
+
Pureapi::Model::PERMIT_OPERATORS[operator] ? { key => Pureapi::Model::PERMIT_OPERATORS[operator] } : key
|
394
|
+
end
|
395
|
+
### End setup new version of feature comparison conditions
|
396
|
+
|
284
397
|
### Begin setup of paging_standard. If not use will_paginate, write in mode class
|
285
398
|
# Method validate page number (like page params)
|
286
399
|
def validate_page(page, page_total)
|
@@ -312,6 +425,33 @@ module Pureapi::Controller
|
|
312
425
|
### End setup of paging_standard
|
313
426
|
|
314
427
|
### Begin feature records_json and record_json which render format json
|
428
|
+
# Merge target from request params, source from model
|
429
|
+
#
|
430
|
+
# Arguments:
|
431
|
+
# target: (Hash)
|
432
|
+
# source: (Hash)
|
433
|
+
def merge_as_json(target ,source)
|
434
|
+
result = {}
|
435
|
+
|
436
|
+
if source[:only].is_a?(Array)
|
437
|
+
result[:only] = target[:only].is_a?(Array) ? (target[:only] & source[:only]) : source[:only]
|
438
|
+
end
|
439
|
+
|
440
|
+
if source[:methods].is_a?(Array) && target[:only].is_a?(Array)
|
441
|
+
result[:methods] = target[:only] & source[:methods]
|
442
|
+
end
|
443
|
+
|
444
|
+
if source[:include].is_a?(Hash) && target[:include].is_a?(Hash)
|
445
|
+
result[:include] = {}
|
446
|
+
|
447
|
+
(source[:include].keys & target[:include].keys).each do |k|
|
448
|
+
result[:include][k] = merge_as_json(target[:include][k], source[:include][k])
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
result.delete_if { |k, v| v.blank? }
|
453
|
+
end
|
454
|
+
|
315
455
|
# Methods return hash contain full params use for ActiveRecord includes()
|
316
456
|
# and ActiveModel::Serializers::JSON as_json()
|
317
457
|
def parse_includes(fields, model, includes_deep_level = 2)
|
data/lib/pureapi/model.rb
CHANGED
@@ -33,6 +33,33 @@ module Pureapi::Model
|
|
33
33
|
LOGICAL_OPERATORS_INVERT = LOGICAL_OPERATORS.invert
|
34
34
|
NULL_OPERATOR_KEYS = NULL_OPERATORS.keys
|
35
35
|
|
36
|
+
# New version of +COMPARISON_OPERATORS+ & others
|
37
|
+
module Operators
|
38
|
+
EQ = { id: :eq, is: '=' }
|
39
|
+
NE = { id: :ne, is: '<>' }
|
40
|
+
GT = { id: :gt, is: '>' }
|
41
|
+
LT = { id: :lt, is: '<' }
|
42
|
+
GTE = { id: :gte, is: '>=' }
|
43
|
+
LTE = { id: :lte, is: '<=' }
|
44
|
+
LIKE = { id: :like, is: 'LIKE' }
|
45
|
+
NLIKE = { id: :nlike, is: 'NOT LIKE' }
|
46
|
+
REGEXP = { id: :regexp, is: 'REGEXP' }
|
47
|
+
IN = { id: :in, is: 'IN', permit: [] }
|
48
|
+
ISNIL = { id: :isnil, is: 'IS NULL' }
|
49
|
+
ISNNIL = { id: :isnnil, is: 'IS NOT NULL' }
|
50
|
+
end
|
51
|
+
|
52
|
+
REFLECT_OPERATORS = Operators.constants.inject({}) do |memo, const_name|
|
53
|
+
item = Operators.const_get(const_name)
|
54
|
+
memo[item[:id]] = item[:is]
|
55
|
+
memo
|
56
|
+
end
|
57
|
+
|
58
|
+
PERMIT_OPERATORS = Operators.constants.inject({}) do |memo, const_name|
|
59
|
+
item = Operators.const_get(const_name)
|
60
|
+
memo[item[:id]] = item[:permit]
|
61
|
+
memo
|
62
|
+
end
|
36
63
|
|
37
64
|
# return default array contains methods for as_json
|
38
65
|
# Eg. [:status_name, :path_detail, :restrictions, :channel_course_code]
|
@@ -158,8 +185,137 @@ module Pureapi::Model
|
|
158
185
|
self.column_names.map(&:to_sym)
|
159
186
|
end
|
160
187
|
|
188
|
+
# Define relation entities can be included
|
189
|
+
# Example:
|
190
|
+
# >> {User => [:manager], Department => [:department]}
|
191
|
+
def include_entities
|
192
|
+
{}
|
193
|
+
end
|
194
|
+
|
161
195
|
# Require params is hash contain Integer :page, :per_page
|
162
196
|
def paginate(params)
|
163
197
|
self.limit(params[:per_page]).offset((params[:page] - 1) * params[:per_page])
|
164
198
|
end
|
199
|
+
|
200
|
+
# Get all includes of relations in model
|
201
|
+
def get_includes nested_entities
|
202
|
+
_results = {}
|
203
|
+
_entities = include_entities
|
204
|
+
|
205
|
+
(_entities.keys - nested_entities).each do |_c|
|
206
|
+
_entities[_c].each do |_r|
|
207
|
+
_results[_r] = _c._json_fields(nested_entities)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
_results
|
212
|
+
end
|
213
|
+
|
214
|
+
# Return all available values around model
|
215
|
+
def _json_fields nested_entities = []
|
216
|
+
nested_entities << self
|
217
|
+
|
218
|
+
{
|
219
|
+
only: default_onlyasjsons,
|
220
|
+
methods: json_methods,
|
221
|
+
include: get_includes(nested_entities),
|
222
|
+
}
|
223
|
+
end
|
224
|
+
|
225
|
+
# Static of +_json_fields+
|
226
|
+
def as_json_fields
|
227
|
+
@as_json_fields ||= self._json_fields
|
228
|
+
end
|
229
|
+
|
230
|
+
### Begin methods for feature compconds filter
|
231
|
+
# Return list of all belongs_to => class_name
|
232
|
+
# Example:
|
233
|
+
# >> {ad: Ad, lead_level: LeadLevel, course: Course}
|
234
|
+
def of_entities
|
235
|
+
{}
|
236
|
+
end
|
237
|
+
|
238
|
+
# Full compcond regexp for key
|
239
|
+
# Example:
|
240
|
+
# >> id.gte
|
241
|
+
def compcond_regexp
|
242
|
+
@compcond_regexp ||= /^(#{compcond_columns.join("|")})\.(#{REFLECT_OPERATORS.keys.join("|")})$/
|
243
|
+
end
|
244
|
+
|
245
|
+
# Compcond regexp for key
|
246
|
+
# Example:
|
247
|
+
# >> id
|
248
|
+
def compcond_regexp2nd
|
249
|
+
@compcond_regexp2nd ||= /^(#{compcond_columns.join("|")})$/
|
250
|
+
end
|
251
|
+
|
252
|
+
# Return matchs of key with +compcond_regexp+ || +compcond_regexp2nd+
|
253
|
+
def compcond_match(str)
|
254
|
+
_matchs = compcond_regexp.match(str) || compcond_regexp2nd.match(str)
|
255
|
+
|
256
|
+
if _matchs
|
257
|
+
{
|
258
|
+
f: _matchs[1],
|
259
|
+
o: _matchs[2] ? _matchs[2].to_sym : :eq,
|
260
|
+
}
|
261
|
+
else
|
262
|
+
nil
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# Return all fields can use for search of model
|
267
|
+
def _search_fields
|
268
|
+
_results = {only: compcond_columns, include: {}}
|
269
|
+
|
270
|
+
of_entities.each do |entity, _c|
|
271
|
+
_results[:include][entity] = _c._search_fields
|
272
|
+
end
|
273
|
+
|
274
|
+
_results
|
275
|
+
end
|
276
|
+
|
277
|
+
# Static of +_search_fields+
|
278
|
+
def compcond_fields
|
279
|
+
@compcond_fields ||= self._search_fields
|
280
|
+
end
|
281
|
+
|
282
|
+
# Search by params of attributes of model
|
283
|
+
def _self_search only_params
|
284
|
+
criterias = self
|
285
|
+
|
286
|
+
only_params.each do |filter|
|
287
|
+
case filter[:o]
|
288
|
+
when Operators::EQ[:id], Operators::IN[:id]
|
289
|
+
criterias = criterias.where(filter[:f] => filter[:v])
|
290
|
+
when Operators::ISNIL[:id], Operators::ISNNIL[:id]
|
291
|
+
criterias = criterias.where("`#{self.table_name}`.`#{filter[:f]}` #{REFLECT_OPERATORS[filter[:o]]}")
|
292
|
+
else
|
293
|
+
criterias = criterias.where("`#{self.table_name}`.`#{filter[:f]}` #{REFLECT_OPERATORS[filter[:o]]} ?", filter[:v])
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
return criterias.where({})
|
298
|
+
end
|
299
|
+
|
300
|
+
# Search by params of relations
|
301
|
+
def _include_search include_params
|
302
|
+
criterias = self
|
303
|
+
|
304
|
+
include_params.each do |entity, query|
|
305
|
+
criterias = criterias.where(entity => of_entities[entity].compcond_search(query)) if of_entities[entity]
|
306
|
+
end
|
307
|
+
|
308
|
+
return criterias.where({})
|
309
|
+
end
|
310
|
+
|
311
|
+
# Collaborate +_self_search+ & +_include_search+
|
312
|
+
def compcond_search params
|
313
|
+
criterias = self
|
314
|
+
|
315
|
+
criterias = criterias._self_search(params[:only]) if params[:only].is_a?(Array)
|
316
|
+
criterias = criterias._include_search(params[:include]) if params[:include].is_a?(Hash)
|
317
|
+
|
318
|
+
return criterias.where({})
|
319
|
+
end
|
320
|
+
### End methods for feature compconds filter
|
165
321
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'pureapi/model'
|
3
|
+
|
4
|
+
# Provide methods (override, polymorphic) for use data handling
|
5
|
+
# # => comfortable when use postgresql
|
6
|
+
|
7
|
+
module Pureapi::PostgresModel
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
include Pureapi::Model
|
10
|
+
|
11
|
+
# New version of +COMPARISON_OPERATORS+ & others
|
12
|
+
module Operators
|
13
|
+
EQ = { id: :eq, is: '=' }
|
14
|
+
NE = { id: :ne, is: '<>' }
|
15
|
+
GT = { id: :gt, is: '>' }
|
16
|
+
LT = { id: :lt, is: '<' }
|
17
|
+
GTE = { id: :gte, is: '>=' }
|
18
|
+
LTE = { id: :lte, is: '<=' }
|
19
|
+
LIKE = { id: :like, is: 'LIKE' }
|
20
|
+
NLIKE = { id: :nlike, is: 'NOT LIKE' }
|
21
|
+
REGEXP = { id: :regexp, is: '~' }
|
22
|
+
IN = { id: :in, is: 'IN', permit: [] }
|
23
|
+
ISNIL = { id: :isnil, is: 'IS NULL' }
|
24
|
+
ISNNIL = { id: :isnnil, is: 'IS NOT NULL' }
|
25
|
+
end
|
26
|
+
|
27
|
+
REFLECT_OPERATORS = Operators.constants.inject({}) do |memo, const_name|
|
28
|
+
item = Operators.const_get(const_name)
|
29
|
+
memo[item[:id]] = item[:is]
|
30
|
+
memo
|
31
|
+
end
|
32
|
+
|
33
|
+
PERMIT_OPERATORS = Operators.constants.inject({}) do |memo, const_name|
|
34
|
+
item = Operators.const_get(const_name)
|
35
|
+
memo[item[:id]] = item[:permit]
|
36
|
+
memo
|
37
|
+
end
|
38
|
+
|
39
|
+
# Comparsion operator conditions method
|
40
|
+
# Array +params+ contains hash = {f, o, v}
|
41
|
+
# :f is column name
|
42
|
+
# :o is comparsion operator
|
43
|
+
# :v is value
|
44
|
+
def compconds(params = [])
|
45
|
+
criterias = self
|
46
|
+
|
47
|
+
params.each do |param|
|
48
|
+
if param[:o] == COMPARISON_OPERATORS[:eq]
|
49
|
+
criterias = criterias.where(param[:f] => param[:v])
|
50
|
+
else
|
51
|
+
criterias = criterias.where("\"#{self.table_name}\".\"#{param[:f]}\" #{param[:o]} ?", param[:v])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
return criterias.where({})
|
56
|
+
end
|
57
|
+
|
58
|
+
# Search by params of attributes of model
|
59
|
+
def _self_search only_params
|
60
|
+
criterias = self
|
61
|
+
|
62
|
+
only_params.each do |filter|
|
63
|
+
case filter[:o]
|
64
|
+
when Operators::EQ[:id], Operators::IN[:id]
|
65
|
+
criterias = criterias.where(filter[:f] => filter[:v])
|
66
|
+
when Operators::ISNIL[:id], Operators::ISNNIL[:id]
|
67
|
+
criterias = criterias.where("\"#{self.table_name}\".\"#{filter[:f]}\" #{REFLECT_OPERATORS[filter[:o]]}")
|
68
|
+
else
|
69
|
+
criterias = criterias.where("\"#{self.table_name}\".\"#{filter[:f]}\" #{REFLECT_OPERATORS[filter[:o]]} ?", filter[:v])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
return criterias.where({})
|
74
|
+
end
|
75
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pureapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dieu Pham
|
@@ -36,6 +36,7 @@ files:
|
|
36
36
|
- lib/pureapi/controller.rb
|
37
37
|
- lib/pureapi/model.rb
|
38
38
|
- lib/pureapi/mongoid_model.rb
|
39
|
+
- lib/pureapi/postgres_model.rb
|
39
40
|
homepage: http://rubygems.org/gems/pureapi
|
40
41
|
licenses:
|
41
42
|
- MIT
|