File: pg_schema_caching.rb

package info (click to toggle)
ruby-sequel 5.97.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,188 kB
  • sloc: ruby: 123,115; makefile: 3
file content (90 lines) | stat: -rw-r--r-- 2,868 bytes parent folder | download
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
# frozen-string-literal: true
#
# The pg_schema_caching extension builds on top of the schema_caching
# extension, and allows it to handle custom PostgreSQL types. On
# PostgreSQL, column schema hashes include an :oid entry for the OID
# for the column's type.  For custom types, this OID is dependent on
# the PostgreSQL database, so in most cases, test and development
# versions of the same database, created with the same migrations,
# will have different OIDs.
#
# To fix this case, the pg_schema_caching extension removes custom
# OIDs from the schema cache when dumping the schema, replacing them
# with a placeholder. When loading the cached schema, the Database
# object makes a single query to get the OIDs for all custom types
# used by the cached schema, and it updates all related column
# schema hashes to set the correct :oid entry for the current
# database.
#
# Related module: Sequel::Postgres::SchemaCaching

require_relative "schema_caching"

module Sequel
  module Postgres
    module SchemaCaching
      include Sequel::SchemaCaching

      private

      # Load custom oids from database when loading schema cache file.
      def load_schema_cache_file(file)
        set_custom_oids_for_cached_schema(super)
      end

      # Find all column schema hashes that use custom types.
      # Load the oids for custom types in a single query, and update
      # each related column schema hash with the correct oid.
      def set_custom_oids_for_cached_schema(schemas)
        custom_oid_rows = {}

        schemas.each_value do |cols|
          cols.each do |_, h|
            if h[:oid] == :custom
              (custom_oid_rows[h[:db_type]] ||= []) << h
            end
          end
        end

        unless custom_oid_rows.empty?
          from(:pg_type).where(:typname=>custom_oid_rows.keys).select_hash(:typname, :oid).each do |name, oid|
            custom_oid_rows.delete(name).each do |row|
              row[:oid] = oid
            end
          end
        end

        unless custom_oid_rows.empty?
          warn "Could not load OIDs for the following custom types: #{custom_oid_rows.keys.sort.join(", ")}", uplevel: 3

          schemas.keys.each do |k|
            if schemas[k].any?{|_,h| h[:oid] == :custom}
              # Remove schema entry for table, so it will be queried at runtime to get the correct oids
              schemas.delete(k)
            end
          end
        end

        schemas
      end

      # Replace :oid entries for custom types with :custom.
      def dumpable_schema_cache
        sch = super

        sch.each_value do |cols|
          cols.each do |_, h|
            if (oid = h[:oid]) && oid >= 10000
              h[:oid] = :custom
            end
          end
        end

        sch
      end
    end
  end

  Database.register_extension(:pg_schema_caching, Postgres::SchemaCaching)
end