eloqua 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/.yardopts +2 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +81 -0
- data/LICENSE +21 -0
- data/README.md +245 -0
- data/Rakefile +13 -0
- data/TODO.md +8 -0
- data/eloqua.gemspec +32 -0
- data/eloqua_initializer.tpl.rb +3 -0
- data/lib/eloqua.rb +51 -0
- data/lib/eloqua/api.rb +119 -0
- data/lib/eloqua/api/action.rb +41 -0
- data/lib/eloqua/api/service.rb +240 -0
- data/lib/eloqua/asset.rb +31 -0
- data/lib/eloqua/builder/templates.rb +31 -0
- data/lib/eloqua/builder/xml.rb +129 -0
- data/lib/eloqua/entity.rb +72 -0
- data/lib/eloqua/exceptions.rb +5 -0
- data/lib/eloqua/helper/attribute_map.rb +78 -0
- data/lib/eloqua/query.rb +291 -0
- data/lib/eloqua/remote_object.rb +274 -0
- data/lib/eloqua/version.rb +3 -0
- data/lib/eloqua/wsdl/action.wsdl +1 -0
- data/lib/eloqua/wsdl/data.wsdl +1 -0
- data/lib/eloqua/wsdl/email.wsdl +1 -0
- data/lib/eloqua/wsdl/service.wsdl +1 -0
- data/lib/tasks/test.rake +24 -0
- data/rspec.watchr +74 -0
- data/spec/fixtures/add_group_member/success.xml +18 -0
- data/spec/fixtures/create/contact_duplicate.xml +30 -0
- data/spec/fixtures/create/contact_success.xml +25 -0
- data/spec/fixtures/create_asset/failure.xml +30 -0
- data/spec/fixtures/create_asset/group_success.xml +25 -0
- data/spec/fixtures/delete_asset/access_deny.xml +31 -0
- data/spec/fixtures/describe_asset/success.xml +72 -0
- data/spec/fixtures/describe_asset_type/success.xml +23 -0
- data/spec/fixtures/describe_entity/success.xml +54 -0
- data/spec/fixtures/describe_entity_type/success.xml +45 -0
- data/spec/fixtures/get_member_count_in_step_by_status/success.xml +15 -0
- data/spec/fixtures/list_asset_types/success.xml +28 -0
- data/spec/fixtures/list_entity_types/success.xml +21 -0
- data/spec/fixtures/list_group_membership/success.xml +25 -0
- data/spec/fixtures/list_members_in_step_by_status/success.xml +15 -0
- data/spec/fixtures/query/contact_email_one.xml +38 -0
- data/spec/fixtures/query/contact_email_two.xml +56 -0
- data/spec/fixtures/query/contact_missing.xml +19 -0
- data/spec/fixtures/query/fault.xml +43 -0
- data/spec/fixtures/remove_group_member/success.xml +18 -0
- data/spec/fixtures/retrieve/contact_missing.xml +17 -0
- data/spec/fixtures/retrieve/contact_multiple.xml +3460 -0
- data/spec/fixtures/retrieve/contact_single.xml +38 -0
- data/spec/fixtures/retrieve_asset/failure.xml +17 -0
- data/spec/fixtures/retrieve_asset/success.xml +50 -0
- data/spec/fixtures/update/contact_success.xml +26 -0
- data/spec/lib/eloqua/api/action_spec.rb +36 -0
- data/spec/lib/eloqua/api/service_spec.rb +498 -0
- data/spec/lib/eloqua/api_spec.rb +133 -0
- data/spec/lib/eloqua/asset_spec.rb +63 -0
- data/spec/lib/eloqua/builder/templates_spec.rb +68 -0
- data/spec/lib/eloqua/builder/xml_spec.rb +254 -0
- data/spec/lib/eloqua/entity_spec.rb +224 -0
- data/spec/lib/eloqua/helper/attribute_map_spec.rb +14 -0
- data/spec/lib/eloqua/query_spec.rb +596 -0
- data/spec/lib/eloqua/remote_object_spec.rb +742 -0
- data/spec/lib/eloqua_spec.rb +171 -0
- data/spec/shared/attribute_map.rb +173 -0
- data/spec/shared/class_to_api_delegation.rb +50 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/support/helper.rb +73 -0
- metadata +366 -0
data/lib/eloqua/asset.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'eloqua/remote_object'
|
2
|
+
|
3
|
+
module Eloqua
|
4
|
+
|
5
|
+
class Asset < RemoteObject
|
6
|
+
|
7
|
+
self.remote_group = :asset
|
8
|
+
|
9
|
+
def add_member(entity)
|
10
|
+
member_operation(:add_group_member, entity)
|
11
|
+
end
|
12
|
+
|
13
|
+
def remove_member(entity)
|
14
|
+
member_operation(:remove_group_member, entity)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def member_operation(method, entity)
|
20
|
+
unless (entity.is_a?(Eloqua::Entity))
|
21
|
+
raise(ArgumentError, "Must pass a Eloqua::Entity")
|
22
|
+
end
|
23
|
+
unless (entity.persisted?)
|
24
|
+
raise(ArgumentError, "Cannot add member Entity has not been saved. (!entity.persisted?")
|
25
|
+
end
|
26
|
+
api.send(method, remote_type, id, entity.remote_type, entity.id)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Eloqua
|
2
|
+
module Builder
|
3
|
+
|
4
|
+
module Templates
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :builder_templates
|
10
|
+
self.builder_templates = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
def builder_template(name, *args)
|
16
|
+
template = builder_templates[name]
|
17
|
+
Proc.new do |xml|
|
18
|
+
template.call(xml, *args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def define_builder_template(name, &block)
|
23
|
+
builder_templates[name] = block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'eloqua/builder/templates'
|
2
|
+
|
3
|
+
module Eloqua
|
4
|
+
|
5
|
+
module Builder
|
6
|
+
|
7
|
+
# This could (and likely should) be submitted as a patch for
|
8
|
+
# the main builder class
|
9
|
+
class Xml < ::Builder::XmlMarkup
|
10
|
+
|
11
|
+
include Eloqua::Builder::Templates
|
12
|
+
|
13
|
+
# XML Templates
|
14
|
+
|
15
|
+
# For use with strings and integers may do strange
|
16
|
+
# things on the SOAP server side if given a float
|
17
|
+
define_builder_template :array do |xml, array|
|
18
|
+
array.each do |element|
|
19
|
+
tag = 'string'
|
20
|
+
if(element.is_a?(String))
|
21
|
+
tag = 'string'
|
22
|
+
elsif(element.is_a?(Numeric))
|
23
|
+
tag = 'int'
|
24
|
+
end
|
25
|
+
xml.arr(tag.to_sym, element)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
define_builder_template :int_array do |xml, array|
|
30
|
+
array.each do |element|
|
31
|
+
unless(element.is_a?(Numeric))
|
32
|
+
element = element.to_i
|
33
|
+
if(element == 0 || !element)
|
34
|
+
next
|
35
|
+
end
|
36
|
+
end
|
37
|
+
xml.arr(:int, element)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# For use with add/remove membership
|
42
|
+
define_builder_template :object do |xml, object_type, type, id|
|
43
|
+
xml.tag!(object_type) do
|
44
|
+
xml.object_type!(object_type) do
|
45
|
+
xml.template!(:object_type, type)
|
46
|
+
end
|
47
|
+
xml.Id(id)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# For use with the entity function
|
52
|
+
define_builder_template :object_type do |xml, object|
|
53
|
+
xml.ID(object[:id])
|
54
|
+
xml.Name(object[:name])
|
55
|
+
xml.Type(object[:type])
|
56
|
+
end
|
57
|
+
|
58
|
+
# defines entity attribute fields for use in update/create
|
59
|
+
define_builder_template :fields do |xml, object_type, entity_attributes|
|
60
|
+
entity_attributes.each do |attribute, value|
|
61
|
+
xml.tag!("#{object_type.to_s.camelize}Fields") do
|
62
|
+
xml.InternalName(attribute.to_s)
|
63
|
+
xml.Value(value)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Dynamic entity for update/create/etc...
|
69
|
+
|
70
|
+
define_builder_template :dynamic do |xml, object_type, type, id, attributes|
|
71
|
+
xml.tag!("#{object_type.to_s.camelize}Type") do
|
72
|
+
xml.template!(:object_type, type)
|
73
|
+
end
|
74
|
+
|
75
|
+
xml.FieldValueCollection do
|
76
|
+
xml.template!(:fields, object_type, attributes)
|
77
|
+
end
|
78
|
+
|
79
|
+
xml.Id(id) if id
|
80
|
+
end
|
81
|
+
|
82
|
+
delegate :builder_template, :to => self
|
83
|
+
|
84
|
+
|
85
|
+
def initialize(options = {}, &block)
|
86
|
+
super
|
87
|
+
@namespace = nil
|
88
|
+
@namespace = options[:namespace].to_sym if options[:namespace]
|
89
|
+
yield self if block_given?
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.create(options = {}, &block)
|
93
|
+
new(options, &block).target!
|
94
|
+
end
|
95
|
+
|
96
|
+
def template!(template, *args)
|
97
|
+
builder_template(template, *args).call(self)
|
98
|
+
end
|
99
|
+
|
100
|
+
def dynamic_object!(sym, *args, &block)
|
101
|
+
tag!("Dynamic#{sym.to_s.camelize}", *args, &block)
|
102
|
+
end
|
103
|
+
|
104
|
+
def object_type!(sym, *args, &block)
|
105
|
+
tag!("#{sym.to_s.camelize}Type", *args, &block)
|
106
|
+
end
|
107
|
+
|
108
|
+
def object_type_lower!(sym, *args, &block)
|
109
|
+
tag!("#{sym}Type", *args, &block)
|
110
|
+
end
|
111
|
+
|
112
|
+
def object_collection!(sym, *args, &block)
|
113
|
+
tag!("#{sym.to_s.pluralize.downcase}", *args, &block)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Extend to allow default namespace
|
117
|
+
def method_missing(sym, *args, &block)
|
118
|
+
if(@namespace && !args.first.kind_of?(Symbol))
|
119
|
+
args.unshift(sym.to_sym)
|
120
|
+
sym = @namespace
|
121
|
+
end
|
122
|
+
super(sym, *args, &block)
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'eloqua/remote_object'
|
2
|
+
|
3
|
+
module Eloqua
|
4
|
+
|
5
|
+
class Entity < RemoteObject
|
6
|
+
|
7
|
+
self.remote_group = :entity
|
8
|
+
|
9
|
+
# Returns an :id indexed list of memberships for contact
|
10
|
+
#
|
11
|
+
# # Example output
|
12
|
+
# {'1' => {:id => '1', :name => 'Contact Group Name', :type => 'ContactGroup}}
|
13
|
+
#
|
14
|
+
# @return [Hash] Integer => Hash
|
15
|
+
def list_memberships
|
16
|
+
self.class.list_memberships(id)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_membership(asset)
|
20
|
+
asset.add_member(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def remove_membership(asset)
|
24
|
+
asset.remove_member(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
|
29
|
+
# Returns an :id indexed list of memberships for given contact id
|
30
|
+
#
|
31
|
+
# # Example output
|
32
|
+
# {'1' => {:id => '1', :name => 'Contact Group Name', :type => 'ContactGroup}}
|
33
|
+
#
|
34
|
+
# @param [String, Integer] contact id
|
35
|
+
# @return [Hash] Integer => Hash
|
36
|
+
def list_memberships(id)
|
37
|
+
memberships = api.list_memberships(remote_type, id)
|
38
|
+
|
39
|
+
if(memberships && !memberships.empty?)
|
40
|
+
memberships.inject({}) do |map, membership|
|
41
|
+
map[membership[:id]] = membership
|
42
|
+
map
|
43
|
+
end
|
44
|
+
else
|
45
|
+
memberships || {}
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def where(conditions = nil, fields = [], limit = 200, page = 1)
|
51
|
+
if(conditions)
|
52
|
+
query = where
|
53
|
+
conditions.each do |key, value|
|
54
|
+
query.on(key, '=', value)
|
55
|
+
end
|
56
|
+
query.fields(fields) if fields
|
57
|
+
query.limit(limit)
|
58
|
+
query.page(page)
|
59
|
+
results = query.all
|
60
|
+
if(results.blank?)
|
61
|
+
false
|
62
|
+
else
|
63
|
+
results
|
64
|
+
end
|
65
|
+
else
|
66
|
+
Eloqua::Query.new(self)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Eloqua
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
module AttributeMap
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :attribute_map, :attribute_map_reverse
|
10
|
+
|
11
|
+
attr_reader :instance_reverse_keys
|
12
|
+
|
13
|
+
self.attribute_map = {}.with_indifferent_access
|
14
|
+
self.attribute_map_reverse = {}.with_indifferent_access
|
15
|
+
|
16
|
+
class << self
|
17
|
+
alias_method_chain :inherited, :clone_attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
|
24
|
+
def inherited_with_clone_attributes(klass)
|
25
|
+
klass.attribute_map = attribute_map.clone
|
26
|
+
klass.attribute_map_reverse = attribute_map_reverse.clone
|
27
|
+
inherited_without_clone_attributes(klass) if method_defined?(:inherited_without_clone_attributes)
|
28
|
+
end
|
29
|
+
|
30
|
+
def eloqua_attribute(attribute)
|
31
|
+
(attribute_map_reverse.fetch(attribute) { attribute }).to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def map_attribute(attribute)
|
35
|
+
attribute_map.fetch(attribute) { attribute.to_s }
|
36
|
+
end
|
37
|
+
|
38
|
+
# This shoud always be used over directly editing attribute_map
|
39
|
+
def map(hash)
|
40
|
+
hash.each do |key, value|
|
41
|
+
value = value.to_sym
|
42
|
+
key = key.to_sym
|
43
|
+
|
44
|
+
attribute_map[key] = value
|
45
|
+
attribute_map_reverse[value] = key
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
module InstanceMethods
|
52
|
+
|
53
|
+
def map_attributes(attributes)
|
54
|
+
@instance_reverse_keys ||= attribute_map_reverse.clone
|
55
|
+
results = {}.with_indifferent_access
|
56
|
+
|
57
|
+
attributes.each do |key, value|
|
58
|
+
formatted_key = attribute_map.fetch(key) { key.to_s.gsub(/^C_/, '').underscore }
|
59
|
+
@instance_reverse_keys[formatted_key] = key
|
60
|
+
results[formatted_key] = value
|
61
|
+
end
|
62
|
+
results
|
63
|
+
end
|
64
|
+
|
65
|
+
def reverse_map_attributes(attributes)
|
66
|
+
results = {}.with_indifferent_access
|
67
|
+
attributes.each do |key, value|
|
68
|
+
results[@instance_reverse_keys.fetch(key){key}] = value
|
69
|
+
end
|
70
|
+
results
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
data/lib/eloqua/query.rb
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
require 'eloqua/api/service'
|
2
|
+
require 'eloqua/remote_object'
|
3
|
+
|
4
|
+
module Eloqua
|
5
|
+
class Query
|
6
|
+
|
7
|
+
delegate :api, :to => :remote_object
|
8
|
+
|
9
|
+
attr_reader :collection, :remote_object, :conditions, :total_pages
|
10
|
+
attr_internal :current_page, :query_started
|
11
|
+
|
12
|
+
|
13
|
+
# The amount of time in seconds to wait before sending another request to Eloqua
|
14
|
+
@@request_delay = 1
|
15
|
+
cattr_accessor :request_delay
|
16
|
+
|
17
|
+
# Create a new query to attach conditions to.
|
18
|
+
#
|
19
|
+
# class Contact < Eloqua::Entity
|
20
|
+
# remote_type = api.remote_type('Contact')
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# Eloqua::Query.new(Contact)
|
24
|
+
#
|
25
|
+
# @param [Eloqua::RemoteObject] or one of its descendants
|
26
|
+
def initialize(remote_object)
|
27
|
+
unless(remote_object.is_a?(Class) && Eloqua::RemoteObject >= remote_object)
|
28
|
+
raise(ArgumentError, 'must provide an Eloqua::RemoteObject or one of its descendants')
|
29
|
+
end
|
30
|
+
|
31
|
+
@page = 1
|
32
|
+
@limit = 200
|
33
|
+
@collection = []
|
34
|
+
@remote_object = remote_object
|
35
|
+
@conditions = []
|
36
|
+
@fields = nil
|
37
|
+
@has_requested = false
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
## CHAIN-ABLES they reset the has_requested? but do not clear the collection
|
42
|
+
|
43
|
+
# Sets or gets limit
|
44
|
+
#
|
45
|
+
# query.limit(5) # sets limit returns self
|
46
|
+
# query.limit # returns 5
|
47
|
+
#
|
48
|
+
# @param [Integer]
|
49
|
+
# @return [self, Integer]
|
50
|
+
def limit(value = nil); end
|
51
|
+
|
52
|
+
# Sets or gets page
|
53
|
+
#
|
54
|
+
# query.page(5) # sets limit returns self
|
55
|
+
# query.page # returns 5
|
56
|
+
#
|
57
|
+
# @param [Integer]
|
58
|
+
# @return [self, Integer]
|
59
|
+
#
|
60
|
+
def page(value = nil); end
|
61
|
+
|
62
|
+
# Sets or gets the array of fields to find.
|
63
|
+
# Can use a literal string or a symbol of a {Eloqua::RemoteObject#map mapped} attribute
|
64
|
+
#
|
65
|
+
# query.fields([:email, 'Date'])
|
66
|
+
# query.fields # returns [:email, 'Date']
|
67
|
+
#
|
68
|
+
# @see Eloqua::RemoteObject::map
|
69
|
+
# @param [Array]
|
70
|
+
# @return [self, Array]
|
71
|
+
def fields(value = nil); end
|
72
|
+
|
73
|
+
|
74
|
+
# This mess defines the limit and page getter/setter methods
|
75
|
+
# when they are set they will also set #has_requested? to false
|
76
|
+
[:fields, :limit, :page].each do |attr|
|
77
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
78
|
+
remove_method(:#{attr})
|
79
|
+
def #{attr}(value = nil)
|
80
|
+
if(value.nil?)
|
81
|
+
@#{attr}
|
82
|
+
else
|
83
|
+
@has_requested = false
|
84
|
+
@#{attr} = value
|
85
|
+
self
|
86
|
+
end
|
87
|
+
end
|
88
|
+
RUBY
|
89
|
+
end
|
90
|
+
|
91
|
+
# Clears all conditions added by {on}
|
92
|
+
#
|
93
|
+
# query.on(:id, '>', '1')
|
94
|
+
# query.clear_conditions!
|
95
|
+
#
|
96
|
+
def clear_conditions!
|
97
|
+
@has_requested = false
|
98
|
+
conditions.clear
|
99
|
+
end
|
100
|
+
|
101
|
+
# Adds a condition to the query; may be chained.
|
102
|
+
#
|
103
|
+
# query.on(:email, '=', 'value').on('created_at', '>', '2011-04-20')
|
104
|
+
#
|
105
|
+
# @param [String, Symbol] field name
|
106
|
+
# @param [String] operator can use: `[ =, !=, <, >, >=, <=]`
|
107
|
+
# @param [String] value to search for
|
108
|
+
# @return self
|
109
|
+
def on(field, operator, value)
|
110
|
+
@has_requested = false
|
111
|
+
@conditions << {
|
112
|
+
:field => field,
|
113
|
+
:type => operator,
|
114
|
+
:value => value
|
115
|
+
}
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
# Send the built request to eloqua
|
121
|
+
#
|
122
|
+
# query.on(:email, '=', '*') # wildcard
|
123
|
+
# query.request!
|
124
|
+
# query.collection # Array of results
|
125
|
+
# query.current_page # Current page
|
126
|
+
# query.total_pages # Number of pages
|
127
|
+
#
|
128
|
+
# @return self
|
129
|
+
def request!
|
130
|
+
return if has_requested?
|
131
|
+
sleep_for = wait_for_request_delay
|
132
|
+
if(sleep_for)
|
133
|
+
sleep(sleep_for)
|
134
|
+
end
|
135
|
+
xml_query = api.builder do |xml|
|
136
|
+
xml.eloquaType do
|
137
|
+
xml.template!(:object_type, remote_object.remote_type)
|
138
|
+
end
|
139
|
+
xml.searchQuery(build_query)
|
140
|
+
|
141
|
+
# This won't harm anything but it is changing the
|
142
|
+
# fields to its mapped elouqa name.
|
143
|
+
if(!fields.blank? && fields.is_a?(Array))
|
144
|
+
fields.map! do |field|
|
145
|
+
field = remote_object.eloqua_attribute(field)
|
146
|
+
end
|
147
|
+
xml.fieldNames do
|
148
|
+
xml.template!(:array, fields)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
xml.pageNumber(page)
|
153
|
+
xml.pageSize(limit)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Add timestamp of when we made request
|
157
|
+
@_query_started = Time.now
|
158
|
+
result = api.request(:query, xml_query)
|
159
|
+
|
160
|
+
# Clear collection
|
161
|
+
collection.clear
|
162
|
+
|
163
|
+
# Mark as requested
|
164
|
+
@has_requested = true
|
165
|
+
|
166
|
+
|
167
|
+
if(result[:entities])
|
168
|
+
@total_pages = result[:total_pages].to_i
|
169
|
+
entities = Eloqua.format_results_for_array(result, :entities, :dynamic_entity)
|
170
|
+
records = entities.inject([]) do |records, entity|
|
171
|
+
record_attrs = {}
|
172
|
+
entity_id = entity[:id]
|
173
|
+
entity[:field_value_collection][:entity_fields].each do |entity_attr|
|
174
|
+
record_attrs[entity_attr[:internal_name]] = entity_attr[:value]
|
175
|
+
end
|
176
|
+
record_attrs[remote_object.primary_key] = entity_id
|
177
|
+
record_object = remote_object.new(record_attrs, :remote)
|
178
|
+
|
179
|
+
collection << record_object
|
180
|
+
end
|
181
|
+
collection
|
182
|
+
else
|
183
|
+
@total_pages = 0
|
184
|
+
false
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def wait_for_request_delay
|
189
|
+
if(request_delay && query_started)
|
190
|
+
now = Time.now
|
191
|
+
wait_until = Time.at((request_delay + query_started.to_f))
|
192
|
+
if(wait_until > now)
|
193
|
+
wait_until - now
|
194
|
+
end
|
195
|
+
else
|
196
|
+
false
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
# Has the request been made yet?
|
202
|
+
#
|
203
|
+
# query.has_requested? # false
|
204
|
+
# query.on(:email, '=', '*').request!
|
205
|
+
# query.has_requested? # true
|
206
|
+
#
|
207
|
+
# @return [Boolean]
|
208
|
+
def has_requested?
|
209
|
+
@has_requested
|
210
|
+
end
|
211
|
+
|
212
|
+
# Sends request if not already set and iterates through result
|
213
|
+
#
|
214
|
+
# query.each do |record|
|
215
|
+
# record.class # query.remote_object
|
216
|
+
# end
|
217
|
+
#
|
218
|
+
# Currently this is a shortcut for
|
219
|
+
#
|
220
|
+
# query.all.each do |record|
|
221
|
+
# ...
|
222
|
+
# end
|
223
|
+
#
|
224
|
+
# @param [Proc] a block iterator
|
225
|
+
def each(&block)
|
226
|
+
all.each(&block)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Sends request and returns collection
|
230
|
+
#
|
231
|
+
# query.on(:email, '=', '*').all # => [Eloqua::RemoteObject.new(), ...]
|
232
|
+
#
|
233
|
+
# @return [Array] collection of Eloqua::RemoteObject
|
234
|
+
def all
|
235
|
+
request!
|
236
|
+
collection
|
237
|
+
end
|
238
|
+
|
239
|
+
# Iterates through each page up to max_pages
|
240
|
+
# when max_pages is nil (default) will iterate through
|
241
|
+
# each page yielding a block with a record.
|
242
|
+
#
|
243
|
+
# with max_pages you could and then resume the loop through
|
244
|
+
# pages
|
245
|
+
#
|
246
|
+
# query.each_page(2) |record|
|
247
|
+
# query.total_pages # 10
|
248
|
+
# query.page # 1 ... 2
|
249
|
+
# end
|
250
|
+
#
|
251
|
+
# ...
|
252
|
+
#
|
253
|
+
# query.each_page(2) |record|
|
254
|
+
# query.total_pages # 10
|
255
|
+
# query.page # 3 ... 4
|
256
|
+
# end
|
257
|
+
#
|
258
|
+
# @see Query#each
|
259
|
+
# @param [Integer] max pages to iterate through
|
260
|
+
def each_page(max_pages = nil, &block)
|
261
|
+
each(&block)
|
262
|
+
while(total_pages > page)
|
263
|
+
break if max_pages && page >= max_pages
|
264
|
+
page(page + 1)
|
265
|
+
each(&block)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
protected
|
270
|
+
|
271
|
+
# Builds query from conditions
|
272
|
+
# conditions are assembled by their field, type and then value as below
|
273
|
+
#
|
274
|
+
# #{field}#{type}'#{value}'
|
275
|
+
#
|
276
|
+
# then joined by AND which acts more like an SQL "OR" in Eloqua
|
277
|
+
# > and < are escaped with > and <
|
278
|
+
def build_query
|
279
|
+
conditions.inject([]) do |parts, cond|
|
280
|
+
part = ""
|
281
|
+
part << remote_object.eloqua_attribute(cond[:field])
|
282
|
+
part << cond[:type].to_s
|
283
|
+
part << "'#{cond[:value]}'"
|
284
|
+
parts << part
|
285
|
+
end.join(" AND ")
|
286
|
+
end
|
287
|
+
|
288
|
+
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|