sobjectmodel 0.1.2

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.
@@ -0,0 +1,60 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'cgi'
5
+
6
+ require_relative 'http'
7
+ require_relative 'query_result'
8
+ require_relative 'errors'
9
+
10
+ module SObjectModel
11
+ module Rest
12
+ class Client
13
+ attr_reader :instance_url, :access_token, :api_version
14
+
15
+ def initialize(instance_url:, access_token:, api_version:)
16
+ @instance_url = instance_url
17
+ @access_token = access_token
18
+ @api_version = api_version
19
+ @http = Http.new(instance_url, access_token)
20
+ end
21
+
22
+ def query(soql)
23
+ response = http.get "/services/data/v#{api_version}/query?q=#{CGI.escape(soql)}"
24
+ QueryResult.new(response)
25
+ end
26
+
27
+ def describe(object_type)
28
+ response = http.get "/services/data/v#{api_version}/sobjects/#{object_type.to_sym}/describe"
29
+ JSON.parse(response)
30
+ end
31
+
32
+ def find(object_type, id, fields: [])
33
+ query = fields.empty? ? '' : %|?fields=#{fields.map(&:to_s).join(',')}|
34
+ response = http.get "/services/data/v#{api_version}/sobjects/#{object_type}/#{id}#{query}"
35
+ JSON.parse(response)
36
+ end
37
+
38
+ def create(object_type, values)
39
+ response = http.post "/services/data/v#{api_version}/sobjects/#{object_type}/", values
40
+ JSON.parse(response)['id']
41
+ end
42
+
43
+ def update(object_type, id, values)
44
+ http.patch "/services/data/v#{api_version}/sobjects/#{object_type}/#{id}/", values
45
+ id
46
+ end
47
+
48
+ def delete(object_type, id)
49
+ http.delete "/services/data/v#{api_version}/sobjects/#{object_type}/#{id}/"
50
+ id
51
+ end
52
+
53
+ private
54
+
55
+ def http
56
+ @http
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,19 @@
1
+ module SObjectModel
2
+ module Rest
3
+ class RecordNotFoundError < StandardError
4
+ end
5
+
6
+ class RequestError < StandardError
7
+ attr_reader :error_code, :error_message
8
+ def initialize(code, msg)
9
+ @error_code = code
10
+ @error_message = msg
11
+ super(to_s)
12
+ end
13
+
14
+ def to_s
15
+ %|[#{@code}] #{@msg}|
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,61 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'json'
4
+
5
+ module SObjectModel
6
+ module Rest
7
+ class Http
8
+ attr_reader :instance_url, :access_token
9
+
10
+ def initialize(instance_url, access_token)
11
+ @instance_url = instance_url
12
+ @access_token = access_token
13
+ end
14
+
15
+ def get(path)
16
+ url = URI.parse(instance_url + path)
17
+ res = Net::HTTP.get(url, headers)
18
+
19
+ if res =~/errorCode/
20
+ err = JSON.parse(res).first
21
+ if err['errorCode'] == 'NOT_FOUND'
22
+ raise RecordNotFoundError.new
23
+ else
24
+ raise RequestError.new(err['errorCode'], err['message'])
25
+ end
26
+ end
27
+
28
+ res
29
+ end
30
+
31
+ def post(path, data)
32
+ response = post_request(path, data)
33
+ response.body
34
+ end
35
+
36
+ def patch(path, data)
37
+ response = post_request(path + '?_HttpMethod=PATCH', data)
38
+ response.code
39
+ end
40
+
41
+ def delete(path)
42
+ response = post_request(path + '?_HttpMethod=DELETE', '')
43
+ response.code
44
+ end
45
+
46
+ private
47
+
48
+ def headers
49
+ { 'Authorization' => ('Bearer %{token}' % {token: access_token}), 'Content-Type' => 'application/json' }
50
+ end
51
+
52
+ def post_request(path, data)
53
+ url = URI.parse(instance_url + path)
54
+ response = Net::HTTP.post(url, JSON.dump(data), headers)
55
+ raise RequestError.new(response.code, response.message) if response.is_a?(Net::HTTPClientError) || response.is_a?(Net::HTTPServerError)
56
+
57
+ response
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,66 @@
1
+ module SObjectModel
2
+ module Rest
3
+ class QueryResult
4
+ def initialize(api_response)
5
+ @response = JSON.parse(api_response)
6
+ end
7
+
8
+ def total_size
9
+ @total_size ||= response['totalSize']
10
+ end
11
+
12
+ def done?
13
+ @done ||= response['done']
14
+ end
15
+
16
+ alias completed? done?
17
+
18
+ def next_records_url
19
+ @next_records_url ||= response['nextRecordsUrl']
20
+ end
21
+
22
+ def to_records(model_class: nil)
23
+ records.each_with_object([]) do |h, a|
24
+ record = prepare_record(h)
25
+ a << (model_class ? model_class.new(**record) : record)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def response
32
+ @response
33
+ end
34
+
35
+ def records
36
+ @records ||= response['records']
37
+ end
38
+
39
+ def prepare_record(hash)
40
+ hash.delete 'attributes'
41
+
42
+ hash.keys.each do |k|
43
+ if parent?(hash[k])
44
+ hash[k] = prepare_record(hash[k])
45
+ elsif children?(hash[k])
46
+ hash[k] = hash[k]['records'].map{|h| prepare_record(h)}
47
+ end
48
+ end
49
+
50
+ hash
51
+ end
52
+
53
+ def children?(h)
54
+ return false unless h.instance_of?(Hash)
55
+
56
+ h.has_key? 'records'
57
+ end
58
+
59
+ def parent?(h)
60
+ return false unless h.instance_of?(Hash)
61
+
62
+ h.has_key?('records') == false
63
+ end
64
+ end
65
+ end
66
+ end