This file is indexed.

/usr/lib/ruby/vendor_ruby/sequel/plugins/class_table_inheritance.rb is in ruby-sequel 3.36.1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
module Sequel
  module Plugins
    # The class_table_inheritance plugin allows you to model inheritance in the
    # database using a table per model class in the hierarchy, with only columns
    # unique to that model class (or subclass hierarchy) being stored in the related
    # table.  For example, with this hierarchy:
    #
    #       Employee
    #      /        \ 
    #   Staff     Manager
    #                |
    #            Executive
    #
    # the following database schema may be used (table - columns):
    #
    # * employees - id, name, kind
    # * staff - id, manager_id
    # * managers - id, num_staff
    # * executives - id, num_managers
    #
    # The class_table_inheritance plugin assumes that the main table
    # (e.g. employees) has a primary key field (usually autoincrementing),
    # and all other tables have a foreign key of the same name that points
    # to the same key in their superclass's table.  For example:
    #
    # * employees.id  - primary key, autoincrementing
    # * staff.id - foreign key referencing employees(id)
    # * managers.id - foreign key referencing employees(id)
    # * executives.id - foreign key referencing managers(id)
    #
    # When using the class_table_inheritance plugin, subclasses use joined 
    # datasets:
    #
    #   Employee.dataset.sql  # SELECT * FROM employees
    #   Manager.dataset.sql   # SELECT * FROM employees
    #                         # INNER JOIN managers USING (id)
    #   Executive.dataset.sql # SELECT * FROM employees 
    #                         # INNER JOIN managers USING (id)
    #                         # INNER JOIN executives USING (id)
    #
    # This allows Executive.all to return instances with all attributes
    # loaded.  The plugin overrides the deleting, inserting, and updating
    # in the model to work with multiple tables, by handling each table
    # individually.
    #
    # This plugin allows the use of a :key option when loading to mark
    # a column holding a class name.  This allows methods on the
    # superclass to return instances of specific subclasses.
    # This plugin also requires the lazy_attributes plugin and uses it to
    # return subclass specific attributes that would not be loaded
    # when calling superclass methods (since those wouldn't join
    # to the subclass tables).  For example:
    #
    #   a = Employee.all # [<#Staff>, <#Manager>, <#Executive>]
    #   a.first.values # {:id=>1, name=>'S', :kind=>'Staff'}
    #   a.first.manager_id # Loads the manager_id attribute from the database
    # 
    # Usage:
    #
    #   # Set up class table inheritance in the parent class
    #   # (Not in the subclasses)
    #   Employee.plugin :class_table_inheritance
    #
    #   # Set the +kind+ column to hold the class name, and
    #   # set the subclass table to map to for each subclass 
    #   Employee.plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}
    module ClassTableInheritance
      # The class_table_inheritance plugin requires the lazy_attributes plugin
      # to handle lazily-loaded attributes for subclass instances returned
      # by superclass methods.
      def self.apply(model, opts={})
        model.plugin :lazy_attributes
      end
      
      # Initialize the per-model data structures and set the dataset's row_proc
      # to check for the :key option column for the type of class when loading objects.
      # Options:
      # * :key - The column symbol holding the name of the model class this
      #   is an instance of.  Necessary if you want to call model methods
      #   using the superclass, but have them return subclass instances.
      # * :table_map - Hash with class name symbol keys and table name symbol
      #   values.  Necessary if the implicit table name for the model class
      #   does not match the database table name
      def self.configure(model, opts={})
        model.instance_eval do
          m = method(:constantize)
          @cti_base_model = self
          @cti_key = key = opts[:key] 
          @cti_tables = [table_name]
          @cti_columns = {table_name=>columns}
          @cti_table_map = opts[:table_map] || {}
          dataset.row_proc = if key
            lambda{|r| (m.call(r[key]) rescue model).call(r)}
          else
            model
          end
        end
      end

      module ClassMethods
        # The parent/root/base model for this class table inheritance hierarchy.
        # This is the only model in the hierarchy that load the
        # class_table_inheritance plugin.
        attr_reader :cti_base_model
        
        # Hash with table name symbol keys and arrays of column symbol values,
        # giving the columns to update in each backing database table.
        attr_reader :cti_columns
        
        # The column containing the class name as a string.  Used to
        # return instances of subclasses when calling the superclass's
        # load method.
        attr_reader :cti_key
        
        # An array of table symbols that back this model.  The first is
        # cti_base_model table symbol, and the last is the current model
        # table symbol.
        attr_reader :cti_tables
        
        # A hash with class name symbol keys and table name symbol values.
        # Specified with the :table_map option to the plugin, and used if
        # the implicit naming is incorrect.
        attr_reader :cti_table_map
        
        # Add the appropriate data structures to the subclass.  Does not
        # allow anonymous subclasses to be created, since they would not
        # be mappable to a table.
        def inherited(subclass)
          cc = cti_columns
          ck = cti_key
          ct = cti_tables.dup
          ctm = cti_table_map.dup
          cbm = cti_base_model
          pk = primary_key
          ds = dataset
          subclass.instance_eval do
            raise(Error, "cannot create anonymous subclass for model class using class_table_inheritance") if !(n = name) || n.empty?
            table = ctm[n.to_sym] || implicit_table_name
            columns = db.from(table).columns
            @cti_key = ck 
            @cti_tables = ct + [table]
            @cti_columns = cc.merge(table=>columns)
            @cti_table_map = ctm
            @cti_base_model = cbm
            # Need to set dataset and columns before calling super so that
            # the main column accessor module is included in the class before any
            # plugin accessor modules (such as the lazy attributes accessor module).
            set_dataset(ds.join(table, [pk]))
            set_columns(self.columns)
          end
          super
          subclass.instance_eval do
            m = method(:constantize)
            dataset.row_proc = if cti_key
              lambda{|r| (m.call(r[ck]) rescue subclass).call(r)}
            else
              subclass
            end
            (columns - [cbm.primary_key]).each{|a| define_lazy_attribute_getter(a)}
            cti_tables.reverse.each do |table|
              db.schema(table).each{|k,v| db_schema[k] = v}
            end
          end
        end
        
        # The primary key in the parent/base/root model, which should have a
        # foreign key with the same name referencing it in each model subclass.
        def primary_key
          return super if self == cti_base_model
          cti_base_model.primary_key
        end
        
        # The table name for the current model class's main table (not used
        # by any superclasses).
        def table_name
          self == cti_base_model ? super : cti_tables.last
        end
      end

      module InstanceMethods
        # Set the cti_key column to the name of the model.
        def before_create
          send("#{model.cti_key}=", model.name.to_s) if model.cti_key
          super
        end
        
        # Delete the row from all backing tables, starting from the
        # most recent table and going through all superclasses.
        def delete
          m = model
          m.cti_tables.reverse.each do |table|
            m.db.from(table).filter(m.primary_key=>pk).delete
          end
          self
        end
        
        private
        
        # Insert rows into all backing tables, using the columns
        # in each table.  
        def _insert
          return super if model == model.cti_base_model
          iid = @values[primary_key] 
          m = model
          m.cti_tables.each do |table|
            h = {}
            h[m.primary_key] ||= iid if iid
            m.cti_columns[table].each{|c| h[c] = @values[c] if @values.include?(c)}
            nid = m.db.from(table).insert(h)
            iid ||= nid
          end
          @values[primary_key] = iid
        end
        
        # Update rows in all backing tables, using the columns in each table.
        def _update(columns)
          pkh = pk_hash
          m = model
          m.cti_tables.each do |table|
            h = {}
            m.cti_columns[table].each{|c| h[c] = columns[c] if columns.include?(c)}
            m.db.from(table).filter(pkh).update(h) unless h.empty?
          end
        end
      end
    end
  end
end