reso_transport 1.5.1 → 1.5.7

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.
@@ -1,36 +1,52 @@
1
1
  module ResoTransport
2
2
  class Client
3
- attr_reader :connection, :uid, :vendor, :endpoint, :auth, :md_file
4
-
3
+ attr_reader :connection, :uid, :vendor, :endpoint, :authentication, :md_file, :md_cache, :ds_file, :ds_cache,
4
+ :use_replication_endpoint
5
+
5
6
  def initialize(options)
6
- @endpoint = options.fetch(:endpoint)
7
- @md_file = options.fetch(:md_file, nil)
8
- @authentication = ensure_valid_auth_strategy(options.fetch(:authentication))
9
- @vendor = options.fetch(:vendor, {})
10
- @faraday_options = options.fetch(:faraday_options, {})
11
- @logger = options.fetch(:logger, nil)
12
-
13
- @connection = Faraday.new(@endpoint, @faraday_options) do |faraday|
7
+ @use_replication_endpoint = options.fetch(:use_replication_endpoint, false)
8
+ @endpoint = options.fetch(:endpoint)
9
+ @md_file = options.fetch(:md_file, nil)
10
+ @ds_file = options.fetch(:ds_file, nil)
11
+ @authentication = ensure_valid_auth_strategy(options.fetch(:authentication))
12
+ @vendor = options.fetch(:vendor, {})
13
+ @faraday_options = options.fetch(:faraday_options, {})
14
+ @logger = options.fetch(:logger, nil)
15
+ @md_cache = options.fetch(:md_cache, ResoTransport::MetadataCache)
16
+ @ds_cache = options.fetch(:ds_cache, ResoTransport::MetadataCache)
17
+ @connection = establish_connection
18
+ end
19
+
20
+ def establish_connection
21
+ Faraday.new(@endpoint, @faraday_options) do |faraday|
14
22
  faraday.request :url_encoded
15
- # faraday.response :logger, ResoTransport.configuration.logger if ResoTransport.configuration.logger
16
- # faraday.response :logger, @logger if @logger
17
- faraday.response :logger
18
- #yield faraday if block_given?
23
+ faraday.response :logger, @logger || ResoTransport.configuration.logger
19
24
  faraday.use Authentication::Middleware, @authentication
20
- faraday.adapter Faraday.default_adapter #unless faraday.builder.send(:adapter_set?)
25
+ faraday.adapter Faraday.default_adapter # unless faraday.builder.send(:adapter_set?)
21
26
  end
22
27
  end
23
28
 
24
29
  def resources
25
- @resources ||= metadata.entity_sets.map {|es| {es.name => Resource.new(self, es)} }.reduce(:merge!)
30
+ @resources ||= metadata.entity_sets.map { |es| { es.name => resource_for(es) } }.reduce(:merge!)
31
+ end
32
+
33
+ def resource_for(entity_set)
34
+ localizations = {}
35
+ localizations = datasystem.localizations_for(entity_set.entity_type) if metadata.datasystem?
36
+
37
+ Resource.new(self, entity_set, localizations)
26
38
  end
27
39
 
28
40
  def metadata
29
41
  @metadata ||= Metadata.new(self)
30
42
  end
31
43
 
44
+ def datasystem
45
+ @datasystem ||= Datasystem.new(self)
46
+ end
47
+
32
48
  def to_s
