insights-api-common 5.0.0 → 5.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/lib/insights/api/common/application_controller_mixins/request_path.rb +6 -2
- data/lib/insights/api/common/error_document.rb +2 -1
- data/lib/insights/api/common/filter.rb +26 -2
- data/lib/insights/api/common/graphql/generator.rb +33 -1
- data/lib/insights/api/common/graphql/templates/aggregate_model_type.erb +8 -0
- data/lib/insights/api/common/graphql/templates/aggregate_type.erb +14 -0
- data/lib/insights/api/common/graphql/templates/model_type.erb +13 -0
- data/lib/insights/api/common/graphql/templates/query_type.erb +21 -11
- data/lib/insights/api/common/metrics.rb +1 -1
- data/lib/insights/api/common/version.rb +1 -1
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8a770535b65f1da98fa3196078052c5048bd13dcd4253145aa04afa5d6c1bf9
|
4
|
+
data.tar.gz: 13f54d55fe5343eaec0116095014e3782232e836e8e1d610a1e1120ea59b68b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d329437271a364dc4d03b31b484400c2ab496b91a17f2e39c80fd57c249a992b7e6764b69724677120fe1de219c315472835809df5001a348fd264bb66a8961c
|
7
|
+
data.tar.gz: 93510825434809fde1d60e46b73a8f80f61535d41d77f8ebe2df716e26212d1903a0f9d9911f328bf4e6607c6aaa5a64aea46617ad39a763819f6325cab851d7
|
data/README.md
CHANGED
@@ -30,6 +30,7 @@ Or install it yourself as:
|
|
30
30
|
| Supported Comparators | Comparator |
|
31
31
|
| --------------------- | ---------- |
|
32
32
|
| Integer | eq |
|
33
|
+
| | not_eq |
|
33
34
|
| | gt |
|
34
35
|
| | gte |
|
35
36
|
| | lt |
|
@@ -37,12 +38,14 @@ Or install it yourself as:
|
|
37
38
|
| | nil |
|
38
39
|
| | not_nil |
|
39
40
|
| String | eq |
|
41
|
+
| | not_eq |
|
40
42
|
| | contains |
|
41
43
|
| | starts_with |
|
42
44
|
| | ends_with |
|
43
45
|
| | nil |
|
44
46
|
| | not_nil |
|
45
47
|
| String (case insensitive) | eq_i |
|
48
|
+
| | not_eq_i |
|
46
49
|
| | contains_i |
|
47
50
|
| | starts_with_i |
|
48
51
|
| | ends_with_i |
|
@@ -53,6 +56,7 @@ After implementing filtering in your application, this is the way to filter via
|
|
53
56
|
| --------------- | --------------------- | ----------------- |
|
54
57
|
| "?filter[name]=reviews" | { :filter => { :name => "reviews" } } | filter: { name: "reviews" } |
|
55
58
|
| "?filter[name][eq]=reviews" | { :filter => { :name => { :eq => "reviews" } } } | filter: { name: { eq: "reviews" } } |
|
59
|
+
| "?filter[name][not_eq]=reviews" | { :filter => { :name => { :not_eq => "reviews" } } } | filter: { name: { not_eq: "reviews" } } |
|
56
60
|
| "?filter[name][starts_with]=a" | { :filter => { :name => { :starts_with => "a" } } } | filter: { name: { starts_with: "a" } } |
|
57
61
|
| "?filter[name][ends_with]=manager" | { :filter => { :name => { :ends_with => "manager" } } } | filter: { name: { ends_with: "manager" } } |
|
58
62
|
| "?filter[name][contains]=openshift" | { :filter => { :name => { :contains => "openshift" } } } | filter: { name: { contains: "openshift" } } |
|
@@ -44,10 +44,14 @@ module Insights
|
|
44
44
|
private
|
45
45
|
|
46
46
|
def id_regexp(primary_collection_name)
|
47
|
-
@
|
47
|
+
@id_regexp_table ||= {}
|
48
|
+
|
49
|
+
if @id_regexp_table.empty? || @id_regexp_table[primary_collection_name].nil?
|
48
50
|
id_parameter = id_parameter_from_api_doc(primary_collection_name)
|
49
|
-
id_parameter ? id_parameter.fetch_path("schema", "pattern") : /^\d+$/
|
51
|
+
@id_regexp_table[primary_collection_name] = id_parameter ? id_parameter.fetch_path("schema", "pattern") : /^\d+$/
|
50
52
|
end
|
53
|
+
|
54
|
+
@id_regexp_table[primary_collection_name]
|
51
55
|
end
|
52
56
|
|
53
57
|
def id_parameter_from_api_doc(primary_collection_name)
|
@@ -4,7 +4,8 @@ module Insights
|
|
4
4
|
class ErrorDocument
|
5
5
|
def add(status = 400, message)
|
6
6
|
@status = status
|
7
|
-
|
7
|
+
safe_message = message.to_s.encode('UTF-8', :invalid => :replace, :undef => :replace)
|
8
|
+
errors << {"status" => status, "detail" => safe_message}
|
8
9
|
self
|
9
10
|
end
|
10
11
|
|
@@ -2,8 +2,8 @@ module Insights
|
|
2
2
|
module API
|
3
3
|
module Common
|
4
4
|
class Filter
|
5
|
-
INTEGER_COMPARISON_KEYWORDS = ["eq", "gt", "gte", "lt", "lte", "nil", "not_nil"].freeze
|
6
|
-
STRING_COMPARISON_KEYWORDS = ["contains", "contains_i", "eq", "eq_i", "starts_with", "starts_with_i", "ends_with", "ends_with_i", "nil", "not_nil"].freeze
|
5
|
+
INTEGER_COMPARISON_KEYWORDS = ["eq", "not_eq", "gt", "gte", "lt", "lte", "nil", "not_nil"].freeze
|
6
|
+
STRING_COMPARISON_KEYWORDS = ["contains", "contains_i", "eq", "not_eq", "eq_i", "not_eq_i", "starts_with", "starts_with_i", "ends_with", "ends_with_i", "nil", "not_nil"].freeze
|
7
7
|
ALL_COMPARISON_KEYWORDS = (INTEGER_COMPARISON_KEYWORDS + STRING_COMPARISON_KEYWORDS).uniq.freeze
|
8
8
|
|
9
9
|
attr_reader :apply, :arel_table, :api_doc_definition, :extra_filterable_attributes, :model
|
@@ -177,6 +177,20 @@ module Insights
|
|
177
177
|
end
|
178
178
|
end
|
179
179
|
|
180
|
+
def self.build_filtered_scope(scope, api_version, klass_name, filter)
|
181
|
+
return scope unless filter
|
182
|
+
|
183
|
+
openapi_doc = ::Insights::API::Common::OpenApi::Docs.instance[api_version]
|
184
|
+
openapi_schema_name, = ::Insights::API::Common::GraphQL::Generator.openapi_schema(openapi_doc, klass_name)
|
185
|
+
|
186
|
+
action_parameters = ActionController::Parameters.new(filter)
|
187
|
+
definitions = openapi_doc.definitions
|
188
|
+
|
189
|
+
association_attribute_properties = association_attribute_properties(definitions, action_parameters)
|
190
|
+
|
191
|
+
new(scope, action_parameters, definitions[openapi_schema_name], association_attribute_properties).apply
|
192
|
+
end
|
193
|
+
|
180
194
|
def timestamp(k, val)
|
181
195
|
if val.kind_of?(Hash)
|
182
196
|
val.each do |comparator, value|
|
@@ -242,6 +256,16 @@ module Insights
|
|
242
256
|
self.query = query.where(model_arel_attribute(key).eq_any(Array(value)))
|
243
257
|
end
|
244
258
|
|
259
|
+
def comparator_not_eq(key, value)
|
260
|
+
self.query = query.where.not(model_arel_attribute(key).eq_any(Array(value)))
|
261
|
+
end
|
262
|
+
|
263
|
+
def comparator_not_eq_i(key, value)
|
264
|
+
values = Array(value).map { |v| query.sanitize_sql_like(v.downcase) }
|
265
|
+
|
266
|
+
self.query = query.where.not(model_arel_table(key).grouping(arel_lower(key).matches_any(values)))
|
267
|
+
end
|
268
|
+
|
245
269
|
def comparator_eq_i(key, value)
|
246
270
|
values = Array(value).map { |v| query.sanitize_sql_like(v.downcase) }
|
247
271
|
|
@@ -20,8 +20,32 @@ module Insights
|
|
20
20
|
openapi_path.split("/")[1..-1]
|
21
21
|
end
|
22
22
|
|
23
|
+
def self.template_file_by(type, root_dir = __dir__)
|
24
|
+
Pathname.new(root_dir).join(File.expand_path("templates", root_dir), "#{type}.erb")
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.root_dir
|
28
|
+
Rails.root
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.app_name
|
32
|
+
Rails.application.class.parent.name.underscore
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.pluggable_template_file_by(type)
|
36
|
+
templates_relative_path = "lib/#{app_name}/api/graphql/templates"
|
37
|
+
template_path = File.expand_path(templates_relative_path, root_dir)
|
38
|
+
Pathname.new(root_dir).join(template_path, "#{type}.erb")
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.template_path_by(type)
|
42
|
+
template_path_pluggable = pluggable_template_file_by(type)
|
43
|
+
template_path_default = template_file_by(type)
|
44
|
+
template_path_pluggable.exist? ? template_path_pluggable : template_path_default
|
45
|
+
end
|
46
|
+
|
23
47
|
def self.template(type)
|
24
|
-
File.read(
|
48
|
+
File.read(template_path_by(type))
|
25
49
|
end
|
26
50
|
|
27
51
|
def self.graphql_type(property_name, property_format, property_type)
|
@@ -140,8 +164,16 @@ module Insights
|
|
140
164
|
|
141
165
|
graphql_model_type_template = ERB.new(template("model_type"), nil, '<>').result(binding)
|
142
166
|
graphql_namespace.module_eval(graphql_model_type_template)
|
167
|
+
|
168
|
+
unless graphql_namespace.const_defined?("#{klass_name}AggregateType", false)
|
169
|
+
graphql_aggregate_model_type_template = ERB.new(template("aggregate_model_type"), nil, '<>').result(binding)
|
170
|
+
graphql_namespace.module_eval(graphql_aggregate_model_type_template)
|
171
|
+
end
|
143
172
|
end
|
144
173
|
|
174
|
+
graphql_aggregate_type_template = ERB.new(template("aggregate_type"), nil, '<>').result(binding)
|
175
|
+
graphql_namespace.module_eval(graphql_aggregate_type_template)
|
176
|
+
|
145
177
|
graphql_query_type_template = ERB.new(template("query_type"), nil, '<>').result(binding)
|
146
178
|
graphql_namespace.module_eval(graphql_query_type_template)
|
147
179
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= klass_name %>AggregateType = ::GraphQL::ObjectType.define do
|
2
|
+
name "<%= klass_name %>AggregateType"
|
3
|
+
description "A <%= klass_name %>AggregateType to wrap metrics aggregation"
|
4
|
+
|
5
|
+
field :aggregate, AggregateType do
|
6
|
+
resolve ->(object, _args, _ctx) { object }
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
AggregateType = ::GraphQL::ObjectType.define do
|
2
|
+
name "AggregateType"
|
3
|
+
description "A AggregateType type for aggregation metrics"
|
4
|
+
|
5
|
+
field :total_count, !types.Int do
|
6
|
+
resolve ->(object, _args, _ctx) {
|
7
|
+
if object.kind_of?(QueryRelation) # from nested aggregation
|
8
|
+
object.count # count is array operation
|
9
|
+
else
|
10
|
+
object
|
11
|
+
end
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
@@ -30,6 +30,19 @@
|
|
30
30
|
::Insights::API::Common::GraphQL::AssociationLoader.new(<%= klass_name.constantize %>, "<%= associations %>", args, graphql_options).load(obj)
|
31
31
|
}
|
32
32
|
end
|
33
|
+
|
34
|
+
field :<%= associations %>_aggregate do
|
35
|
+
description "Aggregation of <%= associations %> associated with <%= klass_name %> model."
|
36
|
+
type <%= "#{association_class_name}AggregateType" %>
|
37
|
+
|
38
|
+
associations_name = "<%= associations %>"
|
39
|
+
preload :<%= associations %>
|
40
|
+
|
41
|
+
resolve lambda { |obj, args, _ctx|
|
42
|
+
::Insights::API::Common::GraphQL::AssociationLoader.new(<%= klass_name.constantize %>, "<%= associations %>", args, graphql_options).load(obj)
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
33
46
|
<% end %>
|
34
47
|
<% end %>
|
35
48
|
end
|
@@ -31,18 +31,9 @@ QueryType = ::GraphQL::ObjectType.define do
|
|
31
31
|
scope = model_class
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
openapi_doc = ::Insights::API::Common::OpenApi::Docs.instance["<%= api_version %>"]
|
36
|
-
openapi_schema_name, _schema = ::Insights::API::Common::GraphQL::Generator.openapi_schema(openapi_doc, klass_name)
|
37
|
-
association_attribute_properties =
|
38
|
-
Insights::API::Common::Filter.association_attribute_properties(openapi_doc.definitions, ActionController::Parameters.new(args[:filter]))
|
39
|
-
scope = ::Insights::API::Common::Filter.new(
|
40
|
-
scope,
|
41
|
-
ActionController::Parameters.new(args[:filter]),
|
42
|
-
openapi_doc.definitions[openapi_schema_name],
|
43
|
-
association_attribute_properties).apply
|
44
|
-
end
|
34
|
+
scope = ::Insights::API::Common::Filter.build_filtered_scope(scope, "<%= api_version %>", klass_name, args[:filter])
|
45
35
|
scope = ::Insights::API::Common::GraphQL.search_options(scope, args)
|
36
|
+
|
46
37
|
if <%= graphql_options[:use_pagination_v2] %> == true
|
47
38
|
::Insights::API::Common::PaginatedResponseV2.new(
|
48
39
|
base_query: scope, request: nil, limit: args[:limit], offset: args[:offset], sort_by: args[:sort_by]
|
@@ -54,5 +45,24 @@ QueryType = ::GraphQL::ObjectType.define do
|
|
54
45
|
end
|
55
46
|
}
|
56
47
|
end
|
48
|
+
|
49
|
+
field_aggregate = "#{collection}_aggregate"
|
50
|
+
field field_aggregate do
|
51
|
+
description "The #{collection} aggregation associated with this #{klass_name}"
|
52
|
+
klass_name_type = "::Insights::API::Common::GraphQL::Api::#{version_namespace}::#{klass_name}AggregateType".constantize
|
53
|
+
argument :filter, ::Insights::API::Common::GraphQL::Types::QueryFilter, "The Query Filter for querying the #{collection}"
|
54
|
+
|
55
|
+
type klass_name_type
|
56
|
+
|
57
|
+
resolve lambda { |_obj, args, _ctx|
|
58
|
+
if base_query.present?
|
59
|
+
scope = base_query.call(model_class, args, ctx)
|
60
|
+
else
|
61
|
+
scope = model_class
|
62
|
+
end
|
63
|
+
|
64
|
+
::Insights::API::Common::Filter.build_filtered_scope(scope, "<%= api_version %>", klass_name, args[:filter]).count
|
65
|
+
}
|
66
|
+
end
|
57
67
|
end
|
58
68
|
end
|
@@ -17,7 +17,7 @@ module Insights
|
|
17
17
|
|
18
18
|
private_class_method def self.ensure_exporter_server
|
19
19
|
require 'socket'
|
20
|
-
TCPSocket.open("
|
20
|
+
TCPSocket.open("127.0.0.1", metrics_port) {}
|
21
21
|
rescue Errno::ECONNREFUSED
|
22
22
|
require 'prometheus_exporter/server'
|
23
23
|
server = PrometheusExporter::Server::WebServer.new(port: metrics_port)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: insights-api-common
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0.
|
4
|
+
version: 5.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Insights Authors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acts_as_tenant
|
@@ -160,16 +160,16 @@ dependencies:
|
|
160
160
|
name: graphql
|
161
161
|
requirement: !ruby/object:Gem::Requirement
|
162
162
|
requirements:
|
163
|
-
- -
|
163
|
+
- - '='
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version:
|
165
|
+
version: 1.11.7
|
166
166
|
type: :runtime
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
|
-
- -
|
170
|
+
- - '='
|
171
171
|
- !ruby/object:Gem::Version
|
172
|
-
version:
|
172
|
+
version: 1.11.7
|
173
173
|
- !ruby/object:Gem::Dependency
|
174
174
|
name: graphql-batch
|
175
175
|
requirement: !ruby/object:Gem::Requirement
|
@@ -396,6 +396,8 @@ files:
|
|
396
396
|
- lib/insights/api/common/graphql/associated_records.rb
|
397
397
|
- lib/insights/api/common/graphql/association_loader.rb
|
398
398
|
- lib/insights/api/common/graphql/generator.rb
|
399
|
+
- lib/insights/api/common/graphql/templates/aggregate_model_type.erb
|
400
|
+
- lib/insights/api/common/graphql/templates/aggregate_type.erb
|
399
401
|
- lib/insights/api/common/graphql/templates/model_type.erb
|
400
402
|
- lib/insights/api/common/graphql/templates/query_type.erb
|
401
403
|
- lib/insights/api/common/graphql/templates/schema.erb
|
@@ -457,7 +459,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
457
459
|
- !ruby/object:Gem::Version
|
458
460
|
version: '0'
|
459
461
|
requirements: []
|
460
|
-
rubygems_version: 3.0.3
|
462
|
+
rubygems_version: 3.0.3.1
|
461
463
|
signing_key:
|
462
464
|
specification_version: 4
|
463
465
|
summary: Common Utilites for Insights microservices
|