File: duplicate_columns_handler.rb

package info (click to toggle)
ruby-sequel 5.63.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 10,408 kB
  • sloc: ruby: 113,747; makefile: 3
file content (94 lines) | stat: -rw-r--r-- 3,371 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
# frozen-string-literal: true
#
# The duplicate_columns_handler extension allows you to customize handling of
# duplicate column names in your queries on a per-database or per-dataset level.
#
# For example, you may want to raise an exception if you join 2 tables together
# which contains a column that will override another columns.
#
# To use the extension, you need to load the extension into the database:
#
#   DB.extension :duplicate_columns_handler
#
# or into individual datasets:
#
#   ds = DB[:items].extension(:duplicate_columns_handler)
#
# A database option is introduced: :on_duplicate_columns. It accepts a Symbol
# or any object that responds to :call.
#
#   on_duplicate_columns: :raise
#   on_duplicate_columns: :warn
#   on_duplicate_columns: :ignore
#   on_duplicate_columns: lambda{|columns| arbitrary_condition? ? :raise : :warn}
#
# You may also configure duplicate columns handling for a specific dataset:
#
#   ds.on_duplicate_columns(:warn)
#   ds.on_duplicate_columns(:raise)
#   ds.on_duplicate_columns(:ignore)
#   ds.on_duplicate_columns{|columns| arbitrary_condition? ? :raise : :warn}
#   ds.on_duplicate_columns(lambda{|columns| arbitrary_condition? ? :raise : :warn})
#
# If :raise is specified, a Sequel::DuplicateColumnError is raised.
# If :warn is specified, you will receive a warning via +warn+.
# If a callable is specified, it will be called.
# If no on_duplicate_columns is specified, the default is :warn.
#
# Related module: Sequel::DuplicateColumnsHandler

module Sequel
  module DuplicateColumnsHandler
    # :nocov:
    CALLER_ARGS = (RUBY_VERSION >= '2.0' ? [0,1] : [0]).freeze
    # :nocov:

    # Customize handling of duplicate columns for this dataset.
    def on_duplicate_columns(handler = (raise Error, "Must provide either an argument or a block to on_duplicate_columns" unless defined?(yield); nil), &block)
      raise Error, "Cannot provide both an argument and a block to on_duplicate_columns" if handler && block
      clone(:on_duplicate_columns=>handler||block)
    end

    private

    # Call handle_duplicate_columns if there are duplicate columns.
    def columns=(cols)
      if cols && cols.uniq.size != cols.size
        handle_duplicate_columns(cols)
      end
      super
    end

    # Invoke the appropriate behavior when duplicate columns are present.
    def handle_duplicate_columns(cols)
      message = "#{caller(*CALLER_ARGS).first}: One or more duplicate columns present in #{cols.inspect}"

      case duplicate_columns_handler_type(cols)
      when :raise
        raise DuplicateColumnError, message
      when :warn
        warn message
      end
    end

    # Try to find dataset option for on_duplicate_columns. If not present on the dataset,
    # use the on_duplicate_columns option on the database. If not present on the database,
    # default to :warn.
    def duplicate_columns_handler_type(cols)
      handler = opts.fetch(:on_duplicate_columns){db.opts.fetch(:on_duplicate_columns, :warn)}

      if handler.respond_to?(:call)
        handler.call(cols)
      else
        handler
      end
    end
  end

  # Error which is raised when duplicate columns are present in a dataset which is configured
  # to :raise on_duplicate_columns.
  class DuplicateColumnError < Error
  end

  Dataset.register_extension(:duplicate_columns_handler, Sequel::DuplicateColumnsHandler)
end