Class: ActiveRecord::Tasks::VirgodbDatabaseTasks

Inherits:
SQLiteDatabaseTasks
  • Object
show all
Defined in:
lib/active_record/tasks/virgodb_database_tasks.rb

Overview

ActiveRecord::Tasks::SQLiteDatabaseTasks#structure_dump just shells out to the real sqlite3 CLI (.schema --nosys, or a raw SELECT sql FROM sqlite_master when a host app has any ActiveRecord::SchemaDumper.ignore_tables configured -- e.g. excluding tables owned by a separate replication/backup mechanism) against the configured database file -- DDL only. ActiveRecord::Tasks::DatabaseTasks.dump_schema then special-cases exactly one table on top of that: if schema_migrations exists, it appends that table's real row data (connection .dump_schema_versions) to the same dump file, because Rails' own migration bookkeeping needs those rows to survive a db:schema:load/ structure_load, not just the table shape.

schema_versions (this adapter's own bookkeeping table, plural, distinct from Rails' singular schema_migrations) needs exactly the same treatment and doesn't get it for free: it holds real data (the versioned column list compact::schema_from_columns on the Rust side depends on), not just structure, and Rails has no way to know that a table it didn't create needs the same row-preserving special case. Confirmed empirically: without this, a fresh database prepared via structure_load (which Rails does automatically whenever a db:migrate invocation for a later environment/connection finds an existing, version-matching dump already on disk from an earlier one -- not something this adapter can opt out of) ends up with the real host-app table but an EMPTY schema_versions, so Manifest::current_schema_version() on the Rust side returns None even though the SQLite table itself is correct.

Constant Summary collapse

DEFAULT_DATA_DIR_PROVIDER =
lambda do |sql_table_name|
  Rails.root.join("storage", "#{Rails.env}_virgodb_#{sql_table_name}_data").to_s
end

Class Attribute Summary collapse

Instance Method Summary collapse

Class Attribute Details

.data_dir_providerObject

Optional host-app hook: ->(sql_table_name) { path_or_nil }. Convention over configuration, not opt-in like table_layout_provider above: this gem is Rails-specific (see the class doc comment above -- "Lets any Rails app..."), so it bakes in the same convention Rails' own generators use for SQLite's storage location (config/database.yml's generated storage/#{Rails.env}.sqlite3) -- storage/#{Rails.env}_virgodb_#{sql_table_name}_data, right next to the manifest. A host app gets working data-dir cleanup with zero setup. One with its own directory convention calls data_dir_provider = to override; = nil opts every table out entirely, same as plain SQLiteDatabaseTasks -- distinguished from "never touched this accessor" via defined? below so an explicit opt-out can't be silently overridden by the default.



63
64
65
# File 'lib/active_record/tasks/virgodb_database_tasks.rb', line 63

def data_dir_provider
  defined?(@data_dir_provider) ? @data_dir_provider : DEFAULT_DATA_DIR_PROVIDER
end

.table_layout_providerObject

Optional host-app hook: ->(sql_table_name) { {sort_by:, key_column:, partition_column:} or nil }. Purely a documentation comment written above CREATE TABLE at dump time -- nothing on the Rust or Ruby side ever reads it back. This adapter gem stays host-app-agnostic (see the class doc comment above: "lets any Rails app..."), so it can't hardcode any one host app's sort_by/key_column config (that's app/services/virgodb/registry.rb's job, which already has this exact data for real -- passed to Virgodb.start_maintenance on every boot). A host app that wants it surfaced sets this once, e.g. in an initializer; left nil, structure_dump behaves exactly as before.



48
49
50
# File 'lib/active_record/tasks/virgodb_database_tasks.rb', line 48

def table_layout_provider
  @table_layout_provider
end

Instance Method Details

#dropObject

Overridden (not just inherited from SQLiteDatabaseTasks) so dropping the manifest also cleans up whatever data_dir_provider says each of its tables' physical files live under. db:drop only ever knew about the ONE file database.yml declares -- left alone, it silently orphans every Parquet run file and Tier 1 inline-batch pointer file forever, since there's no catalog left afterward to even reference them (compact::vacuum, which cleans those up via the manifest's own orphaned_files table, can't reach them either once the manifest's gone).

Reads which tables exist via a fresh, read-only, raw SQLite3 connection (not connection/ActiveRecord::Base.lease_connection -- unlike structure_dump, drop doesn't establish one for this specific db_config, and this shouldn't depend on whatever happens to be currently leased) BEFORE calling super, since super deletes the manifest file -- schema_versions goes with it.



96
97
98
99
100
101
102
103
104
# File 'lib/active_record/tasks/virgodb_database_tasks.rb', line 96

def drop
  provider = self.class.data_dir_provider
  table_names = provider ? table_names_for_data_dir_cleanup : []
  super
  table_names.each do |table_name|
    dir = provider.call(table_name)
    FileUtils.rm_rf(dir) if dir
  end
end

#structure_dump(filename, extra_flags) ⇒ Object



73
74
75
76
77
78
# File 'lib/active_record/tasks/virgodb_database_tasks.rb', line 73

def structure_dump(filename, extra_flags)
  super
  reformat_create_table_statements!(filename)
  annotate_physical_layout!(filename)
  dump_schema_versions!(filename)
end