Module: ActiveRecord::ConnectionAdapters::Materialize::SchemaStatements
- Included in:
- ActiveRecord::ConnectionAdapters::MaterializeAdapter
- Defined in:
- lib/active_record/connection_adapters/materialize/schema_statements.rb
Instance Method Summary collapse
- #add_column(table_name, column_name, type, **options) ⇒ Object
-
#add_index(table_name, column_name, options = {}) ⇒ Object
:nodoc:.
- #change_column(table_name, column_name, type, options = {}) ⇒ Object
- #change_column_default(table_name, column_name, default_or_changes) ⇒ Object
- #change_column_null(table_name, column_name, null, default = nil) ⇒ Object
-
#collation ⇒ Object
Unsupported collation.
-
#columns_for_distinct(columns, orders) ⇒ Object
TODO: verify same functionality as postgres Materialize requires the ORDER BY columns in the select list for distinct queries, and requires that the ORDER BY include the distinct column.
-
#create_database(name, options = {}) ⇒ Object
Create a new Materialize database.
-
#create_schema(schema_name) ⇒ Object
Creates a schema for the given schema name.
-
#create_schema_dumper(options) ⇒ Object
:nodoc:.
-
#ctype ⇒ Object
Get ctype.
-
#current_database ⇒ Object
Unsupported current_database() use default config.
-
#current_schema ⇒ Object
Returns the current schema name.
-
#default_sequence_name(table_name, pk = "id") ⇒ Object
Returns the sequence name for compatability.
-
#drop_database(name) ⇒ Object
Drops a Materialize database.
-
#drop_schema(schema_name, options = {}) ⇒ Object
Drops the schema for the given schema name.
-
#drop_table(table_name, options = {}) ⇒ Object
:nodoc:.
-
#encoding ⇒ Object
Get encoding of database.
-
#index_name_exists?(table_name, index_name) ⇒ Boolean
Verifies existence of an index with a given name.
-
#indexes(table_name) ⇒ Object
Returns an array of indexes for the given table.
-
#primary_keys(table_name) ⇒ Object
Primary keys - approximation.
-
#recreate_database(name, options = {}) ⇒ Object
Drops the database specified on the
name
attribute and creates it again using the providedoptions
. -
#remove_index(table_name, options = {}) ⇒ Object
:nodoc:.
- #rename_column(table_name, column_name, new_column_name) ⇒ Object
-
#rename_index(table_name, old_name, new_name) ⇒ Object
Renames an index of a table.
-
#rename_table(table_name, new_name) ⇒ Object
Renames a table with index references.
-
#schema_exists?(name) ⇒ Boolean
Returns true if schema exists.
-
#schema_names ⇒ Object
Returns an array of schema names.
-
#schema_search_path ⇒ Object
Returns the active schema search path.
-
#table_comment(table_name) ⇒ Object
Returns a comment stored in database for given table.
-
#table_options(table_name) ⇒ Object
:nodoc:.
-
#type_to_sql(type, limit: nil, precision: nil, scale: nil) ⇒ Object
Maps logical Rails types to Materialize-specific data types.
-
#update_table_definition(table_name, base) ⇒ Object
:nodoc:.
-
#validate_constraint(table_name, constraint_name) ⇒ Object
Validates the given constraint.
-
#validate_foreign_key(from_table, to_table = nil, **options) ⇒ Object
Validates the given foreign key.
Instance Method Details
#add_column(table_name, column_name, type, **options) ⇒ Object
179 180 181 182 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 179 def add_column(table_name, column_name, type, **) #:nodoc: clear_cache! super end |
#add_index(table_name, column_name, options = {}) ⇒ Object
:nodoc:
214 215 216 217 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 214 def add_index(table_name, column_name, = {}) #:nodoc: index_name, index_type, index_columns_and_opclasses, , index_algorithm, index_using, comment = (table_name, column_name, **) execute("CREATE INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns_and_opclasses})") end |
#change_column(table_name, column_name, type, options = {}) ⇒ Object
185 186 187 188 189 190 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 185 def change_column(table_name, column_name, type, = {}) #:nodoc: clear_cache! sqls, procs = Array(change_column_for_alter(table_name, column_name, type, )).partition { |v| v.is_a?(String) } execute "ALTER TABLE #{quote_table_name(table_name)} #{sqls.join(", ")}" procs.each(&:call) end |
#change_column_default(table_name, column_name, default_or_changes) ⇒ Object
193 194 195 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 193 def change_column_default(table_name, column_name, default_or_changes) # :nodoc: execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_default_for_alter(table_name, column_name, default_or_changes)}" end |
#change_column_null(table_name, column_name, null, default = nil) ⇒ Object
198 199 200 201 202 203 204 205 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 198 def change_column_null(table_name, column_name, null, default = nil) #:nodoc: clear_cache! unless null || default.nil? column = column_for(table_name, column_name) execute "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(default, column)} WHERE #{quote_column_name(column_name)} IS NULL" if column end execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_null_for_alter(table_name, column_name, null, default)}" end |
#collation ⇒ Object
Unsupported collation
114 115 116 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 114 def collation nil end |
#columns_for_distinct(columns, orders) ⇒ Object
TODO: verify same functionality as postgres Materialize requires the ORDER BY columns in the select list for distinct queries, and requires that the ORDER BY include the distinct column.
264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 264 def columns_for_distinct(columns, orders) #:nodoc: order_columns = orders.reject(&:blank?).map { |s| # Convert Arel node to string s = visitor.compile(s) unless s.is_a?(String) # Remove any ASC/DESC modifiers s .gsub(/\s+(?:ASC|DESC)\b/i, "") .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "") }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" } (order_columns << super).join(", ") end |
#create_database(name, options = {}) ⇒ Object
Create a new Materialize database. Options include :owner
, :template
, :encoding
(defaults to utf8), :collation
, :ctype
, :tablespace
, and :connection_limit
(note that MySQL uses :charset
while Materialize uses :encoding
).
Example:
create_database config[:database], config
create_database 'foo_development', encoding: 'unicode'
22 23 24 25 26 27 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 22 def create_database(name, = {}) = {}.merge(.symbolize_keys) if_exists = "IF NOT EXISTS " unless [false, 'false', '0', 0].include? [:if_exists] execute "CREATE DATABASE #{if_exists}#{quote_table_name(name)}" end |
#create_schema(schema_name) ⇒ Object
Creates a schema for the given schema name.
136 137 138 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 136 def create_schema(schema_name) execute "CREATE SCHEMA #{quote_schema_name(schema_name.to_s)}" end |
#create_schema_dumper(options) ⇒ Object
:nodoc:
281 282 283 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 281 def create_schema_dumper() # :nodoc: Materialize::SchemaDumper.create(self, ) end |
#ctype ⇒ Object
Get ctype
119 120 121 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 119 def ctype query_value("SELECT datctype FROM pg_database WHERE datname = #{quote(current_database)}", "SCHEMA") end |
#current_database ⇒ Object
Unsupported current_database() use default config
99 100 101 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 99 def current_database @config[:database] end |
#current_schema ⇒ Object
Returns the current schema name.
104 105 106 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 104 def current_schema query_value("SELECT current_schema", "SCHEMA") end |
#default_sequence_name(table_name, pk = "id") ⇒ Object
Returns the sequence name for compatability
151 152 153 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 151 def default_sequence_name(table_name, pk = "id") #:nodoc: Materialize::Name.new(nil, "#{table_name}_#{pk}_seq").to_s end |
#drop_database(name) ⇒ Object
Drops a Materialize database.
Example:
drop_database 'matt_development'
33 34 35 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 33 def drop_database(name) #:nodoc: execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}" end |
#drop_schema(schema_name, options = {}) ⇒ Object
Drops the schema for the given schema name.
141 142 143 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 141 def drop_schema(schema_name, = {}) execute "DROP SCHEMA#{' IF EXISTS' if [:if_exists]} #{quote_schema_name(schema_name.to_s)} CASCADE" end |
#drop_table(table_name, options = {}) ⇒ Object
:nodoc:
37 38 39 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 37 def drop_table(table_name, = {}) # :nodoc: execute "DROP TABLE#{' IF EXISTS' if [:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if [:force] == :cascade}" end |
#encoding ⇒ Object
Get encoding of database
109 110 111 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 109 def encoding query_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = #{quote(current_database)}", "SCHEMA") end |
#index_name_exists?(table_name, index_name) ⇒ Boolean
Verifies existence of an index with a given name.
47 48 49 50 51 52 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 47 def index_name_exists?(table_name, index_name) available_indexes = execute(<<~SQL, "SCHEMA") SHOW INDEXES FROM #{quote_table_name(table_name)} SQL available_indexes.map { |c| c['key_name'] }.include? index_name.to_s end |
#indexes(table_name) ⇒ Object
Returns an array of indexes for the given table.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 55 def indexes(table_name) # :nodoc: available_indexes = execute(<<~SQL, "SCHEMA") SHOW INDEXES FROM #{quote_table_name(table_name)} SQL available_indexes.group_by { |c| c['key_name'] }.map do |k, v| index_name = k IndexDefinition.new( table_name, index_name, unique = false, columns = v.map { |c| c['column_name'] }, lengths: {}, orders: {}, opclasses: {}, where: nil, type: nil, using: nil, comment: nil ) end end |
#primary_keys(table_name) ⇒ Object
Primary keys - approximation
156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 156 def primary_keys(table_name) # :nodoc: available_indexes = execute(<<~SQL, "SCHEMA").group_by { |c| c['key_name'] } SHOW INDEXES FROM #{quote_table_name(table_name)} SQL possible_primary = available_indexes.keys.select { |c| c.include? "primary_idx" } if possible_primary.size == 1 available_indexes[possible_primary.first].map { |c| c['column_name'] } else [] end end |
#recreate_database(name, options = {}) ⇒ Object
Drops the database specified on the name
attribute and creates it again using the provided options
.
9 10 11 12 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 9 def recreate_database(name, = {}) #:nodoc: drop_database(name) create_database(name, ) end |
#remove_index(table_name, options = {}) ⇒ Object
:nodoc:
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 219 def remove_index(table_name, = {}) #:nodoc: table = Utils.extract_schema_qualified_name(table_name.to_s) if .is_a?(Hash) && .key?(:name) provided_index = Utils.extract_schema_qualified_name([:name].to_s) [:name] = provided_index.identifier table = Materialize::Name.new(provided_index.schema, table.identifier) unless table.schema.present? if provided_index.schema.present? && table.schema != provided_index.schema raise ArgumentError.new("Index schema '#{provided_index.schema}' does not match table schema '#{table.schema}'") end end index_to_remove = Materialize::Name.new(table.schema, index_name_for_remove(table.to_s, )) algorithm = if .is_a?(Hash) && .key?(:algorithm) index_algorithms.fetch([:algorithm]) do raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}") end end execute "DROP INDEX #{algorithm} #{quote_table_name(index_to_remove)}" end |
#rename_column(table_name, column_name, new_column_name) ⇒ Object
208 209 210 211 212 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 208 def rename_column(table_name, column_name, new_column_name) #:nodoc: clear_cache! execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}" rename_column_indexes(table_name, column_name, new_column_name) end |
#rename_index(table_name, old_name, new_name) ⇒ Object
Renames an index of a table. Raises error if length of new index name is greater than allowed limit.
245 246 247 248 249 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 245 def rename_index(table_name, old_name, new_name) validate_index_length!(table_name, new_name) execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}" end |
#rename_table(table_name, new_name) ⇒ Object
Renames a table with index references
169 170 171 172 173 174 175 176 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 169 def rename_table(table_name, new_name) clear_cache! execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}" if index_name_exists?(new_name, "#{table_name}_primary_idx") rename_index(new_name, "#{table_name}_primary_idx", "#{new_name}_primary_idx") end rename_table_indexes(table_name, new_name) end |
#schema_exists?(name) ⇒ Boolean
Returns true if schema exists.
42 43 44 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 42 def schema_exists?(name) schema_names.include? name.to_s end |
#schema_names ⇒ Object
Returns an array of schema names.
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 124 def schema_names query_values(<<~SQL, "SCHEMA") SELECT s.name FROM mz_schemas s LEFT JOIN mz_databases d ON s.database_id = d.id WHERE d.name = #{quote(current_database)} SQL end |
#schema_search_path ⇒ Object
Returns the active schema search path.
146 147 148 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 146 def schema_search_path @schema_search_path ||= query_value("SHOW search_path", "SCHEMA") end |
#table_comment(table_name) ⇒ Object
Returns a comment stored in database for given table
84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 84 def table_comment(table_name) # :nodoc: scope = quoted_scope(table_name, type: "BASE TABLE") if scope[:name] query_value(<<~SQL, "SCHEMA") SELECT pg_catalog.obj_description(c.oid, 'pg_class') FROM pg_catalog.pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = #{scope[:name]} AND c.relkind IN (#{scope[:type]}) AND n.nspname = #{scope[:schema]} SQL end end |
#table_options(table_name) ⇒ Object
:nodoc:
77 78 79 80 81 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 77 def (table_name) # :nodoc: if comment = table_comment(table_name) { comment: comment } end end |
#type_to_sql(type, limit: nil, precision: nil, scale: nil) ⇒ Object
Maps logical Rails types to Materialize-specific data types.
252 253 254 255 256 257 258 259 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 252 def type_to_sql(type, limit: nil, precision: nil, scale: nil, **) # :nodoc: type = type.to_sym if type if native = native_database_types[type] (native.is_a?(Hash) ? native[:name] : native).dup else type.to_s end end |
#update_table_definition(table_name, base) ⇒ Object
:nodoc:
277 278 279 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 277 def update_table_definition(table_name, base) # :nodoc: Materialize::Table.new(table_name, base) end |
#validate_constraint(table_name, constraint_name) ⇒ Object
Validates the given constraint.
Validates the constraint named constraint_name
on accounts
.
validate_constraint :accounts, :constraint_name
290 291 292 293 294 295 296 297 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 290 def validate_constraint(table_name, constraint_name) return unless supports_validate_constraints? at = create_alter_table table_name at.validate_constraint constraint_name execute schema_creation.accept(at) end |
#validate_foreign_key(from_table, to_table = nil, **options) ⇒ Object
Validates the given foreign key.
Validates the foreign key on accounts.branch_id
.
validate_foreign_key :accounts, :branches
Validates the foreign key on accounts.owner_id
.
validate_foreign_key :accounts, column: :owner_id
Validates the foreign key named special_fk_name
on the accounts
table.
validate_foreign_key :accounts, name: :special_fk_name
The options
hash accepts the same keys as SchemaStatements#add_foreign_key.
314 315 316 317 318 319 320 |
# File 'lib/active_record/connection_adapters/materialize/schema_statements.rb', line 314 def validate_foreign_key(from_table, to_table = nil, **) return unless supports_validate_constraints? fk_name_to_validate = foreign_key_for!(from_table, to_table: to_table, **).name validate_constraint from_table, fk_name_to_validate end |