Module: Checkpoint::DB

Defined in:
lib/checkpoint/db.rb,
lib/checkpoint/db/permit.rb

Overview

Module for everything related to the Checkpoint database.

Defined Under Namespace

Classes: DatabaseError, Permit

Constant Summary collapse

CONNECTION_ERROR =
'The Checkpoint database is not initialized. Call initialize! first.'
ALREADY_CONNECTED =
'Already connected; refusing to connect to another database.'
MISSING_CONFIG =
<<~MSG
  CHECKPOINT_DATABASE_URL and DATABASE_URL are both missing and a connection
  has not been configured. Cannot connect to the Checkpoint database.
  See Checkpoint::DB.connect! for help.
MSG
LOAD_ERROR =
<<~MSG
  Error loading Checkpoint database models.
  Verify connection information and that the database is migrated.
MSG
SCHEMA_HEADER =
"# Checkpoint Database Version\n"

Class Method Summary collapse

Class Method Details

.[](*args) ⇒ Object

Forward the Sequel::Database []-syntax down to db for convenience. Everything else must be called on db directly, but this is nice sugar.



156
157
158
# File 'lib/checkpoint/db.rb', line 156

def [](*args)
  db[*args]
end

.configObject



137
138
139
140
141
# File 'lib/checkpoint/db.rb', line 137

def config
  @config ||= OpenStruct.new(
    url: ENV['CHECKPOINT_DATABASE_URL'] || ENV['DATABASE_URL']
  )
end

.conn_optsObject



124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/checkpoint/db.rb', line 124

def conn_opts
  log = { logger: Logger.new('db/checkpoint.log') }
  url = config.url
  opts = config.opts
  if url
    [url, log]
  elsif opts
    [log.merge(opts)]
  else
    []
  end
end

.connect!(config = {}) ⇒ Sequel::Database

Connect to the Checkpoint database.

The default is to use the settings under config, but can be supplied here (and they will be merged into config as a side effect). The keys that will be used from either source are documented here as the options.

Only one “mode” will be used; the first of these supplied will take precedence:

  1. An already-connected Sequel::Database object

  2. A connection string

  3. A connection options hash

While Checkpoint serves as a singleton, this will raise a DatabaseError if already connected. Check ‘connected?` if you are unsure.

Parameters:

  • config (Hash) (defaults to: {})

    Optional connection config

Options Hash (config):

  • :url (String)

    A Sequel database URL

  • :opts (Hash)

    A set of connection options

  • :db (Sequel::Database)

    An already-connected database;

Returns:

  • (Sequel::Database)

    The initialized database connection

Raises:

See Also:

  • {Sequel{Sequel.connect}


72
73
74
75
76
77
78
79
80
# File 'lib/checkpoint/db.rb', line 72

def connect!(config = {})
  raise DatabaseError, ALREADY_CONNECTED if connected?
  merge_config!(config)
  raise DatabaseError, MISSING_CONFIG if self.config.db.nil? && conn_opts.empty?

  # We splat here because we might give one or two arguments depending
  # on whether we have a string or not; to add our logger regardless.
  @db = self.config.db || Sequel.connect(*conn_opts)
end

.connected?Boolean

Returns:

  • (Boolean)


143
144
145
# File 'lib/checkpoint/db.rb', line 143

def connected?
  !@db.nil?
end

.dbSequel::Database

The Checkpoint database

Returns:

  • (Sequel::Database)

    The connected database; be sure to call initialize! first.

Raises:



149
150
151
152
# File 'lib/checkpoint/db.rb', line 149

def db
  raise DatabaseError, CONNECTION_ERROR unless connected?
  @db
end

.dump_schema!Object



98
99
100
101
102
# File 'lib/checkpoint/db.rb', line 98

def dump_schema!
  connect! unless connected?
  version = db[schema_table].first.to_yaml
  File.write(schema_file, SCHEMA_HEADER + version)
end

.initialize!Object

Initialize Checkpoint

This connects to the database if it has not already happened and requires all of the Checkpoint model classes. It is required to do the connection setup first because of the design decision in Sequel that the schema is examined at the time of extending Sequel::Model.



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/checkpoint/db.rb', line 37

def initialize!
  connect! unless connected?
  begin
    model_files.each do |file|
      require_relative file
    end
  rescue Sequel::DatabaseError, NoMethodError => e
    raise DatabaseError, LOAD_ERROR + "\n" + e.message
  end
  db
end

.load_schema!Object



104
105
106
107
108
109
# File 'lib/checkpoint/db.rb', line 104

def load_schema!
  connect! unless connected?
  version = YAML.load_file(schema_file)[:version]
  db[schema_table].delete
  db[schema_table].insert(version: version)
end

.merge_config!(config = {}) ⇒ Object

Merge url, opts, or db settings from a hash into our config



118
119
120
121
122
# File 'lib/checkpoint/db.rb', line 118

def merge_config!(config = {})
  self.config.url  = config[:url]  if config.key?(:url)
  self.config.opts = config[:opts] if config.key?(:opts)
  self.config.db   = config[:db]   if config.key?(:db)
end

.migrate!Object

Run any pending migrations. This will connect with the current config if not already connected.



84
85
86
87
88
# File 'lib/checkpoint/db.rb', line 84

def migrate!
  connect! unless connected?
  Sequel.extension :migration
  Sequel::Migrator.run(db, File.join(__dir__, '../../db/migrations'), table: schema_table)
end

.model_filesObject



111
112
113
114
115
# File 'lib/checkpoint/db.rb', line 111

def model_files
  [
    'db/permit'
  ]
end

.schema_fileObject



94
95
96
# File 'lib/checkpoint/db.rb', line 94

def schema_file
  'db/checkpoint.yml'
end

.schema_tableObject



90
91
92
# File 'lib/checkpoint/db.rb', line 90

def schema_table
  :checkpoint_schema
end