close 0.1.0 → 0.1.1

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: 9aa1bc5d8124785414823311b95736c9ddde2ca4c5f2746e6308443f313ace7a
4
- data.tar.gz: e3eac1f1c53b1da521845eb66bd3a8ec6cd342c608cf216b2cef62e7b0cea410
3
+ metadata.gz: 2854258a74b425cbfcde648007a00465eebb1c42b41ea3dcb5dd8b9af558839e
4
+ data.tar.gz: e1032fe4a32b4927b50d1aedf0bbfb6eb85b8af6e81f20a04fa77141f77f9ace
5
5
  SHA512:
6
- metadata.gz: 0a5b9a3e0ee10bced5cccad33bc838c8b156fad65c821f332f548a94d0a6eff47847a340b946b5e91b12c0503bc36c0af883347cca12aa95887ad4d62e3d3144
7
- data.tar.gz: 991f361451aedaf253e9d602f3f8975deb3495202fb2f294c058b32b4ba83ecd20a9d262e7ab2d23aff1ba0d64dea314cfe9c0c05c8773beac094dfdcc218e64
6
+ metadata.gz: 5506272793581e06aee3d9ca3f7302f512436978aaab7e9826dc8c68cedd2d91165a24dcff21ce549af48d05151e68b83930aea5e93679c7142ef7d37c788186
7
+ data.tar.gz: 815914f77867cbe2152eb143ffe4ace620b297ed0a0283512d324c55ae2520564138c26043ccb2e229cae735980801e61864de7664ceccf3d704f34dcad7ff8f
data/Gemfile CHANGED
@@ -12,3 +12,7 @@ gem "rspec", "~> 3.0"
12
12
  gem "rubocop", "~> 1.21"
13
13
 
14
14
  gem "faraday"
15
+
16
+ gem "webmock"
17
+
18
+ gem "sinatra"
data/Gemfile.lock CHANGED
@@ -8,17 +8,28 @@ PATH
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
+ addressable (2.8.1)
12
+ public_suffix (>= 2.0.2, < 6.0)
11
13
  ast (2.4.2)
14
+ crack (0.4.5)
15
+ rexml
12
16
  diff-lcs (1.5.0)
13
17
  faraday (2.6.0)
14
18
  faraday-net_http (>= 2.0, < 3.1)
15
19
  ruby2_keywords (>= 0.0.4)
16
20
  faraday-net_http (3.0.1)
21
+ hashdiff (1.0.1)
17
22
  json (2.6.2)
23
+ mustermann (3.0.0)
24
+ ruby2_keywords (~> 0.0.1)
18
25
  ostruct (0.5.5)
19
26
  parallel (1.22.1)
20
27
  parser (3.1.2.1)
21
28
  ast (~> 2.4.1)
29
+ public_suffix (5.0.0)
30
+ rack (2.2.4)
31
+ rack-protection (3.0.2)
32
+ rack
22
33
  rainbow (3.1.1)
23
34
  rake (13.0.6)
24
35
  regexp_parser (2.6.0)
@@ -50,7 +61,17 @@ GEM
50
61
  parser (>= 3.1.1.0)
51
62
  ruby-progressbar (1.11.0)
52
63
  ruby2_keywords (0.0.5)
64
+ sinatra (3.0.2)
65
+ mustermann (~> 3.0)
66
+ rack (~> 2.2, >= 2.2.4)
67
+ rack-protection (= 3.0.2)
68
+ tilt (~> 2.0)
69
+ tilt (2.0.11)
53
70
  unicode-display_width (2.3.0)
71
+ webmock (3.18.1)
72
+ addressable (>= 2.8.0)
73
+ crack (>= 0.3.2)
74
+ hashdiff (>= 0.4.0, < 2.0.0)
54
75
 
55
76
  PLATFORMS
56
77
  arm64-darwin-21
@@ -61,6 +82,8 @@ DEPENDENCIES
61
82
  rake (~> 13.0)
62
83
  rspec (~> 3.0)
63
84
  rubocop (~> 1.21)
85
+ sinatra
86
+ webmock
64
87
 
65
88
  BUNDLED WITH
