Module: Checkpoint::DB

Defined in:
lib/checkpoint/db.rb,
lib/checkpoint/db/grant.rb,
lib/checkpoint/db/params.rb,
lib/checkpoint/db/query/ac.rb,
lib/checkpoint/db/query/ar.rb,
lib/checkpoint/db/query/cr.rb,
lib/checkpoint/db/query/acr.rb,
lib/checkpoint/db/cartesian_select.rb

Overview

Module for everything related to the Checkpoint database.

Defined Under Namespace

Modules: Query Classes: CartesianSelect, DatabaseError, Grant, Params

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.



163
164
165
# File 'lib/checkpoint/db.rb', line 163

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

.configObject



144
145
146
147
148
# File 'lib/checkpoint/db.rb', line 144

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

.conn_optsObject



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

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}


79
80
81
82
83
84
85
86
87
# File 'lib/checkpoint/db.rb', line 79

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)


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

def connected?
  !@db.nil?
end

.dbSequel::Database

The Checkpoint database

Returns:

  • (Sequel::Database)

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

Raises:



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

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

.dump_schema!Object



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

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.



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/checkpoint/db.rb', line 44

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



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

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



125
126
127
128
129
# File 'lib/checkpoint/db.rb', line 125

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.



91
92
93
94
95
# File 'lib/checkpoint/db.rb', line 91

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

.model_filesObject



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

def model_files
  [
    'db/grant'
  ]
end

.schema_fileObject



101
102
103
# File 'lib/checkpoint/db.rb', line 101

def schema_file
  'db/checkpoint.yml'
end

.schema_tableObject



97
98
99
# File 'lib/checkpoint/db.rb', line 97

def schema_table
  :checkpoint_schema
end