module RailsSqlViews4 module ConnectionAdapters # :nodoc: module SchemaStatements def self.included(base) base.alias_method_chain :drop_table, :cascade end # Create a view. # The +options+ hash can include the following keys: # [:check_option] # Specify restrictions for inserts or updates in updatable views. ANSI SQL 92 defines two check option # values: CASCADED and LOCAL. See your database documentation for allowed values. # # # we have a problem with the force option in postgres # rescue nil will rescue the ruby program, but we still have an error for postgres # and unfortunatly for postgress, the first error will stop the interpretor : # ActiveRecord::StatementInvalid Exception: PG::InFailedSqlTransaction: ERROR: # current transaction is aborted, commands ignored until end of transaction block # def create_view(name, select_query, options={}) create_or_create_view_base(name, select_query, options, "CREATE VIEW ") end def create_or_replace_view(name, select_query, options={}) create_or_create_view_base(name, select_query, options, "CREATE OR REPLACE VIEW ") end def create_or_create_view_base(name, select_query, options, init_create_sql) if supports_views? view_definition = ViewDefinition.new(self, select_query) if block_given? yield view_definition end if options[:force] puts" TOTO : Please, force option is not correctly implemented in postgres" drop_view(name) rescue nil end # create_sql = "CREATE VIEW " create_sql = init_create_sql create_sql << "#{quote_table_name(name)} " if supports_view_columns_definition? && !view_definition.to_sql.blank? create_sql << "(" create_sql << view_definition.to_sql create_sql << ") " end create_sql << "AS #{view_definition.select_query}" create_sql << " WITH #{options[:check_option]} CHECK OPTION" if options[:check_option] execute create_sql end end # Also creates a view, with the specific purpose of remapping column names # to make non-ActiveRecord tables friendly with the naming # conventions, while maintaining legacy app compatibility. def create_mapping_view(old_name, new_name, options = {}) return unless supports_views? col_names = columns(old_name).collect { |col| col.name.to_sym } mapper = MappingDefinition.new(col_names) yield mapper if options[:force] drop_view(new_name) rescue nil end view_sql = "CREATE VIEW #{new_name} " if supports_view_columns_definition? view_sql << "(#{mapper.view_cols.collect { |c| quote_column_name(c) }.join(', ')}) " end view_sql << "AS SELECT #{mapper.select_cols.collect { |c| quote_column_name(c) }.join(', ')} FROM #{old_name}" execute view_sql end # TODO : est appelé avec SQLITE, alors que c'est pas ok def drop_table_with_cascade(table_name, options = {}) # execute "DROP TABLE #{quote_table_name(table_name)} CASCADE" if supports_drop_table_cascade? execute "DROP TABLE #{quote_table_name(table_name)} CASCADE" else execute "DROP TABLE #{quote_table_name(table_name)}" end end # Drop a view. # The +options+ hash can include the following keys: # [:drop_behavior] # Specify the drop behavior. ANSI SQL 92 defines two drop behaviors, CASCADE and RESTRICT. See your # database documentation to determine what drop behaviors are available. def drop_view(name, options={}) # if supports_views? # because of postgres (see create_view with force option) if supports_views? & table_exists?(name) drop_sql = "DROP VIEW #{quote_table_name(name)}" drop_sql << " #{options[:drop_behavior]}" if options[:drop_behavior] execute drop_sql end end end end end