aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/postgresql/utils.rb
blob: aa7940188a7c71c06fdbee0ef4340c5e601217e2 (plain) (blame)
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
module ActiveRecord
  module ConnectionAdapters
    module PostgreSQL
      # Value Object to hold a schema qualified name.
      # This is usually the name of a PostgreSQL relation but it can also represent
      # schema qualified type names. +schema+ and +identifier+ are unquoted to prevent
      # double quoting.
      class Name # :nodoc:
        SEPARATOR = "."
        attr_reader :schema, :identifier

        def initialize(schema, identifier)
          @schema, @identifier = unquote(schema), unquote(identifier)
        end

        def to_s
          parts.join SEPARATOR
        end

        def quoted
          if schema
            PG::Connection.quote_ident(schema) << SEPARATOR << PG::Connection.quote_ident(identifier)
          else
            PG::Connection.quote_ident(identifier)
          end
        end

        def ==(o)
          o.class == self.class && o.parts == parts
        end
        alias_method :eql?, :==

        def hash
          parts.hash
        end

        protected

          def parts
            @parts ||= [@schema, @identifier].compact
          end

        private
          def unquote(part)
            if part && part.start_with?('"')
              part[1..-2]
            else
              part
            end
          end
      end

      module Utils # :nodoc:
        extend self

        # Returns an instance of <tt>ActiveRecord::ConnectionAdapters::PostgreSQL::Name</tt>
        # extracted from +string+.
        # +schema+ is +nil+ if not specified in +string+.
        # +schema+ and +identifier+ exclude surrounding quotes (regardless of whether provided in +string+)
        # +string+ supports the range of schema/table references understood by PostgreSQL, for example:
        #
        # * <tt>table_name</tt>
        # * <tt>"table.name"</tt>
        # * <tt>schema_name.table_name</tt>
        # * <tt>schema_name."table.name"</tt>
        # * <tt>"schema_name".table_name</tt>
        # * <tt>"schema.name"."table name"</tt>
        def extract_schema_qualified_name(string)
          schema, table = string.scan(/[^".\s]+|"[^"]*"/)
          if table.nil?
            table = schema
            schema = nil
          end
          PostgreSQL::Name.new(schema, table)
        end
      end
    end
  end
end