Class: FmRest::Spyke::Relation

Inherits:
Spyke::Relation
  • Object
show all
Defined in:
lib/fmrest/spyke/relation.rb

Constant Summary collapse

SORT_PARAM_MATCHER =
/(.*?)(!|__desc(?:end)?)?\Z/.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*_args) ⇒ Relation

Returns a new instance of Relation.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/fmrest/spyke/relation.rb', line 17

def initialize(*_args)
  super

  @limit_value = klass.default_limit

  if klass.default_sort.present?
    @sort_params = Array.wrap(klass.default_sort).map { |s| normalize_sort_param(s) }
  end

  @query_params = []

  @included_portals = nil
  @portal_params = {}
  @script_params = {}
end

Instance Attribute Details

#included_portalsObject

Returns the value of attribute included_portals.



14
15
16
# File 'lib/fmrest/spyke/relation.rb', line 14

def included_portals
  @included_portals
end

#limit_valueObject

Returns the value of attribute limit_value.



14
15
16
# File 'lib/fmrest/spyke/relation.rb', line 14

def limit_value
  @limit_value
end

#offset_valueObject

Returns the value of attribute offset_value.



14
15
16
# File 'lib/fmrest/spyke/relation.rb', line 14

def offset_value
  @offset_value
end

#portal_paramsObject

Returns the value of attribute portal_params.



14
15
16
# File 'lib/fmrest/spyke/relation.rb', line 14

def portal_params
  @portal_params
end

#query_paramsObject

Returns the value of attribute query_params.



14
15
16
# File 'lib/fmrest/spyke/relation.rb', line 14

def query_params
  @query_params
end

#script_paramsObject

Returns the value of attribute script_params.



14
15
16
# File 'lib/fmrest/spyke/relation.rb', line 14

def script_params
  @script_params
end

#sort_paramsObject

Returns the value of attribute sort_params.



14
15
16
# File 'lib/fmrest/spyke/relation.rb', line 14

def sort_params
  @sort_params
end

Instance Method Details

#find_each(batch_size: 1000) ⇒ Enumerator

Looping through a collection of records from the database (using the

all method, for example) is very inefficient since it will fetch and

instantiate all the objects at once.

In that case, batch processing methods allow you to work with the records in batches, thereby greatly reducing memory consumption and be lighter on the Data API server.

The find_each method uses #find_in_batches with a batch size of 1000 (or as specified by the :batch_size option).

NOTE: By its nature, batch processing is subject to race conditions if other processes are modifying the database

Examples:

Person.find_each do |person|
  person.greet
end

Person.query(name: "==Mitch").find_each do |person|
  person.say_hi
end

Parameters:

  • batch_size (Integer) (defaults to: 1000)

    Specifies the size of the batch.

Returns:

  • (Enumerator)

    if called without a block.



255
256
257
258
259
260
261
262
263
264
265
# File 'lib/fmrest/spyke/relation.rb', line 255

def find_each(batch_size: 1000)
  unless block_given?
    return to_enum(:find_each, batch_size: batch_size) do
      limit(1).find_some..data_info.found_count
    end
  end

  find_in_batches(batch_size: batch_size) do |records|
    records.each { |r| yield r }
  end
end

#find_in_batches(batch_size: 1000) ⇒ Enumerator

Yields each batch of records that was found by the find options.

NOTE: By its nature, batch processing is subject to race conditions if other processes are modifying the database

Parameters:

  • batch_size (Integer) (defaults to: 1000)

    Specifies the size of the batch.

Returns:

  • (Enumerator)

    if called without a block.



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/fmrest/spyke/relation.rb', line 203

def find_in_batches(batch_size: 1000)
  unless block_given?
    return to_enum(:find_in_batches, batch_size: batch_size) do
      total = limit(1).find_some..data_info.found_count
      (total - 1).div(batch_size) + 1
    end
  end

  offset = 1 # DAPI offset is 1-based

  loop do
    relation = offset(offset).limit(batch_size)

    records = relation.find_some

    yield records if records.length > 0

    break if records.length < batch_size

    # Save one iteration if the total is a multiple of batch_size
    if found_count = records..data_info && records..data_info.found_count
      break if found_count == (offset - 1) + batch_size
    end

    offset += batch_size
  end
end

#find_oneFmRest::Spyke::Base Also known as: first, any

Finds a single instance of the model by forcing limit = 1, or simply fetching the record by id if the primary key was set

Returns:



183
184
185
186
187
188
189
190
191
192
# File 'lib/fmrest/spyke/relation.rb', line 183

def find_one
  @find_one ||=
    if primary_key_set?
      without_collection_params { super }
    else
      klass.new_collection_from_result(limit(1).fetch).first
    end
rescue ::Spyke::ConnectionError => error
  fallback_or_reraise(error, default: nil)
end

#has_query?Boolean

Returns whether a query was set on this relation.

Returns:

  • (Boolean)

    whether a query was set on this relation



175
176
177
# File 'lib/fmrest/spyke/relation.rb', line 175

def has_query?
  query_params.present?
end

#limit(value_or_hash) ⇒ FmRest::Spyke::Relation

