Sequel::Plugins::InlineSchema::

ClassMethods module

Sequel plugin API – add these methods to model classes which load the plugin.

Public Class Methods

extended( model_class )

Extension callback – add some class instance variables to keep track of schema info.

# File lib/sequel/plugins/inline_schema.rb, line 104
def self::extended( model_class )
        super

        model_class.require_valid_table = false

        # The Sequel::Dataset used to create the model's view (if it's modelling a view
        # instead of a table). Setting this causes the model's schema to be ignored when
        # its table is created, creating a view by the same name instead.
        model_class.singleton_class.attr_accessor( :view_dataset )

        # The options used when creating the view for the model.
        model_class.singleton_class.attr_accessor( :view_options )
end

Public Instance Methods

after_create_table()

Table-creation hook; called on a model class after its table is created.

# File lib/sequel/plugins/inline_schema.rb, line 288
def after_create_table
        return true
end
after_create_view()

View-creation hook; called after the backing view is created.

# File lib/sequel/plugins/inline_schema.rb, line 300
def after_create_view
        return true
end
after_drop_table()

Table-drop hook; called after the table is dropped.

# File lib/sequel/plugins/inline_schema.rb, line 312
def after_drop_table
        return true
end
after_drop_view()

View-drop hook; called after the backing view is dropped.

# File lib/sequel/plugins/inline_schema.rb, line 336
def after_drop_view
        return true
end
before_create_table()

Table-creation hook; called on a model class before its table is created.

# File lib/sequel/plugins/inline_schema.rb, line 282
def before_create_table
        return true
end
before_create_view()

View-creation hook; called before the backing view is created.

# File lib/sequel/plugins/inline_schema.rb, line 294
def before_create_view
        return true
end
before_drop_table()

Table-drop hook; called before the table is dropped.

# File lib/sequel/plugins/inline_schema.rb, line 306
def before_drop_table
        return true
end
before_drop_view()

View-drop hook; called before the backing view is dropped.

# File lib/sequel/plugins/inline_schema.rb, line 330
def before_drop_view
        return true
end
create_table( *args, &block )

Creates table, using the column information from set_schema.

# File lib/sequel/plugins/inline_schema.rb, line 152
def create_table( *args, &block )
        self.set_schema( *args, &block ) if block
        self.before_create_table
        self.db.create_table( self.table_name, generator: self.schema )
        @db_schema = get_db_schema( true )
        self.after_create_table
        return self.columns
end
create_table!( *args, &block )

Drops the table if it exists and then runs create_table. Should probably not be used except in testing.

# File lib/sequel/plugins/inline_schema.rb, line 164
def create_table!( *args, &block )
        self.drop_table?
        return self.create_table( *args, &block )
end
create_table?( *args, &block )

Creates the table unless the table already exists

# File lib/sequel/plugins/inline_schema.rb, line 171
def create_table?( *args, &block )
        self.create_table( *args, &block ) unless self.table_exists?
end
create_view( options={} )

Create the view for this model class.

# File lib/sequel/plugins/inline_schema.rb, line 208
def create_view( options={} )
        dataset = self.view_dataset or raise "No view declared for this model."
        options = self.view_options.merge( options )

        self.before_create_view
        self.db.log_info "Creating view %s(%p): %s" % [ self.table_name, options, dataset.sql ]
        self.db.create_view( self.table_name, dataset, options )
        @db_schema = get_db_schema( true )
        self.after_create_view
end
create_view!( options={} )

Drops the view if it exists and then runs create_view.

# File lib/sequel/plugins/inline_schema.rb, line 221
def create_view!( options={} )
        self.drop_view?
        return self.create_view
end
create_view?( options={} )

Creates the view unless it already exists.

# File lib/sequel/plugins/inline_schema.rb, line 228
def create_view?( options={} )
        self.create_view( options ) unless self.view_exists?
end
drop_table( opts={} )

Drops table. If the table doesn’t exist, this will probably raise an error.

# File lib/sequel/plugins/inline_schema.rb, line 177
def drop_table( opts={} )
        self.before_drop_table
        self.db.drop_table( self.table_name, opts )
        self.after_drop_table
end
drop_table?( opts={} )

Drops table if it already exists, do nothing.

# File lib/sequel/plugins/inline_schema.rb, line 185
def drop_table?( opts={} )
        self.drop_table( opts ) if self.table_exists?
end
drop_view( options={} )

Drop the view backing this model.

# File lib/sequel/plugins/inline_schema.rb, line 241
def drop_view( options={} )
        self.before_drop_view
        self.db.drop_view( self.table_name, self.view_options.merge(options) )
        self.after_drop_view
end
drop_view?( options={} )

Drop the view if it already exists, otherwise do nothing.

# File lib/sequel/plugins/inline_schema.rb, line 249
def drop_view?( options={} )
        self.drop_view( options ) if self.view_exists?
end
is_view_class?()

Returns true if the receiver is defined via a view rather than a table.

# File lib/sequel/plugins/inline_schema.rb, line 365
def is_view_class?
        return self.respond_to?( :view_dataset ) && self.view_dataset ? true : false
end
refresh_view()

Refresh the view for this model class. This can only be called on materialized views.