66
89
  2.3.7
data/README.md CHANGED
@@ -70,6 +70,23 @@ lead.save
70
70
 
71
71
  ## Supported Resources
72
72
 
73
+ ### Advanced Filters
74
+ [Close API Docs](https://developer.close.com/resources/leads/)
75
+
76
+ Advanced Filters are a clever way to open up search to the API, with the caveat that they are very dense and appear to be written in search DSL (Elastic, Solr, etc).
77
+
78
+ I have tried to encapsulate the complexity of the DSL into a simple interface that is easy to use. This is mostly by defining queries before
79
+ they are run and then running them with parameters when they are needed.
80
+
81
+ An example of an advanced filter query:
82
+
83
+ ```ruby
84
+ # Run a prebuilt query
85
+ Close::AdvancedFilter.run('find_leads_by_email', {email: 'buster.bluth@gmail.com'})
86
+
87
+
88
+ ```
89
+
73
90
  ### Leads
74
91
  [Close API Docs](https://developer.close.com/resources/leads/)
75
92
 
data/close-0.1.0.gem ADDED
Binary file
@@ -0,0 +1,60 @@
1
+ {
2
+ "limit": null,
3
+ "query": {
4
+ "negate": false,
5
+ "queries": [
6
+ {
7
+ "negate": false,
8
+ "object_type": "lead",
9
+ "type": "object_type"
10
+ },
11
+ {
12
+ "negate": false,
13
+ "queries": [
14
+ {
15
+ "negate": false,
16
+ "related_object_type": "contact",
17
+ "related_query": {
18
+ "negate": false,
19
+ "queries": [
20
+ {
21
+ "negate": false,
22
+ "related_object_type": "contact_email",
23
+ "related_query": {
24
+ "negate": false,
25
+ "queries": [
26
+ {
27
+ "condition": {
28
+ "mode": "full_words",
29
+ "type": "text",
30
+ "value": "%EMAIL%"
31
+ },
32
+ "field": {
33
+ "field_name": "email",
34
+ "object_type": "contact_email",
35
+ "type": "regular_field"
36
+ },
37
+ "negate": false,
38
+ "type": "field_condition"
39
+ }
40
+ ],
41
+ "type": "and"
42
+ },
43
+ "this_object_type": "contact",
44
+ "type": "has_related"
45
+ }
46
+ ],
47
+ "type": "and"
48
+ },
49
+ "this_object_type": "lead",
50
+ "type": "has_related"
51
+ }
52
+ ],
53
+ "type": "and"
54
+ }
55
+ ],
56
+ "type": "and"
57
+ },
58
+ "results_limit": null,
59
+ "sort": []
60
+ }
data/lib/close/errors.rb CHANGED
@@ -3,4 +3,6 @@ module Close
3
3
  class InvalidRequestError < StandardError; end
4
4
  class AuthenticationError < StandardError; end
5
5
  class APIError < StandardError; end
6
+ class QueryNotFoundError < StandardError; end
7
+ class MissingParameterError < StandardError; end
6
8
  end
@@ -0,0 +1,99 @@
1
+ # This class attempts to abstract away the Advanced Filter API.
2
+ # It is very powerful and fast, but building the queries is very tedious.
3
+ # It allows to store preset queries as JSON for common queries that
4
+ # can be commited to the repo and validated. It also lets you
5
+ # define queries on the fly which can then be reused across the
6
+ # codebase without having to copy and paste the query all the time.
7
+ module Close
8
+ class Filter
9
+ extend APIOperations
10
+
11
+ @@queries = {}
12
+
13
+ # Executes a raw query against the Close API.
14
+ # @param [Hash] query The query to execute.
15
+ # @return [Array] An array of results.
16
+ def self.execute(query = {})
17
+ response = request(:post, 'api/v1/data/search/', query)
18
+ response['data']
19
+ end
20
+
21
+ # Executes a query by name.
22
+ # @param [String] name The name of the query to execute.
23
+ # @param [Hash] params The parameters to pass to the query.
24
+ # @return [Array] An array of results.
25
+ def self.run(name, params = {})
26
+ query_string = load_query_from_file(name)
27
+ expected_params = find_params(query_string)
28
+ preflight_params(params, expected_params)
29
+ parameterized_query = apply_params(query_string, params)
30
+ execute(parameterized_query)
31
+ end
32
+
33
+ # Loads a query from a file or from memory.
34
+ # @param [String] name The name of the query.
35
+ # @return [String] A stringified JSON query.
36
+ def self.load_query(name)
37
+ if @@queries[name.to_s]
38
+ @@queries[name.to_s]
39
+ else
40
+ load_query_from_file(name)
41
+ end
42
+ end
43
+
44
+ # This method is used to defined a query at run time.
45
+ # If a name collision occurs, the query will be overwritten.
46
+ # @param [String] name The name of the query.
47
+ # @param [Hash] query_body A hash with placeholders in keys.
48
+ # @return [Void]
49
+ def self.add_query(name, query_body)
50
+ @@queries[name.to_s] = query_body.to_json
51
+ end
52
+
53
+ # Applies the params to the query string.
54
+ # @param [String] query_string The stringified JSON query.
55
+ # @param [Hash] params The parameters to apply.
56
+ # @return [String] The stringified JSON query with the parameters applied.
57
+ def self.apply_params(query_string, params)
58
+ qs = query_string.dup
59
+ params.each do |key, value|
60
+ qs.gsub!(/%#{key.upcase}%/, value)
61
+ end
62
+ qs
63
+ end
64
+
65
+ # Check that all of the params are present in expected_params.
66
+ # @param [Hash] params The parameters to check.
67
+ # @param [Array] expected_params The expected parameters.
68
+ # @return [Void]
69
+ # @raise [Close::MissingParameterError] if a parameter is missing.
70
+ def self.preflight_params(params, expected_params)
71
+ expected_params.each do |param|
72
+ if !params.transform_keys(&:to_s).has_key?(param.to_s)
73
+ raise Close::MissingParameterError, "Missing parameter: #{param}"
74
+ end
75
+ end
76
+ end
77
+
78
+ # Loads a predefined query from a file.
79
+ # @param [String] name The name of the query.
80
+ # @return [String] A stringified JSON query.
81
+ # @raise [Close::QueryNotFoundError] if the file does not exist.
82
+ def self.load_query_from_file(name)
83
+ begin
84
+ file = File.read("lib/close/data/filters/#{name}.json")
85
+ rescue Errno::ENOENT
86
+ raise Close::QueryNotFoundError.new("Query #{name} not found.")
87
+ end
88
+ end
89
+
90
+ # Scans a string a returns the parameters it will expect
91
+ # when executed.
92
+ # @param [String] str The string to scan.
93
+ # @return [Array] An array of parameters.
94
+ def self.find_params(str)
95
+ str.scan(/%[A-Z]+(?:_[A-Z]+)*%/).map{ |x| x[1..-2].downcase }.uniq
96
+ end
97
+
98
+ end
99
+ end
data/lib/close/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Close
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/close.rb CHANGED
@@ -5,6 +5,7 @@ require "faraday"
5
5
  require_relative "close/close_object"
6
6
  require_relative "close/api_operations"
7
7
  require_relative "close/api_resource"
8
+ require_relative "close/filter"
8
9
  require_relative "close/resources"
9
10
  require_relative "close/errors"
10
11
  require_relative "close/version"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: close
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - JoyNerd LLC
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-18 00:00:00.000000000 Z
11
+ date: 2022-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ostruct
@@ -54,11 +54,14 @@ files:
54
54
  - LICENSE.txt
55
55
  - README.md
56
56
  - Rakefile
57
+ - close-0.1.0.gem
57
58
  - lib/close.rb
58
59
  - lib/close/api_operations.rb
59
60
  - lib/close/api_resource.rb
60
61
  - lib/close/close_object.rb
62
+ - lib/close/data/filters/find_lead_by_contact_email.json
61
63
  - lib/close/errors.rb
64
+ - lib/close/filter.rb
62
65
  - lib/close/resource/contact.rb
63
66
  - lib/close/resource/custom_activity_type.rb
64
67
  - lib/close/resource/lead.rb