Module: ClickhouseRuby::ActiveRecord::SchemaStatements
- Included in:
- ConnectionAdapter
- Defined in:
- lib/clickhouse_ruby/active_record/schema_statements.rb
Overview
ClickHouse schema operations differ significantly from traditional RDBMS:
-
Tables require ENGINE specification (MergeTree, etc.)
-
No SERIAL/AUTO_INCREMENT (use generateUUIDv4() or application-side IDs)
-
No ALTER TABLE ADD COLUMN migrations (use ALTER TABLE ADD COLUMN)
-
Indexes are defined at table creation time
Schema introspection and manipulation methods for ClickHouse
Provides methods to query and modify database schema through ClickHouse’s system tables (system.tables, system.columns, etc.)
Instance Method Summary collapse
-
#add_column(table_name, column_name, type, **options) ⇒ void
Add a column to a table.
-
#add_index(table_name, column_name, **options) ⇒ void
Add an index to a table ClickHouse uses data skipping indexes (minmax, set, bloom_filter, etc.).
-
#change_column(table_name, column_name, type, **options) ⇒ void
Change a column’s type.
-
#column_exists?(table_name, column_name, type = nil, **options) ⇒ Boolean
Check if a column exists.
-
#columns(table_name) ⇒ Array<Column>
Returns list of columns for a table.
-
#create_database(database_name, **options) ⇒ void
Create a database.
-
#create_table(table_name, **options) {|TableDefinition| ... } ⇒ void
Create a new table.
-
#current_database ⇒ String
Get the current database name.
-
#databases ⇒ Array<String>
List all databases.
-
#drop_database(database_name, **options) ⇒ void
Drop a database.
-
#drop_table(table_name, **options) ⇒ void
Drop a table.
-
#index_exists?(table_name, index_name) ⇒ Boolean
Check if an index exists.
-
#indexes(table_name) ⇒ Array<Hash>
Returns list of indexes for a table.
-
#primary_keys(table_name) ⇒ Array<String>?
Returns the primary key columns for a table.
-
#remove_column(table_name, column_name, _type = nil, **_options) ⇒ void
Remove a column from a table.
-
#remove_index(table_name, options_or_column = nil, **options) ⇒ void
Remove an index from a table.
-
#rename_column(table_name, old_name, new_name) ⇒ void
Rename a column.
-
#rename_table(old_name, new_name) ⇒ void
Rename a table.
-
#table_exists?(table_name) ⇒ Boolean
Check if a table exists.
-
#tables ⇒ Array<String>
Returns list of tables in the current database.
-
#truncate_table(table_name, **_options) ⇒ void
Truncate a table (delete all data).
-
#view_exists?(view_name) ⇒ Boolean
Check if a view exists.
-
#views ⇒ Array<String>
Returns list of views in the current database.
Instance Method Details
#add_column(table_name, column_name, type, **options) ⇒ void
This method returns an undefined value.
Add a column to a table
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 231 def add_column(table_name, column_name, type, **) sql_type = type_to_sql(type, **) # Handle nullable sql_type = "Nullable(#{sql_type})" if [:null] != false && !sql_type.match?(/^Nullable/i) sql = "ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{sql_type}" # Add AFTER clause if specified sql += " AFTER #{quote_column_name(options[:after])}" if [:after] # Add DEFAULT if specified sql += " DEFAULT #{quote(options[:default])}" if .key?(:default) execute(sql, "ADD COLUMN") end |
#add_index(table_name, column_name, **options) ⇒ void
This method returns an undefined value.
Add an index to a table ClickHouse uses data skipping indexes (minmax, set, bloom_filter, etc.)
305 306 307 308 309 310 311 312 313 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 305 def add_index(table_name, column_name, **) columns = Array(column_name).map { |c| quote_column_name(c) }.join(", ") index_name = [:name] || "idx_#{Array(column_name).join("_")}" index_type = [:type] || "minmax" granularity = [:granularity] || 1 sql = "ALTER TABLE #{quote_table_name(table_name)} ADD INDEX #{quote_column_name(index_name)} (#{columns}) TYPE #{index_type} GRANULARITY #{granularity}" execute(sql, "ADD INDEX") end |
#change_column(table_name, column_name, type, **options) ⇒ void
This method returns an undefined value.
Change a column’s type
280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 280 def change_column(table_name, column_name, type, **) sql_type = type_to_sql(type, **) # Handle nullable sql_type = "Nullable(#{sql_type})" if [:null] != false && !sql_type.match?(/^Nullable/i) sql = "ALTER TABLE #{quote_table_name(table_name)} MODIFY COLUMN #{quote_column_name(column_name)} #{sql_type}" # Add DEFAULT if specified sql += " DEFAULT #{quote(options[:default])}" if .key?(:default) execute(sql, "MODIFY COLUMN") end |
#column_exists?(table_name, column_name, type = nil, **options) ⇒ Boolean
Check if a column exists
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 358 def column_exists?(table_name, column_name, type = nil, **) sql = " SELECT type\n FROM system.columns\n WHERE database = currentDatabase()\n AND table = '\#{quote_string(table_name.to_s)}'\n AND name = '\#{quote_string(column_name.to_s)}'\n LIMIT 1\n SQL\n\n result = execute(sql, \"SCHEMA\")\n return false if result.empty?\n\n if type\n # Check if type matches\n column_type = result.first[\"type\"]\n expected_type = type_to_sql(type, **options)\n column_type.downcase.include?(expected_type.downcase)\n else\n true\n end\nend\n" |
#columns(table_name) ⇒ Array<Column>
Returns list of columns for a table
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 116 def columns(table_name) sql = " SELECT\n name,\n type,\n default_kind,\n default_expression,\n comment,\n is_in_primary_key,\n is_in_sorting_key,\n is_in_partition_key\n FROM system.columns\n WHERE database = currentDatabase()\n AND table = '\#{quote_string(table_name.to_s)}'\n ORDER BY position\n SQL\n\n result = execute(sql, \"SCHEMA\")\n result.map do |row|\n new_column(\n row[\"name\"],\n row[\"default_expression\"],\n fetch_type_metadata(row[\"type\"]),\n row[\"type\"] =~ /^Nullable/i,\n row[\"comment\"],\n )\n end\nend\n" |
#create_database(database_name, **options) ⇒ void
This method returns an undefined value.
Create a database
404 405 406 407 408 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 404 def create_database(database_name, **) if_not_exists = .fetch(:if_not_exists, false) sql = "CREATE DATABASE #{if_not_exists ? "IF NOT EXISTS " : ""}`#{database_name}`" execute(sql, "CREATE DATABASE") end |
#create_table(table_name, **options) {|TableDefinition| ... } ⇒ void
This method returns an undefined value.
Create a new table
176 177 178 179 180 181 182 183 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 176 def create_table(table_name, **) td = create_table_definition(table_name, **) yield td if block_given? sql = schema_creation.accept(td) execute(sql, "CREATE TABLE") end |
#current_database ⇒ String
Get the current database name
384 385 386 387 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 384 def current_database result = execute("SELECT currentDatabase() AS db", "SCHEMA") result.first["db"] end |
#databases ⇒ Array<String>
List all databases
392 393 394 395 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 392 def databases result = execute("SELECT name FROM system.databases ORDER BY name", "SCHEMA") result.map { |row| row["name"] } end |
#drop_database(database_name, **options) ⇒ void
This method returns an undefined value.
Drop a database
417 418 419 420 421 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 417 def drop_database(database_name, **) if_exists = .fetch(:if_exists, false) sql = "DROP DATABASE #{if_exists ? "IF EXISTS " : ""}`#{database_name}`" execute(sql, "DROP DATABASE") end |
#drop_table(table_name, **options) ⇒ void
This method returns an undefined value.
Drop a table
192 193 194 195 196 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 192 def drop_table(table_name, **) if_exists = .fetch(:if_exists, false) sql = "DROP TABLE #{if_exists ? "IF EXISTS " : ""}#{quote_table_name(table_name)}" execute(sql, "DROP TABLE") end |
#index_exists?(table_name, index_name) ⇒ Boolean
Check if an index exists
339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 339 def index_exists?(table_name, index_name) sql = " SELECT 1\n FROM system.data_skipping_indices\n WHERE database = currentDatabase()\n AND table = '\#{quote_string(table_name.to_s)}'\n AND name = '\#{quote_string(index_name.to_s)}'\n LIMIT 1\n SQL\n\n result = execute(sql, \"SCHEMA\")\n result.any?\nend\n" |
#indexes(table_name) ⇒ Array<Hash>
Returns list of indexes for a table
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 88 def indexes(table_name) sql = " SELECT\n name,\n type,\n expr,\n granularity\n FROM system.data_skipping_indices\n WHERE database = currentDatabase()\n AND table = '\#{quote_string(table_name.to_s)}'\n ORDER BY name\n SQL\n\n result = execute(sql, \"SCHEMA\")\n result.map do |row|\n {\n name: row[\"name\"],\n type: row[\"type\"],\n expression: row[\"expr\"],\n granularity: row[\"granularity\"],\n }\n end\nend\n" |
#primary_keys(table_name) ⇒ Array<String>?
Returns the primary key columns for a table
149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 149 def primary_keys(table_name) sql = " SELECT name\n FROM system.columns\n WHERE database = currentDatabase()\n AND table = '\#{quote_string(table_name.to_s)}'\n AND is_in_primary_key = 1\n ORDER BY position\n SQL\n\n result = execute(sql, \"SCHEMA\")\n keys = result.map { |row| row[\"name\"] }\n keys.empty? ? nil : keys\nend\n" |
#remove_column(table_name, column_name, _type = nil, **_options) ⇒ void
This method returns an undefined value.
Remove a column from a table
255 256 257 258 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 255 def remove_column(table_name, column_name, _type = nil, **) sql = "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}" execute(sql, "DROP COLUMN") end |
#remove_index(table_name, options_or_column = nil, **options) ⇒ void
This method returns an undefined value.
Remove an index from a table
321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 321 def remove_index(table_name, = nil, **) index_name = if .is_a?(Hash) [:name] elsif [:name] [:name] else "idx_#{Array(options_or_column).join("_")}" end sql = "ALTER TABLE #{quote_table_name(table_name)} DROP INDEX #{quote_column_name(index_name)}" execute(sql, "DROP INDEX") end |
#rename_column(table_name, old_name, new_name) ⇒ void
This method returns an undefined value.
Rename a column
267 268 269 270 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 267 def rename_column(table_name, old_name, new_name) sql = "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(old_name)} TO #{quote_column_name(new_name)}" execute(sql, "RENAME COLUMN") end |
#rename_table(old_name, new_name) ⇒ void
This method returns an undefined value.
Rename a table
204 205 206 207 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 204 def rename_table(old_name, new_name) sql = "RENAME TABLE #{quote_table_name(old_name)} TO #{quote_table_name(new_name)}" execute(sql, "RENAME TABLE") end |
#table_exists?(table_name) ⇒ Boolean
Check if a table exists
53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 53 def table_exists?(table_name) sql = " SELECT 1\n FROM system.tables\n WHERE database = currentDatabase()\n AND name = '\#{quote_string(table_name.to_s)}'\n LIMIT 1\n SQL\n\n result = execute(sql, \"SCHEMA\")\n result.any?\nend\n" |
#tables ⇒ Array<String>
Returns list of tables in the current database
20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 20 def tables sql = " SELECT name\n FROM system.tables\n WHERE database = currentDatabase()\n AND engine NOT IN ('View', 'MaterializedView', 'LiveView')\n ORDER BY name\n SQL\n\n result = execute(sql, \"SCHEMA\")\n result.map { |row| row[\"name\"] }\nend\n" |
#truncate_table(table_name, **_options) ⇒ void
This method returns an undefined value.
Truncate a table (delete all data)
215 216 217 218 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 215 def truncate_table(table_name, **) sql = "TRUNCATE TABLE #{quote_table_name(table_name)}" execute(sql, "TRUNCATE TABLE") end |
#view_exists?(view_name) ⇒ Boolean
Check if a view exists
70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 70 def view_exists?(view_name) sql = " SELECT 1\n FROM system.tables\n WHERE database = currentDatabase()\n AND name = '\#{quote_string(view_name.to_s)}'\n AND engine IN ('View', 'MaterializedView', 'LiveView')\n LIMIT 1\n SQL\n\n result = execute(sql, \"SCHEMA\")\n result.any?\nend\n" |
#views ⇒ Array<String>
Returns list of views in the current database
36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/clickhouse_ruby/active_record/schema_statements.rb', line 36 def views sql = " SELECT name\n FROM system.tables\n WHERE database = currentDatabase()\n AND engine IN ('View', 'MaterializedView', 'LiveView')\n ORDER BY name\n SQL\n\n result = execute(sql, \"SCHEMA\")\n result.map { |row| row[\"name\"] }\nend\n" |