# File lib/sequel/plugins/inline_schema.rb, line 235
def refresh_view
        self.db.refresh_view( self.table_name )
end
schema()

Returns the table schema created with set_schema.

# File lib/sequel/plugins/inline_schema.rb, line 120
def schema
        if !@schema && @schema_block
                self.set_dataset( self.db[@schema_name] ) if @schema_name
                @schema = self.db.create_table_generator( &@schema_block )
                self.set_primary_key( @schema.primary_key_name ) if @schema.primary_key_name
        end
        return @schema || ( superclass.schema unless superclass == Sequel::Model )
end
set_schema( name=nil, require_table: false, &block )

Defines a table schema (see Schema::CreateTableGenerator for more information).

This will also set the dataset if you provide a name, as well as setting the primary key if you define one in the passed block.

Since this plugin allows you to declare the schema inline with the model class that acts as its interface, the table will not always exist when the class loads, so calling set_schema will call require_valid_table to false for you. You can disable this by passing require_table: true.

# File lib/sequel/plugins/inline_schema.rb, line 139
def set_schema( name=nil, require_table: false, &block )
        self.require_valid_table = require_table
        @schema = nil
        @schema_name = name
        @schema_block = block
end
set_view_dataset( ds=nil, **options ) { |ds| ... }

Set the dataset to use for the model to ds. If a block is provided, it will be called with the specified ds, and should return the modified dataset to use. Any options that are given will be passed to Sequel::Database#create_or_replace_view

# File lib/sequel/plugins/inline_schema.rb, line 199
def set_view_dataset( ds=nil, **options ) # :yield: ds
        ds = yield( ds ) if block_given?

        self.view_dataset = ds
        self.view_options = options
end
table_exists?()

Returns true if table exists, false otherwise.

# File lib/sequel/plugins/inline_schema.rb, line 191
def table_exists?
        return self.db.table_exists?( self.table_name )
end
uninstalled_tables()

Return an Array of model classes whose tables don’t yet exist, in the order they need to be created to satisfy foreign key constraints.

# File lib/sequel/plugins/inline_schema.rb, line 347
def uninstalled_tables
        self.db.log_info "  searching for unbacked model classes..."

        self.tsort.find_all do |modelclass|
                next unless modelclass.name && modelclass.name != '' && !modelclass.is_view_class?
                !modelclass.table_exists?
        end.uniq( &:table_name )
end
uninstalled_views()

Return an Array of model classes whose views don’t yet exist, in the order they need to be created.

# File lib/sequel/plugins/inline_schema.rb, line 359
def uninstalled_views
        return self.tsort.find_all( &:is_view_class? ).reject( &:table_exists? )
end
view_exists?()

Returns true if the view associated with this model exists, false otherwise. :FIXME: This is PostgreSQL-specific, but there doesn’t appear to be any cross-driver way to check for a view.

# File lib/sequel/plugins/inline_schema.rb, line 257
def view_exists?
        # Make shortcuts for fully-qualified names
        class_table = Sequel[:pg_catalog][:pg_class].as( :c )
        ns_table = Sequel[:pg_catalog][:pg_namespace].as( :n )
        is_visible = Sequel[:pg_catalog][:pg_table_is_visible]

        _, table, _ = Sequel.split_symbol( self.table_name )

        ds = db[ class_table ].
                join( ns_table, oid: :relnamespace )
        ds = ds.where( Sequel[:c][:relkind] => ['v', 'm'] ).
                exclude( Sequel[:n][:nspname] => /^pg_toast/ ).
                where( Sequel[:c][:relname] => table.to_s ).
                where( Sequel.function(is_visible, Sequel[:c][:oid]) )

        return ds.count == 1
end

Protected Instance Methods

cancel_action( msg=nil )

Cancel the currently-running before_* hook. If a msg is given, use it when constructing the HookFailed exception.

# File lib/sequel/plugins/inline_schema.rb, line 391
def cancel_action( msg=nil )
        self.raise_hook_failure( msg )
end
raise_hook_failure( type=nil )

Raise an appropriate Sequel::HookFailure exception for the specified type.

# File lib/sequel/plugins/inline_schema.rb, line 375
def raise_hook_failure( type=nil )
        msg = case type
                when String
                        type
                when Symbol
                        "the #{type} hook failed"
                else
                        "a hook failed"
                end

        raise Sequel::HookFailed.new( msg, self )
end
tsort_each_child( model_class ) { |model_class| ... }

TSort API – yield each of the given model_class‘s dependent model classes.

# File lib/sequel/plugins/inline_schema.rb, line 404
def tsort_each_child( model_class ) # :yields: model_class
        # Include (non-anonymous) parents other than Model
        model_class.ancestors[1..-1].
                select {|cl| cl < self }.
                select( &:name ).
                each do |parentclass|
                        yield( parentclass )
                end

        # Include associated classes for which this model class's table has a
        # foreign key
        model_class.association_reflections.each do |name, config|
                next if config[:polymorphic]

                associated_class = config.associated_class

                yield( associated_class ) if config[:type] == :many_to_one
        end
end
tsort_each_node( &block )

TSort API – yield each model class.

# File lib/sequel/plugins/inline_schema.rb, line 397
def tsort_each_node( &block )
        self.descendents.select( &:name ).each( &block )
end