Returns a new relation with the limits applied.

Examples:

Person.limit(10) # Set layout limit
Person.limit(children: 10) # Set portal limit

Parameters:

  • value_or_hash (Integer, Hash)

    the limit value for this layout, or a hash with limits for the layout's portals

Returns:



75
76
77
78
79
80
81
82
83
# File 'lib/fmrest/spyke/relation.rb', line 75

def limit(value_or_hash)
  with_clone do |r|
    if value_or_hash.respond_to?(:each)
      r.set_portal_params(value_or_hash, :limit)
    else
      r.limit_value = value_or_hash
    end
  end
end

#offset(value_or_hash) ⇒ FmRest::Spyke::Relation

Returns a new relation with the offsets applied.

Examples:

Person.offset(10) # Set layout offset
Person.offset(children: 10) # Set portal offset

Parameters:

  • value_or_hash (Integer, Hash)

    the offset value for this layout, or a hash with offsets for the layout's portals

Returns:



92
93
94
95
96
97
98
99
100
# File 'lib/fmrest/spyke/relation.rb', line 92

def offset(value_or_hash)
  with_clone do |r|
    if value_or_hash.respond_to?(:each)
      r.set_portal_params(value_or_hash, :offset)
    else
      r.offset_value = value_or_hash
    end
  end
end

#omit(params) ⇒ Object



170
171
172
# File 'lib/fmrest/spyke/relation.rb', line 170

def omit(params)
  query(params.merge(omit: true))
end

#portal(*args) ⇒ FmRest::Spyke::Relation Also known as: includes, portals

Sets the portals to include with each record in the response.

Examples:

Person.portal(:relatives, :pets)
Person.portal(false) # Disables portals
Person.portal(true) # Enables portals (includes all)

Parameters:

  • args (Array<Symbol, String>, true, false)

    the names of portals to include, or false to request no portals

Returns:

Raises:

  • (ArgumentError)


134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/fmrest/spyke/relation.rb', line 134

def portal(*args)
  raise ArgumentError, "Call `portal' with at least one argument" if args.empty?

  with_clone do |r|
    if args.length == 1 && args.first.eql?(true) || args.first.eql?(false)
      r.included_portals = args.first ? nil : []
    else
      r.included_portals ||= []
      r.included_portals += args.flatten.map { |p| normalize_portal_param(p) }
      r.included_portals.uniq!
    end
  end
end

#query(*params) ⇒ Object



164
165
166
167
168
# File 'lib/fmrest/spyke/relation.rb', line 164

def query(*params)
  with_clone do |r|
    r.query_params += params.flatten.map { |p| normalize_query_params(p) }
  end
end

#script(options) ⇒ FmRest::Spyke::Relation

Returns a new relation with the script options applied.

Examples:

# Find records and run the script named "My script"
Person.script("My script").find_some

# Find records and run the script named "My script" with param "the param"
Person.script(["My script", "the param"]).find_some

# Find records and run a prerequest, presort and after (normal) script
Person.script(after: "Script", prerequest: "Prereq script", presort: "Presort script").find_some

# Same as above, but passing parameters too
Person.script(
  after:      ["After script", "the param"],
  prerequest: ["Prereq script", "the param"],
  presort: o  ["Presort script", "the param"]
).find_some

Person.script(nil).find_some # Disable script execution
Person.script(false).find_some # Disable script execution

Parameters:

  • options (String, Array, Hash, nil, false)

    sets script params to execute in the next get or find request

Returns:



58
59
60
61
62
63
64
65
66
# File 'lib/fmrest/spyke/relation.rb', line 58

def script(options)
  with_clone do |r|
    if options.eql?(false) || options.eql?(nil)
      r.script_params = {}
    else
      r.script_params = script_params.merge(FmRest::V1.convert_script_params(options))
    end
  end
end

#sort(*args) ⇒ FmRest::Spyke::Relation Also known as: order

Allows sort params given in either hash format (using FM Data API's format), or as a symbol, in which case the of the attribute must match a known mapped attribute, optionally suffixed with ! or __desc to signify it should use descending order.

Examples:

Person.sort(:first_name, :age!)
Person.sort(:first_name, :age__desc)
Person.sort(:first_name, :age__descend)
Person.sort({ fieldName: "FirstName" }, { fieldName: "Age", sortOrder: "descend" })

Parameters:

  • args (Array<Symbol, Hash>)

    the names of attributes to sort by with optional ! or __desc suffix, or a hash of options as expected by the FM Data API

Returns:



117
118
119
120
121
# File 'lib/fmrest/spyke/relation.rb', line 117

def sort(*args)
  with_clone do |r|
    r.sort_params = args.flatten.map { |s| normalize_sort_param(s) }
  end
end

#with_all_portalsFmRest::Spyke::Relation

Same as calling portal(true)

Returns:



153
154
155
# File 'lib/fmrest/spyke/relation.rb', line 153

def with_all_portals
  portal(true)
end

#without_portalsFmRest::Spyke::Relation

Same as calling portal(false)

Returns:



160
161
162
# File 'lib/fmrest/spyke/relation.rb', line 160

def without_portals
  portal(false)
end