33
- %(#<ResoTransport::Client endpoint="#{endpoint}", md_file="#{md_file}">)
49
+ %(#<ResoTransport::Client endpoint="#{endpoint}", md_file="#{md_file}", ds_file="#{ds_file}">)
34
50
  end
35
51
 
36
52
  def inspect
@@ -42,7 +58,7 @@ module ResoTransport
42
58
  def ensure_valid_auth_strategy(options)
43
59
  case options
44
60
  when Hash
45
- if options.has_key?(:endpoint)
61
+ if options.key?(:endpoint)
46
62
  Authentication::FetchTokenAuth.new(options)
47
63
  else
48
64
  Authentication::StaticTokenAuth.new(options)
@@ -51,6 +67,5 @@ module ResoTransport
51
67
  raise ArgumentError, "#{options.inspect} invalid: cannot determine strategy"
52
68
  end
53
69
  end
54
-
55
70
  end
56
71
  end
@@ -0,0 +1,22 @@
1
+ require_relative 'base_metadata'
2
+
3
+ module ResoTransport
4
+ class Datasystem < BaseMetadata
5
+ def initialize(client)
6
+ super client
7
+ @prefix = 'ds'
8
+ @classname = self.class.name
9
+ end
10
+
11
+ def localizations_for(resource_name)
12
+ localizations = parser.resources.dig(resource_name, 'Localizations') || []
13
+ localizations.map { |l| [l['Name'], l] }.to_h
14
+ end
15
+
16
+ def response
17
+ @response ||= client.connection.get('DataSystem') do |req|
18
+ req.headers['Accept'] = 'application/json'
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ module ResoTransport
2
+ class DatasystemParser
3
+ def parse(doc)
4
+ begin
5
+ data = doc.is_a?(File) ? doc.read : doc
6
+ @json = JSON.parse data
7
+ rescue JSON::ParserError => e
8
+ @json = {}
9
+ puts e.message
10
+ end
11
+ self
12
+ end
13
+
14
+ # value ->
15
+ # Resources ->
16
+ # Name ->
17
+ # ResourcePath ->
18
+ # Localizations ->
19
+ # Name ->
20
+ # ResourcePath ->
21
+
22
+ def resources
23
+ @resources ||= @json['value'].map { |v| v['Resources'] }.flatten.compact.map { |r| [r['Name'], r] }.to_h
24
+ end
25
+ end
26
+ end
@@ -1,11 +1,9 @@
1
1
  module ResoTransport
2
2
  EntitySet = Struct.new(:name, :schema, :entity_type) do
3
-
4
3
  def self.from_stream(args)
5
- schema, entity_type = ResoTransport.split_schema_and_class_name(args["EntityType"])
4
+ schema, entity_type = ResoTransport.split_schema_and_class_name(args['EntityType'])
6
5
 
7
- new(args["Name"], schema, entity_type)
6
+ new(args['Name'], schema, entity_type)
8
7
  end
9
-
10
8
  end
11
9
  end
@@ -1,30 +1,29 @@
1
1
  module ResoTransport
2
2
  EntityType = Struct.new(:name, :base_type, :primary_key, :schema) do
3
-
4
3
  def self.from_stream(args)
5
- new(args["Name"], args["BaseType"])
4
+ new(args['Name'], args['BaseType'])
6
5
  end
7
6
 
8
7
  def parse(record)
9
- record.each_pair do |k,v|
8
+ record.each_pair do |k, v|
10
9
  next if v.nil?
11
- if property = (property_map[k] || navigation_property_map[k])
12
- record[k] = property.parse(v)
13
- end
10
+
11
+ property = property_map[k] || navigation_property_map[k]
12
+ record[k] = property.parse(v) if property
14
13
  end
15
14
  end
16
15
 
17
16
  def parse_value(record)
18
- record.each_pair do |k,v|
17
+ record.each_pair do |k, v|
19
18
  next if v.nil?
20
- if property = (property_map[k] || navigation_property_map[k])
21
- record[k] = property.parse(v)
22
- end
19
+
20
+ property = property_map[k] || navigation_property_map[k]
21
+ record[k] = property.parse(v) if property
23
22
  end
24
23
  end
25
24
 
26
25
  def property_map
27
- @property_map ||= properties.inject({}) {|hsh, p| hsh[p.name] = p; hsh }
26
+ @property_map ||= properties.each_with_object({}) { |p, hsh| hsh[p.name] = p; }
28
27
  end
29
28
 
30
29
  def properties
@@ -32,7 +31,7 @@ module ResoTransport
32
31
  end
33
32
 
34
33
  def navigation_property_map
35
- @navigation_property_map ||= navigation_properties.inject({}) {|hsh, p| hsh[p.name] = p; hsh }
34
+ @navigation_property_map ||= navigation_properties.each_with_object({}) { |p, hsh| hsh[p.name] = p; }
36
35
  end
37
36
 
38
37
  def navigation_properties
@@ -42,6 +41,5 @@ module ResoTransport
42
41
  def enumerations
43
42
  @enumerations ||= []
44
43
  end
45
-
46
44
  end
47
45
  end
@@ -1,10 +1,12 @@
1
- module ResoTransport
2
- Metadata = Struct.new(:client) do
1
+ require_relative 'base_metadata'
3
2
 
4
- MIME_TYPES = {
5
- xml: "application/xml",
6
- json: "application/json"
7
- }
3
+ module ResoTransport
4
+ class Metadata < BaseMetadata
5
+ def initialize(client)
6
+ super client
7
+ @prefix = 'md'
8
+ @classname = self.class.name
9
+ end
8
10
 
9
11
  def entity_sets
10
12
  parser.entity_sets
@@ -14,36 +16,14 @@ module ResoTransport
14
16
  parser.schemas
15
17
  end
16
18
 
17
- def parser
18
- @parser ||= MetadataParser.new.parse(get_data)
19
+ def datasystem?
20
+ parser.datasystem?
19
21
  end
20
22
 
21
- def get_data
22
- if client.md_file
23
- if File.exist?(client.md_file) && File.size(client.md_file) > 0
24
- File.new(client.md_file)
25
- else
26
- raw_md = raw
27
- File.open(client.md_file, "w") {|f| f.write(raw.force_encoding("UTF-8")) } unless raw_md.length == 0
28
- File.new(client.md_file)
29
- end
30
- else
31
- raw
32
- end
33
- end
34
-
35
- def raw
36
- resp = client.connection.get("$metadata") do |req|
23
+ def response
24
+ @response ||= client.connection.get('$metadata') do |req|
37
25
  req.headers['Accept'] = MIME_TYPES[client.vendor.fetch(:metadata_format, :xml).to_sym]
38
26
  end
39
-
40
- if resp.success?
41
- resp.body
42
- else
43
- puts resp.body
44
- raise "Error getting metadata!"
45
- end
46
27
  end
47
-
48
28
  end
49
29
  end
@@ -0,0 +1,20 @@
1
+ module ResoTransport
2
+ class MetadataCache
3
+ attr_reader :name
4
+
5
+ def initialize(name)
6
+ @name = name
7
+ end
8
+
9
+ def read
10
+ return nil if !File.exist?(name) || File.size(name).zero?
11
+
12
+ File.new(name)
13
+ end
14
+
15
+ def write(raw)
16
+ File.open(name, 'w') { |f| f.write(raw.force_encoding('UTF-8')) } if raw.length.positive?
17
+ File.new(name)
18
+ end
19
+ end
20
+ end
@@ -14,12 +14,14 @@ module ResoTransport
14
14
  @current_complex_type = nil
15
15
  @current_enum_type = nil
16
16
  @current_member = nil
17
+
18
+ @datasystem = nil
17
19
  end
18
20
 
19
21
  def parse(doc)
20
22
  REXML::Document.parse_stream(doc, self)
21
23
  finalize
22
- return self
24
+ self
23
25
  end
24
26
 
25
27
  def finalize
@@ -54,55 +56,62 @@ module ResoTransport
54
56
 
55
57
  def tag_start(name, args)
56
58
  case name
57
- when "Schema"
59
+ when 'Schema'
58
60
  @schemas << ResoTransport::Schema.from_stream(args)
59
- when "EntitySet"
61
+ when 'EntitySet'
60
62
  @entity_sets << ResoTransport::EntitySet.from_stream(args)
61
- when "EntityType"
63
+ when 'EntityType'
62
64
  @current_entity_type = ResoTransport::EntityType.from_stream(args)
63
- when "ComplexType"
65
+ when 'ComplexType'
64
66
  @current_complex_type = ResoTransport::EntityType.from_stream(args)
65
- when "PropertyRef"
67
+ when 'PropertyRef'
66
68
  @current_entity_type.primary_key = args['Name']
67
- when "Property"
68
- @current_entity_type.properties << ResoTransport::Property.from_stream(args.merge(schema: @schemas.last)) if @current_entity_type
69
- @current_complex_type.properties << ResoTransport::Property.from_stream(args.merge(schema: @schemas.last)) if @current_complex_type
70
- when "NavigationProperty"
69
+ when 'Property'
70
+ if @current_entity_type
71
+ @current_entity_type.properties << ResoTransport::Property.from_stream(args.merge(schema: @schemas.last))
72
+ end
73
+ if @current_complex_type
74
+ @current_complex_type.properties << ResoTransport::Property.from_stream(args.merge(schema: @schemas.last))
75
+ end
76
+ when 'NavigationProperty'
71
77
  @current_entity_type.navigation_properties << ResoTransport::Property.from_stream(args)
72
- when "EnumType"
78
+ when 'EnumType'
73
79
  @current_enum_type = ResoTransport::Enum.from_stream(args.merge(schema: @schemas.last))
74
- when "Member"
80
+ when 'Member'
75
81
  @current_member = ResoTransport::Member.from_stream(args)
76
- when "Annotation"
82
+ when 'Annotation'
77
83
  if @current_enum_type && @current_member
78
84
  @current_member.annotation = args['String']
79
- else
80
- if @current_entity_type || @current_complex_type
81
- #raise args.inspect
82
- end
85
+ elsif @current_entity_type || @current_complex_type
86
+ # raise args.inspect
83
87
  end
84
88
  end
85
- rescue => e
89
+ rescue StandardError => e
86
90
  puts e.inspect
87
91
  puts "Error processing Tag: #{[name, args].inspect}"
88
92
  end
89
93
 
90
94
  def tag_end(name)
91
95
  case name
92
- when "EntityType"
96
+ when 'EntityType'
93
97
  @current_entity_type.schema = @schemas.last.namespace
94
98
  @schemas.last.entity_types << @current_entity_type
95
- when "ComplexType"
99
+ when 'ComplexType'
96
100
  @current_complex_type.schema = @schemas.last.namespace
97
101
  @schemas.last.complex_types << @current_complex_type
98
- when "EnumType"
102
+ when 'EnumType'
99
103
  @enumerations << @current_enum_type
100
104
  @current_enum_type = nil
101
- when "Member"
105
+ when 'Member'
102
106
  @current_enum_type.members << @current_member
103
107
  @current_member = nil
104
108
  end
105
109
  end
106
110
 
111
+ def datasystem?
112
+ return @datasystem unless @datasystem.nil?
113
+
114
+ @datasystem = @schemas.any? { |s| s.entity_types.any? { |t| t.name == 'DataSystem' } }
115
+ end
107
116
  end
108
117
  end
@@ -1,23 +1,22 @@
1
1
  module ResoTransport
2
2
  Query = Struct.new(:resource) do
3
-
4
- def all(*contexts, &block)
3
+ def all(*_contexts, &block)
5
4
  new_query_context('and')
6
5
  instance_eval(&block)
7
6
  clear_query_context
8
- return self
7
+ self
9
8
  end
10
9
 
11
10
  def any(&block)
12
11
  new_query_context('or')
13
12
  instance_eval(&block)
14
13
  clear_query_context
15
- return self
14
+ self
16
15
  end
17
16
 
18
- [:eq, :ne, :gt, :ge, :lt, :le].each do |op|
17
+ %i[eq ne gt ge lt le].each do |op|
19
18
  define_method(op) do |conditions|
20
- conditions.each_pair do |k,v|
19
+ conditions.each_pair do |k, v|
21
20
  current_query_context << "#{k} #{op} #{encode_value(k, v)}"
22
21
  end
23
22
  return self
@@ -26,36 +25,36 @@ module ResoTransport
26
25
 
27
26
  def limit(size)
28
27
  options[:top] = size
29
- return self
28
+ self
30
29
  end
31
30
 
32
31
  def offset(size)
33
32
  options[:skip] = size
34
- return self
33
+ self
35
34
  end
36
35
 
37
- def order(field, dir=nil)
38
- options[:orderby] = [field, dir].join(" ").strip
39
- return self
36
+ def order(field, dir = nil)
37
+ options[:orderby] = [field, dir].join(' ').strip
38
+ self
40
39
  end
41
40
 
42
41
  def include_count
43
42
  options[:count] = true
44
- return self
43
+ self
45
44
  end
46
45
 
47
46
  def select(*fields)
48
- os = options.fetch(:select, "").split(",")
49
- options[:select] = (os + Array(fields)).uniq.join(",")
47
+ os = options.fetch(:select, '').split(',')
48
+ options[:select] = (os + Array(fields)).uniq.join(',')
50
49
 
51
- return self
50
+ self
52
51
  end
53
52
 
54
53
  def expand(*names)
55
- ex = options.fetch(:expand, "").split(",")
56
- options[:expand] = (ex + Array(names)).uniq.join(",")
54
+ ex = options.fetch(:expand, '').split(',')
55
+ options[:expand] = (ex + Array(names)).uniq.join(',')
57
56
 
58
- return self
57
+ self
59
58
  end
60
59
 
61
60
  def count
@@ -63,7 +62,7 @@ module ResoTransport
63
62
  limit(1).include_count
64
63
  resp = resource.get(compile_params)
65
64
  parsed_body = JSON.parse(resp.body)
66
- parsed_body.fetch("@odata.count", 0)
65
+ parsed_body.fetch('@odata.count', 0)
67
66
  end
68
67
 
69
68
  def results
@@ -73,20 +72,27 @@ module ResoTransport
73
72
  resp[:results]
74
73
  else
75
74
  puts resp[:meta]
76
- raise "Request Failed"
75
+ raise 'Request Failed'
77
76
  end
78
77
  end
79
78
 
80
79
  def execute
81
80
  resp = resource.get(compile_params)
82
- parsed_body = JSON.parse(resp.body)
83
- results = Array(parsed_body.delete("value"))
84
-
85
- {
86
- success: resp.success? && !parsed_body.has_key?("error"),
87
- meta: parsed_body,
88
- results: resource.parse(results)
89
- }
81
+ if resp.success?
82
+ parsed_body = JSON.parse(resp.body)
83
+ results = Array(parsed_body.delete('value'))
84
+
85
+ {
86
+ success: resp.success? && !parsed_body.key?('error'),
87
+ meta: parsed_body,
88
+ results: resource.parse(results)
89
+ }
90
+ else
91
+ {
92
+ success: false,
93
+ meta: resp.body
94
+ }
95
+ end
90
96
  end
91
97
 
92
98
  def new_query_context(context)
@@ -110,7 +116,7 @@ module ResoTransport
110
116
  end
111
117
 
112
118
  def sub_queries
113
- @sub_queries ||= Hash.new {|h,k| h[k] = { context: 'and', criteria: [] } }
119
+ @sub_queries ||= Hash.new { |h, k| h[k] = { context: 'and', criteria: [] } }
114
120
  end
115
121
 
116
122
  def compile_filters
@@ -120,36 +126,32 @@ module ResoTransport
120
126
 
121
127
  filter_chunks = []
122
128
 
123
- if global && global[:criteria]&.any?
124
- filter_chunks << global[:criteria].join(" #{global[:context]} ")
125
- end
129
+ filter_chunks << global[:criteria].join(" #{global[:context]} ") if global && global[:criteria]&.any?
126
130
 
127
131
  filter_chunks << filter_groups.map do |g|
128
132
  "(#{g[:criteria].join(" #{g[:context]} ")})"
129
- end.join(" and ")
133
+ end.join(' and ')
130
134
 
131
- filter_chunks.reject {|c| c == ""}.join(" and ")
135
+ filter_chunks.reject { |c| c == '' }.join(' and ')
132
136
  end
133
137
 
134
138
  def compile_params
135
139
  params = {}
136
140
 
137
- options.each_pair do |k,v|
141
+ options.each_pair do |k, v|
138
142
  params["$#{k}"] = v
139
143
  end
140
144
 
141
- if !sub_queries.empty?
142
- params["$filter"] = compile_filters
143
- end
145
+ params['$filter'] = compile_filters unless sub_queries.empty?
144
146
 
145
147
  params
146
148
  end
147
149
 
148
- def encode_value(key, v)
150
+ def encode_value(key, val)
149
151
  field = resource.property(key.to_s)
150
152
  raise "Couldn't find property #{key} for #{resource.name}" if field.nil?
151
- field.encode(v)
152
- end
153
153
 
154
+ field.encode(val)
155
+ end
154
156
  end
155
157
  end