Class: DirectoryDiff::Transformer::TempTable

Inherits:
Object
  • Object
show all
Defined in:
lib/directory_diff/transformer/temp_table.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(current_directory) ⇒ TempTable

Returns a new instance of TempTable.



14
15
16
17
# File 'lib/directory_diff/transformer/temp_table.rb', line 14

def initialize(current_directory)
  @current_directory = current_directory
  @operations = []
end

Instance Attribute Details

#current_directoryObject (readonly)

Returns the value of attribute current_directory.



8
9
10
# File 'lib/directory_diff/transformer/temp_table.rb', line 8

def current_directory
  @current_directory
end

#operationsObject (readonly)

Returns the value of attribute operations.



8
9
10
# File 'lib/directory_diff/transformer/temp_table.rb', line 8

def operations
  @operations
end

Instance Method Details

#into(new_directory, options = {}) ⇒ Object

Parameters:

  • new_directory

    a table containing only the new records to compare against, most likely a temp table.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/directory_diff/transformer/temp_table.rb', line 21

def into(new_directory, options = {})
  current_directory_temp_table do |temp_current_directory|
    new_directory_temp_table(new_directory) do |deduped_csv|
      # Get Arel tables for referencing fields, table names
      employees = temp_current_directory.table
      csv = deduped_csv.table

      # Reusable Arel predicates
      csv_employee_join = csv[:email].eq(employees[:email])
      attributes_unchanged = employees[:name].eq(csv[:name])
                              .and(
                                employees[:phone_number].eq(csv[:phone_number])
                                  .or(csv[:phone_number].eq(""))
                                  # ☝🏽 Comparing to an empty string because we cast
                                  # phone number to an empty string. The reason is
                                  # comparing NULL = NULL is always false in SQL
                              )
                              .and(
                                employees[:assistants].eq(csv[:assistants])
                                  .or(csv[:assistants].eq("{}"))
                              )

      # Creates joins between the temp table and the csv table and
      # vice versa
      # Cribbed from https://gist.github.com/mildmojo/3724189
      csv_to_employees = csv.join(employees, Arel::Nodes::OuterJoin)
                          .on(csv_employee_join)
                          .join_sources
      employees_to_csv = employees.join(csv, Arel::Nodes::OuterJoin)
                          .on(csv_employee_join)
                          .join_sources

      # Representation of the joined csv-employees, with csv on the left
      csv_records = deduped_csv.joins(csv_to_employees).order('row_number asc')
      # Representation of the joined employees-csv, with employees on the
      # left
      employee_records = temp_current_directory.joins(employees_to_csv)

      connection.execute(SQL.cleanup_sql(csv.name))

      csv_fields = %I[name email phone_number assistants extra].map { |c| csv[c] }
      emp_fields = %I[name email phone_number assistants].map { |c| employees[c] }

      # new records are records in the new directory that don't exist in
      # the current directory
      new_records = csv_records
                      .select("'insert'::varchar operation, row_number")
                      .select(csv_fields)
                      .where({ employees.name => { email: nil } })
      # deleted records are records in the current directory that don't
      # exist in the new directory
      deleted_records = employee_records
                          .select("'delete'::varchar operation, row_number")
                          .select(emp_fields)
                          .select("null extra")
                          .where({ csv.name => { email: nil } })
      # changed records are records that have difference in name, phone
      # number and/or assistants
      changed_records = csv_records
                          .select("'update'::varchar operation, row_number")
                          .select(csv_fields)
                          .where.not(attributes_unchanged)
      # unchanged records are records that are exactly the same in both
      # directories (without considering the extra field)
      unchanged_records = csv_records
                            .select("'noop'::varchar operation, row_number")
                            .select(csv_fields)
                            .where(attributes_unchanged)

      # create temp table for holding operations
      temp_table(new_records.to_sql) do |operations|
        insert_into_operations(operations, deleted_records.to_sql)
        insert_into_operations(operations, changed_records.to_sql)
        if options[:skip_noop] != true
          insert_into_operations(operations, unchanged_records.to_sql)
        end

        operations.order(:row_number).each do |operation|
          add_operation(operation)
        end
      end
    end
  end

  prioritize_assistants(operations)
end