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
|
# frozen-string-literal: true
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
#
# 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_pg_row)
model.register_row_type if model.instance_variable_get(:@dataset)
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
# 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 << '::'
ds.quote_schema_table_append(sql, model.dataset.first_source_table)
end
end
end
end
end
|