Class: HTM::Database

Inherits:
Object
  • Object
show all
Defined in:
lib/htm/database.rb

Overview

Database setup and configuration for HTM Handles schema creation and database initialization using Sequel

Class Method Summary collapse

Class Method Details

.default_configHash?

Get default database configuration

Uses HTM::Config for database settings.

Returns:

  • (Hash, nil)

    Connection configuration hash with PG-style keys



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/htm/database.rb', line 325

def default_config
  htm_config = HTM.config

  if htm_config.database_configured?
    db_config = htm_config.database_config

    # Convert to PG-style keys
    {
      host: db_config[:host],
      port: db_config[:port],
      dbname: db_config[:database],
      user: db_config[:username],
      password: db_config[:password],
      sslmode: db_config[:sslmode] || 'prefer'
    }
  elsif ENV['HTM_DATABASE__URL']
    parse_connection_url(ENV['HTM_DATABASE__URL'])
  elsif ENV['HTM_DATABASE__NAME']
    parse_connection_params
  end
end

.drop(db_url = nil) ⇒ void

This method returns an undefined value.

Drop all HTM tables (respects RAILS_ENV)

Parameters:

  • db_url (String) (defaults to: nil)

    Database connection URL (uses default_config if not provided)



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/htm/database.rb', line 84

def drop(db_url = nil)
  config = db_url ? parse_connection_url(db_url) : default_config
  raise "Database configuration not found" unless config

  puts "Environment: #{HTM.env}"
  puts "Database: #{config[:dbname]}"

  conn = PG.connect(config)

  tables = %w[nodes node_tags tags robots robot_nodes file_sources schema_migrations]

  puts "Dropping HTM tables..."
  tables.each do |table|
    conn.exec("DROP TABLE IF EXISTS #{table} CASCADE")
    puts "  Dropped #{table}"
  rescue PG::Error => e
    puts "  Error dropping #{table}: #{e.message}"
  end

  # Drop functions and triggers
  begin
    conn.exec("DROP FUNCTION IF EXISTS extract_ontology_topics() CASCADE")
    puts "  Dropped ontology functions and triggers"
  rescue PG::Error => e
    puts "  Error dropping functions: #{e.message}"
  end

  # Drop views
  begin
    conn.exec("DROP VIEW IF EXISTS ontology_structure CASCADE")
    conn.exec("DROP VIEW IF EXISTS topic_relationships CASCADE")
    puts "  Dropped ontology views"
  rescue PG::Error => e
    puts "  Error dropping views: #{e.message}"
  end

  conn.close
  puts "All HTM tables dropped"
end

.dump_schema(db_url = nil) ⇒ void

This method returns an undefined value.

Dump current database schema to db/schema.sql (respects RAILS_ENV)

Uses pg_dump to create a clean SQL schema file without data

Parameters:

  • db_url (String) (defaults to: nil)

    Database connection URL (uses default_config if not provided)



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/htm/database.rb', line 151

def dump_schema(db_url = nil)
  config = db_url ? parse_connection_url(db_url) : default_config
  raise "Database configuration not found" unless config

  schema_file = File.expand_path('../../db/schema.sql', __dir__)

  puts "Dumping schema to #{schema_file}..."

  env = {
    'PGPASSWORD' => config[:password]
  }

  cmd = [
    'pg_dump',
    '--schema-only',
    '--no-owner',
    '--no-privileges',
    '--no-tablespaces',
    '--exclude-schema=_timescaledb_*',
    '--exclude-schema=information_schema',
    '--exclude-schema=pg_catalog',
    '-h', config[:host],
    '-p', config[:port].to_s,
    '-U', config[:user],
    '-d', config[:dbname]
  ]

  require 'open3'
  stdout, stderr, status = Open3.capture3(env, *cmd)

  unless status.success?
    puts "Error dumping schema:"
    puts stderr
    exit 1
  end

  cleaned_schema = clean_schema_dump(stdout)
  File.write(schema_file, cleaned_schema)

  puts "Schema dumped successfully to #{schema_file}"
  puts "  Size: #{File.size(schema_file)} bytes"
end

.generate_docs(db_url = nil) ⇒ void

This method returns an undefined value.

Generate database documentation using tbls

Parameters:

  • db_url (String) (defaults to: nil)

    Database connection URL (uses ENV if not provided)



246
247
248
249
250
251
252
# File 'lib/htm/database.rb', line 246

def generate_docs(db_url = nil)
  check_tbls_installed!
  tbls_config = locate_tbls_config!
  dsn         = build_tbls_dsn(db_url)
  run_tbls_doc(tbls_config, dsn)
  print_tbls_doc_success
end

.info(db_url = nil) ⇒ void

This method returns an undefined value.

Show database info (respects RAILS_ENV)

Parameters:

  • db_url (String) (defaults to: nil)

    Database connection URL (uses default_config if not provided)



259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/htm/database.rb', line 259

def info(db_url = nil)
  config = db_url ? parse_connection_url(db_url) : default_config
  raise "Database configuration not found" unless config

  conn = PG.connect(config)
  puts "\nHTM Database Information (#{HTM.env})"
  puts "=" * 80
  print_connection_info(config)
  print_pg_version(conn)
  print_extensions_list(conn)
  print_table_counts(conn)
  print_db_size(conn, config[:dbname])
  conn.close
  puts "=" * 80
end

.load_schema(db_url = nil) ⇒ void

This method returns an undefined value.

Load schema from db/schema.sql (respects RAILS_ENV)

Uses psql to load the schema file

Parameters:

  • db_url (String) (defaults to: nil)

    Database connection URL (uses default_config if not provided)



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/htm/database.rb', line 201

