Class: RailsSync::Analyzer

Inherits:
Object
  • Object
show all
Includes:
Table
Defined in:
lib/rails_sync/analyzer.rb

Instance Attribute Summary collapse

Attributes included from Table

#dest_table_name

Instance Method Summary collapse

Methods included from Table

#create_temp_table, #dest_columns, #dest_indexes, #dest_primary_key, #dest_sql_table, #drop_temp_table, #instance_table, #reset_temp_table, #same_server?

Constructor Details

#initialize(options = {}) ⇒ Analyzer

Returns a new instance of Analyzer.



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/rails_sync/analyzer.rb', line 5

def initialize(options = {})
  @adapter = RailsSync::Adapter.new(options[:dest])
  @dest = options[:dest]
  @record = options[:record]
  @server_id = options[:server_id]

  @synchro_type = @record.name
  @table_name = @record.table_name
  @dest_table = options[:dest_table]
  @primary_key = options[:primary_key]
  @dest_primary_key = options[:dest_primary_key]
  @dest_conditions = Hash(options[:dest_conditions])

  @full_mappings = options[:full_mappings]
  @my_columns = @primary_key + @full_mappings.map { |col| col[0] }
  @dest_columns = @dest_primary_key + @full_mappings.map { |col| col[1] }

  instance_table
  @my_arel_table ||= Arel::Table.new(@table_name)
  @dest_arel_table ||= Arel::Table.new(@dest_table_name, as: 't1')
end

Instance Attribute Details

#adapterObject (readonly)

Returns the value of attribute adapter.



3
4
5
# File 'lib/rails_sync/analyzer.rb', line 3

def adapter
  @adapter
end

#dest_arel_tableObject (readonly)

Returns the value of attribute dest_arel_table.



3
4
5
# File 'lib/rails_sync/analyzer.rb', line 3

def dest_arel_table
  @dest_arel_table
end

#my_arel_tableObject (readonly)

Returns the value of attribute my_arel_table.



3
4
5
# File 'lib/rails_sync/analyzer.rb', line 3

def my_arel_table
  @my_arel_table
end

#synchro_typeObject (readonly)

Returns the value of attribute synchro_type.



3
4
5
# File 'lib/rails_sync/analyzer.rb', line 3

def synchro_type
  @synchro_type
end

Instance Method Details

#analyze_conditionsObject



96
97
98
99
100
101
# File 'lib/rails_sync/analyzer.rb', line 96

def analyze_conditions
  mappings = @full_mappings.map do |mapping|
    my_arel_table[mapping[0]].not_eq(dest_arel_table[mapping[1]])
  end
  Arel::Nodes::SqlLiteral.new mappings.map(&:to_sql).join(' OR ')
end

#analyze_diffs(type = 'update') ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rails_sync/analyzer.rb', line 58

def analyze_diffs(type = 'update')
  return [] if skip_analyze?(type)
  sql = fetch_diffs(type)
  results = connection.execute(sql)
  fields = results.fields.in_groups(2).first
  results.map do |result|
    r = result.in_groups(2)
    hash_value = fields.zip( r[0].zip(r[1]) ).to_h
    hash_value.select do |key, v|
      v[0].to_s != v[1].to_s || @primary_key.include?(key)
    end
  end
end

#analyze_tableObject



90
91
92
93
94
# File 'lib/rails_sync/analyzer.rb', line 90

def analyze_table
  attrs = @my_columns.map { |col| my_arel_table[col] }
  attrs += @dest_columns.map { |col| dest_arel_table[col] }
  my_arel_table.project(*attrs)
end

#cache_diffs(type = 'update') ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rails_sync/analyzer.rb', line 36

def cache_diffs(type = 'update')
  analyze_diffs(type).each do |diff|
    audit = SyncAudit.new synchro_type: synchro_type

    _params = {}
    @primary_key.each do |primary_key|
      _params[primary_key] = diff.delete(primary_key).compact.first
    end

    audit.synchro_params = _params
    audit.synchro_id = _params['id']

    audit.operation = type
    audit.audited_changes = diff
    begin
      audit.save
    rescue ActiveRecord::ValueTooLong => e # todo not require active record
      puts e.message
    end
  end
end

#connectionObject



27
28
29
# File 'lib/rails_sync/analyzer.rb', line 27

def connection
  @record.connection
end

#fetch_diffs(type = 'update') ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/rails_sync/analyzer.rb', line 72

def fetch_diffs(type = 'update')
  if type == 'update'
    query = analyze_table.join(dest_arel_table).on(on_conditions)
    query.where(analyze_conditions)
  elsif type == 'insert'
    query = analyze_table.join(dest_arel_table, Arel::Nodes::RightOuterJoin).on(on_conditions)
    query.where(my_arel_table[@primary_key[0]].eq(nil))
  elsif type == 'delete'
    query = analyze_table.join(dest_arel_table, Arel::Nodes::OuterJoin).on(on_conditions)
    query.where(my_arel_table[@primary_key[0]].not_eq(nil).and(dest_arel_table[@dest_primary_key[0]].eq(nil)))
  else
    query = analyze_table.join(dest_arel_table, Arel::Nodes::FullOuterJoin).on(on_conditions)
  end

  query.where(where_conditions) if where_conditions.present?
  query.to_sql
end

#on_conditionsObject



103
104
105
106
107
108
# File 'lib/rails_sync/analyzer.rb', line 103

def on_conditions
  mappings = @primary_key.map.with_index do |left_key, index|
    my_arel_table[left_key].eq(dest_arel_table[@dest_primary_key[index]])
  end
  Arel::Nodes::SqlLiteral.new mappings.map(&:to_sql).join(' AND ')
end

#skip_analyze?(type) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
# File 'lib/rails_sync/analyzer.rb', line 31

def skip_analyze?(type)
  ( type == 'delete' && !@primary_key.include?(@record.primary_key) ) ||
    ( type == 'insert' && @record.id_insert? && !@primary_key.include?(@record.primary_key) )
end

#where_conditionsObject



110
111
112
113
114
115
116
117
# File 'lib/rails_sync/analyzer.rb', line 110

def where_conditions
  cons = @dest_conditions.map do |key, value|
    col, meth = key.to_s.split('-')
    dest_arel_table[col].send meth, value
  end

  Arel::Nodes::SqlLiteral.new cons.map(&:to_sql).join(' AND ')
end