reso_transport 1.5.1 → 1.5.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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