/lib/polo/translator.rb

https://github.com/IFTTT/polo · Ruby · 84 lines · 60 code · 18 blank · 6 comment · 9 complexity · fb71cd2547c2c20eed56d31f41c4079c MD5 · raw file

  1. require "polo/sql_translator"
  2. require "polo/configuration"
  3. module Polo
  4. class Translator
  5. # Public: Creates a new Polo::Collector
  6. #
  7. # selects - An array of SELECT queries
  8. #
  9. def initialize(selects, configuration=Configuration.new)
  10. @selects = selects
  11. @configuration = configuration
  12. end
  13. # Public: Translates SELECT queries into INSERTS.
  14. #
  15. def translate
  16. SqlTranslator.new(instances, @configuration).to_sql.uniq
  17. end
  18. def instances
  19. active_record_selects, raw_selects = @selects.partition{|s| s[:klass]}
  20. active_record_instances = active_record_selects.flat_map do |select|
  21. select[:klass].find_by_sql(select[:sql]).to_a
  22. end
  23. if fields = @configuration.blacklist
  24. obfuscate!(active_record_instances, fields)
  25. end
  26. raw_instance_values = raw_selects.flat_map do |select|
  27. table_name = select[:sql][/^SELECT .* FROM (?:"|`)([^"`]+)(?:"|`)/, 1]
  28. select[:connection].select_all(select[:sql]).map { |values| {table_name: table_name, values: values} }
  29. end
  30. active_record_instances + raw_instance_values
  31. end
  32. private
  33. def obfuscate!(instances, fields)
  34. instances.each do |instance|
  35. next if intersection(instance.attributes.keys, fields).empty?
  36. fields.each do |field, strategy|
  37. field = field.to_s
  38. if table = table_name(field)
  39. field = field_name(field)
  40. end
  41. correct_table = table.nil? || instance.class.table_name == table
  42. if correct_table && instance.attributes[field]
  43. instance.send("#{field}=", new_field_value(field, strategy, instance))
  44. end
  45. end
  46. end
  47. end
  48. def field_name(field)
  49. field.to_s.include?('.') ? field.split('.').last : field.to_s
  50. end
  51. def table_name(field)
  52. field.to_s.include?('.') ? field.split('.').first : nil
  53. end
  54. def intersection(attrs, fields)
  55. attrs & fields.map { |pair| field_name(pair.first) }
  56. end
  57. def new_field_value(field, strategy, instance)
  58. value = instance.attributes[field]
  59. if strategy.nil?
  60. value.split("").shuffle.join
  61. else
  62. strategy.arity == 1 ? strategy.call(value) : strategy.call(value, instance)
  63. end
  64. end
  65. end
  66. end