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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d9fb8764a0f41c1080473eddd2d98dee2df8170f88da25fa2b033470957cf4f
4
- data.tar.gz: eb025888657a1ad4c68054aba85aa099ae4455e0ec028d1208ca7468f1a7a04d
3
+ metadata.gz: b8a770535b65f1da98fa3196078052c5048bd13dcd4253145aa04afa5d6c1bf9
4
+ data.tar.gz: 13f54d55fe5343eaec0116095014e3782232e836e8e1d610a1e1120ea59b68b8
5
5
  SHA512:
6
- metadata.gz: 9faab22d7dc2bd6f140fbf0db52c1f546101fff8c08039d3acef806495a5381baa5969e63eb345b769869fe321534cbc0fe26601eff88ce327aec22a6cf1a3ea
7
- data.tar.gz: 928591637a490109a8a3d38841c4b5b79e13205f565a9f14d145270257952885f40cc4cf84574bc70fdb2bc2b4338f17cc55274636261e5de630b7ae558c7e01
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
- @id_regexp ||= begin
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
- errors << {"status" => status, "detail" => message}
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(Pathname.new(__dir__).join(File.expand_path("templates", __dir__), "#{type}.erb").to_s)
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
- if args[:filter]
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("localhost", metrics_port) {}
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)
@@ -1,7 +1,7 @@
1
1
  module Insights
2
2
  module API
3
3
  module Common
4
- VERSION = "5.0.0".freeze
4
+ VERSION = "5.0.5".freeze
5
5
  end
6
6
  end
7
7
  end
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.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-01-14 00:00:00.000000000 Z
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: '1.9'
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: '1.9'
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