Module: BetterAuth::Telemetry::Detectors::Database
- Defined in:
- lib/better_auth/telemetry/detectors/database.rb
Overview
Database detector. Returns a small hash describing the database backend the host application is using (or ‘nil` when no signal is available).
This is the Ruby-specific replacement for upstream’s ‘detect-database.ts`, which only walked the Node `package.json` for known SQL/ORM packages. The Ruby port adds two earlier precedence rules (a caller-supplied context override and a `BetterAuth::Configuration` adapter check) so an application with a configured Better Auth adapter does not fall through to the generic gem fallback.
## Precedence chain (Requirement 10)
-
**Context override** — when the caller supplied a non-empty ‘context.database` string, return it verbatim with `version: nil`. This is the upstream `context.database` seam.
-
**Configuration adapter** — when ‘options` is a Configuration (or a hash with a `:database` key) and the value is a known adapter symbol (ADAPTER_SYMBOLS) or a `BetterAuth::Adapters::*` instance (ADAPTER_CLASS_MAP), return its short identifier with `version: nil`.
-
**Gem fallback** — when neither rule above matches, walk ‘Gem.loaded_specs` in GEM_FALLBACKS order and return the first match as `<gem_name>, version: <spec.version.to_s>`.
-
Otherwise — ‘nil`.
## Failure handling
The whole call is wrapped in ‘rescue StandardError; nil` so a surprise from any branch (an exotic `context` shape, a `Configuration` reader that raises on a partially constructed instance, a `Gem.loaded_specs` mutation, …) degrades to `nil` rather than escaping out of the init payload composition in BetterAuth::Telemetry.create.
Constant Summary collapse
- ADAPTER_CLASS_MAP =
Map from ‘BetterAuth::Adapters::*` class name to the short identifier reported in the init event. Class names are matched as strings so loading the telemetry gem does not autoload every adapter constant.
{ "BetterAuth::Adapters::Postgres" => "postgres", "BetterAuth::Adapters::MySQL" => "mysql", "BetterAuth::Adapters::SQLite" => "sqlite", "BetterAuth::Adapters::MSSQL" => "mssql", "BetterAuth::Adapters::Memory" => "memory" }.freeze
- ADAPTER_SYMBOLS =
Map from a known Configuration#database symbol value to the short identifier reported in the init event.
{ postgres: "postgres", mysql: "mysql", sqlite: "sqlite", mssql: "mssql", memory: "memory" }.freeze
- GEM_FALLBACKS =
Gems to probe in ‘Gem.loaded_specs`, in upstream-spec order. First match wins.
%w[sequel pg mysql2 sqlite3 activerecord mongoid mongo rom-sql].freeze
Class Method Summary collapse
-
.call(options, context) ⇒ Hash{Symbol => String, nil}?
Resolve the database signal for the host application.
-
.configuration_database(options) ⇒ Object?
Read ‘database` from a Configuration or a raw hash.
-
.context_override(context) ⇒ String?
Read ‘database` from a NormalizedContext-like or hash-like context.
-
.detect_from_gems ⇒ Hash{Symbol => String}?
Walk GEM_FALLBACKS in order and return the first ‘Gem.loaded_specs` match as `version:`.
-
.identify_adapter(value) ⇒ String?
Map a known adapter symbol or a ‘BetterAuth::Adapters::*` instance to its short identifier.
-
.identify_from_options(options) ⇒ String?
Translate the configuration’s ‘database` value into a short identifier when it matches a known adapter symbol or a known `BetterAuth::Adapters::*` class.
Class Method Details
.call(options, context) ⇒ Hash{Symbol => String, nil}?
Resolve the database signal for the host application.
97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/better_auth/telemetry/detectors/database.rb', line 97 def call(, context) override = context_override(context) return {name: override, version: nil} if override identifier = () return {name: identifier, version: nil} if identifier detect_from_gems rescue nil end |
.configuration_database(options) ⇒ Object?
Read ‘database` from a Configuration or a raw hash. Returns `nil` for any other input shape.
150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/better_auth/telemetry/detectors/database.rb', line 150 def configuration_database() return nil if .nil? if defined?(::BetterAuth::Configuration) && .is_a?(::BetterAuth::Configuration) return .database end return [:database] || ["database"] if .is_a?(Hash) nil end |
.context_override(context) ⇒ String?
Read ‘database` from a NormalizedContext-like or hash-like context. Returns the raw string when present and non-empty, otherwise `nil`. Non-string values (e.g. a symbol set accidentally) are ignored to keep the wire shape stable.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/better_auth/telemetry/detectors/database.rb', line 116 def context_override(context) return nil if context.nil? value = if context.respond_to?(:database) context.database elsif context.respond_to?(:[]) context[:database] || context["database"] end return nil unless value.is_a?(String) return nil if value.empty? value end |
.detect_from_gems ⇒ Hash{Symbol => String}?
Walk GEM_FALLBACKS in order and return the first ‘Gem.loaded_specs` match as `version:`. Returns `nil` when no listed gem is loaded.
181 182 183 184 185 186 187 188 189 190 |
# File 'lib/better_auth/telemetry/detectors/database.rb', line 181 def detect_from_gems GEM_FALLBACKS.each do |name| spec = ::Gem.loaded_specs[name] next if spec.nil? version = spec.respond_to?(:version) ? spec.version : nil return {name: name, version: version&.to_s} end nil end |
.identify_adapter(value) ⇒ String?
Map a known adapter symbol or a ‘BetterAuth::Adapters::*` instance to its short identifier. Returns `nil` when the value is neither a known symbol nor a known adapter class.
168 169 170 171 172 173 174 |
# File 'lib/better_auth/telemetry/detectors/database.rb', line 168 def identify_adapter(value) if value.is_a?(Symbol) return ADAPTER_SYMBOLS[value] end ADAPTER_CLASS_MAP[value.class.name] end |
.identify_from_options(options) ⇒ String?
Translate the configuration’s ‘database` value into a short identifier when it matches a known adapter symbol or a known `BetterAuth::Adapters::*` class.
138 139 140 141 142 143 |
# File 'lib/better_auth/telemetry/detectors/database.rb', line 138 def () database = configuration_database() return nil if database.nil? identify_adapter(database) end |