Module: DutyFree::Extensions::ClassMethods

Defined in:
lib/duty_free/extensions.rb

Overview

:nodoc:

Instance Method Summary collapse

Instance Method Details

#df_export(is_with_data = true, import_template = nil, use_inner_joins = false) ⇒ Object

Export at least column header, and optionally include all existing data as well



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
107
108
109
110
111
112
113
# File 'lib/duty_free/extensions.rb', line 22

def df_export(is_with_data = true, import_template = nil, use_inner_joins = false)
  use_inner_joins = true unless respond_to?(:left_joins)
  # In case they are only supplying the columns hash
  if is_with_data.is_a?(Hash) && !import_template
    import_template = is_with_data
    is_with_data = true
  end
  import_template ||= if constants.include?(:IMPORT_TEMPLATE)
                        self::IMPORT_TEMPLATE
                      else
                        suggest_template(0, false, false)
                      end

  # Friendly column names that end up in the first row of the CSV
  # Required columns get prefixed with a *
  requireds = (import_template[:required] || [])
  rows = ::DutyFree::Extensions._template_columns(self, import_template).map do |col|
    is_required = requireds.include?(col)
    col = col.to_s.titleize
    # Alias-ify the full column names
    aliases = (import_template[:as] || [])
    aliases.each do |k, v|
      if col.start_with?(v)
        col = k + col[v.length..-1]
        break
      end
    end
    (is_required ? '* ' : '') + col
  end
  rows = [rows]

  if is_with_data
    order_by = []
    order_by << ['_', primary_key] if primary_key
    all = import_template[:all] || import_template[:all!]
    # Automatically create a JOINs strategy and select list to get back all related rows
    template_cols, template_joins = ::DutyFree::Extensions._recurse_def(self, all, import_template, nil, order_by)
    # We do this so early here because it removes type objects from template_joins so then
    # template_joins can immediately be used for inner and outer JOINs.
    our_names = [[self, '_']] + ::DutyFree::Util._recurse_arel(template_joins)
    relation = use_inner_joins ? joins(template_joins) : left_joins(template_joins)

    # So we can properly create the SELECT list, create a mapping between our
    # column alias prefixes and the aliases AREL creates.
    # %%% If with Rails 3.1 and older you get "NoMethodError: undefined method `eq' for nil:NilClass"
    # when trying to call relation.arel, then somewhere along the line while navigating a has_many
    # relationship it can't find the proper foreign key.
    core = relation.arel.ast.cores.first
    # Accommodate AR < 3.2
    arel_alias_names = if core.froms.is_a?(Arel::Table)
                         # All recent versions of AR have #source which brings up an Arel::Nodes::JoinSource
                         ::DutyFree::Util._recurse_arel(core.source)
                       else
                         # With AR < 3.2, "froms" brings up the top node, an Arel::Nodes::InnerJoin
                         ::DutyFree::Util._recurse_arel(core.froms)
                       end
    # Make sure our_names lines up with the arel_alias_name by comparing the ActiveRecord type.
    # AR < 5.0 behaves differently than newer versions, and AR 5.0 and 5.1 have a bug in the
    # way the types get determined, so if we want perfect results then we must compensate for
    # these foibles.  Thank goodness that AR 5.2 and later find the proper type and make it
    # available through the type_caster object, which is what we use when building the list of
    # arel_alias_names.
    mapping = arel_alias_names.each_with_object({}) do |arel_alias_name, s|
      if our_names.first&.first == arel_alias_name.first
        s[our_names.first.last] = arel_alias_name.last
        our_names.shift
      end
      s
    end
    relation = (order_by.empty? ? relation : relation.order(order_by.map { |o| "#{mapping[o.first]}.#{o.last}" }))
    # puts mapping.inspect
    # puts relation.dup.select(template_cols.map { |x| x.to_s(mapping) }).to_sql

    # Allow customisation of query before running it
    relation = yield(relation, mapping) if block_given?

    relation&.select(template_cols.map { |x| x.to_s(mapping) })&.each do |result|
      rows << ::DutyFree::Extensions._template_columns(self, import_template).map do |col|
        value = result.send(col)
        case value
        when true
          'Yes'
        when false
          'No'
        else
          value.to_s
        end
      end
    end
  end
  rows
end

#df_import(data, import_template = nil, insert_only = false) ⇒ Object



115
116
117
# File 'lib/duty_free/extensions.rb', line 115

def df_import(data, import_template = nil, insert_only = false)
  ::DutyFree::Extensions.import(self, data, import_template, insert_only)
end