def load_schema(db_url = nil)
  config = db_url ? parse_connection_url(db_url) : default_config
  raise "Database configuration not found" unless config

  schema_file = File.expand_path('../../db/schema.sql', __dir__)

  unless File.exist?(schema_file)
    puts "Schema file not found: #{schema_file}"
    puts "  Run 'rake htm:db:schema:dump' first to create it"
    exit 1
  end

  puts "Loading schema from #{schema_file}..."

  env = {
    'PGPASSWORD' => config[:password]
  }

  cmd = [
    'psql',
    '-h', config[:host],
    '-p', config[:port].to_s,
    '-U', config[:user],
    '-d', config[:dbname],
    '-f', schema_file,
    '--quiet'
  ]

  require 'open3'
  _, stderr, status = Open3.capture3(env, *cmd)

  unless status.success?
    puts "Error loading schema:"
    puts stderr
    exit 1
  end

  puts "Schema loaded successfully"
end

.migrate(db_url = nil) ⇒ void

This method returns an undefined value.

Run pending database migrations

Parameters:

  • db_url (String) (defaults to: nil)

    Database connection URL (uses ENV if not provided)



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/htm/database.rb', line 47

def migrate(db_url = nil)
  require 'sequel'
  require_relative 'sequel_config'

  # Establish Sequel connection (don't load models - tables may not exist)
  HTM::SequelConfig.establish_connection!(load_models: false)

  run_sequel_migrations

  # Load models now that tables exist
  HTM::SequelConfig.ensure_models_loaded!

  puts "Database migrations completed"
end

.migration_status(db_url = nil) ⇒ void

This method returns an undefined value.

Show migration status

Parameters:

  • db_url (String) (defaults to: nil)

    Database connection URL (uses ENV if not provided)



67
68
69
70
71
72
73
74
75
76
77
# File 'lib/htm/database.rb', line 67

def migration_status(db_url = nil)
  require 'sequel'
  require_relative 'sequel_config'

  HTM::SequelConfig.establish_connection!(load_models: false)

  available = load_available_migrations
  applied   = load_applied_versions

  print_migration_status_table(available, applied)
end

.parse_connection_paramsHash?

Build config from individual environment variables

Returns:

  • (Hash, nil)

    Connection configuration hash



306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/htm/database.rb', line 306

def parse_connection_params
  return nil unless ENV['HTM_DATABASE__NAME']

  {
    host: ENV['HTM_DATABASE__HOST'] || 'localhost',
    port: (ENV['HTM_DATABASE__PORT'] || 5432).to_i,
    dbname: ENV.fetch('HTM_DATABASE__NAME', nil),
    user: ENV.fetch('HTM_DATABASE__USER', nil),
    password: ENV.fetch('HTM_DATABASE__PASSWORD', nil),
    sslmode: ENV['HTM_DATABASE__SSLMODE'] || 'prefer'
  }
end

.parse_connection_url(url) ⇒ Hash?

Parse database connection URL

Parameters:

  • url (String)

    Connection URL (e.g., postgresql://user:pass@host:port/dbname)

Returns:

  • (Hash, nil)

    Connection configuration hash

Raises:

  • (ArgumentError)

    If URL format is invalid



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/htm/database.rb', line 281

def parse_connection_url(url)
  return nil unless url

  uri = URI.parse(url)
  validate_pg_uri!(uri)

  dbname = uri.path&.slice(1..-1)
  params = URI.decode_www_form(uri.query || '').to_h

  {
    host: uri.host,
    port: uri.port || 5432,
    dbname: dbname,
    user: uri.user,
    password: uri.password,
    sslmode: params['sslmode'] || 'prefer'
  }
rescue URI::InvalidURIError => e
  raise ArgumentError, "Invalid database URL format: #{e.message}"
end

.seed(db_url = nil) ⇒ void

This method returns an undefined value.

Seed database with sample data

Loads and executes db/seeds.rb file following Rails conventions.

Parameters:

  • db_url (String) (defaults to: nil)

    Database connection URL (uses ENV if not provided)



131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/htm/database.rb', line 131

def seed(db_url = nil)
  seeds_file = File.expand_path('../../db/seeds.rb', __dir__)

  unless File.exist?(seeds_file)
    puts "Error: Seeds file not found at #{seeds_file}"
    puts "  Please create db/seeds.rb with your seeding logic"
    exit 1
  end

  # Load and execute seeds.rb
  load seeds_file
end

.setup(db_url = nil, run_migrations: true, dump_schema: false) ⇒ void

This method returns an undefined value.

Set up the HTM database schema

Parameters:

  • db_url (String) (defaults to: nil)

    Database connection URL (uses ENV if not provided)

  • run_migrations (Boolean) (defaults to: true)

    Whether to run migrations (default: true)

  • dump_schema (Boolean) (defaults to: false)

    Whether to dump schema to db/schema.sql after setup (default: false)



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/htm/database.rb', line 18

def setup(db_url = nil, run_migrations: true, dump_schema: false)
  require 'sequel'
  require_relative 'sequel_config'

  # Establish Sequel connection (don't load models yet - tables may not exist)
  HTM::SequelConfig.establish_connection!(load_models: false)

  # Run migrations using Sequel
  if run_migrations
    puts "Running Sequel migrations..."
    run_sequel_migrations
  end

  # Now that tables exist, load models
  HTM::SequelConfig.ensure_models_loaded!

  puts "HTM database schema created successfully"

  # Optionally dump schema
  return unless dump_schema
  puts ""
  self.dump_schema(db_url)
end