/usr/lib/ruby/vendor_ruby/sequel/plugins/pg_row.rb is in ruby-sequel 4.15.0-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 | module Sequel
module Plugins
# The pg_row plugin allows you to use Sequel::Model classes as composite type
# classes, via the pg_row extension. So if you have an address table:
#
# DB.create_table(:address) do
# String :street
# String :city
# String :zip
# end
#
# and a company table with an address:
#
# DB.create_table(:company) do
# String :name
# address :address
# end
#
# You can create a Sequel::Model for the address table, and load the plugin,
# which registers the row type:
#
# class Address < Sequel::Model(:address)
# plugin :pg_row
# end
#
# Then when you select from the company table (even using a plain dataset),
# it will return address values as instances of Address:
#
# DB[:company].first
# # => {:name=>'MS', :address=>
# # Address.load(:street=>'123 Foo St', :city=>'Bar Town', :zip=>'12345')}
#
# If you want a lot of your models to be used as row types, you can load the
# plugin into Sequel::Model itself:
#
# Sequel::Model.plugin :pg_row
#
# And then call register_row_type in the class
#
# Address.register_row_type
#
# Note that automatic conversion only works with the native postgres adapter.
# For other adapters that connect to PostgreSQL, you need to call the conversion
# proc manually.
#
# In addition to returning row-valued/composite types as instances of Sequel::Model,
# this also lets you use model instances in datasets when inserting, updating, and
# filtering:
#
# DB[:company].insert(:name=>'MS', :address=>
# Address.load(:street=>'123 Foo St', :city=>'Bar Town', :zip=>'12345'))
module PgRow
# When loading the extension, make sure the database has the pg_row extension
# loaded, load the custom database extensions, and automatically register the
# row type if the model has a dataset.
def self.configure(model)
model.db.extension(:pg_row)
model.db.extend(DatabaseMethods)
model.register_row_type if model.instance_variable_get(:@dataset)
end
module DatabaseMethods
ESCAPE_RE = /("|\\)/.freeze
ESCAPE_REPLACEMENT = '\\\\\1'.freeze
COMMA = ','
# Handle Sequel::Model instances in bound variables.
def bound_variable_arg(arg, conn)
case arg
when Sequel::Model
"(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(COMMA)})"
else
super
end
end
# If a Sequel::Model instance is given, return it as-is
# instead of attempting to convert it.
def row_type(db_type, v)
if v.is_a?(Sequel::Model)
v
else
super
end
end
private
# Handle Sequel::Model instances in bound variable arrays.
def bound_variable_array(arg)
case arg
when Sequel::Model
"\"(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(COMMA).gsub(ESCAPE_RE, ESCAPE_REPLACEMENT)})\""
else
super
end
end
end
module ClassMethods
# Register the model's row type with the database.
def register_row_type
table = dataset.first_source_table
db.register_row_type(table, :converter=>self, :typecaster=>method(:new))
db.instance_variable_get(:@schema_type_classes)[:"pg_row_#{table}"] = self
end
end
module InstanceMethods
ROW = 'ROW'.freeze
CAST = '::'.freeze
# Literalize the model instance and append it to the sql.
def sql_literal_append(ds, sql)
sql << ROW
ds.literal_append(sql, values.values_at(*columns))
sql << CAST
ds.quote_schema_table_append(sql, model.dataset.first_source_table)
end
end
end
end
end
|