class LaunchDarkly::Impl::FeatureStoreDataSetSorter

Implements a dependency graph ordering for data to be stored in a feature store. We must use this on every data set that will be passed to the feature store's init() method.

Public Class Methods

add_with_dependencies_first(item, dependency_fn, remaining_items, items_out) click to toggle source
# File lib/ldclient-rb/impl/store_data_set_sorter.rb, line 44
def self.add_with_dependencies_first(item, dependency_fn, remaining_items, items_out)
  item_key = item[:key].to_sym
  remaining_items.delete(item_key)  # we won't need to visit this item again
  dependency_fn.call(item).each do |dep_key|
    dep_item = remaining_items[dep_key.to_sym]
    self.add_with_dependencies_first(dep_item, dependency_fn, remaining_items, items_out) if !dep_item.nil?
  end
  items_out[item_key] = item
end
sort_all_collections(all_data) click to toggle source

Returns a copy of the input hash that has the following guarantees: the iteration order of the outer hash will be in ascending order by the VersionDataKind's :priority property (if any), and for each data kind that has a :get_dependency_keys function, the inner hash will have an iteration order where B is before A if A has a dependency on B.

This implementation relies on the fact that hashes in Ruby have an iteration order that is the same as the insertion order. Also, due to the way we deserialize JSON received from LaunchDarkly, the keys in the inner hash will always be symbols.

# File lib/ldclient-rb/impl/store_data_set_sorter.rb, line 19
def self.sort_all_collections(all_data)
  outer_hash = {}
  kinds = all_data.keys.sort_by { |k|
    k[:priority].nil? ? k[:namespace].length : k[:priority]  # arbitrary order if priority is unknown
  }
  kinds.each do |kind|
    items = all_data[kind]
    outer_hash[kind] = self.sort_collection(kind, items)
  end
  outer_hash
end
sort_collection(kind, input) click to toggle source
# File lib/ldclient-rb/impl/store_data_set_sorter.rb, line 31
def self.sort_collection(kind, input)
  dependency_fn = kind[:get_dependency_keys]
  return input if dependency_fn.nil? || input.empty?
  remaining_items = input.clone
  items_out = {}
  while !remaining_items.empty?
    # pick a random item that hasn't been updated yet
    key, item = remaining_items.first
    self.add_with_dependencies_first(item, dependency_fn, remaining_items, items_out)
  end
  items_out
end